I would like to get the text of my TextInput via a StringProperty, but it does not work. I get an empty string. In the second example, I am declaring the whole TextInput as an ObjectProperty and then it does work. What is wrong with my first example?
How can a StringProperty be used to define the text inside a TextInput?
First example does not print text of TextInput
example1.py
from kivy.app import App
from kivy.base import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<rootwi>:
orientation: 'vertical'
Button:
on_press: root.print_txt()
TextInput:
text: root.textinputtext
""")
class rootwi(BoxLayout):
textinputtext = StringProperty()
def print_txt(self):
print(self.textinputtext)
class MyApp(App):
def build(self):
return rootwi()
if __name__ == '__main__':
MyApp().run()
Second example does print text of TextInput, but uses a ObjectProperty not StringProperty example2.py
from kivy.app import App
from kivy.base import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
Builder.load_string("""
<rootwi>:
txt: txt
orientation: 'vertical'
Button:
on_press: root.print_txt()
TextInput:
id: txt
""")
class rootwi(BoxLayout):
txt = ObjectProperty()
def print_txt(self):
print(self.txt.text)
class MyApp(App):
def build(self):
return rootwi()
if __name__ == '__main__':
MyApp().run()
If I set the text to sth specific, it shows up in the TextInput. (But still, cannot be printed)
from kivy.app import App
from kivy.base import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<rootwi>:
orientation: 'vertical'
Button:
on_press: root.print_txt()
TextInput:
text: root.textinputtext
""")
class rootwi(BoxLayout):
textinputtext = StringProperty()
def __init__(self, **kwargs):
self.textinputtext = 'palim'
super(rootwi, self).__init__(**kwargs)
def print_txt(self):
print(self.textinputtext)
class MyApp(App):
def build(self):
return rootwi()
if __name__ == '__main__':
MyApp().run()
If you want set and get the text using the StringProperty then you should create a bidirectional bind:
from kivy.app import App
from kivy.base import Builder
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<rootwi>:
orientation: 'vertical'
textinputtext: txt.text
Button:
on_press: root.print_txt()
TextInput:
id: txt
text: root.textinputtext
""")
class rootwi(BoxLayout):
textinputtext = StringProperty()
def __init__(self, **kwargs):
super(rootwi, self).__init__(**kwargs)
self.textinputtext = 'palim'
def print_txt(self):
print(self.textinputtext)
class MyApp(App):
def build(self):
return rootwi()
if __name__ == '__main__':
MyApp().run()
Output:
Related
So I wanted to read data from my Arduino through serial port, and update the data I read to a label text to display. It is working when I only have simple code to just read and update, but when I add in the ScreenManager and Screen, it stops updating the text.
Eventually I will need to have different animation according to the data I received, this is more on a testing if this function works
Thanks in Advance!
Here's my entire code
import os
os.environ['KIVY_GL_BACKEND'] ='gl'
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import (NumericProperty, StringProperty, ReferenceListProperty, ObjectProperty, ListProperty)
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.text import LabelBase
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
LabelBase.register(name='Sans',fn_regular="Sansation-Regular.ttf")
import serial
kivy = Builder.load_string("""
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<MyManager>:
transition: FadeTransition()
MainScreen:
OperationScreen:
<MainScreen>:
name: 'main'
Label:
text: 'Welcome'
font_size: 40
on_touch_up : app.root.current = 'operation'
Label:
text: 'dafault'
font_size: 20
pos: -200,-100
id: data_label
<OperationScreen>:
name: 'operation'
Label:
text: 'Youre in'
font_size: 40
""")
class OperationScreen(Screen):
pass
class MainScreen(Screen):
def __init__(self,**kwargs):
super(MainScreen,self).__init__(**kwargs)
def Read(self,dt):
Clock.unschedule(self.Read)
data = arduino.readline()
if data != '':
self.ids.data_label.text = data
Clock.schedule_once(self.Read)
pass
class MyManager(ScreenManager):
pass
class mainApp(App):
Main = MainScreen()
def build(self):
Clock.schedule_once(self.Main.Read)
return MyManager()
if __name__ == '__main__':
try:
arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
except:
print("failed to connect")
mainApp().run()
I expect the label with text 'default' to be changing accordingly but it just froze with the 'default'
Problem
When your app runs, there are two instances of class MainScreen. One was instantiated in kv file. The other one was instantiated manually, Main = MainScreen() in class mainApp.
The scheduling of method Read() is in the instance created manually, Main = MainScreen() and there is no modal view associated with this one.
Solution
In kv file, add id: main_screen for MainScreen:
Remove Main = MainScreen() in class mainApp
Implement a constructor for class MyManager()
Move the scheduling from class mainApp into the constructor of class MyManager()
In your case, it is better to use Clock.create_trigger() instead of Clock.schedule_once()
The correct way to cancel a Clock event is either event.cancel() or Clock.unschedule(event)
Example
main.py
import os
os.environ['KIVY_GL_BACKEND'] = 'gl'
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import (NumericProperty, StringProperty, ReferenceListProperty, ObjectProperty, ListProperty)
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.text import LabelBase
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
# LabelBase.register(name='Sans', fn_regular="Sansation-Regular.ttf")
import serial
kivy = Builder.load_string("""
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<MyManager>:
transition: FadeTransition()
MainScreen:
id: main_screen
OperationScreen:
<MainScreen>:
name: 'main'
Label:
text: 'Welcome'
font_size: 40
on_touch_up : app.root.current = 'operation'
Label:
text: 'dafault'
font_size: 20
pos: -200,-100
id: data_label
<OperationScreen>:
name: 'operation'
Label:
text: 'Youre in'
font_size: 40
""")
class OperationScreen(Screen):
pass
class MainScreen(Screen):
def Read(self, dt):
data = str(dt)
# data = arduino.readline()
if data != '':
self.ids.data_label.text = data
self.manager.event_trigger()
else:
self.manager.event_trigger.cancel()
class MyManager(ScreenManager):
event_trigger = ObjectProperty(None)
def __init__(self, **kwargs):
super(MyManager, self).__init__(**kwargs)
self.event_trigger = Clock.create_trigger(self.ids.main_screen.Read)
self.event_trigger()
class mainApp(App):
def build(self):
return MyManager()
if __name__ == '__main__':
# try:
# arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# except:
# print("failed to connect")
mainApp().run()
Output
I have already tried the location to the font thing, like this:
Label:
font_name: 'Titr.ttf'
font_size: 34
text: "پاسمار"
i used b titr, i renamed b titr to titr, it does find it as the ttf is in the same folder, i can see the differences, when there isn't font_name: 'Titr.ttf', it gives out a bunch of random things, but when the titr is there, its only vertical rectangles.
#! /usr/local/bin/python -*- coding: UTF-8 -*-
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.properties import ObjectProperty
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.tabbedpanel import TabbedPanelHeader
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from functools import partial
from kivy.base import runTouchApp
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
import sys
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivy.lang import Builder
from kivy.base import runTouchApp
import random
import time
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.properties import ObjectProperty, NumericProperty
import time
import threading
class ScreensApp(App):
def build(self):
return RootWidget()
class ScreenOne(Screen):
pass
class ScreenTwo(Screen):
def __init__(self, **kwargs):
super(ScreenTwo, self).__init__(**kwargs)
class RootWidget(FloatLayout):
pass
class ImageButton(ButtonBehavior, Image):
def on_press(self):
print ('pressed')
def displayScreenThenLeave(self):
self.changeScreen()
def changeScreen(self):
if self.manager.current == 'screen1':
self.manager.current = 'screen2'
else:
self.manager.current = 'screen1'
class Manager(ScreenManager):
screen_one = ObjectProperty(None)
screen_two = ObjectProperty(None)
class ScreensApp(App):
def build(self):
m = Manager(transition=NoTransition())
return m
if __name__ == "__main__":
ScreensApp().run()
class The_AssignmentApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
The_AssignmentApp().run()
#:kivy 1.10.1
-- coding: utf-8 --
<ScreenOne>:
BoxLayout:
orientation: "vertical"
size: root.size
spacing: 15
padding: 200
Label:
font_name: 'Titr.ttf'
font_size: 34
text: "پاسمار"
Button:
background_color: 0, 255, 0, .255
text: "Start Pasmar"
on_release: root.manager.current = "screen2"
<ScreenTwo>:
BoxLayout:
orientation: "vertical"
size: root.size
spacing: 20
padding: 20
ImageButton:
Image:
source:'Card_club.png'
size_hint: .2, .2
<Manager>:
id: screen_manager
screen_one: screen_one
screen_two: screen_two
ScreenOne:
id: screen_one
name: "screen1"
manager: screen_manager
ScreenTwo:
id: screen_two
name: "screen2"
manager: screen_manager
i have an app, that in the future, will be a cards game counter, but right now its nowhere near that stage, anyways, i have 3 files, main.py, screens.kv,screens2.kv(which doesnt have anything in it) now i also got a picture, and its a button, each time its pressed, for test it writes down "pressed", i've been on this for at least 2 hours and cant figure out how to make the button appear when i press "Start Pasmar" (Pasmar is the name of the game in future), all it brings up is a blank screen after i press the button, but i did replace them and it only showed the button, nothing else.
This my current code:
#-*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.properties import ObjectProperty
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.tabbedpanel import TabbedPanelHeader
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from functools import partial
from kivy.base import runTouchApp
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
import sys
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivy.lang import Builder
from kivy.base import runTouchApp
import random
import time
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.properties import ObjectProperty, NumericProperty
import time
import threading
class ScreensApp(App):
def build(self):
return RootWidget()
class ScreenOne(Screen):
pass
class ScreenTwo(Screen):
def __init__(self, **kwargs):
super(ScreenTwo, self).__init__(**kwargs)
class RootWidget(FloatLayout):
pass
class ImageButton(ButtonBehavior, Image):
def on_press(self):
print ('pressed')
def displayScreenThenLeave(self):
self.changeScreen()
def changeScreen(self):
if self.manager.current == 'screen1':
self.manager.current = 'screen2'
else:
self.manager.current = 'screen1'
class Manager(ScreenManager):
screen_one = ObjectProperty(None)
screen_two = ObjectProperty(None)
class ScreensApp(App):
def build(self):
m = Manager(transition=NoTransition())
return m
if __name__ == "__main__":
ScreensApp().run()
class The_AssignmentApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
The_AssignmentApp().run()
This is the kv file:
#:kivy 1.10.1
<ScreenOne>:
BoxLayout:
orientation: "vertical"
size: root.size
spacing: 15
padding: 200
Label:
font_size: 34
text: "Pasmar"
Button:
background_color: 0, 255, 0, .255
text: "Start Pasmar"
on_release: root.manager.current = "screen2"
<ScreenTwo>:
BoxLayout:
orientation: "vertical"
size: root.size
spacing: 20
padding: 20
<Manager>:
id: screen_manager
screen_one: screen_one
screen_two: screen_two
ScreenOne:
id: screen_one
name: "screen1"
manager: screen_manager
ScreenTwo:
id: screen_two
name: "screen2"
manager: screen_manager
I`m trying to make a simple GUI with Kivy(1.9) using a popup to change some options from a list and save it to a db, for example. When i call popup(), Python(3.4.5) crash..
main.py:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
from kivy.lang import Builder
Builder.load_string('''
<PopView>:
title: 'Popup'
size_hint: (.8, .8)
Button:
text: 'Save'
''')
class MainApp(App):
def build(self):
b = Button(text='click to open popup')
b.bind(on_click=self.view_popup())
return b
def view_popup(self):
a=PopView()
a.data=[1,2,3,4] #e.g.
a.open()
class PopView(Popup):
def __init__(self):
self.data = ListProperty()
def save_data(self):
#db.query(self.data)
pass
if __name__ in ('__main__', '__android__'):
MainApp().run()
Here are a couple of things.
First, if you are going to overite __init__ remember to call super
But in this simple case you dont need __init__
Then, there is no on_click event on Button. Use on_press or on_release
And last but not least: You dont need to call the method in the bind function. Only pass it (without ())
So now your example looks like this.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
from kivy.lang import Builder
Builder.load_string('''
<PopView>:
title: 'Popup'
size_hint: (.8, .8)
Button:
text: 'Save'
''')
class MainApp(App):
def build(self):
b = Button(text='click to open popup')
b.bind(on_release=self.view_popup)
return b
def view_popup(self,*args):
a = PopView()
a.data=[1,2,3,4] #e.g.
a.open()
class PopView(Popup):
data = ListProperty()
def save_data(self):
#db.query(self.data)
pass
if __name__ in ('__main__', '__android__'):
MainApp().run()
I'm semi-OK with Python but brand new to Kivy, I know my problem is referencing the label ID but I can't seem to solve it and searching doesn't seem to give me what I need.
I'm trying to get a label to display the current time, so I know I have the right framework in terms of updating etc but I'm sure its all down to referencing the label ID somehow and its that I'm struggling with?
The following code runs fine, displays the labels etc until I try to update the label_text.text at which point i get an error: AttributeError: 'float' object has no attribute 'lbl_time'. I've tried str(time.strftime("%H:%M:%S")) but that doesn't solve it.
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition, FadeTransition
from kivy.uix.anchorlayout import AnchorLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import time
from datetime import datetime
class MainScreen(Screen):
def update_time(self):
lbl_time = ObjectProperty()
MyTime = time.strftime("%H:%M:%S")
self.lbl_time.text = MyTime
class DetailScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class MyScreenManager(ScreenManager):
pass
root_widget = Builder.load_string('''
MyScreenManager:
MainScreen:
DetailScreen:
SettingsScreen:
<MainScreen>:
name: 'main'
BoxLayout:
orientation: 'vertical'
Label:
id: lbl_time
text: 'Time'
font_size: 60
Label:
text: 'Main2'
font_size: 30
GridLayout:
cols: 2
Label:
text: 'Bottom'
font_size: 30
Label:
text: 'Bottom1'
font_size: 30
<DetailScreen>:
name: 'details'
<SettingsScreen>:
name: 'settings'
''')
class ScreenManagerApp(App):
def build(self):
return root_widget
def on_start(self):
Clock.schedule_interval(MainScreen.update_time, 1)
ScreenManagerApp().run()
This was more of a Python problem rather than a Kivy one. You were calling the update_time of the class MainScreen class, not of the object/instance of the MainScreen. Basically, you would need to save a reference to the object (self.main_screen) in the build method, and then use it in the on_start.
class ScreenManagerApp(App):
def build(self):
self.main_screen = MainScreen()
return self.main_screen
def on_start(self):
Clock.schedule_interval(self.main_screen.update_time, 1)
Also you cannot access id outside of the kv language, i.e. in the python. You have to reference the id by adding a property, e.g. the_time:
<MainScreen>:
name: 'main'
the_time: _id_lbl_time
BoxLayout:
orientation: 'vertical'
Label:
id: _id_lbl_time
A minor problem is that the update_time() receives to parameters. Also, there were quite a few weird things in your code, so I couldn't run the code. I fixed all the above in the code below:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import time
from datetime import datetime
Builder.load_string('''
<MainScreen>:
name: 'main'
the_time: _id_lbl_time
BoxLayout:
orientation: 'vertical'
Label:
id: _id_lbl_time
text: 'Time'
font_size: 60
''')
class MainScreen(Screen):
def update_time(self, sec):
MyTime = time.strftime("%H:%M:%S")
self.the_time.text = MyTime
class ScreenManagerApp(App):
def build(self):
self.main_screen = MainScreen()
return self.main_screen
def on_start(self):
Clock.schedule_interval(self.main_screen.update_time, 1)
ScreenManagerApp().run()