Cannot deploy kivy app with RstDocument - python

I have a problem deploying a Kivy application using RstDocument. It works fine on PC. I can deploy it if I use Label instead of RstDocument, but it stops in the latter case.
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen
import configparser
class MainFrame(Screen):
def __init__(self, **kwargs):
super(MainFrame, self).__init__(**kwargs)
pass
def on_quit_button_click(self):
quit()
class BasicApp(App):
def build(self):
return MainFrame()
pass
if __name__ == '__main__':
BasicApp().run()
with the following basic.kv
<MainFrame>:
BoxLayout:
RstDocument:
#Label:
text: 'Hello *world*!'
Button:
text: 'Click to quit'
on_press: root.on_quit_button_click()
Nothing significant in logcat, just
WindowManager: finishDrawingWindow: Window{bf4383ed0 u0 Application Error: testrstdocument.testrstdocument} mDrawState=HAS_DRAWN

Buildozer.spec
I am able to run a Kivy App with rstDocument on an Acer Android tablet by adding docutils into buildozer's requirement.
requirements = kivy, configparser, docutils

Related

Python kivy on android with hardware barcode scanner

I have a project where I need to integrate a hardware barcode scanner built into an Android Barcode scanning Device (Cipherlab). My app is built and the only part outstanding is reading the barcode. The barcodes are terminated by an enter keycode. The enter keys are being detected but the rest of the barcode does not display in the textinput which has focus.
I have tested the scanner in a text editor and it's not that. So it looks like the text is being scanned in the app as the enter keycode triggers the on_text_validate event.
Any ideas would be greatly appreciated.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string('''
<MainScreen>:
text_in: text_in
memberStatus: memberStatus
BoxLayout:
orientation: 'vertical'
Label:
id: memberStatus
TextInput:
id: text_in
multiline: False
on_text_validate:
root.process_barcode()
''')
class MainScreen(Screen):
def process_barcode(self):
self.memberStatus.text = "Read Value:"+ self.text_in.text
self.text_in.text = ""
Clock.schedule_once(lambda *args: setattr(self.text_in, 'focus', True))
def on_enter(self):
self.memberStatus.text = "Text Input has focus"
Clock.schedule_once(lambda *args: setattr(self.text_in, 'focus', True))
class MyApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainScreen(name="screen_main"))
return sm
if __name__ == '__main__':
MyApp().run()

How to make kivy app from different py files

I am trying to make an app out of different .py files. But I don't know how to add them together, I have one main file, and one login file with plans to add a lot more, but with these I'm experimenting right now. They are pretty basic for now until I figure out this "bonding" between them and then I will start adding some more complex stuff. I tried couple of things and they didn't work, but I left them in code for you to see (I tried to make the app to start with MainWindow, and on press of the first button it goes to login page*). Here's the code and please help me.
*Right now when I press the button it gives me this error: OSError: exception: access violation writing 0x0000000080006010
this is main.py:
from kivy.lang import Builder
from kivy.app import App
import login
from kivy.uix.screenmanager import Screen
kv = Builder.load_string('''
<MainWindow>:
GridLayout:
cols:1
GridLayout:
rows:5
Button:
text:"NOVA ROBA"
on_release:
root.call_login()
Button:
text:"KUPCI"
Button:
text:"PRODATO"
Button:
text: "AGRONOMI"
Button:
text: "STANJE U MAGACINU"
''')
class MainWindow(Screen):
def call_login(self):
login.app().run()
pass
class main_app(App):
def build(self):
return MainWindow()
if __name__ == '__main__':
main_app().run()
this is login.py:
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.app import App
class Login(Screen, App):
def build(self):
return
pass
kv = Builder.load_string('''
<Login>:
name:"login"
GridLayout:
rows:2
GridLayout:
cols:2
Label:
text:"Password: "
TextInput:
id:passwd
multiline: False
Button:
text: "Submit"
on_release:
passwd.text = ""
''')
class app(App):
def build(self):
return Login()
if __name__ == "__main__":
app().run()
You are creating 2 apps, which is not needed. Instead of inheriting from both Screen and App in the Loginscreen, inherit only from Screen. Then create a ScreenManager in your main.py's build method and then add the imported loginscreen as a widget, to switch to the new screen, use self.manager.current = "login" in the call_login method of MainWindow
class app(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainWindow())
sm.add_widget(Login())
return sm

How to run kivy and flask apps together?

I have a flask app serving as a server and I have a kivy app serving as a front end to a server. How can I run flask and then kivy app so they work together at the same time?
Flask app:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello'
if __name__ == "__main__":
app.run()
Kivy app:
from kivy.app import App
from kivy.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
kivy.require('1.10.0')
Builder.load_file('kivy.kv')
sm = ScreenManager()
class MainScreen(Screen)
pass
class OtherScreen(Screen)
pass
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class MyApp(App):
def build(self):
return sm
MyApp().run()
Update:
If someone is having problems implementing a webserver with apache, try docker, simpler and faster solution, in my opinion!
I wanted Flask to run continuously. I tried the proposed solution to run them together as threads as suggested by #amanb. I found out Flask is blocking Kivy and vice versa no matter the timing or how arranged are the threads. The reason being the interpreter's GIL. Therefore I tried with processes and it seems it does the work.
CODE
#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-
# kivy modules first, if not Kivy may cause problems
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
kivy.require('1.10.0')
# common modules
import sys
import signal
from multiprocessing import Process
# Flask & similar modules
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
import eventlet
from eventlet import wsgi
# async server setup
app = Flask(__name__)
api = Api(app)
def start_Flask():
print("Starting server...")
# start an eventlet WSGI server on port 5000
wsgi.server(eventlet.listen(('', 5000)), app)
def signal_handler(signal, frame):
# for fetching CTRL+C and relatives
print " CTRL + C detected, exiting ... "
exit(1)
# Kivy screen class
class MainScreen(Screen):
def __init__(self, **kwargs):
self.name="MAIN SCREEN"
super(Screen, self).__init__(**kwargs)
# Kivy app class
class Kivy(App):
w_MessageBox10_1 = "MAIN SCREEN"
w_MessageBox10_2 = "One golden glance of what should be"
w_MessageBox30_2 = "CHORUS"
w_MessageBox30_3 = "EXIT"
# exit button action
def exit(self):
print "exiting... one shaft of light will show the way..."
p1.terminate() # terminate Flask by pressing on cancel
exit(1)
# do magic button action
def do_magic(self):
# your code goes here or maybe not
print "***** it's a kind of magic *************************"
# Kivy UI builder file
def build(self):
sm = Builder.load_string("""
ScreenManager
MainScreen:
size_hint: 1, .7
auto_dismiss: False
title: app.w_MessageBox10_1
title_align: "center"
BoxLayout:
orientation: "vertical"
Label:
text: app.w_MessageBox10_2
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
Button:
text: app.w_MessageBox30_2 # DO MAGIC
on_press:
app.do_magic()
Button:
text: app.w_MessageBox30_3 # EXIT
on_press:
app.exit()
""")
return sm
if __name__ == '__main__':
# #CTRL+C signal handler
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
global p1
p1 = Process(target=start_Flask) # assign Flask to a process
p1.start() # run Flask as process
Kivy().run() # run Kivy UI
UPDATE
To run Flask on demand by pressing a button in Kivy I use the script below.
#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-
# kivy modules first, if not Kivy may cause problems
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
kivy.require('1.10.0')
# common modules
import sys
import os
import time
import signal
from multiprocessing import Process
# Flask modules
from flask import Flask
# wsgi (Web Server Gateway Interface) modules
import eventlet
from eventlet import wsgi
# async server setup
app = Flask(__name__)
def signal_handler(signal, frame):
print " CTRL + C detected, exiting ... "
exit(0)
# kivy gui classes ######################################################
class MainScreen(Screen):
def __init__(self, **kwargs):
self.name="MAIN SCREEN"
super(Screen, self).__init__(**kwargs)
class MainApp(App):
MainScreenTitle = "MainScreen title"
MainScreenLabel = "MainScreen label"
MessageButtonEnter = "START"
MessageButtonExit = "EXIT"
def start_Flask(self):
print("Starting Flask...")
wsgi.server(eventlet.listen(('', 5000)), app) # deploy as an eventlet WSGI server
def stop(self):
print "terminating Flask and exiting..."
global p1
p1.terminate()
exit(1)
def start(self):
print "starting Flask as process..."
global p1
p1 = Process(target=self.start_Flask) # assign Flask to a process
p1.daemon = True
p1.start() #launch Flask as separate process
def build(self):
sm = Builder.load_string("""
ScreenManager
MainScreen:
size_hint: 1, .7
auto_dismiss: False
title: app.MainScreenTitle
title_align: "center"
BoxLayout:
orientation: "vertical"
Label:
text: app.MainScreenLabel
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
Button:
text: app.MessageButtonEnter # start app
on_press:
app.start()
Button:
text: app.MessageButtonExit # exit app
on_press:
app.stop()
""")
return sm
# main ################################################
if __name__ == '__main__':
#CTRL+C signal handler
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
MainApp().run() # run Kivy app
The development server in Flask is part of Werkzeug. It should only be used for development purposes as it cannot accommodate high loads as in production deployments. I suggest that you set-up an Apache server with mod_wsgi to run both apps together. This will also provide isolation & parallelism at the same time and is ideal for development,testing and production deployments.
A solution with threading works but with a caveat: The Werkzeug server can run in a separate thread but the app reloader expects to run in the main thread. This means that your Flask app will not reload when you make any changes to the app. Take a look at this answer.
The below code uses two separate threads to run each app. A 'Hello World' window appears for the Kivy app and at the same time it is possible to display a 'Hello World' message in the browser when the Flask app is run on http://localhost:5000/.
import threading
import kivy
from kivy.app import App
from flask import Flask
import os
from kivy.uix.label import Label
kivy.require('1.10.0')
new_environ = os.environ.copy()
app = Flask(__name__)
#app.route('/')
def hello():
return 'Hello World'
def start_app():
print("Starting Flask app...")
app.run(port=5000, debug=False) #specify separate port to run Flask app
class MyApp(App):
def build(self):
return Label(text='Hello world')
if __name__ == '__main__':
if os.environ.get("WERKZEUG_RUN_MAIN") != 'true':
threading.Thread(target=start_app).start()
MyApp().run()

python kivy i don't see just an empty window

I made my first kivy program. When I run this app, then it appears empty window.
This is the whole program.
Python code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty
class Myfirstwidget(BoxLayout):
def text(self, val):
print('text input text is: {txt}'.format(txt=val))
class MainAPP(App):
def build(self):
return Myfirstwidget()
if __name__ == '__main__':
MainAPP().run()
Kivy code myfirstwidget.kv :
#:kivy 1.9.1
<Myfirstwidget>:
Button:
on_press: self.text(txt_inpt.text)
TextInput:
id: txt_inpt
Change name of the kv file to main.kv.
Its name must be like the name of the App class, but lower case, and without 'app'. More info here docs.
The problem is in your kv file.
When you do
Button:
on_press: self.text(txt_inpt.text)
you are doing it to the button, not to the MyFirstWidget instance
Instead, you have to do:
Button:
on_press:root.text(txt_inpt.text)
That should work

Loading one line of text from file to Kivy label

I want to make a simple program that is just showing definitions that are stored in text file.One label and button to show next definition. I try to do it with documentation but i cannot find how to load text into label. Can someone show me to some good resources or code samples ?
My code for now (i want to build in on top of example from kivy website):
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.label import Label
class MyApp(App):
def build(self):
return Label(text = 'Hello world')
if __name__ == '__main__':
MyApp().run()
The easiest way to update widgets in the UI are by binding to their properties. This can be done in code, but the real power of kivy in my opinion comes from using it's declarative UI language. Using kv, you get automatic binding.
Here is a quick example of what you might do:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
kv = '''
BoxLayout:
orientation: 'vertical'
Label:
text: app.text
Button:
text: 'click me'
on_press: app.clicked()
'''
class MyApp(App):
text = StringProperty("hello world")
def build(self):
return Builder.load_string(kv)
def clicked(self):
self.text = "clicked!"
if __name__ == '__main__':
MyApp().run()
In the kv description of the UI, you tell kivy that you want the text on the Label to be bound to a StringProperty on the app which you defined on the class. The auto-binding means that anytime you set a value to that property (like in the clicked function), the UI will update with the new value automatically.

Categories