I got a popup filechooser from the below link:
Kivy popup Filechooser pass variable (selection)
I cannot get the file path string value to pass between my main Tab() class instance of the app and the class FileChoosePopup popup instance. I know this question has been asked before, but I cannot seem to figure it out. When I run the app and click on the file I want to pass to a TextInput on my main class I get the following error:
AttributeError: 'super' object has no attribute '__getattr__'
I have tried passing a reference to the popup class instance in the main class by using the super init method, but then the app does not even initialize.
Here is my popup in python:
class FileChoosePopup(Popup):
file_path = StringProperty("No file chosen")
def __init__(self, **kwargs):
super(FileChoosePopup, self).__init__(**kwargs)
self.Tab = Tab()
def load(self, selection):
self.file_path = str(selection[0])
path_file = self.file_path
the_file = self.ids.get_file #is the textinput id
if path_file != "No file chosen":
the_file.text = path_file
self.dismiss()
else:
self.dismiss()
class Tab(StackLayout):
def open_popup(self):
the_popup = FileChoosePopup()
the_popup.open()
Here the kivy code:
<FileChoosePopup>:
title: "Choose a .CSV File"
size_hint: .9, .9
auto_dismiss: False
BoxLayout:
orientation: "vertical"
FileChooser:
id: filechooser
FileChooserIconLayout
BoxLayout:
size_hint: (1, 0.1)
pos_hint: {'center_x': .5, 'center_y': .5}
spacing: 20
RoundedCancelButton:
text: "Cancel"
on_release: root.dismiss()
RoundedAcceptButton:
text: "Load"
on_release: root.load(filechooser.selection)
id: ldbtn
disabled: True if filechooser.selection==[] else False
<Tab>:
TabbedPanel:
do_defualt_tab: False
background_color: (.87, .87, .87, 1)
border: [0, 0, 0, 0]
background_image: 'path/to/background/image'
TabbedPanelItem:
text: 'Import'
background_color: (1, .5, 0, 1)
background_normal: ''
StackLayout:
orientation: 'lr-tb'
size_hint_y: None
height: 30
spacing: 5
Label:
text: ''
size_hint_x: 1
Label:
text: ''
size_hint_x: 0.2
RoundedButton:
text: 'Choose File'
size_hint_x: 0.2
on_press: root.open_popup()
TextInput:
id: get_file
readonly: True
size_hint_x: 0.4
Label:
text: ''
size_hint_x: 0.2
Can someone please give me some pointers on how to get the value to pass from the popup to the textinput?
Reference TextInput
Populate TextInput by using the following:
self.ids.get_file.text = self.file_path
Example
main.py
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import ObjectProperty, StringProperty
from kivy.lang import Builder
class FileChoosePopup(Popup):
load = ObjectProperty()
class Tab(TabbedPanel):
file_path = StringProperty("No file chosen")
the_popup = ObjectProperty(None)
def open_popup(self):
self.the_popup = FileChoosePopup(load=self.load)
self.the_popup.open()
def load(self, selection):
self.file_path = str(selection[0])
self.the_popup.dismiss()
print(self.file_path)
# check for non-empty list i.e. file selected
if self.file_path:
self.ids.get_file.text = self.file_path
Builder.load_file('main.kv')
class TestApp(App):
def build(self):
return Tab()
if __name__ == "__main__":
TestApp().run()
main.kv
<FileChoosePopup>:
title: "Choose a .CSV File"
size_hint: .9, .9
auto_dismiss: False
BoxLayout:
orientation: "vertical"
FileChooser:
id: filechooser
FileChooserIconLayout
BoxLayout:
size_hint: (1, 0.1)
pos_hint: {'center_x': .5, 'center_y': .5}
spacing: 20
Button:
text: "Cancel"
on_release: root.dismiss()
Button:
text: "Load"
on_release: root.load(filechooser.selection)
id: ldbtn
disabled: True if filechooser.selection==[] else False
<Tab>:
do_default_tab: False
TabbedPanelItem:
text: 'Import'
background_color: (1, .5, 0, 1)
background_normal: ''
StackLayout:
orientation: 'lr-tb'
size_hint_y: None
height: 30
spacing: 5
Label:
text: ''
size_hint_x: 1
Label:
text: ''
size_hint_x: 0.2
Button:
text: 'Choose File'
size_hint_x: 0.2
on_press: root.open_popup()
TextInput:
id: get_file
readonly: True
size_hint_x: 0.4
Label:
text: ''
size_hint_x: 0.2
Output
Related
I am making an application with different functions, one of them is Notes. I want to implement a transition to another window in which the text field will be located when a button is pressed. The problem is that when I switch, I cannot set the text parameter for TextInput to whatever I want, since the function responsible for switching to another window is in another class.
Unfortunately, the text parameter is being changed but not displayed in the window.. I'm just learning how to build Kivy applications, any help would be greatly appreciated.
python.py
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.animation import Animation
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from functools import partial
Window.size = (500, 700)
Window.clearcolor = "#1b1a28"
class MainWindow(Screen):
def go_window(self, window, widget, *args):
self.manager.current = window
animate = Animation(duration=0.4, background_color=(96/255, 85/255, 83/255, 1), color=(1,1,1,1))
animate.start(widget)
def animation(self, widget, *args):
animate = Animation(duration=0.1)
animate += Animation(size_hint=(1.2,1.2),duration=0.1,background_color=(0,0,0,-1))
animate += Animation(size_hint=(1,1),duration=0.1,color=(0,0,1,0))
animate.start(widget)
def on_press(self, widget, *args):
if widget.gid == "accounts":
self.animation(widget)
Clock.schedule_once(partial(self.go_window, "second", widget), 0.5)
if widget.gid == "notes":
self.animation(widget)
Clock.schedule_once(partial(self.go_window, "third", widget), 0.5)
ThirdWindow().write() #I call a function from another class, hoping that it will work(
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
def __init__(self, **kwargs):
super(ThirdWindow, self).__init__(**kwargs)
Window.bind(on_request_close=self.exit_program)
def go_back(self, widget, *args):
if widget.gid == "notes":
print(self.ids.notes2.text)
self.manager.current = "main"
def write(self):
self.ids.notes2.text = "test"
print(1)
def exit_program(self, *args):
print(self.ids.notes2.text)
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("widgets.kv")
class MyApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyApp().run()
file.kv
WindowManager:
MainWindow:
SecondWindow:
ThirdWindow:
<MainWindow>:
name: "main"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
id: text
text: "Wellcome!"
halign: "center"
font_size: 50
size_hint: (1, .3)
color: "#dcd3c2"
bold: True
ScrollView:
GridLayout:
cols: 2
spacing: 5
padding: 22, 0, 22, 50
size_hint: (1, 1.3)
Button:
gid: "accounts"
text: "Accounts"
font_size: 40
background_normal: ''
background_color: "#605553"
bold: True
on_release: root.on_press(self)
Button:
gid: "notes"
text: "Notes"
font_size: 40
background_normal: ''
background_color: "#605553"
bold: True
on_release: root.on_press(self)
Button:
gid: "people"
background_normal: ''
background_color: "#605553"
bold: True
text: "People"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
Button:
background_normal: ''
background_color: "#605553"
bold: True
text: "Test"
font_size: 40
on_release: root.on_press(self)
<SecondWindow>
name: "second"
BoxLayout:
orientation: "vertical"
TextInput:
text: "Hello"
Button:
text: "Go Back"
on_release: app.root.current = "main"
<ThirdWindow>:
name: "third"
the_time: notes2
BoxLayout:
orientation: "vertical"
TextInput:
id: notes2
font_size: 35
background_color: "#1D2847"
foreground_color: "#F5B662"
size_hint: (1, 1.8)
Button:
gid: "notes"
background_normal: ''
background_color: "#605553"
bold: True
text: "Back"
font_size: 40
size_hint: (1, 0.2)
on_release: root.go_back(self)
The problem is with your line of code:
ThirdWindow().write()
This code is creating a new instance of ThirdWindow and calling its write() method. But the new instance of ThirdWindow is not the instance that is in your App. The correct instance of ThirdWindow is created by your Builder.load_file() call, which creates a WindowManager with an instance of ThirdWindow as one of its children. So you can access the correct instance of ThirdWindow via that WindowManager, like this:
thirdWindow = self.manager.get_screen('third')
thirdWindow.write()
I want to know the method of loading the second screen when authentication is passed.
I can call the second screen from the .kv file vi on_press or other methods. But I need to call from python code to check the authentication.
Can anyone help with my code?
Here is my code:
app.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
class my_layout(FloatLayout):
screen_mngr = ObjectProperty(None)
class myapp(MDApp):
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file("app.kv")
def logger(self):
if self.root.ids.user.text == 'admin' and self.root.ids.password.text=='admin':
self.root.ids.welcome_label.text = f'Sup {self.root.ids.user.text}!'
screen = Screen(name='screen2')
else:
self.root.ids.welcome_label.text = 'Wrong credentials'
if __name__ == "__main__":
myapp().run()
And here is my design kv file.
app.kv file:
my_layout:
screen_mngr: screen_mngr
ScreenManager:
id: screen_mngr
home: home
Screen:
id: home
name: 'home'
MDCard:
size_hint: None, None
size: 450, 600
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: 25
spacing: 25
orientation: 'vertical'
MDLabel:
id: welcome_label
text: "WELCOME"
font_size: 40
halign: 'center'
size_hint_y: None
height: self.texture_size[1]
padding_y: 15
MDTextField:
id: user
hint_text: "username"
icon_right: "account"
size_hint_x: None
width: 200
font_size: 18
pos_hint: {"center_x": 0.5}
MDTextField:
id: password
hint_text: "password"
icon_right: "eye-off"
size_hint_x: None
width: 200
font_size: 18
pos_hint: {"center_x": 0.5}
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: screen2
Screen:
id: screen2
name: 'screen2'
MDRoundFlatButton:
text: "This is Second Screen\nGo to Screen1"
size_hint: 0.2,0.1
pos_hint: {"center_x":0.5,"y":0.5}
on_press: screen_mngr.current = "home"
A couple small problems:
First, in your kv you need to have your LOG IN Button call the code to handle the log in, like this:
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: app.logger() # call the method that handles login
Then, in that method, you can change to the screen2 by using the current property of the ScreenManager, like this:
def logger(self):
if self.root.ids.user.text == 'admin' and self.root.ids.password.text=='admin':
self.root.ids.welcome_label.text = f'Sup {self.root.ids.user.text}!'
self.root.ids.screen_mngr.current = 'screen2' # go to screen2
# screen = Screen(name='screen2')
else:
self.root.ids.welcome_label.text = 'Wrong credentials'
I have made a popup to show up when an error occurs, with a button that closes the popup when clicked. All worked well until I tried getting an error for 2 times. In the second time the popup did not close and I am wondering if there is a way to work it out.
This is the python code:
class MyPopup(Popup):
filechooser= ObjectProperty(None)
class ErrorPopup(Popup):
filechooser= ObjectProperty(None)
class Main(FloatLayout):
audio_check= ObjectProperty(None)
video_check= ObjectProperty(None)
spinner_id= ObjectProperty(None)
yt_link=ObjectProperty(None)
name=ObjectProperty(None)
error_label=ObjectProperty(None)
def submit_text(self):
self.error_popup=MyApp()
if self.audio_check.active and self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text).first().download(path, filename=self.name.text+'.mp4')
except:
self.error_popup.error()
elif self.audio_check.active and not self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(only_audio=True).first().download(path, filename=self.name.text+'.mp3')
except:
self.error_popup.error()
elif not self.audio_check.active and self.video_check.active:
try:
YouTube(self.yt_link.text).streams.filter(res=self.spinner_id.text, only_video =True).first().download(path, filename=self.name.text+'.mp4')
except:
self.error_popup.error()
elif not self.audio_check.active and not self.video_check.active:
self.error_popup.error()
def spinner_clicked(self, value):
self.ids.spinner_id.text= value
class MyApp(App):
def build(self):
return Main()
def open_popup(self):
self.popup = MyPopup()
self.popup.open()
def dismiss_popup(self):
self.popup.dismiss()
global path
path=self.popup.filechooser.path
def error(self):
self.error_popup= ErrorPopup()
self.error_popup.open()
def try_again(self):
self.error_popup.dismiss()
print("Andrew")
if __name__ == '__main__':
MyApp().run()
This is the kivy code:
<MyPopup>:
auto_dismiss: False
title: "Select a folder"
filechooser: filechooser
FloatLayout:
FileChooserIconView:
id: filechooser
Button:
id:my_button
text: 'Save'
size_hint: (0.1, 0.1)
pos_hint:{'x': 0, 'y': 0}
on_release: app.dismiss_popup()
<ErrorPopup>:
title: "Error"
Button:
text: "Try Again"
on_release: app.try_again()
<Main>:
audio_check: audio_check
video_check: video_check
spinner_id: spinner_id
yt_link: yt_link
name: name
folder_button: folder_button
BoxLayout:
orientation:'vertical'
cols: 4
Label:
text: "YouTube Downloader"
halign: 'center'
bold: True
font_size:'50sp'
TextInput:
id: yt_link
size_hint: (.5, .2)
multiline: False
hint_text: 'Enter the link of the Youtube video you want to download.'
pos_hint: {"x": 0.25}
TextInput:
id: name
size_hint: (.5, .2)
multiline: False
hint_text: 'Enter the name you want the file to have.'
pos_hint: {"x": 0.25}
BoxLayout:
cols:4
BoxLayout:
Label:
text: "Audio:"
halign: 'center'
font_size:'20sp'
CheckBox:
id: audio_check
BoxLayout:
Label:
text: "Video:"
halign: 'center'
font_size:'20sp'
CheckBox:
id: video_check
FloatLayout:
Spinner:
id: spinner_id
text: "Quality"
values: ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p']
on_text: root.spinner_clicked(spinner_id.text)
size_hint: None, None
size: 130, 50
pos_hint: {'x': .2, 'y':.4}
FloatLayout:
Button:
id:folder_button
text: 'Folder'
on_release: app.open_popup()
size_hint: None, None
size: 130, 50
pos_hint: {'x':0.2,'y':.4}
Button:
text: "Submit"
size_hint: (.5, .2)
pos_hint: {"x": 0.25}
on_release: root.submit_text()
The problem is in your submit() method. The code:
self.error_popup=MyApp()
is creating a new instance of MyApp, then the code:
self.error_popup.error()
is calling the error() method from that new instance of MyApp. You need to be calling the methods of the App that you are running. To do that, just remove the line:
self.error_popup=MyApp()
And replace:
self.error_popup.error()
with:
App.get_running_app().error()
This makes sure that you are calling the error() method of the App that you are running.
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.
I have problems with giving the text of my button when clicking on the label in list from MDDropdownMenu. In my testing main.py and main.kv it has been working, but when it was implemented in main code - it has an error AttributeError: 'super' object has no attribute '__getattr__'
There is my main.py:
# encoding=utf8
import sys
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.core.text import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.screenmanager import SlideTransition
from kivy.properties import ObjectProperty, NumericProperty, StringProperty, BooleanProperty, ListProperty
from kivy.utils import get_hex_from_color
from kivy.metrics import dp, sp, pt
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
from kivymd.theming import ThemeManager
from kivymd.dialog import MDDialog
from kivymd.label import MDLabel
from kivymd.button import MDRoundFlatButton
from kivymd.button import MDRaisedButton
from kivymd.list import ILeftBodyTouch
from kivymd.popupscreen import MDPopupScreen
from newpickers import MDDatePicker
from kivymd.menus import MDDropdownMenu
year1 = 0
monthlist = ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь',]
monthnum = 0
selected_date = ''
class Manager(ScreenManager):
def __init__(self, **kwargs):
super(Manager, self).__init__(**kwargs)
class MainMenu(Screen):
pass
class InfoMenu(Screen):
pass
class ListButton(MDRaisedButton):
pass
class DateSetupMenu(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu_items = [
{
"viewclass": "MDMenuItem",
"text": "%d" % i,
"callback": self.callbackforlist,
}
for i in range(1900, 2100)
]
def callbackforlist(self, *args):
pass
class Year_layout_popup1(GridLayout):
pass
class Year_layout_scrollview1(ScrollView):
pass
class YearButton1(MDRaisedButton):
pass
class YearSelectionButton(MDRoundFlatButton):
def on_release(self):
global year1
year1 = int(self.text)
class DatePickPopup(Popup):
pass
class Month_layout_popup(GridLayout):
pass
class Month_layout_scrollview(ScrollView):
pass
class MonthButton(MDRaisedButton):
pass
class DatePickerWidget(MDDatePicker):
pass
class MonthSelectionButton(MDRoundFlatButton):
def on_release(self):
global monthlist
global monthnum
monthnum = int(monthlist.index(str(self.text)))
monthnum += 1
class MonthPickPopup(Popup):
pass
class yearselectbtn(Button):
pass
class monthselectbtn(Button):
pass
class rt_android(App):
theme_cls = ThemeManager()
theme_cls.device_orientation == 'portrait'
title = 'Rectif Tattva Android Edition'
yearselectlabeltext = StringProperty('Выберите год рождения')
monthselectlabeltext = StringProperty('Выберите месяц рождения')
dateselectlabeltext = StringProperty('Выберите день рождения')
mlist = ['Месяц','Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь']
VARIABLE = ""
def build(self):
self.theme_cls.theme_style = 'Light'
Window.size = (480, 854)
return Manager()
def CloseExitPopup(self, *args):
from kivymd.toast.kivytoast import toast
if args[0] == 'Да':
App.get_running_app().stop()
else:
pass
def ExitDialog(self):
self.dialog = MDDialog(
title='Выход из приложения', size_hint=(.8, .25), text_button_ok='Нет',
text="Вы точно хотите выйти?",
text_button_cancel='Да',
events_callback=self.CloseExitPopup)
self.dialog.open()
def OpenDatePicker(self, *args):
DatePickerWidget(self.set_date, year1, monthnum, 1).open()
def set_date(self, date_obj):
global selected_date
global year1
global monthnum
global daynum
self.setupdate = date_obj
selected_date = str(self.setupdate)
year1 = int(selected_date[0:4])
monthnum = int(selected_date[5:7])
daynum = int(selected_date[8:10])
month_id = monthnum-1
def year_select_clicked1(self):
self.ylp = Year_layout_popup1()
self.ylp.bind(minimum_height=self.ylp.setter('height'))
# for i in range(1950, 2019):
# self.ysb = YearSelectionButton()
# self.ysb.text = str(i)
# self.ylp.add_widget(self.ysb)
for i in range(1950, 2019):
self.ysb = yearselectbtn()
self.ysb.text = str(i)
self.ylp.add_widget(self.ysb)
root = Year_layout_scrollview1()
root.add_widget(self.ylp)
self.popup = DatePickPopup()
self.popup.content = root
self.popup.open()
def month_select_clicked(self):
global monthlist
self.mlp = Month_layout_popup()
self.mlp.bind(minimum_height=self.mlp.setter('height'))
# for i in range(0, 12):
# self.msb = MonthSelectionButton()
# self.msb.text = str(monthlist[i])
# self.msb.id = str(i)
# self.mlp.add_widget(self.msb)
for i in range(0, 12):
self.msb = monthselectbtn()
self.msb.text = str(monthlist[i])
self.msb.id = str(i)
self.mlp.add_widget(self.msb)
root = Month_layout_scrollview()
root.add_widget(self.mlp)
self.popup_m = DatePickPopup()
self.popup_m.content = root
self.popup_m.open()
def closeitpls(self):
self.popup.dismiss()
def closeitpls_m(self):
self.popup_m.dismiss()
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
class CreditsImage(Image):
pass
with open("main_interface.kv", encoding='utf8') as f:
main_interface = Builder.load_string(f.read())
if __name__ == '__main__':
rt_android().run()
And there is my main_interface.kv:
# encoding=utf8
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
#:import Factory kivy.factory.Factory
#:import MDLabel kivymd.label.MDLabel
#:import MDRaisedButton kivymd.button.MDRaisedButton
#:import MDRectangleFlatButton kivymd.button.MDRectangleFlatButton
#:import MDToolbar kivymd.toolbar.MDToolbar
#:import MDRoundFlatButton kivymd.button.MDRoundFlatButton
#:import MDDropdownMenu kivymd.menus.MDDropdownMenu
#:import MDMenuItem kivymd.menus.MDMenuItem
#:import hex kivy.utils.get_color_from_hex
#:set white hex('#00a86b')
<MenuButton#MDRaisedButton>:
font_size: dp(8)
elevation_normal: 3
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint_x: 0.5
height: dp(50)
<InfoMenuButton#MDRaisedButton>:
font_size: dp(8)
elevation_normal: 3
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
height: dp(50)
<DateSetupMenuButton#MDRaisedButton>:
font_size: dp(8)
elevation_normal: 3
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
height: dp(50)
<Year_layout_popup1>:
cols: 1
spacing: 15
padding: [10,10,10,10]
size_hint_y: None
<Year_layout_scrollview1>:
size_hint: (1, None)
size: Window.width*0.8, Window.height*0.7
<YearButton1>:
font_size: dp(8)
elevation_normal: 3
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
height: dp(50)
<DatePickPopup>:
title: 'Выбор года рождения'
size_hint: 0.8, 0.8
auto_dismiss: False
separator_color: white
title_color: white
background: 'assets/whiteback.png'
<YearSelectionButton>:
font_size: dp(8)
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: 1, None
height: dp(50)
on_press:
app.yearselectlabeltext = self.text
on_release:
app.closeitpls()
<Month_layout_popup>:
cols: 1
spacing: 15
padding: [10,10,10,10]
size_hint_y: None
<Month_layout_scrollview>:
size_hint: (1, None)
size: Window.width*0.8, Window.height*0.7
<MonthButton>:
font_size: dp(8)
elevation_normal: 3
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
height: dp(50)
<MonthPickPopup>:
title: 'Выбор месяца рождения'
size_hint: 0.8, 0.8
auto_dismiss: False
separator_color: white
title_color: white
background: 'assets/whiteback.png'
<MonthSelectionButton>:
id: ''
font_size: dp(8)
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: 1, None
height: dp(50)
on_press:
app.monthselectlabeltext = self.text
on_release:
app.closeitpls_m()
<yearselectbtn>:
font_size: dp(16)
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: 1, None
height: dp(50)
background_color: (255, 255, 255, 1)
color: (0,0,0,1)
on_press:
app.yearselectlabeltext = self.text
on_release:
app.closeitpls()
<monthselectbtn>:
font_size: dp(16)
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: 1, None
height: dp(50)
background_color: (255, 255, 255, 1)
color: (0,0,0,1)
on_press:
app.monthselectlabeltext = self.text
on_release:
app.closeitpls_m()
<MDMenuItem>:
on_release:
app.root.ids.buttonoflist.text = self.text
<ListButton>:
id: buttonoflist
font_size: dp(8)
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
height: dp(50)
<Manager>:
MainMenu:
name: 'main_menu'
InfoMenu:
name: 'info_menu'
DateSetupMenu:
name: 'date_setup_menu'
<MainMenu>:
AnchorLayout:
anchor_y: 'top'
MDToolbar:
title: app.title
elevation: 10
md_bg_color: white
AnchorLayout:
anchor_y: 'bottom'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.25
spacing: dp(10)
padding: [0, 0, 0, dp(10)]
MenuButton:
text: 'Приступить'
on_press:
app.root.transition = SlideTransition(direction='left', duration = .17)
on_release:
root.manager.current = 'date_setup_menu'
MenuButton:
text: 'Инфо'
on_press:
app.root.transition = SlideTransition(direction='left', duration = .17)
on_release:
root.manager.current = 'info_menu'
MenuButton:
text: 'Выход'
on_release:
app.ExitDialog()
<InfoMenu>:
AnchorLayout:
anchor_y: 'top'
MDToolbar:
title: 'Инфо'
elevation: 10
md_bg_color: white
BoxLayout:
size_hint_y: 0.4
orientation: 'vertical'
spacing: 5
padding: [0, dp(90), 0, 0]
pos_hint: {'center_x': .5, 'center_y': 1}
CreditsImage:
source: 'assets/info_credits_table.png'
size_hint_y: 0.8
MDLabel:
text: 'версия программы: 1.0.0'
font_name: 'assets/Ponter.ttf'
color: (255,255,255,1)
size_hint_y: 0.2
font_size: dp(20)
halign: 'center'
valign: 'top'
text_size: self.size
AnchorLayout:
anchor_y: 'bottom'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.25
padding: [0, 0, 0, dp(15)]
InfoMenuButton:
text: 'Назад'
on_press:
app.root.transition = SlideTransition(direction='right', duration = .17)
on_release:
root.manager.current = 'main_menu'
<DateSetupMenu>:
AnchorLayout:
anchor_y: 'top'
MDToolbar:
title: 'Выбор параметров'
elevation: 10
md_bg_color: white
AnchorLayout:
anchor_y: 'center'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.25
padding: [0, dp(15), 0, 0]
spacing: dp(5)
ListButton:
id: buttonoflist
text: 'Выбор'
on_release:
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
YearButton1:
text: app.yearselectlabeltext
on_release:
app.year_select_clicked1()
MonthButton:
text: app.monthselectlabeltext
on_release:
app.month_select_clicked()
DateSetupMenuButton:
text: app.dateselectlabeltext
on_release:
app.OpenDatePicker()
AnchorLayout:
anchor_y: 'bottom'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.25
padding: [0, 0, 0, dp(15)]
DateSetupMenuButton:
text: 'Назад'
on_press:
app.root.transition = SlideTransition(direction='right', duration = .17)
on_release:
root.manager.current = 'main_menu'
I need to change the text of «ListButton» object after clicking MDMenuItem proreply. I dont know, why it is working in standalone code, but in my main code it has that horrible problem...
Errors - KeyError & AttributeError
Traceback (most recent call last):
File "kivy/properties.pyx", line 860, in kivy.properties.ObservableDict.__getattr__
KeyError: 'buttonoflist'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
...
File ".../main.kv", line 132, in <module>
app.root.ids.buttonoflist.text = self.text
File "kivy/properties.pyx", line 863, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
Root Cause
The first error encountered was KeyError because the id, 'buttonoflist' does not exist in Kivy self.ids dictionary type property.
The second error encountered was AttributeError because the id, 'buttonoflist' does not exist in the root (which is a ScreenManager).
Solution
Since id: buttonoflist is declared in the Screen,
DateSetupMenu:, you have to add an id to DateSetupMenu object so
that you can access / reference it.
Replace app.root.ids.buttonoflist.text with app.root.ids.date_setup_menu.ids.buttonoflist.text
Snippets - kv file
<MDMenuItem>:
on_release:
app.root.ids.date_setup_menu.ids.buttonoflist.text = self.text
...
<Manager>:
...
DateSetupMenu:
id: date_setup_menu
name: 'date_setup_menu'
...
Output