I have been trying off and on for two weeks to figure this out with no luck. This is the first time in my coding learning journey i've felt actually completely stuck. Any help is incredibly appreciated.
Right now my issue is changing screens outside of my .kv file. Right now I am trying to use:
class RootScreen(Screen):
def onNextScreen(self, btn, fileName):
MDApp.get_running_app().root.current = "ScreenVideo1"
MDApp.get_running_app().root.ScreenVideo1.test_on_enter(r'C:\file\location' + fileName + '.MOV')
But that gives the error code:
'RootScreen' object has no attribute 'ScreenVideo1'
main.py
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import MDList
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.properties import ObjectProperty
from kivy.uix.videoplayer import VideoPlayer
from kivy.uix.actionbar import ActionBar
from kivy.uix.button import Button
from kivy.core.window import Window
#remove after dev
Window.size = (300,500)
Window.clearcolor = (.976, .980, .996, 1)
screen_helper = r"""
RootScreen:
MDNavigationLayout:
ScreenManager:
id: screen_manager
ScreenHome:
id: screen_home
manager: screen_manager
name: "Home"
ScrollView:
pos_hint: {'bottom':1}
do_scroll_y: True
BoxLayout:
orientation: 'vertical'
padding: 15
spacing: 20
#size_hint: None, None
height: self.minimum_height
size_hint: (1, 2)
MDToolbar:
title: "POTUS"
left_action_items:[["menu",lambda x: nav_drawer.set_state("open")]]
elevation: 8
Widget:
StrokeButton:
text: "Video Category 1"
back_color: (0.576, 0.698, 0.996, 1) if self.state == 'normal' else (0.502, 0, 0.502, .75)
on_release: screen_manager.current = "Video1"
ScreenAbout:
id: screen_about
manager: screen_manager
name: "About"
MDLabel:
text: "About"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "POTUS"
left_action_items:[["menu",lambda x: nav_drawer.set_state("open")]]
elevation: 8
Widget:
ScreenHelp:
id: screen_help
manager: screen_manager
name: "Help"
MDLabel:
text: "Help"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "POTUS"
left_action_items:[["menu",lambda x: nav_drawer.set_state("open")]]
elevation: 8
Widget:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "POTUS"
left_action_items:[["menu",lambda x: nav_drawer.set_state("open")]]
elevation: 8
Widget:
ScreenVideo1:
id: screen_video1
manager: screen_manager
name: "Video1"
GridLayout:
pos_hint: {'top': 1}
cols:1
rows:5
ActionBar:
pos_hint: {'top': 1}
height:'100sp'
ActionView:
ActionPrevious:
with_previous: True
on_release: screen_manager.current = "Home"
StrokeButton:
text: " Video option 1"
back_color: (0.576, 0.698, 0.996, 1) if self.state == 'normal' else (0.502, 0, 0.502, .75)
on_release: root.onNextScreen(self, 'heart')
StrokeButton:
text: "Video option 2"
back_color: (0.576, 0.698, 0.996, 1) if self.state == 'normal' else (0.502, 0, 0.502, .75)
on_release:
StrokeButton:
text: "Video option 3"
back_color: (0.576, 0.698, 0.996, 1) if self.state == 'normal' else (0.502, 0, 0.502, .75)
on_release:
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation: 'vertical'
spacing: '8dp'
padding: '8dp'
MDLabel:
text: "blah blah blah"
font_style: 'Subtitle1'
size_hint_y: None
height: self.texture_size[1]
MDLabel:
text: "blah blah blah"
font_style: "Caption"
size_hint_y: None
height: self.texture_size[1]
ScrollView:
MDList:
OneLineIconListItem:
on_release:
screen_manager.current = "Home"
text: 'Home'
IconLeftWidget:
icon:"folder-home"
on_release:
screen_manager.current = "Home"
OneLineIconListItem:
on_release:
screen_manager.current = "Help"
text: 'Help'
IconLeftWidget:
icon:"help-circle-outline"
on_release:
screen_manager.current = "Help"
OneLineIconListItem:
on_release:
screen_manager.current = "About"
text: 'About'
IconLeftWidget:
icon: "doctor"
on_release:
screen_manager.current = "About"
<StrokeButton#Button>:
background_color:(0,0,0,0)
background_normal:''
back_color:(1,0,1,1)
border_radius: 18
color: self.back_color
bold: True
canvas.before:
Color:
rgba: self.back_color
Line:
rounded_rectangle: (self.pos[0],self.pos[1],self.size[0],self.size[1],self.border_radius)
width: 1.2
"""
class RootScreen(Screen):
def onNextScreen(self, btn, fileName):
MDApp.get_running_app().root.current = "ScreenVideo1"
MDApp.get_running_app().root.ScreenVideo1.test_on_enter(r'C:\file\location' + fileName + '.MOV')
class ScreenHome(Screen):
pass
class ScreenAbout(Screen):
pass
class ScreenHelp(Screen):
pass
class ScreenVideo1(Screen):
def test_on_enter(self, vidname):
#self.add_widget(Button(text="Back"))
self.vid = VideoPlayer(source=vidname, state='play',
options={'allow_stretch':True,
'eos': 'loop'})
self.add_widget(self.vid)
def on_leave(self):
pass
def onBackBtn(self):
self.vid.state = 'stop'
self.remove_widget(self.vid)
MDApp.get_running_app().root.current = "ScreenVideo1"
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(screen_helper)
return screen
DemoApp().run()
It used to be very easy when I was building my app with Manager
class Manager(ScreenManager):
transition = NoTransition()
screen_one = ObjectProperty(None)
screen_two = ObjectProperty(None)
screen_home = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(Manager, self).__init__(*args, **kwargs)
# list to keep track of screens we were in
self.list_of_prev_screens = []
class ScreensApp(MDApp):
def build(self):
return Manager()
if __name__ == "__main__":
ScreensApp().run()
And then I would just change screens using manager. But now that I am using the navigation drawer I can no longer build my app with manager.
class ScreenOne(Screen):
def onNextScreen(self, btn, fileName):
self.manager.list_of_prev_screens.append(btn.parent.name)
self.manager.current = 'screen2'
self.manager.screen_two.test_on_enter(r'C:\file\location' + fileName + '.MOV')
Your code:
class RootScreen(Screen):
def onNextScreen(self, btn, fileName):
MDApp.get_running_app().root.current = "ScreenVideo1"
MDApp.get_running_app().root.ScreenVideo1.test_on_enter(r'C:\file\location' + fileName + '.MOV')
is trying to treat the root widget of the App as a ScreenManager, but it isn't, it is a RootScreen. So, you need to access the ScreenManager, like this:
class RootScreen(Screen):
def onNextScreen(self, btn, fileName):
MDApp.get_running_app().root.ids.screen_manager.current = "Video1"
MDApp.get_running_app().root.ids.screen_manager.current_screen.test_on_enter(r'C:\file\location' + fileName + '.MOV')
Related
I have created code with 2 screens and need one of them to have an expansion panel.
Unfortunately I can't get the panel to show up with the content inside of it. Instead I'm stuck with chaos in my head and a side of migraine, so here is my code, an example of what I want it to look like and what I managed to create minus my full code.
Video example: https://www.kapwing.com/videos/62f4074bafd00100c829b84c
Video example of problem: https://www.kapwing.com/videos/62f41c828f6acd00521caae1
As shown in the video example:
1st code:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.expansionpanel import MDExpansionPanelOneLine
from kivymd.uix.boxlayout import MDBoxLayout
KV = '''
MDScreen:
MDNavigationLayout:
ScreenManager:
id: manager
MDScreen:
name: 'Home'
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
MDToolbar:
md_bg_color: 0, 0, 0, 0.5
title: "Example"
elevation: 10
left_action_items: [["menu", lambda x: mud_list.set_state("open")]]
right_action_items: [["dots-vertical", lambda x:app.dropdown(x)]]
MDNavigationDrawer:
id: mud_list
BoxLayout:
orientation: 'vertical'
spacing: '5dp'
padding: '5dp'
ScrollView:
MDList:
OneLineIconListItem:
text: '[Settings]'
on_release:
manager.current = 'Settings'
root.ids.mud_list.set_state(new_state='toggle', animation=True)
divider: None
IconLeftWidget:
icon: 'cog'
on_release:
manager.current = 'Settings'
root.ids.mud_list.set_state(new_state='toggle', animation=True)
MDLabel:
text:' By Author'
size_hint_y: None
font_style: 'Button'
height: self.texture_size[1]
MDScreen:
name: 'Settings'
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
MDToolbar:
id: mdt_color
md_bg_color: 1, 1, 1, 1
elevation: 10
MDIconButton:
icon: "keyboard-backspace"
pos_hint: {"center_x": 0.09, "center_y": 0.945}
on_release: manager.current = 'Home'
MDBoxLayout:
size_hint: 1, 0.89
orientation : 'vertical'
ScrollView:
MDBoxLayout:
orientation:'vertical'
adaptive_height: True
padding:[dp(15),dp(15),dp(15),dp(35)]
spacing:dp(15)
Content
adaptive_height: True
orientation: 'vertical'
OneLineIconListItem:
text: "Dark"
on_release:app.theme_changer2()
divider: None
IconLeftWidget:
icon: 'weather-night'
on_release:app.theme_changer2()
OneLineIconListItem:
text: "Light"
on_release:app.theme_changer()
divider: None
IconLeftWidget:
icon: 'white-balance-sunny'
on_release:app.theme_changer()
ScrollView:
MDGridLayout:
id: box
cols: 1
adaptive_height: True
'''
class Content(MDBoxLayout):
"""Custom content."""
def __draw_shadow__(self, origin, end, context=None):
pass
class MainApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu = None
self.menu_list = None
self.kvs = Builder.load_string(KV)
self.screen = Builder.load_string(KV)
def on_start(self):
self.root.ids.box.add_widget(
MDExpansionPanel(
icon="theme-light-dark",
content=Content(),
panel_cls=MDExpansionPanelOneLine(
text="Theme",
)
)
)
def theme_changer(self):
self.theme_cls.theme_style = "Light"
self.root.ids.mdt_color.md_bg_color = [1, 1, 1, 1]
def theme_changer2(self):
self.theme_cls.theme_style = "Dark"
self.root.ids.mdt_color.md_bg_color = [0, 0, 0, 1]
def build(self):
self.theme_cls.theme_style = "Light"
screen = Screen()
screen.add_widget(self.kvs)
return self.screen
ma = MainApp()
ma.run()
2nd code: I got from the kivymd documentation here https://github.com/kivymd/KivyMD/wiki/Components-Expansion-Panel
3rd code is much the same as the 2nd but I made my own:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelOneLine
KV = '''
<Content>
adaptive_height: True
orientation: 'vertical'
OneLineIconListItem:
text: "Dark"
divider: None
IconLeftWidget:
icon: 'weather-night'
OneLineIconListItem:
text: "Light"
divider: None
IconLeftWidget:
icon: 'white-balance-sunny'
ScrollView:
MDGridLayout:
id: box
cols: 1
adaptive_height: True
'''
class Content(MDBoxLayout):
"""Custom content."""
def __draw_shadow__(self, origin, end, context=None):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
self.root.ids.box.add_widget(
MDExpansionPanel(
icon="theme-light-dark",
content=Content(),
panel_cls=MDExpansionPanelOneLine(
text="Theme",
)
)
)
Test().run()
My problem is, as seen in the example of problem video, that the expansion panel itself doesn't show up.
I am figuring this out as I go along, so among all the chaos I have tried, I have noticed that the position of the "Content" and all that's under it in relation the anchor layout of screen 'settings', causes the panel to show up but the content isn't inside.
Same effect with whether the "content" or "MDGridlayout" have the id: box.
In summary, I want to be able to create something like in the 2nd code but in the settings screen of my main app, or basically copy and paste the 3rd code into my main app.
Oh, and I may make this a question on it's own later, but if it's simple enough, how can I make it so when the theme is changed it becomes the default?
Took a while, but with help i finally got it. Here's an example with what i think are some key notes in the code #Comments#.
Hope this helps someone.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelOneLine
KV = '''
#THE CONTENT GOES ABOVE EVERYTHING ELSE EVEN THE 1ST SCREEN.#
#IT IS REFERENCED LATER IN WHICH EVER SCREEN IT IS TO APPEAR USING MDGridLayout AND A def LATER ON#
#It should also always have these angle brackets <>#
<Content>
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
OneLineIconListItem:
text: 'Dark theme'
on_release:app.theme_changer2()
divider: None
IconLeftWidget:
icon: 'weather-night'
on_release:app.theme_changer2()
OneLineIconListItem:
text: 'Light theme'
on_release:app.theme_changer()
divider: None
IconLeftWidget:
icon: 'white-balance-sunny'
on_release:app.theme_changer()
<Content2>
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
OneLineIconListItem:
text: 'I try to explain what i think are key points to note'
on_release:app.theme_changer2()
divider: None
IconLeftWidget:
icon: 'weather-night'
on_release:app.theme_changer2()
OneLineIconListItem:
text: 'Hope this helps someone else'
on_release:app.theme_changer()
divider: None
IconLeftWidget:
icon: 'white-balance-sunny'
on_release:app.theme_changer()
MDScreen:
MDNavigationLayout:
ScreenManager:
id: manager
MDScreen:
name: 'Home'
#The location of this MDGridLayout shows it appears in the 1st screen.#
MDGridLayout:
cols: 1
adaptive_height: True
#This id is used to reference what content goes to which expansion panel#
id: box2
MDRaisedButton:
pos_hint: {"center_x": 0.5, "center_y": 0.5}
text: "PRESS ME"
on_release: manager.current = 'Home2'
MDScreen:
name: 'Home2'
MDBoxLayout:
orientation: "vertical"
MDToolbar:
id: mdt_color
elevation: 10
ScrollView:
divider: 'None'
#The location of this MDGridLayout shows it appears in the 2nd screen.#
MDGridLayout:
cols: 1
adaptive_height: True
id: box
MDIconButton:
pos_hint: {"center_x": 0.05, "center_y": 0.945}
icon: "keyboard-backspace"
on_release: manager.current = 'Home'
'''
# Every expansion panel should have a class corresponding to it's name e.g.#
class Content(MDBoxLayout):
pass
# The class name is referenced in the contents= section below#
class Content2(MDBoxLayout):
pass
class MainApp(MDApp):
def theme_changer(self):
self.theme_cls.theme_style = "Light"
self.root.ids.mdt_color.md_bg_color = [1, 1, 1, 1]
def theme_changer2(self):
self.theme_cls.theme_style = "Dark"
self.root.ids.mdt_color.md_bg_color = [0, 0, 0, 1]
def build(self):
return Builder.load_string(KV)
def on_start(self):
# Here you see the id box used#
self.root.ids.box.add_widget(
MDExpansionPanel(
icon="theme-light-dark",
# Here the content name Content is referenced in content=#
content=Content(),
panel_cls=MDExpansionPanelOneLine(
text="Theme",
)
)
)
# Here you see the id box2 used#
self.root.ids.box2.add_widget(
MDExpansionPanel(
icon="theme-light-dark",
# Here the content name Content2 is referenced in content=#
content=Content2(),
panel_cls=MDExpansionPanelOneLine(
text="Read the code #comments# for details",
)
)
)
ma = MainApp()
ma.run()
I am using the FileChooserListView from kivy and have run into a overlapping text on scroll with screens that another user came across as well. I looked through their post on GitHub and read that some people are using the plyer FileChooser. I also saw that someone mentioned that it has to do with the Building function of the .kv file. I created a new kivy app and the problem did not occur, but when I return to my older app (no changes of any kind) the problem still occurs.
Sorry for the long post, but I am unsure how these two kivy app codes are different. Am I calling something twice that is causing the FileChooser to "hold" it's position? I am not oppose to using plyer's FileChooser, but could someone give me an example on how to implement it?
testing_kivy.py
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
import os
def train_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class TrainingWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class WindowManager(ScreenManager):
pass
kv_training = Builder.load_file('testing_kivy.kv')
class MyApp(App):
def build(self):
return kv_training
if __name__ == '__main__':
MyApp().run()
testing_kivy.kv
WindowManager:
TrainingWindow:
<TrainingWindow>
name: "training"
BoxLayout:
orientation: "vertical"
Button:
text: "Select Training Images"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Select Training Annots"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Set Parameters"
font_size: 32
on_release:
app.root.current = "parameters_train"
root.manager.transition.direction = "up"
Button:
text: "Back"
font_size: 16
on_release:
app.root.current = "select"
root.manager.transition.direction = "right"
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
Older_app.py
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.spinner import SpinnerOption
import os
import pandas as pd
def invalid_login():
app = App.get_running_app()
app.root.current = "main"
# Create a BoxLayout to add multiple lines or buttons to a PopUp
box = BoxLayout()
# Create PopUp
pop = Popup(
title="Invalid Password",
size_hint=(None, None), size=(200, 100),
content=box,
auto_dismiss=False
)
# Dismiss PopUp
box.add_widget(Button(text="Close", on_release=pop.dismiss))
pop.open()
def model_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
def train_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
def train_model_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
class MainWindow(Screen):
def login(self):
if self.ids.password.text == "password":
self.ids.password.text = ""
app = App.get_running_app()
app.root.current = "select"
else:
self.ids.password.text = ""
invalid_login()
class SelectWindow(Screen):
pass
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class TrainingWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class ModelWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=model_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class TrainModelWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_model_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class ParametersTrainModelWindow(Screen):
pass
class ParametersTrainWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class OverViewTrainWindow(Screen):
pass
class OverViewTrainModelWindow(Screen):
pass
class OverViewModelWindow(Screen):
pass
class MyOption(SpinnerOption):
pass
kv_main= Builder.load_file('main.kv')
class MyApp(App):
def build(self):
return kv_main
if __name__ == '__main__':
MyApp().run()
main.kv
#:import utils kivy.utils
#:include select.kv
#:include training.kv
#:include model.kv
#:include train_model.kv
#:include parameters_train.kv
#:include parameters_train_model.kv
#:include overview_train_model.kv
#:include overview_train.kv
#:include overview_model.kv
WindowManager:
MainWindow:
SelectWindow:
TrainingWindow:
ModelWindow:
TrainModelWindow:
ParametersTrainWindow:
ParametersTrainModelWindow
OverViewTrainWindow:
OverViewTrainModelWindow:
OverViewModelWindow:
<MainWindow>
name: "main"
GridLayout:
cols: 1
BoxLayout:
orientation: "vertical"
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint: 1, 1
text: "SPECPHASE"
font_size: 50
color:
utils.get_color_from_hex('#FF0000')
Label:
size_hint: 1, 1
text: "Object Detection App"
font_size: 40
BoxLayout:
size_hint: 1, 0.005
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
orientation: "horizontal"
size_hint: (0.35, 0.35)
padding: (0,0,25,0)
Label:
font_size: 20
text: "Password"
size_hint: (0.5, 0.35)
pos_hint: {'x': 1, 'y': 0.4}
background_color: (0,0,0,1)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
TextInput:
id: password
multiline: False
size_hint: (0.5, 0.35)
pos_hint: {'x': 1, 'y': 0.4}
focus: True
background_color:
utils.get_color_from_hex('#18B8D9')
cursor_color: (0,0,0,1)
password: True
Button:
text: "Submit"
on_release: root.login()
select.kv
<SelectWindow#Screen>:
name: "select"
GridLayout:
cols: 1
GridLayout:
cols: 2
Button:
text: "Train"
font_size: 32
on_release:
app.root.current = "training"
root.manager.transition.direction = "right"
Button:
text: "Model"
font_size: 32
on_release:
app.root.current = "model"
root.manager.transition.direction = "left"
Button:
text: "Train & Model"
font_size: 32
on_release:
app.root.current = "train_model"
root.manager.transition.direction = "up"
training.kv
<TrainingWindow#Screen>:
name: "training"
BoxLayout:
orientation: "vertical"
Button:
text: "Select Training Images"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Select Training Annots"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Set Parameters"
font_size: 32
on_release:
app.root.current = "parameters_train"
root.manager.transition.direction = "up"
Button:
text: "Back"
font_size: 16
on_release:
app.root.current = "select"
root.manager.transition.direction = "right"
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
After taking a break from this for while and restarting my brain, I was able to find the problem.
Not included in my question, I have a couple more .kv files that have a similar layout to the training.kv. They are used to access other screens. I found that I was calling FileChooserListView in each screen and I belive that is why I was seeing the stacking problem. I ended up removing all of them except for the one in my training.kv file and all is working.
How can I access a button in the Helper in the classroom? I want to change the color of a button later.
I want to change the color of the button whose id is reflex_button after a while, but my only problem is how do I get the button with this id value in ReflexScreen class.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen,ScreenManager
Window.size = (300, 500)
helper = """
ScreenManager:
MenuScreen:
ReflexScreen:
<ReflexScreen>:
name: 'reflex'
Button:
id: reflex_button
text: 'Wait Change The Color'
font_size: '20sp'
pos_hint: {'center_x':0.5, 'center_y':0.5}
on_press: root.manager.current = 'menu'
size_hint_x: None
size_hint_y: None
width: 300
height: 500
background_color: 1,0,0,0.8
<MenuScreen>
name: 'menu'
Screen:
NavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
left_action_items: [["menu", lambda x: nav_drawer.toggle_nav_drawer()]]
right_action_items: [["dots-vertical", lambda x: nav_drawer.toggle_nav_drawer()]]
elevation:10
Widget:
MDRectangleFlatButton:
text: 'Play'
on_press: root.manager.current = 'reflex'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
"""
class MenuScreen(Screen):
pass
class ReflexScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(ReflexScreen(name='reflex'))
sm.add_widget(MenuScreen(name='screen'))
class ReflexApp(MDApp):
def build(self):
screen = Builder.load_string(helper)
return screen
ReflexApp().run()
I started learning Kivy and I am new to this, I would be glad if you could help.
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivymd.app import MDApp
Window.size = (300, 500)
helper = """
ScreenManager:
MenuScreen:
ReflexScreen:
<ReflexScreen>:
name: 'reflex'
Button:
id: reflex_button
text: 'Wait Change The Color'
font_size: '20sp'
pos_hint: {'center_x':0.5, 'center_y':0.5}
on_press: root.manager.current = 'menu'
size_hint_x: None
size_hint_y: None
width: 300
height: 500
background_color: 1,0,0,0.8
<MenuScreen>
name: 'menu'
Screen:
NavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
left_action_items: [["menu", lambda x: nav_drawer.toggle_nav_drawer()]]
right_action_items: [["dots-vertical", lambda x: nav_drawer.toggle_nav_drawer()]]
elevation:10
Widget:
MDRectangleFlatButton:
text: 'Play'
on_press: root.manager.current = 'reflex'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
"""
class MenuScreen(Screen):
pass
class ReflexScreen(Screen):
def on_enter(self, *args):
"""Event fired when the screen is displayed: the entering animation is
complete."""
print(self.ids.reflex_button)
class ReflexApp(MDApp):
def build(self):
screen = Builder.load_string(helper)
return screen
ReflexApp().run()
I'm doing a Navigation Drawer. When use the example of documentation with "Builder.load_string" run without problem. However, if I separed in two files (.py and .kv) using "Builder.load_file" don't run. Why? Thanks!
Here example with "Builder.load_string":
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import OneLineIconListItem, MDList
KV = '''
# Menu item in the DrawerList list.
<ItemDrawer>:
theme_text_color: "Custom"
on_release: self.parent.set_color_item(self)
IconLeftWidget:
id: icon
icon: root.icon
theme_text_color: "Custom"
text_color: root.text_color
<ContentNavigationDrawer>:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
size_hint: None, None
size: "56dp", "56dp"
source: "data/logo/kivy-icon-256.png"
MDLabel:
text: "KivyMD library"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
MDLabel:
text: "kivydevelopment#gmail.comÃ"
font_style: "Caption"
size_hint_y: None
height: self.texture_size[1]
ScrollView:
DrawerList:
id: md_list
Screen:
NavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Navigation Drawer"
elevation: 10
left_action_items: [['menu', lambda x: nav_drawer.toggle_nav_drawer()]]
Widget:
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
id: content_drawer
'''
class ContentNavigationDrawer(BoxLayout):
pass
class ItemDrawer(OneLineIconListItem):
icon = StringProperty()
class DrawerList(ThemableBehavior, MDList):
def set_color_item(self, instance_item):
"""Called when tap on a menu item."""
# Set the color of the icon and text for the menu item.
for item in self.children:
if item.text_color == self.theme_cls.primary_color:
item.text_color = self.theme_cls.text_color
break
instance_item.text_color = self.theme_cls.primary_color
class MainApp(MDApp):
def build(self):
print(type(Builder.load_string(KV)))
return Builder.load_string(KV)
def on_start(self):
icons_item = {
"folder": "My files",
"account-multiple": "Shared with me",
"star": "Starred",
"history": "Recent",
"checkbox-marked": "Shared with me",
"upload": "Upload",
}
for icon_name in icons_item.keys():
print(self.root.ids.content_drawer.ids.md_list.add_widget)
self.root.ids.content_drawer.ids.md_list.add_widget(
ItemDrawer(icon=icon_name, text=icons_item[icon_name])
)
MainApp().run()
Here example with two files "Builder.load_file":
file .py:
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import OneLineIconListItem, MDList
class ContentNavigationDrawer(BoxLayout):
pass
class ItemDrawer(OneLineIconListItem):
icon = StringProperty()
class DrawerList(ThemableBehavior, MDList):
def set_color_item(self, instance_item):
"""Called when tap on a menu item."""
# Set the color of the icon and text for the menu item.
for item in self.children:
if item.text_color == self.theme_cls.primary_color:
item.text_color = self.theme_cls.text_color
break
instance_item.text_color = self.theme_cls.primary_color
class MainApp(MDApp):
def build(self):
print(type(Builder.load_string(KV)))
return Builder.load_file("main.kv")
def on_start(self):
icons_item = {
"folder": "My files",
"account-multiple": "Shared with me",
"star": "Starred",
"history": "Recent",
"checkbox-marked": "Shared with me",
"upload": "Upload",
}
for icon_name in icons_item.keys():
print(self.root.ids.content_drawer.ids.md_list.add_widget)
self.root.ids.content_drawer.ids.md_list.add_widget(
ItemDrawer(icon=icon_name, text=icons_item[icon_name])
)
MainApp().run()
.kv file:
# Menu item in the DrawerList list.
<ItemDrawer>:
theme_text_color: "Custom"
on_release: self.parent.set_color_item(self)
IconLeftWidget:
id: icon
icon: root.icon
theme_text_color: "Custom"
text_color: root.text_color
<ContentNavigationDrawer>:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
size_hint: None, None
size: "56dp", "56dp"
source: "data/logo/kivy-icon-256.png"
MDLabel:
text: "KivyMD library"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
MDLabel:
text: "kivydevelopment#gmail.com"
font_style: "Caption"
size_hint_y: None
height: self.texture_size[1]
ScrollView:
DrawerList:
id: md_list
Screen:
NavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Navigation Drawer"
elevation: 10
left_action_items: [['menu', lambda x: nav_drawer.toggle_nav_drawer()]]
Widget:
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
id: content_drawer
After much headbanging, I've created an app that opens the FileChooser and picks an image. A function will then transform the image and change it on the screen.
< FirstScreen > is just something to start with, relatively unimportant.
< SecondScreen > is the file chooser. The path may need editing. < ThirdScreen > shoudl show the image along with buttons that will eventually lead elsewhere.
I suspect the problem is that the line
sm.current = "_third_screen_"
is creating a new instance separate to everything else I've passed items too. How do I show the image I selected?
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
Builder.load_string("""
<MyScreenManager>:
FirstScreen:
SecondScreen:
ThirdScreen:
<FirstScreen>:
name: '_first_screen_'
BoxLayout:
orientation: "horizontal"
Label:
id: first_screen_label
text: "Hi, I'm the home page"
BoxLayout:
orientation: "vertical"
Button:
text: "Okay!"
on_press: root.manager.current = '_second_screen_'
Button:
text: "Cancel!"
on_press: app.stop()
<SecondScreen>:
name: '_second_screen_'
id: file_chooser
BoxLayout:
id: file_chooser_box_layout
orientation: "horizontal"
Button
text: "Open"
on_press:
root.callback_image_and_other_stuff(file_chooser_list_view.selection)
FileChooserListView:
id: file_chooser_list_view
<ThirdScreen>:
name: '_third_screen_'
BoxLayout:
orientation: "vertical"
id: third_screen
Label:
id: main_title
text: "Upload"
size_hint: (1, 0.1)
Image:
id: main_image
source: root.img
size_hint: (1, 0.75)
BoxLayout:
orientation: "horizontal"
padding: 10
size_hint: (1, 0.15)
Button:
text: "Okay"
size_hint: (0.5, 1)
on_press: image_viewer.image_accepted_by_user(filechooser.selection)
Button:
text: "Cancel"
size_hint: (0.5, 1)
on_press: root.manager.current = '_first_screen_'
""")
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
def callback_image_and_other_stuff(self, new_image_address):
# do other stuff here also, then pass new_image_address along
new_image_address = new_image_address[0].replace("\\", "/")
third_screen = ThirdScreen()
third_screen.callback_image(new_image_address)
class ThirdScreen(Screen):
img = ObjectProperty(None)
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
def callback_image(self, new_image_address):
sm.current = "_third_screen_"
self.img = new_image_address
self.ids.main_image.source = self.img
print(self.img)
# Create the screen manager
sm = ScreenManager() # Problem?
sm.add_widget(FirstScreen(name='_first_screen_'))
sm.add_widget(SecondScreen(name='_second_screen_'))
sm.add_widget(ThirdScreen(name='_third_screen_'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
Every time you use some_obj = SomClass() you are creating a new object, in your case that is what you are doing, you are creating a new ThirdScreen different from the one shown by that you do not observe the image, the solution is that you have to access to the initial object using the ScreenManager and name screen.
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
Builder.load_string("""
<FirstScreen>:
BoxLayout:
orientation: "horizontal"
Label:
id: first_screen_label
text: "Hi, I'm the home page"
BoxLayout:
orientation: "vertical"
Button:
text: "Okay!"
on_press: root.manager.current = '_second_screen_'
Button:
text: "Cancel!"
on_press: app.stop()
<SecondScreen>:
id: file_chooser
BoxLayout:
id: file_chooser_box_layout
orientation: "horizontal"
Button
text: "Open"
on_press:
root.callback_image_and_other_stuff(file_chooser_list_view.selection)
FileChooserListView:
id: file_chooser_list_view
<ThirdScreen>:
BoxLayout:
orientation: "vertical"
id: third_screen
Label:
id: main_title
text: "Upload"
size_hint: (1, 0.1)
Image:
id: main_image
source: root.img
size_hint: (1, 0.75)
BoxLayout:
orientation: "horizontal"
padding: 10
size_hint: (1, 0.15)
Button:
text: "Okay"
size_hint: (0.5, 1)
on_press: image_viewer.image_accepted_by_user(filechooser.selection)
Button:
text: "Cancel"
size_hint: (0.5, 1)
on_press: root.manager.current = '_first_screen_'
""")
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
def callback_image_and_other_stuff(self, new_image_address):
if new_image_address:
third_screen = self.manager.get_screen("_third_screen_")
# do other stuff here also, then pass new_image_address along
new_image_address = new_image_address[0].replace("\\", "/")
third_screen.callback_image(new_image_address)
class ThirdScreen(Screen):
img = ObjectProperty(None)
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
def callback_image(self, new_image_address):
sm.current = "_third_screen_"
self.img = new_image_address
self.ids.main_image.source = self.img
print(self.img)
# Create the screen manager
sm = ScreenManager() # Problem?
sm.add_widget(FirstScreen(name='_first_screen_'))
sm.add_widget(SecondScreen(name='_second_screen_'))
sm.add_widget(ThirdScreen(name='_third_screen_'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()