kivy button calls method of another class - python

I have a simple problem which keeps me busy in the last days.
In Kivy I have two Windows.
FirstWindow has a method update(), which is triggered by a button press.
On SecondWindow I have only one button, which sends me back to FirsWindow, but I want it to trigger the update() method from FirstWindow and change the label, just like the "update label" button does on FirstWindow, without previously pressing the "update label" button.
Any help, please?
file.py
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
FirstWindow().update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my_test.kv')
MyTestApp().run()
my_test.kv
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()
I think critical is this method, whitch needs to be remake, but I have no idea how
def go_first(self):
FirstWindow().update()

You can't directly access another screen which is defined as another class. First, you have to access the ScreenManager i.e. Parent class and then from it get the screen FirstScreen
So the go_first function in your code will look like this:
def go_first(self):
self.parent.get_screen('first').update()
EDIT:
Here's full code:
main.py:
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
self.parent.get_screen('first').update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my.kv')
MyTestApp().run()
my.kv:
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()

Related

Geeting error in reading a file and pronting it as Label in kivy

I am trying to read text from a file and show it as Label in another screen but i am getting error that text file's content in not str even after using str() function.
Error:
ValueError: Screen1.usename accept only str
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivy.properties import StringProperty
class Screen1(Screen):
def gb(self):
f=open('test.txt','r')
b=f.read()
t=str(b)
return t
usename = StringProperty("")
class Screen2(Screen):
username = StringProperty("")
root = Builder.load_string('''
<Screen1>:
BoxLayout:
orientation: "vertical"
Button:
text:'ue'
on_release: root.usename = root.gb; root.manager.current = "screen2"
<Screen2>:
name: "screen2"
Label:
text: root.username
ScreenManager:
Screen1:
id: loginscreen
Screen2:
username: loginscreen.usename
''')
class MyApp(App):
def build(self):
return root
r=MyApp()
r.run()
Your code:
on_release: root.usename = root.gb
is trying to set the usename to a method (root.gb). You probably want to set usename to the return value of that method. Try just adding (), like this:
on_release: root.usename = root.gb()
I finally solved the issue, this's how we can read a text file and display it as label in another screen in kivy.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
from kivy.properties import StringProperty
class Screen1(Screen):
f=open('test.txt','r')
t=f.readlines()
b=t[0]
f.close()
class Screen2(Screen):
username = StringProperty("")
root = Builder.load_string('''
<Screen1>:
name:'xy'
id:loginscreen
BoxLayout:
orientation: "vertical"
Button:
text:'Execution button'
on_release: root.manager.current = "screen2"
<Screen2>:
name: "screen2"
FloatLayout:
Label:
text: root.username
Button:
text:'Back to menu'
size_hint:.3,.3
on_release: root.manager.current = "xy"
ScreenManager:
Screen1:
id:loginscreen
Screen2:
username: loginscreen.b
''')
class MyApp(App):
def build(self):
return root
r=MyApp()
r.run()

How can I send some text from popup to label in another class which is inherited from the Screen class?

Sorry my english.
How can I send some text from popup to label in another class which is inherited from the Screen class?
I tried different options for accessing this object, but nothing happens.
It looks like text sends to another object, because these objects has different memory adresses. I checked it.
Comment indicating the problem is in the code:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.popup import Popup
Builder.load_string("""
#:import Factory kivy.factory.Factory
<Keyboard>:
text_input: text_input
BoxLayout:
orientation: 'vertical'
TextInput:
id: text_input
Button:
text: 'Send text'
on_release: root.send()
<Container>:
label: label
BoxLayout:
orientation: 'vertical'
Label:
id: label
text: 'Here must some be text from popup'
Button:
text: 'My popup'
on_release: Factory.Keyboard().open()
Button:
text: 'Goto options'
on_press: root.manager.current = 'Options'
<Options>:
BoxLayout:
Button:
text: 'Back to time'
on_press: root.manager.current = 'Time'
""")
class Options(Screen):
def show_kv(self, instance, value):
self.manager.current = value
class Container(Screen):
pass
class Keyboard(Popup):
def send(self):
try:
time = self.text_input.text
except:
time = ''
# Here is some problem
Container().label.text = time # Nothing happens
self.dismiss()
class KivyApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Container(name='Time'))
sm.add_widget(Options(name='Options'))
sm.current = "Time"
return sm
if __name__ == '__main__':
KivyApp().run()
The line:
Container().label.text = time
is creating a new instance of Container, and sets the text of a Label in that new instance. However, that instance of Container is not the one that appears in your GUI. You must access the instance that is actually in your GUI. You can do that using the get_screen() method of the ScreenManager that is the root of your GUI. Like this:
container_instance = App.get_running_app().root.get_screen('Time')
container_instance.label.text = time

cannot remove widget in Kivy

i cannot remove widget using the screen with kivy python, i dont know why it just does not do anything
the code was suppose to remove textinput with id:name on the first screen but it just does not do anything and no error message.
here is all of the code it is tested on python 3.7.4, kivy 1.11.1 on window.
module_media_player.py
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.uix.videoplayer import VideoPlayer
from kivy.uix.screenmanager import ScreenManager,Screen
class Player(Screen):
def press(self):
self.ids.name.text = 'nice'
def remove(self):
self.remove_widget(self.ids.name)
class MediaPlayer(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('my.kv')
class GoodApp(App):
def build(self):
return kv
if __name__ == '__main__':
GoodApp().run()
my.kv
WindowManager:
Player:
MediaPlayer:
<Player>:
name:"player"
BoxLayout:
orientation:"vertical"
size:root.width,root.height
cols:2
TextInput:
id:name
multiline:False
text:"first"
font_size:12
size_hint_y:0.3
Button:
text:"click me"
on_press:root.remove()
Button:
text:"next window"
font_size:14
size_hint_y:0.7
on_release:
app.root.current = "mediaplayer"
root.manager.transition.direction = "left"
<MediaPlayer>:
name:"mediaplayer"
BoxLayout:
orientation:"vertical"
size:root.width,root.height
Label:
text:"second"
font_size:12
Button:
text:"previous window"
font_size:14
on_release:
app.root.current = "player"
root.manager.transition.direction = "right"
Your code:
def remove(self):
self.remove_widget(self.ids.name)
is trying to remove the TextInput from the Player Screen, but that Textinput is not a child of Player. It is actually a child of the BoxLayout. You can fix this by modifying your remove() method:
def remove(self):
textinput = self.ids.name
textinput.parent.remove_widget(textinput) # remove widget from its parent

Changing the screen and running a function on kivyMD?

I am learning Kivy, but I do not kown how to change a screen and running a funtion at the same time.
Where should I declare my funtion so the button have access to the code and can run the function?
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press: root.manager.current = 'function screen'
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(FunctionScreen(name='function'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(screen_helper)
return screen
# def funtion(self):
# do stuff and then go to menu screen
DemoApp().run()
Should I try maybe, add the on_opress atribute in the build function?
Can you guys help me?
There are several convenient places to place the function(). One is in the MenuScreen, and in that case, it would be referenced in the kv files as:
root.function()
Another convenient place is in the DemoApp, and in that case, the reference would be:
app.function()
So, here is a version of your code tht puts the function() in the App:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press:
root.manager.current = 'function screen'
app.function()
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
class DemoApp(MDApp):
def build(self):
sm = Builder.load_string(screen_helper)
return sm
def function(self):
# do stuff and then go to menu screen
print('in function')
DemoApp().run()
Note that the lines of your code that built a ScreenManager have been deleted as they are unnecessary.

Only one root object is allowed by .kv

I am doing an online kivy tutorial. Below is the code that I have written. It is exactly as was in the tutorial video.
But when I run the code I get the following error:
...
1:import FadeTransition kivy.uix.screenmanager.FadeTransition
2:
>> 3:ScreenManagement:
4: transition: FadeTransition()
5:
...
Only one root object is allowed by .kv
I think the error is with the FadeTransition because I have two instances-MainScreen and AnotherScreen but I do not know how to rectify it. And in the tutorial video the code ran properly. So why isn't it executing in my computer?
Below is the code that I have written
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_string('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Next Screen"
font_size: 50
on_release: root.app.current = "other"
<AnotherScreen>:
name: "other"
Button:
text: "Back Home"
font_size: 50
on_release: root.app.current = "main"
''')
class MainApp(App):
def build(self):
return presentation()
if __name__=="__main__":
MainApp().run()
Thanks in advance.
Try this code it might help a bit took a long time for me to figure it out:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = ('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Next Screen"
font_size: 50
on_release: root.app.current = "other"
<AnotherScreen>:
name: "other"
Button:
text: "Back Home"
font_size: 50
on_release: root.app.current = "main"
''')
class MainApp(App):
def build(self):
return Builder.load_string(presentation)
if __name__=="__main__":
MainApp().run()
I came across the exact issue as you while watching the same video. You will need to do this instead (assuming you want a fade transition):
Main.py file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager): #here you are creating a screen manager called ScreenManagement
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
presentation = Builder.load_file("Main2.kv") #telling the app which .kv file to use
class MainApp(App):
def build(self):
return presentation
runMain = MainApp()
runMain.run()
Now over to your Main2.kv file:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition() #telling the screen manager to use a fade transition
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main" #this name is what the screen manager uses to distinguish which screen to go to
Button:
text: "Go To Next Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "another" #the screen that the screen manager is told to go to
<AnotherScreen>:
name: "another"
Button:
text: "Go To Main Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "main"
Hope that helped.
In your kv file, you need to surround ScreenManagement class with "<" and ">" as shown in the example below.
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
class ScreenManagement(ScreenManager):
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class MainApp(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
MainApp().run()
main.kv
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
<ScreenManagement>:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Go To Next Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "another"
<AnotherScreen>:
name: "another"
Button:
text: "Go To Main Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "main"
Output

Categories

Resources