I am having trouble using StringProperties. In the below python script if I un-comment the Clock.schedule line in the "class cb(App):" the Kivy UI displays the counting number along with the same number counting in the terminal.
If I run the code as written using the "Start" button from the Kivy UI the counting number will show in the terminal but not in the UI.
I also included the Kivy code.
Thank you in advance for any help,
Dave
#!/usr/bin/python
import sys
import glob
import serial
import time
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
from kivy.clock import Clock
from kivy.properties import StringProperty
Config.set('graphics', 'width', '400')
Config.set('graphics', 'height', '150')
num = 0
class Counter_Timer(BoxLayout):
number = StringProperty()
def count(self, dt):
global num
num = num + 1
print num
numSTR = str(num)
self.number = numSTR
def start_button(self):
counter = Counter_Timer()
Clock.schedule_interval(counter.count, 1.0)
class cb(App):
def build(self):
counter = Counter_Timer()
# Clock.schedule_interval(counter.count, 1.0)
return counter
if __name__=='__main__':
cb().run()
Kivy Code
# cb.kv
<Counter_Timer>:
orientation: 'vertical'
BoxLayout:
Label:
text: root.number + ' ticks'
font_size: '24dp'
Button:
text: "Start"
on_press: root.start_button()
Button:
text: "Stop"
Related
I'm working on a program with a GUI interface, which I've implemented using a kivy app. My end-goal is to enter a desired voltage in the kivy textbox and for it to be set using an Arduino + a DAC converter. For now I'm just trying to access the voltage from the text input from outside the kivy app in my main, so that I can separate the GUI cleanly from communication with the arduino, and other necessary calculations.
The problem is that the program doesn't continue after App.run() until the kivy app has been closed and the entered voltage has been lost. I've tried using the multiprocessing library, but the start() function also runs as long as the app is running. I'm also not sure what the best way is to access the voltage, I tried having it as a class member of the GUI, but maybe that's not a good idea.
This is my GUI.py code:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.properties import StringProperty, NumericProperty
from kivy.uix.button import Button
class GUI_GridLayout(GridLayout):
voltage_label_1 = StringProperty("Voltage 1?")
voltage_label_2 = StringProperty("Voltage 2?")
voltage_input_1 = TextInput()
voltage_input_2 = TextInput()
submit_button_label_1 = StringProperty("Submit 1")
submit_button_label_2 = StringProperty("Submit 2")
voltage_output_1 = NumericProperty(0)
voltage_output_2 = NumericProperty(0)
def press_1(self):
voltage_1 = self.voltage_input_1.text
self.voltage_output_1 = float(voltage_1)
def press_2(self):
voltage_2 = self.voltage_input_2.text
self.voltage_output_2 = float(voltage_2)
def build(self):
self.add_widget(Label(text=self.voltage_label_1))
self.add_widget(self.voltage_input_1)
self.add_widget(Label(text=self.voltage_label_2))
self.add_widget(self.voltage_input_2)
self.submit_button_1 = Button(text=self.submit_button_label_1)
self.submit_button_1.bind(on_press=self.press_1)
self.add_widget(self.submit_button_1)
self.submit_button_2 = Button(text=self.submit_button_label_2)
self.submit_button_2.bind(on_press=self.press_2)
self.add_widget(self.submit_button_2)
class apason_GUIApp(App):
def build(self):
return GUI_GridLayout()
The corresponding kv file:
#:kivy 1.0.9
<GUI_GridLayout>:
cols: 3
voltage_input_1: input_1
voltage_input_2: input_2
Label:
font_size: 50
text: str(root.voltage_label_1)
TextInput:
id: input_1
font_size: 50
multiline: False
text: root.voltage_input_1.text
Button:
font_size: 50
text: str(root.submit_button_label_1)
on_press: root.press_1()
Label:
font_size: 50
center_x: root.width / 4
text: str(root.voltage_label_2)
TextInput:
id: input_2
font_size: 50
multiline: False
text: root.voltage_input_2.text
Button:
font_size: 50
text: str(root.submit_button_label_2)
on_press: root.press_2()
And here's my main:
import GUI.GUI as gui
import multiprocessing as multiproc
import time
class GetVoltage:
def __init__(self):
self.voltage_1 = 0
self.voltage_2 = 0
def fetchVoltage(self, interface):
self.voltage_1 = interface.voltage_output_1
self.voltage_2 = interface.voltage_output_2
def run(self, interface):
while (True):
self.fetchVoltage(interface)
print(self.voltage_1)
print(self.voltage_2)
time.sleep(1)
if __name__ == '__main__':
interface = gui.apason_GUIApp()
interface_process = multiproc.Process(target=interface.run())
checker = GetVoltage()
checker_process = multiproc.Process(target=checker.run(interface))
interface_process.start()
checker_process.start()
Since you already have one process when you run main.py, you really only need to start the second process. And you can communicate between the processes using a Queue. Here is a modified version of your main.py that uses this approach:
import GUI as gui
import multiprocessing as multiproc
class GetVoltage:
def run(self, queue):
while True:
voltage = queue.get() # get the data from the other process by using the Queue
print(voltage)
if __name__ == '__main__':
q = multiproc.Queue()
# start the GetVoltage process
checker = GetVoltage()
checker_process = multiproc.Process(target=checker.run, args=(q,), daemon=True)
checker_process.start()
# start the App
interface = gui.apason_GUIApp()
interface.q = q
interface.run() # this does not return until the App closes
# kill the GetVoltage process after the App exits
checker_process.kill()
And a couple minor changes in the App code:
def press_1(self):
voltage_1 = self.voltage_input_1.text
self.voltage_output_1 = float(voltage_1)
App.get_running_app().q.put('voltage_1 = ' + voltage_1) # put the data in the Queue
def press_2(self):
voltage_2 = self.voltage_input_2.text
self.voltage_output_2 = float(voltage_2)
App.get_running_app().q.put('voltage_2 = ' + voltage_2) # put the data in the Queue
I have created a simple program that demonstrates my current dilemma. Whenever I press button 2 on the kivy GUI I would like to increment a variable. After this variable is incremented I would like to create a thread that runs separately to do something to the value of the variable. For this instance just adding a sleep of 5 seconds before printing it back will be fine. I have to use threading because any use of sleep or interrupts inside gui, stops it from working during that sleep or kills it completely.
You might need to install the kivy lib for the kivy application to work on windows
import threading
from kivy.config import Config
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty
from datetime import datetime
#import adafruit_rfm9x
#from gpiozero import MotionSensor
#import sys
import time
#from gpiozero import MotionSensor
import subprocess
global buttonVal
# Setting up size of window for kivy app
Config.set('graphics', 'resizable', '0')
# fix the width of the window
Config.set('graphics', 'width', '800')
# fix the height of the window
Config.set('graphics', 'height', '480')
# Kivy app dependencies, buttons, labels, etc
Builder.load_string("""
<MySec>:
orientation: 'vertical'
size: root.width, root.height
rotation: 90
Label:
text: 'Master Wall Mount'
font_size: 45
Button:
id: kv_sec
text: root.seconds_string
font_size: 80
Button:
id: button2
text: 'Button 2'
on_press: root.button_toggle()
Button:
id: button3
text: 'Button 3'
""")
# function to turn on screen
def turn_on():
CONTROL = "vcgencmd"
CONTROL_UNBLANK = [CONTROL, "display_power", "1"]
subprocess.call(CONTROL_UNBLANK)
# function to turn off screen
def turn_off():
CONTROL = "vcgencmd"
CONTROL_BLANK = [CONTROL, "display_power", "0"]
subprocess.call(CONTROL_BLANK)
# function that will run as a thread to run the pir sensor infinitely to determine if motion is present and proceed
# to adjust screen brightness.
def pirsensor():
# Setting GPIO pin 4 as pir sensor
pir = MotionSensor(4)
# dhtDevice = adafruit_dht.DHT22(board.D23)
while True:
if pir.motion_detected:
turn_on()
print("Motion Detected!")
time.sleep(120.0)
print("Sleeping for 2 minutes")
else:
turn_off()
print("No Motion Detected!")
def send_button_data():
print(buttonVal)
# pirsenor thread using pirsensor function
t1 = threading.Thread(target=pirsensor)
t2 = threading.Thread(target=send_button_data())
class MySec(BoxLayout):
seconds_string = StringProperty('')
count = 0
def button_toggle(self):
self.count += 1
print(self.count)
buttonVal = self.count
class TestThreadApp(App):
print("Running Thread for PIR Sensor")
t1.start()
print("Running Thread to display current button value" )
t2.start()
def build(self):
Clock.schedule_interval(lambda dt: self.update_time(), 1)
return MySec()
def update_time(self):
self.root.seconds_string = datetime.now().strftime("%H:%M:%S")
TestThreadApp().run()
I am trying to make a program that reads the dictionary after the user inputs their name and assigns a random selection based on weighted values in the dictionary. As of now the logic for selecting a random value from the dictionary is working but I have it printing to the console. I would like it to appear in a popup window (which i have but cannot get the output variable to show up there)
four.kv
WindowManager:
MainWindow:
<MainWindow>:
name:'main'
player_python:player_kv
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text:'Player:'
TextInput:
id: player_kv
multiline: False
Button:
text: 'Random'
on_press: root.btn()
<P>:
output:output
FloatLayout:
Label:
id: output
main4.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
import random
#from Dict import *
#### example dictionary
character = {
'John':
{'Water': 2, #50%
'Fire': 1, #25%
'Earth': 1,}, #25%
'Bill':
{'Water': 1, #25%
'Fire': 2, #50%
'Earth': 1,}} #25%
####
class MainWindow(Screen):
player_python = ObjectProperty(None)
output = StringProperty('')
def btn(self):
show_popup()
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
class P(FloatLayout):
pass
def show_popup():
show = P()
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('four.kv')
class FourApp(App):
def build(self):
return kv
if __name__ == '__main__':
FourApp().run()
https://gist.github.com/PatrickToole/00cc72cdd7ff5146976e5d92baad8e02
Thanks in advance
-P
I haven't tested this code, but try passing self.output to your show_popup() method. This would mean changing your btn() method to something like:
def btn(self):
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
show_popup(self.output)
And in the show_popup() method:
def show_popup(output):
show = P()
show.output.text = output
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
As I mentioned, I haven't tested this code, but something like this should work.
I'm quite new to kivy and programming in general, and am having issues with my code. I simplified it down a lot to try get to the root issue, but it still seems to be not be working. Basically this kivy file is supposed to produce an orange square, and then change the size of the square to an integer value produced by a sensor at COM7. So far, at startup a square is produced, and the sensor does successfully pass integer values to python. I tried changing the value of the NumericProperty "first_rect," but no matter how I try to redefine first_rect, it's value doesn't change, and the size of the rectangle never changes. I have the feeling that there is something very small and straightforward missing, but I'm not sure what it is.
Any help would be greatly appreciated!
.py file
import serial
import time
from functools import partial
from kivy.uix.widget import Widget
from kivy.app import App
#kivy.require("1.10.0")
from kivy.clock import *
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.properties import ObjectProperty, NumericProperty
from kivy.properties import StringProperty
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.slider import Slider
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
from kivy.lang import Builder
from functools import partial
import time
i = 10
class Bar(Widget):
pass
class Trial(Screen):
rect1 = ObjectProperty(None)
# Clock.schedule_interval(Trial().update, 1.0/60.0)
def update(self):
ser = serial.Serial('COM7', 9600, timeout=0)
thing = [0,0]
a = 1
while a==1:
Byte = ser.readline()
Byte = Byte.decode('utf-8')
Byte = Byte.strip()
Byte_proc = Byte.split(',')
if Byte_proc[0] != '':
try:
if Byte_proc[1] != '':
Byte_proc[0] = int(Byte_proc[0])
Byte_proc[1] = int(Byte_proc[1])
TestTrial_SmallApp().first_rect = Byte_proc[0]
print(TestTrial_SmallApp().first_rect)
dummy_var = int(Byte_proc[0])
print(dummy_var)
a = 0
return dummy_var
except:
pass
time.sleep(.02)
class TestTrial_SmallApp(App):
first_rect = NumericProperty(100)
def build(self):
#Builder.load_file('TestTrial.kv')
Trial().add_widget(Bar())
Clock.schedule_interval(lambda dt: Trial().update(), 1.0/60.0)
# Trial().rect1.bind(pos = (200,200))
Trial().update()
return Trial()
TestTrial_SmallApp().run()
.kv file
#:import utils kivy.utils
#:import Window kivy.core.window
#:import Widget kivy.uix.widget
<Trial>:
id: "trial"
rect1: bar_left
canvas.before:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
#Rectangle orange bars
Bar:
id: bar_left
pos: 0.25*self.center_x, 0.02*self.height
<Bar>:
canvas:
Color:
rgb: utils.get_color_from_hex('#F68C43')
Rectangle:
pos: 300, 300
size: 300, app.first_rect
In your statements below
TestTrial_SmallApp().first_rect = Byte_proc[0]
print(TestTrial_SmallApp().first_rect)
each TestTrial_SmallApp() is creating a new instance of TestTrial_SmallApp class.I think that is not what you want. Create an instance that you assign to a reference and then use that reference to use the instance like
app = TestTrial_SmallApp()
app.first_rect = ...
print(app.first_rect)
I'm a newbie in Python and Kivy as well, so I have some trouble.
When I use kivy popup with showing the table (using "PrettyTable" module) I get broken view of this table.
My python code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from prettytable import PrettyTable
class GeneralForm(BoxLayout):
def RUN(self):
def TABLE():
x = PrettyTable(["City name", "Area", "Population"])
x.align["City name"] = "l" # Left align city names
x.padding_width = 1 # One space between column edges and contents (default)
x.add_row(["Adelaide",1295, 1158259])
x.add_row(["Brisbane",5905, 1857594])
return str(x)
popup = Popup(title='Test popup', content=Label(text=TABLE()), auto_dismiss=False)
popup.open()
class TimeTable(App):
def build(self):
return GeneralForm()
if __name__ == '__main__':
TimeTable().run()
My .kv code:
<GeneralForm>:
orientation: "vertical"
BoxLayout:
Button:
id: but
text: "Show!"
on_press: root.RUN()
Your problem is that the default label font is not a monospace font, where every character has the same width. You can instead set the font_name property to one that is. Possibly just 'DroidSansMono' will work, using the mono font kivy bundles.