Kivy ActionBar back Button to switch to previous screen - python

I am trying to run this type of code on android but when i tap mobile back button, inspite of coming to the previous screen app is closed,
i used this piece of code to stop the App for being closed:
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
Window.bind(on_keyboard=self.BackButton)
def BackButton(self, window, key, *args):
if key==27:
return True
But how to return to the previous screen. and how to use ActionPrevious Button to come at previous screen?
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MyAppGUI>:
orientation:'vertical'
id: box
ActionBar:
ActionView:
ActionPrevious:
title: 'How to go back using this button???'
with_previous: True
ScreenManager:
id: screenmanger
Screen:
name: 's1'
Button:
text: 'goto screen 2'
on_release: screenmanger.current='s2'
Screen:
name: 's2'
Button:
text: 'goto screen 3'
on_release: screenmanger.current='s3'
Screen:
name: 's3'
Button:
text: 'goto main screen'
on_release: screenmanger.current='s1'
""")
class MyAppGUI(BoxLayout):
pass
class MyApp(App):
def build(self):
return MyAppGUI()
if __name__=='__main__':
MyApp().run()

To return to the previous window using ActionPrevious button you just need to bind its on_release event to a function that uses current property to set the previous screen using the name returned by ScreenManager.previous () method or use a list that serves as a history of the windows visited. To use the Back key on Android, your code is correct in principle, at least on my device it works without problems:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<MyAppGUI>:
sm: screenmanger
orientation:'vertical'
id: box
ActionBar:
ActionView:
ActionPrevious:
title: 'How to go back using this button???'
with_previous: True
on_release: root.set_previous_screen()
ScreenManager:
id: screenmanger
Screen:
name: 's1'
Button:
text: 'goto screen 2'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s2'
Screen:
name: 's2'
Button:
text: 'goto screen 3'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s3'
Screen:
name: 's3'
Button:
text: 'goto main screen'
on_release:
screenmanger.transition.direction = 'right'
screenmanger.current='s1'
""")
class MyAppGUI(BoxLayout):
sm = ObjectProperty()
def __init__(self, **kwargs):
super(MyAppGUI, self).__init__(**kwargs)
Window.bind(on_keyboard=self._key_handler)
def _key_handler(self, instance, key, *args):
if key is 27:
self.set_previous_screen()
return True
def set_previous_screen(self):
if self.sm.current != 's1':
self.sm.transition.direction = 'left'
self.sm.current = self.sm.previous()
class MyApp(App):
def build(self):
return MyAppGUI()
if __name__ == '__main__':
MyApp().run()

Related

Not able to save data instantly after clicking save button- kivy

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()

How to refer to another class method in kivy

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.

Problem about kivy.uix.widget.WidgetException

I am new to python and kivymd and I am trying to develop a program for data entry. However, when I create a drop-down menu for a selection, an error occurred and I can't update the value of the text field after I select an item.
Here is the python code:
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.properties import ObjectProperty
from kivymd.uix.menu import MDDropdownMenu
class AMRMenu(Screen):
def GIbutton(self):
sm.current = 'GI'
class GIWindow(Screen):
weather = ObjectProperty(None)
menu_weather_items = [{"text":"Sunny"},{"text":"Cloudy"},{"text":"Raining"}]
menu_FeedResponse_items=[{"text":"High"},{"text":"Medium"},{"text":"Low"}]
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu = MDDropdownMenu(
items=self.menu_weather_items,
width_mult=4,
caller = self.weather,
callback=self.set_item)
def set_item(self, instance):
def set_item(interval):
self.weather.text = instance.text
self.menu.dismiss()
Clock.schedule_once(set_item, 0.5)
class WindowManager(ScreenManager):
pass
sm = WindowManager()
class MainApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
kv = Builder.load_file("FR.kv")
def build(self):
screens = [AMRMenu(name = "menu"), GIWindow(name = "GI")]
for screen in screens:
sm.add_widget(screen)
sm.current = "menu"
return sm
if __name__ == "__main__":
MainApp().run()
And here is the kv. file:
<AMRMenu>:
name:"menu"
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Main Menu"
MDList:
OneLineListItem:
text: "General Information"
on_press: root.GIbutton()
OneLineListItem:
text: "Water Temperature"
OneLineListItem
text: "Feeding Amount"
OneLineListItem:
text: "Residue and Feeding response"
OneLineListItem:
text: "Dead fish"
OneLineListItem:
text: "Sell/Use"
<GIWindow>
name: "GI"
weather: weather
ScrollView:
id: screen
MDBoxLayout:
orientation: 'vertical'
adaptive_height: True
MDTextField:
id: weather
pos_hint: {'center_x': .5, 'center_y': .5}
hint_text: "Weather"
icon_right: "arrow-down-drop-circle-outline"
input_filter: lambda text, from_undo: text[:5 - len(self.text)]
on_focus: root.menu.open()
Here is the error message:
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/kivy/core/window/__init__.py", line 1297, in add_widget
(widget, widget.parent)
kivy.uix.widget.WidgetException: Cannot add <kivymd.uix.menu.MDDropdownMenu object at 0x7fd2fa31a6e0> to window, it already has a parent <kivy.core.window.window_sdl2.WindowSDL object at 0x7fd2f65826e0>
I don't know why I made this happen. It helps a lot if someone figures it out. Thank you for reading this question
The problem is that your kv line:
on_focus: root.menu.open()
is opening the menu every time the focus changes. So, it tries to open the menu even when the focus becomes false. An easy fix is to just open the menu when focus is True`:
on_focus: if self.focus: root.menu.open()

Access a kivy screenmanager created in a kv file through the py file

i want to create the ScreenManager in the kv file, but i also need th change the shown screen in the .py file. Thats because i have to create some buttons
dynamically and bind a specific function to them, which will change to a specific (button related) screen. Creating the buttons is way more convient in python. So the main question is: how to access the screenmanager created in a kv file through the py file?
To explain it a bit futher, here is some code:
kv file
#: kivy 1.10.1
ScreenManager:
id: screen_manager
FirstScreen:
id: first_screen
name: 'FirstScreen'
manager: 'screen_manager'
SecondScreen:
id: second_screen
name: 'SecondScreen'
manager: 'screen_manager'
py file
from kivy.modules import console
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.properties import ObjectProperty
class FirstScreen(Screen):
MenuScreen = ObjectProperty(None)
def SwitchToSecond(self):
print(ScreenManagement.current)
ScreenManagement.current = "TestScreen"
class SecondScreen(Screen):
pass
class testApp(App):
pass
if __name__ == "__main__":
testApp().run()
thank you for any guidance in advance
If you want to access the ScreenManager within a Screen you must use its manager attribute, but for this you must not create a property with the same name, in your case you are doing it which is considered a bad practice.
Modifying your code and adding some elements we obtain the following example:
*.kv
#: kivy 1.10.1
ScreenManager:
id: screen_manager
FirstScreen:
id: first_screen
name: 'FirstScreen'
Button:
text: "First"
on_press: first_screen.SwitchToSecond()
SecondScreen:
id: second_screen
name: 'SecondScreen'
Label:
text: "second"
.*py
from kivy.modules import console
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.properties import ObjectProperty
class FirstScreen(Screen):
MenuScreen = ObjectProperty(None)
def SwitchToSecond(self):
self.manager.current = "SecondScreen"
class SecondScreen(Screen):
pass
class testApp(App):
pass
if __name__ == "__main__":
testApp().run()
Here is a simple example using the ScreenManager (I also added a method inside of the MyScreenManager class that accepts a value, which would correspond to the name of the screen you would like to change to, but not necessary for this app to run):
Python
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class Screen3(Screen):
pass
class MyScreenManager(ScreenManager):
def changescreen(self, value):
self.current = value
#Main application
class TestApp(App):
def build(self):
self.sm = MyScreenManager()
return self.sm
if __name__ == '__main__':
TestApp().run()
kv
<MyScreenManager>:
Screen1:
name: 'screen1'
Screen2:
name: 'screen2'
Screen3:
name: 'screen3'
<Screen1>:
GridLayout:
rows: 2
padding: 20
spacing: 20
Button:
text: 'Go to Screen 2'
on_press: root.manager.current = 'screen2'
Button:
text: 'Go to Screen 3'
on_press: root.manager.current = 'screen3'
Label:
text: 'You are on ' + root.name
<Screen2>:
GridLayout:
rows: 2
padding: 20
spacing: 20
Button:
text: 'Go to Screen 1'
on_press: root.manager.current = 'screen1'
Button:
text: 'Go to Screen 3'
on_press: root.manager.current = 'screen3'
Label:
text: 'You are on ' + root.name
<Screen3>:
GridLayout:
rows: 2
padding: 20
spacing: 20
Button:
text: 'Go to Screen 1'
on_press: root.manager.current = 'screen1'
Button:
text: 'Go to Screen 2'
on_press: root.manager.current = 'screen2'
Label:
text: 'You are on ' + root.name

Kivy - Screen Manager - Accessing attribute in other class

Using the Kivy Screen Manager, I create two Screens. Whilst being in screen 1, i want to change a label in screen two. I highlight the problematic area in my code:
my test.ky:
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#: import SettingsScreen screen
ScreenManager:
MenuScreen:
SettingsScreen:
<MenuScreen>:
name: 'MenuScreen'
BoxLayout:
Button:
text: 'Goto nn'
on_press:
root.manager.current = 'SettingsScreen'
root.change_text()
<SettingsScreen>:
name: 'SettingsScreen'
label_id: label_field
BoxLayout:
Label:
id: label_field
text: "to_be_changed"
and my screen.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
def change_text(self):
pass
# HERE: something like
# root.SettingsScreen.label_field.text = 'new text'
class SettingsScreen(Screen):
pass
class TestApp(App):
pass
TestApp().run()
Any help is greatly appreciated!
Thanks, Nico
How about this:
When you press the button on MenuScreen, it sets an attribute on itself containing the text you want to put in the SettingsScreen Label. Then the MenuScreen is assigned an id value in the kv file, which is used to reference this attribute. Example:
main.py
class MenuScreen(Screen):
text = StringProperty('')
def change_text(self):
self.text = "The text you want to set"
self.manager.current = "SettingsScreen"
class SettingsScreen(Screen):
label_text = StringProperty('')
kv file
ScreenManager:
id: screen_manager
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: screen_manager
SettingsScreen:
name: 'SettingsScreen'
manager: screen_manager
label_text: menu_screen.text
<MenuScreen>:
BoxLayout:
Button:
text: 'Goto nn'
on_press:
root.change_text()
<SettingsScreen>:
BoxLayout:
Label:
text: root.label_text
As you can see, I set the names and id of the screens under ScreenManager itself in the kv file, as this is what I would usually do to make this work.

Categories