I am trying to build an App using Python and kivy.
In my kv file I wanted to create a custom widget (MenuFloatLayout)
which can be referenced by the other screens. It is basically a Menu bar that is on every screen. This bar consists of several toggle buttons that are in their down state and disabled if you are currently on the screen this button is linked to.
This is referenced by:
state: "down" if root.manager.current == 'Screenname' else "normal"
The Problem is:
root.manager.current is not linked to the usual screen manager anymore,
because my custom widget is the root now.
Is there a work around?
Or is there a easier way to link the toggle buttons state to the screen the user is on?
I am new to programming and Python, I'm glad for any help or tips you can give me! Thanks!
The Python file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
class StartWindow(Screen):
pass
class PortfolioOverview(Screen):
pass
class Portfolio(Screen):
pass
class Market(Screen):
pass
class Economics(Screen):
pass
class PortfolioTools(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("vigiles.kv")
class VigilesApp(App):
def build(self):
return kv
if __name__ == "__main__":
VigilesApp().run()
And the kv file:
WindowManager:
StartWindow:
PortfolioOverview:
Portfolio:
Market:
Economics:
PortfolioTools:
<MenuFloatLayout#FloatLayout>:
Label:
text: "Portfolio"
markup: True
size_hint: 0.5, None
height: 30
pos_hint:{"top":1, "left":1}
TextInput:
text: "Search"
multiline: False
size_hint: 0.5, None
height: 30
pos_hint:{"top":1, "right":1}
ScrollView:
size_hint: None, None
do_scroll_y: False
do_scroll_x: True
size: 500, 150
GridLayout:
rows: 1
size_hint_y: None
ToggleButton:
group: "pmenu"
text: 'Overview'
state: "down" if root.manager.current == 'poverview' else "normal"
disabled: True if root.manager.current == 'poverview' else False
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_release: app.root.current = "poverview"
ToggleButton:
group: "pmenu"
text: 'Portfolio'
state: "down" if root.manager.current == 'portfolio' else "normal"
disabled: True if root.manager.current == 'portfolio' else False
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_release: app.root.current = "portfolio"
ToggleButton:
group: "pmenu"
text: 'Market'
state: "down" if root.manager.current == 'market' else "normal"
disabled: True if root.manager.current == 'market' else False
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_release: app.root.current = "market"
ToggleButton:
group: "pmenu"
text: 'Economics'
state: "down" if root.manager.current == 'economics' else "normal"
disabled: True if root.manager.current == 'economics' else False
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_release: app.root.current = "economics"
ToggleButton:
group: "pmenu"
text: 'Tools'
state: "down" if root.manager.current == 'ptools' else "normal"
disabled: True if root.manager.current == 'ptools' else False
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_release: app.root.current = "ptools"
<StartWindow>:
name: "start"
BoxLayout:
canvas:
Rectangle:
size: self.size
color: 1, 1, 1, 0
id: login_layout
orientation: 'vertical'
padding: [10,10,10,10]
spacing: 30
Label:
text: 'some text'
font_size: 32
color: 0, 0, 0, 1
BoxLayout:
orientation: 'vertical'
Label:
text: 'Login'
font_size: 18
halign: 'left'
text_size: root.width-20, 20
color: 0, 0, 0, 1
TextInput:
id: login
multiline:False
font_size: 28
BoxLayout:
orientation: 'vertical'
Label:
text: 'Password'
halign: 'left'
font_size: 18
text_size: root.width-20, 20
color: 0, 0, 0, 1
TextInput:
id: password
multiline:False
password:True
font_size: 28
Button:
text: 'Connect'
font_size: 24
on_release: app.root.current = "poverview"
<PortfolioOverview>:
name: "poverview"
MenuFloatLayout:
<Portfolio>:
name: "portfolio"
MenuFloatLayout:
<Market>:
name: "market"
MenuFloatLayout:
<Economics>:
name: "economics"
MenuFloatLayout:
<PortfolioTools>:
name: "ptools"
MenuFloatLayout:
Goal is to either link my custom widget back to my screen manager or find an easier solution to link the toggle buttons state to the current screen.
AttributeError: 'MenuFloatLayout' object has no attribute 'manager'
I would make your root widget a Layout widget (GridLayout, BoxLayout, or FloatLayout), and have your screen manager take up only part of the actual screen. Try changing
WindowManager:
StartWindow:
PortfolioOverview:
Portfolio:
to:
GridLayout:
# Play with using a FloatLayout or BoxLayout instead of GridLayout if you want
cols: 1
MenuFloatLayout:
id: the_menu_id
WindowManager:
StartWindow:
PortfolioOverview:
Portfolio:
That way your menu will persist and the screen manager is only changing part of the actual screen.
By giving the MenuFloatLayout an id you are able to reference it. To reference it from the Python side, use self.root.ids.the_menu_id if you're referencing it from your App object. If you're in some other kind of object, you can do the same by first importing App (import App) and then using App.get_running_app().root.ids.the_menu_id
To reference it from your screens, you can use the app keyword. For example: app.root.ids.the_menu_id
All three ways of referencing the menu's id are essentially identical.
Problems
Too many instances of MenuFloatLayout
Use lots of resources e.g. memory, this makes the app big and poor performance
Solution
Create one instance of MenuFloatLayout
Each screen reference the one and only one instance of MenuFloatLayout
Use nested ScreenManager. This first ScreenManager for controlling the authentication / login screen. The second ScreenManager for navigation between different screens.
Create a dynamic class for ToggleButton
Example
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
class StartWindow(Screen):
pass
class PortfolioOverview(Screen):
pass
class Portfolio(Screen):
pass
class Market(Screen):
pass
class Economics(Screen):
pass
class PortfolioTools(Screen):
pass
class WindowManager(ScreenManager):
pass
Builder.load_file("main.kv")
class TestApp(App):
def build(self):
return WindowManager()
if __name__ == "__main__":
TestApp().run()
main.kv - kv file
<WindowManager>:
sm2: sm2
StartWindow:
Screen:
name: 'connect'
ScreenManager:
id: sm2
PortfolioOverview:
Portfolio:
Market:
Economics:
PortfolioTools:
MenuFloatLayout:
<CustomToggleButton#ToggleButton>: # dynamic class
group: "pmenu"
state: "normal" if app.root is None else "down" if app.root.sm2.current == self.text.lower() else "normal"
background_disabled_down: "atlas://data/images/defaulttheme/button_pressed"
disabled_color: 1, 1, 1, 1
on_state:
if self.state == "down": self.disabled = True
else: self.disabled = False
on_release:
app.root.sm2.current = self.text.lower()
<MenuFloatLayout#FloatLayout>: # dynamic class
Label:
text: "Portfolio"
markup: True
size_hint: 0.5, None
height: 30
pos_hint:{"top":1, "left":1}
TextInput:
hint_text: "Search"
multiline: False
size_hint: 0.5, None
height: 30
pos_hint:{"top":1, "right":1}
ScrollView:
size_hint: None, None
do_scroll_y: False
do_scroll_x: True
size: 500, 150
GridLayout:
rows: 1
size_hint_y: None
CustomToggleButton:
text: 'Overview'
state: 'down' # default
CustomToggleButton:
text: 'Portfolio'
CustomToggleButton:
text: 'Market'
CustomToggleButton:
text: 'Economics'
CustomToggleButton:
text: 'Tools'
<StartWindow>:
name: "start"
BoxLayout:
canvas:
Rectangle:
size: self.size
color: 1, 1, 1, 0
id: login_layout
orientation: 'vertical'
padding: [10,10,10,10]
spacing: 30
Label:
text: 'some text'
font_size: 32
color: 0, 0, 0, 1
BoxLayout:
orientation: 'vertical'
Label:
text: 'Login'
font_size: 18
halign: 'left'
text_size: root.width-20, 20
color: 0, 0, 0, 1
TextInput:
id: login
multiline:False
font_size: 28
BoxLayout:
orientation: 'vertical'
Label:
text: 'Password'
halign: 'left'
font_size: 18
text_size: root.width-20, 20
color: 0, 0, 0, 1
TextInput:
id: password
multiline:False
password:True
font_size: 28
Button:
text: 'Connect'
font_size: 24
on_release:
root.manager.current = 'connect'
<PortfolioOverview>:
name: "overview"
Label:
text: 'Screen - Overview'
<Portfolio>:
name: "portfolio"
Label:
text: 'Screen - Portfolio'
<Market>:
name: "market"
Label:
text: 'Screen - Market'
<Economics>:
name: "economics"
Label:
text: 'Screen - Economics'
<PortfolioTools>:
name: "tools"
Label:
text: 'Screen - Portfolio Tools'
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 write a mobile app with a KivyMD like Bottom Sheet Menu. My problem with KivyMD Buttom Sheet is, when I click the button to open it, takes very long time (depends on the menu length) because the list is generated by calling the function every time the button was pressed. So I want to write my own solution for this.
In my kv file I manually added 20 buttons to see, it's everything work. But i didn't find the way to do it in python file with loop.
Can anyone help me please to add more than 30 buttons to modalview to be scrollable?
Here is my python file:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window
Builder.load_file('mylayout.kv')
Window.size = (350, 700)
class MyLayout(BoxLayout):
pass
class MainApp(App):
def build(self):
return MyLayout()
MainApp().run()
an my kv file:
#:import Factory kivy.factory.Factory
<MyPopup#ModalView>
auto_dismiss: True
size_hint: 1, 0.5
pos_hint: {'x': 0, 'top': 0.5}
background_color: 0,0,0,0
background_normal: ''
canvas.before:
Color:
rgba: 48/150,84/150,150/150,1
Rectangle:
size: self.size
pos: self.pos
ScrollView:
#do_scroll_x: False
GridLayout:
id: container1
cols: 1
size_hint: None, None
size: root.width, 1200
pos_hint: {'center_x': .5, 'center_y': .5}
MyButton:
text: '1'
on_press:
root.dismiss()
print(1)
MyButton:
text: '2'
on_press:
root.dismiss()
print(2)
MyButton:
text: '3'
on_press:
root.dismiss()
print(3)
MyButton:
text: '4'
on_press:
root.dismiss()
print(4)
MyButton:
text: '5'
on_press:
root.dismiss()
print(5)
MyButton:
text: '6'
on_press:
root.dismiss()
print(6)
MyButton:
text: '7'
on_press:
root.dismiss()
print(7)
MyButton:
text: '8'
on_press:
root.dismiss()
print(8)
MyButton:
text: '9'
on_press:
root.dismiss()
print(9)
MyButton:
text: '10'
on_press:
root.dismiss()
print(10)
MyButton:
text: '11'
on_press:
root.dismiss()
print(11)
MyButton:
text: '12'
on_press:
root.dismiss()
print(12)
MyButton:
text: '13'
on_press:
root.dismiss()
print(13)
MyButton:
text: '14'
on_press:
root.dismiss()
print(14)
MyButton:
text: '15'
on_press:
root.dismiss()
print(15)
MyButton:
text: '16'
on_press:
root.dismiss()
print(16)
MyButton:
text: '17'
on_press:
root.dismiss()
print(17)
MyButton:
text: '18'
on_press:
root.dismiss()
print(18)
MyButton:
text: '19'
on_press:
root.dismiss()
print(19)
MyButton:
text: '20'
on_press:
root.dismiss()
print(20)
<MyLayout>
orientation: 'vertical'
size: root.width, root.height
Label:
size_hint: 1, 0.9
text: 'main'
font_size: 24
Button:
size_hint: 1, 0.1
text: 'menu'
font_size: 24
on_release: Factory.MyPopup().open()
<MyButton#Button>
background_color: 0,0,0,0
background_normal: ''
canvas.before:
Color:
rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
Rectangle:
size: self.size
pos: self.pos
In order to build the MyPopup filled with MyButtons, you must either define those classes in the python code or use Factory to create the instances. Here is a modified version of your kv to do this:
<MyPopup#ModalView>
auto_dismiss: True
size_hint: 1, 0.5
pos_hint: {'x': 0, 'top': 0.5}
background_color: 0,0,0,0
background_normal: ''
canvas.before:
Color:
rgba: 48/150,84/150,150/150,1
Rectangle:
size: self.size
pos: self.pos
ScrollView:
#do_scroll_x: False
GridLayout:
id: container1
cols: 1
size_hint: None, None
width: root.width
height: self.minimum_height # let the GridLayout set its own height as needeed
pos_hint: {'center_x': .5, 'center_y': .5}
<MyLayout>
orientation: 'vertical'
size: root.width, root.height
Label:
size_hint: 1, 0.9
text: 'main'
font_size: 24
Button:
size_hint: 1, 0.1
text: 'menu'
font_size: 24
# on_release: Factory.MyPopup().open()
on_release: app.open_popup() # call app method to build MyPopup and fill it
<MyButton#Button>
background_color: 0,0,0,0
background_normal: ''
size_hint_y: None
height: 20
canvas.before:
Color:
rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
Rectangle:
size: self.size
pos: self.pos
Note that the GridLayout height is set to self.minimum_height to allow for any number of MyButton children, and the MyButton height is set to a fixed value (so that GridLayout can calculate the minimum height). Also, the import of Factory is no longer needed in the kv.
The modified python code:
from kivy.app import App
from kivy.factory import Factory
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window
Builder.load_file('mylayout.kv')
Window.size = (350, 700)
class MyLayout(BoxLayout):
pass
class MainApp(App):
def build(self):
return MyLayout()
def open_popup(self, *args):
# create the popup (must use Factory since MyPopup is defined in kv)
self.popup = Factory.MyPopup()
# fill the GridLayout
grid = self.popup.ids.container1
for i in range(60):
grid.add_widget(Factory.MyButton(text=str(i), on_press=self.myButtPress))
# open popup
self.popup.open()
def myButtPress(self, butt):
print(butt.text)
self.popup.dismiss()
MainApp().run()
I'm new to Kivy, I'm working on a tracking app for vehicle repair and I've got a list of appointments and I'm trying to go to a different screen when you press an item on the list and I I have no clue on why it isn't working for me as it says that it is on a different screen but it isn't on the app
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivymd.uix.list import ThreeLineAvatarIconListItem
from kivymd.uix.list import ImageLeftWidget
from kivy.uix.screenmanager import Screen, ScreenManager, SwapTransition, CardTransition
from kivy.core.window import Window
import sqlite3
DatabaseConnection = sqlite3.connect('CarWorkshopDB.db')
cursor = DatabaseConnection.cursor()
Window.size= (400, 650)
class MainScreen(Screen):
pass
class AddScreen(Screen):
pass
class DetailsScreen(Screen):
pass
class WorkApp(MDApp):
def build(self):
self.screen_manager = ScreenManager(transition=CardTransition())
self.screen_manager.add_widget(MainScreen(name='MainScreen'))
self.screen_manager.add_widget(AddScreen(name='AddScreen'))
self.screen_manager.add_widget(DetailsScreen(name='DetailsScreen'))
screen = Builder.load_file("test2.kv")
return screen
def on_start(self):
client = 'John smith'
cursor.execute("SELECT TrackingNumber, Plate, Status FROM Appointments WHERE Customer =?", (client,))
for i in cursor:
self.new_message(i[0], i[1], i[2])
def new_message(self, TrackingNumber, Vehicle, Process):
new_message = ThreeLineAvatarIconListItem(text=TrackingNumber, secondary_text=Vehicle, tertiary_text=Process)
new_message.add_widget(ImageLeftWidget(source='RepairIMG.jpg'))
new_message.bind(on_release=self.on_touch_down)
self.root.ids.list.add_widget(new_message)
def on_touch_down(self, x):
print(self.screen_manager.current)
self.screen_manager.current = "DetailsScreen"
self.screen_manager.transition.direction = 'right'
print(self.screen_manager.current)
WorkApp().run()
this is the list code in the kv file
NavigationLayout:
ScreenManager:
id: screen_manager
MainScreen:
name : "MainScreen"
BoxLayout:
orientation:'vertical'
MDBottomNavigation:
panel_color: 1, .643, 0, 1
MDBottomNavigationItem:
name: 'screen 1'
text: 'Home'
icon: 'alpha-h-circle'
MDToolbar:
title: 'Add Repair'
md_bg_color: 1, .643, 0, 1
elevation: 6
pos_hint: {'top':1}
Widget:
MDBottomNavigationItem:
name: 'screen 2'
text: 'Track'
icon: 'alpha-t-circle'
MDToolbar:
id: toolbar
title: 'Track History'
md_bg_color: 1, .643, 0, 1
elevation: 6
pos_hint: {'top':1}
NavigationLayout:
x: toolbar.height
size_hint_y: 1.0 - toolbar.height/root.height
ScreenManager:
Screen:
name: 'ScrollViewScreen'
ScrollView:
MDList:
id: list
MDFloatingActionButton:
icon: 'plus'
md_bg_color: 1, .643, 0, 1
on_release:
screen_manager.current = 'AddScreen'
screen_manager.transition = CardTransition()
screen_manager.transition.direction = "down"
pos_hint: {'x': .84, 'y': .02}
MDBottomNavigationItem:
name: 'screen 4'
text: 'More'
icon: 'dots-horizontal'
MDToolbar:
title: 'More'
md_bg_color: 1, .643, 0, 1
elevation: 6
pos_hint: {'top':1}
Widget:
MDLabel:
text: 'dfsfdsf'
halign: 'center'
AddScreen:
name: 'AddScreen'
id: Add
FloatLayout:
orientation: 'vertical'
MDToolbar:
id: toolbar2
title: 'Add Tracking Number'
md_bg_color: 1, .643, 0, 1
elevation: 6
pos_hint: {'top':1}
MDIconButton:
icon : 'close'
pos_hint : {'top':0.98, 'x':0.85}
on_release :
screen_manager.current = "Main"
screen_manager.transition = CardTransition()
screen_manager.transition.direction = "up"
FloatLayout:
x: toolbar2.height
size_hint_y: 1.0 - toolbar.height/root.height
ScatterLayout:
MDLabel:
text: 'Track Repair'
font_style: 'H4'
valign: 'top'
pos_hint: {'top':1}
text_size: self.size
size_hint: None, None
MDTextFieldRound:
icon_left: 'alpha-t-circle'
hint_text: 'Tracking Number'
normal_color: 1, .643, 0, 1
pos_hint: {'y':.7}
text_size: self.size
MDTextFieldRound:
icon_left: 'alpha-p-circle'
hint_text: 'Postcode'
normal_color: 1, .643, 0, 1
pos_hint: {'y':.6}
text_size: self.size
MDTextButton:
text: "Cant find your tracking number?"
custom_color: 1, .643, 0, 1
pos_hint: {'y':.5}
halign: 'center'
MDRectangleFlatButton:
text: 'confirm'
pos_hint: {'y':.4}
valign: 'middle'
text_size: self.size
DetailsScreen:
name: 'DetailsScreen'
id: Details
BoxLayout:
orientation: 'vertical'
MDLabel:
text: 'details Screen?'
The problem is that in your build() method you are building a widget tree in the lines:
self.screen_manager = ScreenManager(transition=CardTransition())
self.screen_manager.add_widget(MainScreen(name='MainScreen'))
self.screen_manager.add_widget(AddScreen(name='AddScreen'))
self.screen_manager.add_widget(DetailsScreen(name='DetailsScreen'))
But this widget tree is not used in your GUI. The widget tree in your GUI is built from the kv file by:
screen = Builder.load_file("test2.kv")
When your code tries to change the current Screen by using:
self.screen_manager.current = "DetailsScreen"
it is changing the current Screen of a ScreenManager that is not in your GUI.
A fix is to assign the correct value to self.screen_manager, like this:
class WorkApp(MDApp):
def build(self):
screen = Builder.load_file("test2.kv")
self.screen_manager = screen.ids.screen_manager
return screen
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
I was wondering how I could change the text of a label made inside the Kivy language using Python.
Like how would I have user input from python be made as the text of a label in kivy.
(By the way I have the formatting correct in the actual program but I screwed up pasting it to stackoverflow)
Say if I wanted to make the text of the label in from the code be a random number generated in python how would I go about doing that?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.graphics import Color, Rectangle
from kivy.properties import ObjectProperty
# Create both screens. Please note the root.manager.current: this is how
# you can control the ScreenManager from kv. Each screen has by default a
# property manager that gives you the instance of the ScreenManager used.
Builder.load_string("""
<ButImage#ButtonBehavior+AsyncImage>
<TutImage#ButtonBehavior+AsyncImage>
<MenuScreen>:
GridLayout:
cols: 4
row_force_default: True
col_default_width: 175
row_default_height: 150
padding: 15
spacing: 15
canvas.before:
BorderImage:
# BorderImage behaves like the CSS BorderImage
border: 10, 10, 10, 10
source: '/Users/clayhigh/Desktop/kivy/aot.png'
pos: self.pos
size: self.size
Button:
text: 'Goto settings'
background_color: 1,0,0,0.5
on_press: root.manager.current = 'settings'
ButImage:
on_press: root.manager.current = 'UBW'
id: but
size_hint: .5, .5
opacity: 1 if self.state == 'normal' else .5
allow_stretch: True
keep_ratio: False
source: 'http://s3.amazonaws.com/rapgenius/1361742626_beautiful-ocean-beautiful-pictures-27115524-1440-900.jpg'
Label:
center: but.center
text: "UBW"
color: 0.78,0.145,0.016,2
ButImage:
id: lh
size_hint: .5, .5
opacity: 1 if self.state == 'normal' else .5
allow_stretch: True
keep_ratio: False
source: 'http://s3.amazonaws.com/rapgenius/1361742626_beautiful-ocean-beautiful-pictures-27115524-1440-900.jpg'
Label:
center: lh.center
text: "LH 2"
color: 0,0,0,1
ButImage:
id: ttl
size_hint: .5, .5
opacity: 1 if self.state == 'normal' else .5
allow_stretch: True
keep_ratio: False
source: 'http://s3.amazonaws.com/rapgenius/1361742626_beautiful-ocean-beautiful-pictures-27115524-1440-900.jpg'
Label:
center: ttl.center
text: "TwTl"
color: 0,0,0,1
ButImage:
id: gris
size_hint: .5, .5
opacity: 1 if self.state == 'normal' else .5
allow_stretch: True
keep_ratio: False
source: 'http://s3.amazonaws.com/rapgenius/1361742626_beautiful-ocean-beautiful-pictures-27115524-1440-900.jpg'
Label:
center: gris.center
text: "Gris"
color: 0,0,0,1
ButImage:
id: shig
size_hint: .5, .5
opacity: 1 if self.state == 'normal' else .5
allow_stretch: True
keep_ratio: False
source: 'http://s3.amazonaws.com/rapgenius/1361742626_beautiful-ocean-beautiful-pictures-27115524-1440-900.jpg'
Label:
center: shig.center
text: "Shig"
color: 0,0,0,1
Button:
text: 'Test3'
background_color: 1,0,0,0.5
Button:
text: 'Test4'
background_color: 1,0,0,0.5
Button:
text: 'Quit'
background_color: 1,0,0,0.5
on_press: App.on_stop
<SettingsScreen>:
GridLayout:
row_force_default: True
row_default_height: 100
cols: 2
canvas.before:
BorderImage:
# BorderImage behaves like the CSS BorderImage
border: 10, 10, 10, 10
source: '/Users/clayhigh/Desktop/kivy/ato.jpeg'
pos: self.pos
size: self.size
Button:
text: 'Button'
color: 0,0,.5
background_color: 1,0,0,1
Button:
text: 'Back to menu'
background_color: 1,0,0,1
on_press: root.manager.current = 'menu'
<UBW>:
GridLayout:
row_force_default: True
row_default_height: 100
cols: 2
canvas.before:
Color:
rgb: .5, .5, .5
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: 1, 1, 1
BorderImage:
# BorderImage behaves like the CSS BorderImage
border: 10, 10, 10, 10
source: '/Users/clayhigh/Desktop/kivy/fsn.jpg'
pos: self.pos
size: self.size
Button:
text: 'Back to menu'
color: 0,0,.5
on_press: root.manager.current = 'menu'
background_color: 1,0,0,1
Label:
id: AName
text: "F S/N: UBW"
font_size: '24sp'
""")
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class UBW(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
sm.add_widget(UBW(name='UBW'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
Text of a label can be a kivy property, which can be later changed and since it is a kivy property it will automatically updated everywhere. Here is an example of your .py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
import random
class YourWidget(Widget):
random_number = StringProperty()
def __init__(self, **kwargs):
super(YourWidget, self).__init__(**kwargs)
self.random_number = str(random.randint(1, 100))
def change_text(self):
self.random_number = str(random.randint(1, 100))
class YourApp(App):
def build(self):
return YourWidget()
if __name__ == '__main__':
YourApp().run()
and your .kv
<YourWidget>:
BoxLayout:
size: root.size
Button:
id: button1
text: "Change text"
on_release: root.change_text()
Label:
id: label1
text: root.random_number
When you click the button, it will call change_text() function, which will randomly change the text of the label to random integer between 1 and 100.