Hello I am facing problem when I am using a GUI in python using Kivy. I am using TabbedPanel.
TabbedPanelItem:
text: 'apple'
BoxLayout:
Label:
text: 'Label1'
Entry:
text: 'Entry1'
CheckBox:
text: 'CheckBox1'
Button:
text: 'Button1'
TabbedPanelItem:
text: 'Grape'
BoxLayout:
Label:
text: 'Label1'
Button:
text: 'Button1'
Several things:
you can have only one build method
return in the second build method, is incorrectly indented, should be same as for
you can always only have one App class not class AccordionApp(App): and class KivyGuiApp(App):
Here is a smaller version of your app from which you should be able to implement more from
'''
TabbedPanel
============
Test of the widget TabbedPanel.
'''
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
from kivy.lang import Builder
from kivy.uix.checkbox import CheckBox
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.button import Button
from kivy.app import App
Builder.load_string("""
<Test>:
TabbedPanelItem:
text: 'apple'
BoxLayout:
Label:
text: 'Label1'
Label:
text: 'Entry1'
CheckBox:
text: 'CheckBox1'
Button:
text: 'Button1'
""")
class Test(TabbedPanel):
pass
class KivyGuiApp(App):
def build(self):
test = Test()
acc = Accordion()
for x in range(5):
item = AccordionItem(title='Table %d' % x)
item.add_widget(Button(text='apple\n'))
item.add_widget(Button(text='Grape\n'))
item.add_widget(Button(text='Lemon\n'))
acc.add_widget(item)
panel = TabbedPanelItem()
panel.add_widget(acc)
test.add_widget(panel)
return test
if __name__ == '__main__':
KivyGuiApp().run()
Related
I am trying to write in a text file after getting an input through TextInput in kivy. The problem is the data gets saved only after i close the app but i want the data to get saved as soon as I leave the specific screen and go to another screen. I am trying to input in add_staff and get it saved in the app through save() function.
import kivymd
import kivy
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
Builder.load_string('''
<MenuScreen>:
nm:nm_input
BoxLayout:
TextInput:
id:nm_input
Button:
text: 'Add New Staff'
on_press: root.manager.current = 'add_staff'
Button:
text: 'View Staff Profile'
Button:
text: 'Salary report'
<Add_new_staff>:
nam: str(name_input)
job: job_input
GridLayout:
cols: 2
Label:
text: 'Name'
TextInput:
id: name_input
multiline: False
Label:
text: 'Job'
TextInput:
id: job_input
Label:
text: 'Salary'
TextInput:
Label:
text: 'Date of Joining'
TextInput:
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Button:
text: 'Save'
on_press: root.save(name_input.text, job_input.text);root.manager.current = 'menu'
''')
class MenuScreen(Screen):
pass
class Add_new_staff(Screen):
def save(self, name, job):
fob = open('testi.txt','a')
fob.write(name + "\n")
fob.write(job)
fob.close()
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(Add_new_staff(name='add_staff'))
return sm
def lo(self,nm):
f=open('log.txt','a')
f.write(nm)
f.close()
if __name__ == '__main__':
TestApp().run()
I'm trying to make an app. On button click on the bottom right of the screen there appears a dialog window(popup). On "Done" click the popup window closes (close_dialog method), and a new List Item is expected to appear.
Unfortunately the error occurs on "Done" click:
AttributeError: 'DialogContent' object has no attribute 'get_screen'
Could you please tell me why does the error occur and how can I fix it?
I suppose that it is caused by the fact that DialogContent class inherits from BoxLayout (not from Screen) but I don't know how to fix it.
Code .py:
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.app import MDApp
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.textfield import MDTextField
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.list import TwoLineAvatarListItem
Window.size = (288, 511)
class GroupScreen(Screen):
pass
class DialogContent(BoxLayout):
pass
class MainScreen(Screen):
dialog = None
def show_dialog(self, *args):
'''
Create group creation popup
'''
if not self.dialog:
self.dialog = MDDialog(
title="Create new group",
type="custom",
content_cls=DialogContent(),
auto_dismiss=False
)
self.dialog.open()
def close_dialog(self, *args):
'''
Close popup on Done click
'''
self.dialog.dismiss()
self.new_window()
def new_window(self, *args):
'''
Create new group button
'''
mylist = TwoLineAvatarListItem(text = self.dialog.content_cls.textfield.text,
secondary_text = "1,2,3...")
self.mdlist.add_widget(mylist)
class test2App(MDApp):
def build(self):
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(GroupScreen(name='group'))
scroll = ScrollView()
return sm
if __name__ == '__main__':
test2App().run()
Code .kv:
ScreenManager:
MainScreen:
GroupScreen:
<DialogContent>:
textfield: textfield
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "120dp"
MDTextField:
id: textfield
hint_text: "Group name"
MDFlatButton:
id: btn1
text: "Done"
text_color: self.theme_cls.primary_color
on_release: root.get_screen['main'].close_dialog()
<MainScreen>:
name: 'main'
mdlist: mdlist
FloatLayout:
size_hint: 1, 0.89
ScrollView:
MDList:
id: mdlist
MDFloatingActionButton:
pos_hint: {'right': 0.95, 'y': 0.05}
icon: "android"
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
on_release:
root.show_dialog()
<GroupScreen>:
name: 'group'
MDLabel:
text: 'Welcome'
halign: 'center'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x': 0.5, 'center_y': 0.3}
on_release: root.manager.current = 'main'
Change:
on_release: root.get_screen['main'].close_dialog()
to:
on_release: app.root.get_screen('main').close_dialog()
The app.root gets you a reference to the root widget of the app, which is the ScreenManager. Then you can use get_screen('main') to access the main Screen and call its close_dialog() method.
I am trying to retrieve the value of the checkbox on kivy to write some logic. Could someone please help me and tell me where i can find such information in kivy's documentation as i was left with little luck.
here is the code.
Python file:
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
from kivy.uix.checkbox import CheckBox
from kivy.properties import ObjectProperty
class Tab(TabbedPanel):
check = ObjectProperty(False)
def btn(self):
print(self.check)
class Checkbox(CheckBox):
pass
filekv = Builder.load_file("GUI.kv")
class TabbedPanelApp(App):
def build(self):
return filekv
if __name__ == '__main__':
TabbedPanelApp().run()
Kv file:
<TextInput>:
multiline:False
Tab:
do_default_tab: False
check:checked
TabbedPanelItem:
text: 'Test Request'
GridLayout:
cols:2
spacing: 20
padding: 20
Label:
text: "Sample ID: "
TextInput:
id: id_sample
Checkbox:
#how do i retrieve the value of the checkbox here??
Label:
text: ""
Button:
text: "Submit"
on_press: root.btn()
I tried using:
id: checked
active: checked
value: checked
But nothing worked.
First you have to give an id to the Checkbox:
Checkbox:
id: check_box
... and then you have its state like this:
print(self.ids.check_box.state)
I have a basic, working knowledge of Python I'm trying to teach myself kivy. I'd like to be able to have Python read and write data to kivy widgets.
Imagine there's an address book app that inserts the date and time into a TextInput. When the app starts, just have Python get the date and time and insert it right?
This program code will give an example of a simple address book:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
class AddressApp(App):
def build(self):
pass
if __name__ == '__main__':
AddressApp().run()
Here's its address.kv file:
GridLayout:
cols: 2
Label:
text: 'Date'
TextInput:
id: textinputdate
Label:
text: 'Time'
TextInput:
id: textinputtime
Label:
text: 'Name'
TextInput:
id: textinputname
Label:
text: 'Address'
TextInput:
id: textinputaddress
Label:
text: 'email'
TextInput:
id: textinputemail
Label:
text: 'Phone'
TextInput:
id: textinputphone
After that, if I wanted to have Python read the... I dunno... uh... phone number TextInput, how would that be done?
If you want some widget to have an extra functionality (example: loading current date at app start), then create a custom version of that widget, which meets requirements. And reading values of widgets within a rule is very simple. Example:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
import time
gui = '''
BoxLayout:
orientation: 'vertical'
GridLayout:
cols: 2
Label:
text: 'current time'
DateInput:
id: date_input
Button:
text: 'write date to console'
on_press: print(date_input.text)
'''
class DateInput(TextInput):
def __init__(self, **kwargs):
super(DateInput, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1) # update every second
def update(self, dt):
self.text = time.ctime()
class Test(App):
def build(self):
return Builder.load_string(gui)
Test().run()
A guy named spinningD20 on the FreeNode IRC channel for kivy showed me this.
There's an even easier way than adding a custom widget. As long as you just want to insert a value into the TextInput when the app starts up...
address.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
import time
class AddressApp(App):
def build(self):
self.root.ids.textinputdate.text = time.strftime("%x")
if __name__ == '__main__':
AddressApp().run()
address.kv
GridLayout:
cols: 2
Label:
text: 'Date'
TextInput:
id: textinputdate
Label:
text: 'Time'
TextInput:
id: textinputtime
Label:
text: 'Name'
TextInput:
id: textinputname
Label:
text: 'Address'
TextInput:
id: textinputaddress
Label:
text: 'email'
TextInput:
id: textinputemail
Label:
text: 'Phone'
TextInput:
id: textinputphone
spinningD20 here. To be fair, I answered his immediate question, but also followed it up with an explanation of encapsulating it into a custom widget:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
import time
class DateInput(TextInput):
def __init__(self, **kwargs):
super(DateInput, self).__init__(**kwargs)
self.text = time.strftime("%x")
class Container(GridLayout):
def __init__(self, **kwargs):
# using super calls the base class's init. We'll hand it keyword arguments we received, just in case
super(Container, self).__init__(**kwargs)
# now we can do stuff here
self.ids.textinputtime.text = 'from python'
class AddressApp(App):
def build(self):
pass
if __name__ == '__main__':
AddressApp().run()
and in kv:
# anything without the <> symbols is part of the App's kv. So here's the one thing the App will have in its kv
Container:
# here's the custom widget's kv, just like your previous example
<Container>:
cols: 2
Label:
text: 'Date'
DateInput:
id: dateinputdate
Label:
text: 'Time'
TextInput:
id: textinputtime
Label:
text: 'Name'
TextInput:
id: textinputname
Label:
text: 'Address'
TextInput:
id: textinputaddress
Label:
text: 'email'
TextInput:
id: textinputemail
Label:
text: 'Phone'
TextInput:
id: textinputphone
I hope this helped! Good luck Dave!
Another example, explaining how to populate text inputs with current date through a parent grid layout, avoiding App class to keep it clean:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.gridlayout import GridLayout
import time
gui = '''
#:import time time
DateGrid
cols: 1
Label:
text: 'Customer data'
TextInput:
id: date_input
TextInput:
id: name_input
TextInput:
id: email_input
Button:
text: 'refresh date'
on_press: date_input.text = time.ctime()
'''
class DateGrid(GridLayout):
def __init__(self, **kwargs):
super(DateGrid, self).__init__(**kwargs)
Clock.schedule_once(self.populate_inputs, 0.5)
def populate_inputs(self, *x):
_ = self.ids
_.date_input.text = time.ctime()
_.name_input.text = 'Foo Snowman'
_.email_input.text = 'foo.snowman#gravy.com'
class Test(App):
def build(self):
return Builder.load_string(gui)
Test().run()
In my RootWidget I have a label and two buttons. I want to dynamically change the text of the label whenever one of the buttons is clicked.
Here's a minimal working example of how I do it at the moment.
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
w = Builder.load_string('''
<RootWidget>:
id: root_widget
Label:
id: label
text: 'Push a button'
Button:
text: '1'
on_press: label.text = self.text
Button:
text: '2'
on_press: label.text = self.text
''')
class RootWidget(BoxLayout):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MainApp().run()
Obviously I want to refactor the line on_press: label.text = self.text. My first tries ended in
<RootWidget>:
id: root_widget
Label:
id: label
text: 'Push a button'
MyButton:
text: '1'
MyButton:
text: '2'
<MyButton>:
on_press: label.text = self.text
But obviously the MyButton-class doesn't know the property label of the RootWidget-class. And class rules inside class rules is also not allowed.
Is there a way of accomplishing binding the on_press-action dynamically?
You can refer to the Label like this:
<MyButton#Button>:
on_press: self.parent.ids.label.text = self.text
<RootWidget>:
id: root_widget
Label:
id: label
text: 'Push a button'
MyButton:
text: '1'
MyButton:
text: '2'
It's quite simple actually, because through kv you can access parent of a widget/rule easily with self.parent, so your code would look like:
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
w = Builder.load_string('''
<RootWidget>:
id: root_widget
Label:
id: label
text: 'Push a button'
But:
text: '1'
But:
text: '2'
<But>:
on_press: self.parent.label.text = self.text
''')
class RootWidget(BoxLayout):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MainApp().run()