from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanger import ScreenManager, Screen
Builder.load_string("""
<MenuScreen>:
BoxLayout:
FloatLayout:
Image:
id: homebackg
pos: 0, 0
source: "dark.png"
<SettingsScreen>:
BoxLayout:
FloatLayout:
Image:
id: settingsbackg
pos: 0, 0
source: "dark.png"
Button:
text: ""
color: 1.0, 1.0, 1.0, 0.0
on_press:
root.buttonclick()
""")
class MenuScreen(Screen):
def darkmode(self):
self.ids.homebackg.source = "dark.png"
def litemode(self):
self.ids.homebackg.source = "lite.png"
class SettingsScreen(Screen):
def darkmode(self):
self.ids.settingsbackg.source = "dark.png"
def litemode(self):
self.ids.settingsbackg.source = "lite.png"
def buttonclick(self):
file = open("stat.txt", "r")
themestat = file.read()
file.close()
if themestat == "lite":
SettingsScreen.darkmode(self)
MenuScreen.darkmode(self)
file = open("stat.txt", "w")
file.write("dark")
file.close()
elif themestat == "dark":
SettingsScreen.litemode(self)
MenuScreen.litemode(self)
file = open("stat.txt", "w")
file.write("lite")
file.close()
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
Assume I have done the screen transitions properly not adding to make code less bulky, I have issue with changing background of menuscreen from the settingsscreen. It is for darkmode you see, thanks in advance.
Self is not defined when executing MenuScreen.darkmode(self) from SettingsScreen.
You problem is that you are adding objects of screens to screen manager (and you will see only these objects) and then you are creating new objects and make changes there. So since you are using global variables the simplest solution would be:
sm = ScreenManager()
menuscreen = MenuScreen(name='menu')
settingsscreen = SettingsScreen(name='settings')
sm.add_widget(menuscreen)
sm.add_widget(settingsscreen)
And inside the classes you can just make changes to them like:
menuscreen.darkmode()
P.S. 'self' means object of the class, in Python self is used to have access to class variables and functions from functions defined in that class. And here you don't need to send 'self' to another class because you're sending object of SettingsScreen class to MenuScreen darkmode function and do nothing with it. If you want to send object there should be:
# you send object of SettingsScreen
menuscreen.darkmode(self)
# and receive it as obj for example
def darkmode (self, obj):
...
Related
output KivyMD Programmers, im new in KivyMD....
on_start() list items are sucessfully showing and on_press sending a selected value too passValue() function....
but here now i wants open new Screen under passValue() function...and pass variable value's to new Screen....
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen,ScreenManager
from kivy.lang import Builder
from kivymd.uix.list import OneLineListItem
#Builder String
helper_string = '''
ScreenManager:
Hello:
Bye:
<Hello>:
name: 'hello'
ScrollView:
MDList:
id: list
<Bye>:
name: 'bye'
MDLabel:
text:'Good Bye'
MDLabel:
id:'aaa'
text:""
'''
class Hello(Screen):
pass
class Bye(Screen):
pass
sm = ScreenManager()
sm.add_widget(Hello(name = 'hello'))
sm.add_widget(Bye(name = 'bye'))
class DemoApp(MDApp):
def build(self):
screen = Screen()
self.help_str = Builder.load_string(helper_string)
screen.add_widget(self.help_str)
return screen
def on_start(self):
for i in range(50):
item = OneLineListItem(text='Item ' + str(i),
on_release=lambda x, value_for_pass={i}: self.passValue(value_for_pass)
)
self.help_str.get_screen('hello').ids.list.add_widget(item)
def passValue(self, *args):
args_str = ','.join(map(str,args))
print(args_str)
self.help_str.get_screen('bye').manager.current = 'bye' #how to pass/send args_str's value to bye screen???
DemoApp().run()
Since It's not clear exactly where in your screen Bye you want some variable to be passed, let's suppose you want to pass a list's text to the MDLabel having text 'Good Bye' of the screen Bye by method passValue.
You may achieve this as follows:
First in the kvlang of screen Bye assign an id say, target to the MDLabel,
<Bye>:
name: 'bye'
MDLabel:
id: target
text:'Good Bye'
Then in your method passValue,
def passValue(self, *args):
args_str = ','.join(map(str,args))
print(args_str)
bye_screen = self.help_str.get_screen('bye')
bye_screen.manager.current = 'bye'
bye_screen.ids.target.text = args_str
As a side note you perhaps don't need (as you already defined that in kvlang) the following:
sm = ScreenManager()
sm.add_widget(Hello(name = 'hello'))
sm.add_widget(Bye(name = 'bye'))
I tried to change the text of another screen from current screen. But it didn't work
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
from kivy.lang.builder import Builder
Builder.load_string("""
<Input_Screen>:
input: input
BoxLayout:
orientation : "vertical"
TextInput:
id: input
text: "Changed"
Button:
text: "Enter"
on_press : root.clicked()
<Display_Screen>:
nice: nice
BoxLayout:
orientation : "vertical"
Label:
id: nice
text: "NotChanged"
""")
class Input_Screen(Screen):
input = ObjectProperty(None)
def clicked(self):
Display_Screen().change()
class Display_Screen(Screen):
nice = ObjectProperty(None)
def change(self):
print(self.nice.text) #Checking the Current text of The Label
print(Input_Screen().input.text) #Checking What do we want to change
self.nice.text = Input_Screen().input.text
print(self.nice.text) #Checking if it has change or not
MyApp().sm.current = "Ds" #Changing Screen to Display_Screen
print(self.nice.text) #Checking if it has change or not
class MyApp(App):
sm = ScreenManager()
def build(self):
self.sm.add_widget(Input_Screen(name="Is"))
self.sm.add_widget(Display_Screen(name="Ds"))
return self.sm
MyApp().run()
What I get in My console:
NotChanged #Checked the Current text of The Label
Changed #Checked What do we want to change
Changed #Checked if it has change or not
Changed #Checked if it has change or not
It says that my Label's text has been changed but when it goes to the next screen it hasn't been changed.
Display_Screen
Anyone knows whats the problem? Help me please
Whenever you use a construction like ClassName(), you are creating a new instance of ClassName. You are doing this in your change() method and in your clicked() method. Whenever you do that, you are referencing that new instance, and not the instance that is in your GUI.
To fix that, change:
def clicked(self):
Display_Screen().change()
to:
def clicked(self):
self.manager.get_screen('Ds').change()
and in your change() method, replace:
Input_Screen()
with:
self.manager.get_screen('Is')
and replace"
MyApp()
with:
App.get_running_app()
I am trying to use Kivy to create an interface. But when I try to show the text of a variable (result) it doesn't show it. Here the code:
from kivymd.app import MDApp
from kivy.lang import Builder
from covid import Covid
covid = Covid(source='worldometers')
data = covid.get_status_by_country_name('Italy')
for k in data:
result = k+str(data[k])
KV = '''
Screen:
Label:
text: result
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
'''
class MainApp(MDApp):
def build(self):
self.title = "Covid"
self.theme_cls.theme_style = "Dark" # Light
self.theme_cls.primary_palette = "Red"
return Builder.load_string(KV)
MainApp().run()
I'm sorry for my english but I'm Italian then I'm not very good.
Good day. Kivy is an App framework. You need to create an entire App class and build your logic into the App.
I recommend that after you create the App class, instantiate it, run it, then run your logic code in your App.
kv script:
Screen:
MDRectangleButton:
on_release: app.calculate_result_callback
In Python:
import .......
data = covid.get_status_by_country_name('Italy')
covid = Covid(source='worldometers')
def calculate_result():
result = ""
for k in data:
result += k+str(data[k])
return result
class MyApp(App):
def calculate_result_callback(self, instance, *a):
result = calculate_result()
instance.text = result
I want to be able to use my custom (python written) widget in both the kv file and in python code. I don't know how to create a widget, then use it in my chosen layout.
class SelectableList(FocusBehavior, CompoundSelectionBehavior, StackLayout):
previous_nodes=[]
# this class has a whole bunch of "def's" that I got rid of so that stack would let me post a shorter question
class myScreen(Screen):
def build(self):
self.root_boi = StackLayout(size=(1,1))
stack = SelectableList(touch_multiselect=True,
multiselect=True)
for i in range(0, 6):
stack.add_widget(Button(size_hint_y=None, height=30, text="Button {0}".format(i)))
self.root_boi.add_widget(stack)
return self.root_boi
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(myScreen(name='whatever you want it to be...'))
return myScreen()
TestApp().run()
I'm not sure exactly what I'm doing wrong here. I'm trying to add the "SelectableList" widget into a stack layout. I want to be able to add it to whatever widget I choose, either within a kv file or in my python code. If that makes sense...
I suspect your build() method of myScreen should actually be an __init__() method (with no return). I added self.add_widget(self.root_boi) in place of the return. And the class name should be capitalized (MyScreen), since the kv language gets fussy about that sometimes.
Here is a modified version of your code that demonstrates using your custom widgets:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.behaviors import FocusBehavior, CompoundSelectionBehavior
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.stacklayout import StackLayout
class SelectableList(FocusBehavior, CompoundSelectionBehavior, StackLayout):
previous_nodes=[]
# this class has a whole bunch of "def's" that I got rid of so that stack would let me post a shorter question
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
self.root_boi = StackLayout(size=(1,1))
stack = SelectableList(touch_multiselect=True,
multiselect=True)
for i in range(0, 6):
stack.add_widget(Button(size_hint_y=None, height=30, text="Button {0}".format(i)))
self.root_boi.add_widget(stack)
self.add_widget(self.root_boi)
class TestApp(App):
def build(self):
return Builder.load_string(kv)
kv = '''
# ScreenManager:
# MyScreen:
#
# or
#
ScreenManager:
Screen:
name: 'whatever'
StackLayout:
SelectableList:
touch_multiselect: True
multiselect: True
Button:
text: 'Button 0'
size_hint_y: None
height: 30
Button:
text: 'Button 1'
size_hint_y: None
height: 30
Button:
text: 'Button 2'
size_hint_y: None
height: 30
'''
TestApp().run()
The __init__() method of MyScreen must include a call to the super __init__().
The kv string in the above code shows two different uses of your custom widgets. The first (commented out) uses the MyScreen custom widget. The second (not commented out) uses the SelectableList custom widget.
I have schedule_interval calling a function that fetches weather data from the web and then parses it into a dict. I have my kv file reading that dict and displaying values in a floatlayout. I know the function is being called because I am having it print to the console also, but it is not updating in the floatlayout window. I thought the values would automatically update from what I have read.
GUI.py
class weather(FloatLayout):
def w(self):
a = parse()
print(a)
return a
class weatherApp(App):
def build(self):
d = weather()
Clock.schedule_interval(d.w, 1)
return d
weather.kv
<Layout>:
DragLabel:
font_size: 600
size_hint: 0.1, 0.1
pos: 415,455
text: str(root.w()['temp0'])
This is just one of the labels. I am very new to Kivy so
if this looks atrocious to you experienced kivy
people, I apologize.
The print(a) part of def w(self): works every second, but the window does not display the new variables.
test.py
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
a = {}
a['num'] = 0
class test(FloatLayout):
def w(self):
a['num'] += 1
print(a['num'])
return a
class testApp(App):
def build(self):
d = test()
Clock.schedule_interval(test.w, 1)
return d
if __name__ == '__main__':
p = testApp()
p.run()
test.kv
#:kivy 1.10.1
<Layout>:
Label:
font_size: 200
size_hint: 0.1, 0.1
pos: 415,455
text: str(root.w()['num'])
It seems that you have several misconceptions:
If you invoke a function in python it does not imply that the .kv will be called. So if you call the w method with Clock.schedule_interval() it does not imply that the calculated value updates the value of the Label text.
When you call a function with Clock.schedule_interval you must use the object not a class. in your case, test is class and instead, d is the object.
When you call a function with Clock.schedule_interval you must use the object not a class. in your case, test is class and instead, d is the object.
*.py
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import DictProperty
class test(FloatLayout):
a = DictProperty({"num": 0})
def w(self, dt):
self.a["num"] += 1
print(self.a["num"])
class testApp(App):
def build(self):
d = test()
Clock.schedule_interval(d.w, 1)
return d
if __name__ == "__main__":
p = testApp()
p.run()
*.kv
#:kivy 1.10.1
<Layout>:
Label:
font_size: 200
size_hint: 0.1, 0.1
pos: 415,455
text: str(root.a["num"])