Kivy: changing image source on screen - python

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

Related

Kivy Python: buttons and classes for multiple screens

I have a problem with my Kivy Python Code. I have 2 screens: 1st is to navigate to the second screen and on the 2nd screen there is a button to add text to a scrollview...navigating is working but it does not add any text to the scrollview...I think I need some help here! AttributeError: 'super' object has no attribute 'getattr'
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock, mainthread
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.lang import Builder
Builder.load_string("""
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
""")
# Declare both screens
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self,**kwargs):
super().__init__(**kwargs)
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='mainmenu'))
sm.add_widget(Screen2(name='screen2'))
return sm
def add_text(self):
self.root.ids.label.text += f"Some new Text\n"
self.root.ids.scroll_view.scroll_y = 0
def exit_software(self):
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()
Thank you very much in advance!
The error occurred because self.root.ids gets access to widgets located in the root widget of the main class. To access the secondary screen elements, you need to add it to the main class (in your case, in ScreenManager) and set its id. Also, you have a lot of imported excess, so that it is clearly visible, I advise you to use Pycharm or something like that.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
kv = """
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
ScreenManager:
MenuScreen:
id: menu_scr
Screen2:
id: scr_2
"""
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
return Builder.load_string(kv)
def add_text(self):
self.root.ids.scr_2.ids.label.text += f"Some new Text\n"
self.root.ids.scr_2.ids.scroll_view.scroll_y = 0
#staticmethod
def exit_software():
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()

Kivy FileChooser Overlapping

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.

Kivy Incorporating Video to Navigation Drawer

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

How to populate recycleview from input on another 'screen'

good day
what im trying to accomplish is to input text on one screen then have it create a button on another screen within a recycleview where if I keep adding buttons the recycleview keeps getting populated. I would assume that the button1 function would update the rvs.rv.data and that the recycleview would use the it update itself. could you point me in the right direction please?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
kv = """
<custombutton#BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Button:
text: root.value
<Root>:
RVScreen:
name: 'Rv'
InputScreen:
name: 'input_screen'
<InputScreen>:
name: "input_screen"
orientation: "vertical"
BoxLayout:
orientation: "vertical"
TextInput:
id: textinput
Button:
text: "hi"
on_press: print(app.rvs.rv.data)
on_press: app.rvs.button1('some_value')
Button:
text: 'rvscreen'
on_press: root.manager.current = 'Rv'
<RVScreen>:
name: 'Rv'
rv: rv
orientation: "vertical"
BoxLayout:
orientation: "vertical"
Button:
text: 'refresh'
on_press: root.rv.refresh_from_data()
on_press: print(app.rvs.rv.data)
Button:
text: "input page"
on_press: root.manager.current = 'input_screen'
RecycleView:
id: rv
viewclass: 'custombutton'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
"""
Builder.load_string(kv)
class Root(ScreenManager):
pass
class RVScreen(Screen):
def __init__(self, **kwargs):
super(RVScreen, self).__init__(**kwargs)
def button1(self, value):
self.rv.data.insert(0, {'value': value or 'default value'})
class InputScreen(Screen):
pass
class TestApp(App):
rvs = RVScreen()
def build(self):
return Root()
if __name__ == '__main__':
TestApp().run()
The problem is that you are populating the data of the app.rvs, but that is created by the line:
rvs = RVScreen()
which creates a new RVScreen instance that is entirely unrelated to the RVScreen that is displayed in your GUI. In order to update the RVScreen in your GUI, you need to get a reference to that RVScreen.
I like to that that through a method in the App, just because it makes the code simpler. So here is a modified version of your code that does it my way:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
kv = """
<custombutton#BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Button:
text: root.value
<Root>:
RVScreen:
name: 'Rv'
InputScreen:
name: 'input_screen'
<InputScreen>:
name: "input_screen"
orientation: "vertical"
BoxLayout:
orientation: "vertical"
TextInput:
id: textinput
Button:
text: "hi"
on_press: app.add_data(textinput.text)
Button:
text: 'rvscreen'
on_press: root.manager.current = 'Rv'
<RVScreen>:
name: 'Rv'
rv: rv
orientation: "vertical"
BoxLayout:
orientation: "vertical"
Button:
text: 'refresh'
on_press: rv.refresh_from_data()
Button:
text: "input page"
on_press: root.manager.current = 'input_screen'
RecycleView:
id: rv
viewclass: 'custombutton'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
"""
Builder.load_string(kv)
class Root(ScreenManager):
pass
class RVScreen(Screen):
pass
class InputScreen(Screen):
pass
class TestApp(App):
# rvs = RVScreen() # this code does nothing useful
def build(self):
return Root()
def add_data(self, value):
# get the `Screen` instance
rvs = self.root.get_screen('Rv')
# insert the new value into the data
rvs.ids.rv.data.insert(0, {'value': value or 'default value'})
if __name__ == '__main__':
TestApp().run()
I also made a small modification, so that the new value comes from the TextInput.

How to switch screens from a dynamically created button in kivy recycleview

Problem
I have a screen (OrderScreen) that populates with buttons if there is data to be processed. I would like the user to click one of the buttons to be brought to another screen (MenuScreen) to process the data. While my intention is to populate the next screen with data from the button, I am currently just trying to get the ScreenManager to change to the next screen after a button press. I added a pass_data() method to the OrderButton and tried to trigger the screen manager there but self.manager.current and root.manager.current were throwing exceptions. Any help would be greatly appreciated.
recycleview_test.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.recycleview import RecycleView
from kivy.uix.screenmanager import ScreenManager, Screen
from random import randint
class MenuScreen(Screen):
def quit(self):
App.get_running_app.stop()
Window.close()
class OrderScreen(Screen):
pass
class OrderButton(Button):
def __init__(self, **kwargs):
super(OrderButton, self).__init__(**kwargs)
def pass_data(self):
print("button pushed")
class OrderScroll(RecycleView):
def __init__(self, **kwargs):
super(OrderScroll, self).__init__(**kwargs)
self.data = [{'text': str(f"Make {randint(10, 25)} items from package #{randint(1,4)}")} for x in range(12)]
class WindowManager(ScreenManager):
pass
class RecycleApp(App):
def build(self):
return WindowManager()
if __name__ == "__main__":
RecycleApp().run()
recycle.kv
#:import Factory kivy.factory.Factory
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#:import App kivy.app.App
<OrderScroll>:
viewclass: 'OrderButton'
manager: None
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
padding: 20
spacing: 10
<OrderButton>:
manager: None
font_size: 32
bold: True
on_release:
root.pass_data()
<WindowManager>:
id: screen_manager
OrderScreen:
id: order_screen
name: "OrderScreen"
manager: screen_manager
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: screen_manager
<OrderScreen>:
BoxLayout:
orientation: "vertical"
Label:
text: "Data Buttons"
font_size: 64
size_hint_y: None
# pos_hint: {"x":0, "y":1}
height: 200
OrderScroll:
<MenuScreen>:
BoxLayout:
orientation: "vertical"
Label:
text: "Made it"
font_size: 64
FloatLayout:
Button:
text: 'Keep going'
font_size: 48
size_hint: .8,.5
pos_hint: {"center_x": .5, "center_y": .1}
FloatLayout:
Button:
text: 'Quit'
size_hint: .15,.3
pos_hint: {"center_x": .5, "center_y": .5}
on_release:
root.quit()
Try to create an object of screen manager:
class RecycleApp(App):
def build(self):
self.sm = WindowManager()
return self.sm
And then access it by:
App.get_running_app().sm.current = 'MenuScreen' # in Python
app.sm.current = 'MenuScreen' # in kv

Categories

Resources