I'm a newbie at python, and now doing a dictionary with kivy. Issue is when I type text, it's not working. Below there I just want to check if it's working or not, so I put some popup, and if input text is 'a' then print true. It's just checking it's working or not, hope you guys help me, thank you.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.bubble import Bubble
class CustomPopup(Popup):
pass
class Diction(GridLayout):
def __init__(self, **kwargs):
super(Diction, self).__init__(**kwargs)
self.cols=2
self.add_widget(Label(text="Search"))
self.search=TextInput(multiline=False)
self.add_widget(self.search)
if self.search=='A':
print 'True'
else:
print 'False'
self.add_widget(Button(text="click",on_press=self.show_popup))
def show_popup(self, b):
p = CustomPopup()
p.open()
class MyApp(App):
def build(self):
return LoginScreen()
if __name__=="__main__":
MyApp().run()
There are two reasons why is not working:
The if should be in the method that handles the events, i.e. show_popup
You should compare the text in the Label, not the Label itself. Instead of self.search=='A', you should use self.search.text=='A'
Here is the corrected __init__ and show_popup code:
class Diction(GridLayout):
def __init__(self, **kwargs):
super(Diction, self).__init__(**kwargs)
self.cols=2
self.add_widget(Label(text="Search"))
self.search=TextInput(multiline=False)
self.add_widget(self.search)
self.add_widget(Button(text="click",on_press=self.show_popup))
def show_popup(self, b):
if self.search.text=='A':
print 'True'
else:
print 'False'
p = CustomPopup()
p.open()
An alternative approach using the Kivy Language
The Kivy Language could help you to have a cleaner code. Your code could look like this:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
# DON'T forget to import Label!!!
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.lang import Builder
Builder.load_string("""
<CustomPopup#Popup>:
title: "My Custom Poput"
<Diction#GridLayout>:
cols: 2
search: id_search
Label:
text: "Search"
TextInput:
id: id_search
Button:
text: "click"
on_press: root.show_popup(self)
""")
class CustomPopup(Popup):
pass
class Diction(GridLayout):
def show_popup(self, b):
if self.search.text=='A':
print 'True'
else:
print 'False'
# You can send any content to the popup with the content attribute
CustomPopup(content=Label(text=self.search.text)).open()
class MyApp(App):
def build(self):
return Diction()
It helps to keep the logic separated from the interface. You can even keep in separate files if you use the load_file function instead of the load_string.
Related
I have a custom button. I cannot put it on screen via kv file. I studied a lot topics. No useful info can find. Here is a simple example:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
#:kivy 1.11.0
<MyGrid>:
Button
text: 'hello'
''')
class MyGrid(BoxLayout):
pass
class DropApp(App):
def build(self):
return MyGrid()
if __name__ == '__main__':
DropApp().run()
Note that the Button in this kv file is native Kivy button. I run this code, I can see this button on screen. But now I have a custom Button:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
#:kivy 1.11.0
<MyGrid>:
customButton:
''')
class MyGrid(BoxLayout):
pass
class customButton(Button):
def __init__(self, **kwargs):
self.text = 'hi'
super(Button, self).__init__(**kwargs)
class DropApp(App):
def build(self):
return MyGrid()
if __name__ == '__main__':
DropApp().run()
I run this code, I cannot see this customButton on screen. Note that the custom widget is complex. I have to define it in py file. For example:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
class DropApp(App):
def build(self):
layout = GridLayout(cols=1, spacing=10)
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
return layout
if __name__ == '__main__':
DropApp().run()
Building this layout need for loop. I cannot find a way to build it in kv file. So I define it in Py file. But if I define it in py file, I cannot work with it in kv file.
Question 1: What's wrong with the second code?
Question 2: If I can't make it work, can I achieve the third code in kvlang(in kv file not in python)?
I am new to Kivy, hope someone can help.
When I run the code on Kivy v1.11.1 , Python v3.7.5:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
class DropApp(App):
def build(self):
layout = GridLayout(cols=1, spacing=10)
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
return layout
if __name__ == '__main__':
DropApp().run()
The output is:
If this is the output you require, try running:
pip install --upgrade kivy
For the second code, python is case-sensitive. So instead of customButton, use CustomButton.
If you want to do the 3rd code using .kv file, here is an example:
from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.lang import Builder
Builder.load_string('''
<ExampleRV>:
viewclass: 'Button'
RecycleBoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class ExampleRV(RecycleView):
def __init__(self, **kwargs):
super(ExampleRV, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(20)]
class RecycleApp(App):
def build(self):
return ExampleRV()
RecycleApp().run()
For reference, go HERE.
I'm doing a proyect using kivy but i have a problem with the checkboxes. At first I'm trying to do the program like python coding (I know it is'nt clean, but I understand more) And i have a first screen with this coding:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.checkbox import CheckBox
class MainScreen(GridLayout):
def __init__(self,**kwargs):
e=[]
super(MainScreen, self).__init__(**kwargs)
self.cols=2
def on_checkbox_active(checkbox, value):
if value:
e.append(value)
print e
else:
print('The checkbox', checkbox, 'is inactive')
self.add_widget(Label(text='Inserta assignatures desitjades',font_size=35))
self.add_widget(Label(text=''))
ch1 = CheckBox()
self.add_widget(ch1)
self.add_widget(Label(text='Termotecnia'))
ch2 = CheckBox()
self.add_widget(ch2)
self.add_widget(Label(text='Termotecnia'))
ch3 = CheckBox()
self.add_widget(ch3)
self.add_widget(Label(text='Termotecnia'))
ch4 = CheckBox()
self.add_widget(ch4)
self.add_widget(Label(text='Termotecnia'))
b1=Button(text='Exit',background_color=[0.7,0.7,1,1],font_size=24)
self.add_widget(b1)
b2=Button(text='Next',font_size=24,font_color=[1,3,4,0],background_color=[1,2,3,6])
self.add_widget(b2)
ch1.bind(active=on_checkbox_active)
ch2.bind(active=on_checkbox_active)
b1.bind(on_press=exit)
b2.bind(on_press=reloaded)
...
class SimpleKivy(App):
def build(self):
return MainScreen()
if __name__=='__main__':
SimpleKivy().run()
I want to select two or three options for example, and save it for the next screen, like a type of selection. If anyone knows how to do it and save information for the next screen it woul help me a lot, because i have the code of the next screen for all the options, but i want to preselect in the first screen and then only use which i have selected. Also if anyone can help me, i want to know hoy to do the transition to another class (screen) when the button "Next" is pressed. I know this question are pretty simple but I'm new in kivy programming and some concepts are pretty difficult. Thanks.
What you want is accessing variables in other classes. Sometimes this can be annoying and you can do it either hard way with all __init__() and stuff, or... a simplier way comes along: it's get_running_app().
You can create a dictionary or something else, where you can store any value your other classes need to access. It's similar to using globals and it costs you less lines of code. For example in your case you could use a dictionary(or nested dictionaries, json, ...) to store for example 'checkboxes':'<names of checked ones>' and in each init you can loop over these values to make checkboxes active
Basically all you need is a = App.get_running_app() somewhere and something to access in main - App - class.
Example:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string('''
<Root>:
MainScreen:
name: 'main'
AnotherScreen:
name: 'another'
<MainScreen>:
BoxLayout:
Button:
text: 'next screen'
on_release: root.parent.current='another'
Button:
text: 'ping!'
on_release: root.ping()
<AnotherScreen>:
BoxLayout:
Button:
text: 'previous screen'
on_release: root.parent.current='main'
Button:
text: 'ping!'
on_release: root.ping()
''')
class MainScreen(Screen):
def __init__(self, **kw):
super(MainScreen, self).__init__(**kw)
self.a = App.get_running_app()
def ping(self):
print self.a.big_dict['hi']
class AnotherScreen(Screen):
def ping(self):
b = App.get_running_app()
print b.big_dict['hi']
class Root(ScreenManager):
pass
class SimpleKivy(App):
big_dict={'hi':'hi there!'}
def build(self):
return Root()
SimpleKivy().run()
You can see there's no need to call __init__(), no need to write more lines of code if you really don't need to.
I am having problems understanding the usage of custom Properities and ways of binding methods to events.
Here's my code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import StringProperty
kivy_lang = '''
<MainWidget>:
on_my_property: my_label.text = 'from button bind method via StringProperty' + my_property
Label:
id: my_label
text: root.my_property
Button:
id: my_button
text: 'intro button'
'''
class MainWidget(BoxLayout):
# bind some properties
my_property = StringProperty('0')
def __init__(self, **kwargs):
super(MainWidget, self).__init__(**kwargs)
# if needed to do sth on widget construction
self.ids.my_button.bind(on_press=self.my_method)
def my_method(self,*args,**kwargs):
self.my_property = str(int(self.my_property)+1)
self.ids.my_button.text = 'new'
class MyApp(App):
def build(self):
Builder.load_string(kivy_lang)
return MainWidget()
if __name__ == '__main__':
MyApp().run()
When I run it it renders OK, but when I click a button, as a result I get
NameError: name 'my_property' is not defined
I tried binding method for Button in kv lang with (and removing whole 'init()' on python side):
on_press: root.my_method
and then when I press button the app doesn't crash but nothing happens
Can someone explain me how to adjust this code to work?
I understand the code is a little 'mixed techniques' but I did it that way to get to know different approaches, so I would appreciate if You don't turn it all around :)
1/ you are missing 'self' before 'my_property' in 'on_my_property' bindind, hence the crash
2/ in kv bindings. the python code is called as written, so you need '()' after 'root.my_method', or the statement has no effect.
I don't have any idea to find a solution of my problem.
I have make an application with Carousel Widget. In this Carousel I have 4 slides.
welcomeSlide -> DVDSlide -> DVDPretSlide --> CategorySlide
I have make a class for each slides.
I use a ListAdpter to display the data extracted from an Sqlite3 Database.
My pblem is about the refresh of the list, when I modify a DVD (add name to pret) in the DVDSlide, when I slide to the DVDPret, the DVD do not appears because the List is not refresh.
Like the doccumentation for the carousel I don't find the event when slide change. It will be the best if an event exist to get the current slide index.
Have you got any Idea ?
Thanks,
You can observe index property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
Label:
text: str(id(root))
<Carousel>
on_index: print("slide #{}".format(args[1]))
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
Or you can observe current_slide property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
label_id: label_id
Label:
id: label_id
text: str(id(root))
<Carousel>
on_current_slide: print(args[1].label_id.text)
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
If you want a pure python solution rather than a Kivy Language solution you can create your own carousel that inherits from the Kivy carousel as follows.
import kivy
from kivy.uix.carousel import Carousel
class MyCarousel(Carousel):
# This class is a carousel that runs script
# when a slide gets focus (except first load).
def on_index(self, *args):
print('the slide is', self.index)
# YOUR CODE GOES HERE
Carousel.on_index(self, *args)
I am trying to get the textinput widget to pass text into the callback function that makes a label with the text when called by the printbutton, should be fairly simple when you think about it. But I have a habit of not seeing the wood for the trees. Anyhoo, if anyone can figure this out then code it up :P
import kivy
kivy.require('1.5.1')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
class kivyentrywidget(GridLayout):
def __init__(self, **kwargs):
super(kivyentrywidget, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text='What do you want to print?'))
self.text_input = TextInput(multiline=False)
self.add_widget(self.text_input)
self.printbutton = Button(text='Print')
self.printbutton.bind(on_press=callback)
self.add_widget(self.printbutton)
def callback(self):
return Label(text=self.text_input.text)
class Firstapp(App):
def build(self):
return kivyentrywidget()
if __name__ == '__main__':
Firstapp().run()
def callback(self,evt=None): #not sure if kivy sends event info so added optional arg just in case
return self.add_widget(Label(text=self.text_input.text))
maybe ... not overly familiar with kivy but i think that would do it ..
also
self.printbutton.bind(on_press=self.callback)
should fix your other problem