Changing a label nested in a different screen in Kivy with screenmanager - python

I'm trying but failing on a simple task of changing a label nested in a different screen in Kivy with screenmanager.
I want to show "f_path" variable on "lbl_file_path" label. "lbl_file_path" label is on "W_MainMenu" screen. "f_path" is created on "W_FileSelector" screen.
How can I do this ? Any help is greatly appreciated. You may find the code below;
from logging import root
from charset_normalizer import from_path
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.properties import ObjectProperty
f_path = ""
class MyWinMan(ScreenManager):
pass
class W_MainMenu(Screen):
def transform_to_filechooser(self):
Window.size = (700, 950)
Window.top = 50
Window.left = 100
self.lbl_file_path.text = f_path
class W_FileSelector(Screen):
def transform_to_main(self):
Window.size = (700, 280)
Window.top = 50
Window.left = 100
def selected(self, filename):
try:
print(filename[0])
global f_path
f_path = filename[0]
except:
pass
kv = Builder.load_string("""
MyWinMan:
W_MainMenu:
W_FileSelector:
<W_MainMenu>:
lbl_file_path: lbl_file_path_k
name: "win_Main"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 40
spacing: 10
BoxLayout:
orientation: "horizontal"
size: root.width, root.height
padding: 0
spacing: 10
Button:
text:'Browse for Source Excel File'
font_size: 20
on_release:
app.root.current = "win_FS"
root.manager.transition.direction = "up"
root.transform_to_filechooser()
Image:
source:""
size_hint: ( 0.2, 1)
Label:
text:'Selected Excel File Path'
size_hint: ( 1, 0.4)
font_size: 18
color: ( 180/255, 180/255, 180/255, 1)
background_color: ( 50/255,50/255,50/255,1)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
pos: self.pos
size: self.size
Label:
text: "Initial Text"
# text: f_path
id: lbl_file_path_k
size_hint: ( 1, 0.4)
font_size: 18
color: ( 50/255, 50/255, 50/255,1)
background_color: ( 180/255, 180/255, 180/255, 1)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
pos: self.pos
size: self.size
<W_FileSelector>:
name: "win_FS"
id: my_widget
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Label:
text:'Please select the file...'
size_hint: ( 1, 0.1)
font_size: 20
FileChooserListView:
id: filechooser
path: "."
on_selection:
my_widget.selected(filechooser.selection)
Button:
text:'OK'
font_size: 20
size_hint: ( 1, 0.1)
on_release:
app.root.current = "win_Main"
root.manager.transition.direction = "down"
root.transform_to_main()
""")
Window.size = (700, 280)
Window.top = 50
Window.left = 100
class MyApp(App):
def build(self):
self.title = "Data Importer"
return kv
if __name__ == '__main__':
MyApp().run()

You just need to access the right screen and its contents. One of the many ways would be using the method get_screen as follows,
def selected(self, filename):
try:
# Access the target screen.
main_screen = self.manager.get_screen("win_Main")
# Access its target label.
file_path_label = main_screen.ids.lbl_file_path_k
# Set the text.
file_path_label.text = filename[0]
print(filename[0])
# global f_path
f_path = filename[0]
except:
pass
Other ways include binding directly from FileChooserListView, defining custom variable in that class or in the App's class etc.

Related

Add widget dynamically from outside class (error)

I´m learning kivy, and it has passed 3 weeks since i face this problem without encounter a solution, so i hope any of u guys could help me, i would appreciate it.
I have a main file:
from app import MyProgramApp
if __name__ == "__main__":
winapp = MyProgramApp()
winapp.run()
from where i start my app. Then i have a directory called "app", inside there is the following "init.py" file.
from kivy.app import App
from kivy.utils import QueryDict, rgba
from kivy.core.window import Window
from .view import MainWindow
Window.minimum_width = 500
Window.minimum_height = 650
Window.maximize()
class MyProgramApp(App):
colors = QueryDict()
colors.primary = rgba('#2D9CDB')
colors.secondary = rgba('#16213E')
colors.succes = rgba('#1FC98E')
colors.warning = rgba('#F2C94C')
colors.danger = rgba('#E85757')
colors.grey_dark = rgba('#C4C4C4')
colors.grey_light = rgba('#F5F5F5')
colors.black = rgba('#A1A1A1')
colors.white = rgba('#FFFFFF')
def build(self):
return MainWindow()
Same folder app, i have the following "view.py".
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager
class MainWindow(BoxLayout):
username = StringProperty("Usuario")
def __init__(self, **kw):
super().__init__(**kw)
def on_press_home(self):
self.ids.scrn_mngr.current = "scrn_home"
class ViewManager(ScreenManager):
def __init__(self, **kw):
super().__init__(**kw)
class NavTab(ToggleButtonBehavior, BoxLayout):
text = StringProperty('')
icon = StringProperty('')
def __init__(self, **kw):
super().__init__(**kw)
and finally for that folder i have "myprogram.kv"
#:kivy 2.1.0
#:import Home views.home.Home
<MainWindow>:
spacing: dp(8)
canvas.before:
Color:
rgba: app.colors.white
Rectangle:
pos: self.pos
size: self.size
# NAVIGATION BAR
BoxLayout:
id: nav_menu
size_hint_x: .2
orientation: "vertical"
size_hint_min_x: dp(100)
# LOGO
BoxLayout:
id: logo_nbox
size_hint_y: .1
size_hint_min_y: dp(70)
padding: dp(16)
AnchorLayout:
anchor_x: "right"
size_hint_x: None
width: dp(52)
halign: "left"
Label:
text: "COMPANY"
halign: "center"
BoxLayout:
orientation: "vertical"
Label:
text: "COMPANY"
halign: "center"
Label:
text: "Phrase"
halign: "center"
# OPTIONS
GridLayout:
id: tabs_box
cols: 1
spacing: dp(4)
size_hint_y: .5
canvas.before:
Color:
rgba: app.colors.grey_dark
Rectangle:
pos: self.pos
size: [self.size[0], dp(1)]
NavTab:
text: "Home"
state: "down"
on_press: root.on_press_home()
# BODY
BoxLayout:
size_hint_x: .8
spacing: dp(8)
orientation: "vertical"
padding: [dp(16), dp(8), dp(12), dp(8)]
canvas.before:
Color:
rgba: app.colors.grey_light
Rectangle:
pos: self.pos
size: self.size
# SCREENS
BoxLayout:
ViewManager:
id: scrn_mngr
<ViewManager>:
Screen:
name: "scrn_home"
Home:
id: home
<NavTab>:
background_normal: ""
background_down: ""
background_color: [0,0,0,0]
group: "tabs"
size_hint_y: None
height: dp(45)
spacing: dp(4)
canvas.before:
Color:
rgba: [0,0,0,0] if self.state == "normal" else rgba("#E1F1FF")
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: [0,0,0,0] if self.state == "normal" else app.colors.primary
Rectangle:
pos: [self.pos[0]+self.size[0]-dp(1), self.pos[1]]
size: [dp(8), self.size[1]]
Label:
halign: "left"
valign: "middle"
text: root.text
color: app.colors.grey_dark if root.state == "normal" else app.colors.primary
Then i got another folder called "views" inside i have another folder called "home", inside home we encounter 3 files "init.py", "home.kv", "home.py". the first one "init.py" is the following.
from .home import Home
then we got "home.kv".
#:kivy 2.1.0
<Home>:
orientation: "vertical"
Label:
size_hint_y: .1
text: "Other"
Button:
size_hint_y: .1
text: "popup"
on_press: root.open_popup()
BoxLayout:
size_hint_y: .8
id: home_box
<SomePopup>:
title: "SOME TITLE"
title_align: "center"
title_color: app.colors.primary
size_hint: .25, .8
size_hint_min_x: dp(200)
pos_hint: {"x": .1, "top": .9}
BoxLayout:
orientation: "vertical"
padding: [dp(0), dp(12), dp(0), dp(12)]
Label:
text: "Some text"
Button:
text: "create buttons on box"
on_press: root.modify_home_box()
and finally and the problem that i´m facing is whit the following file "home.py"
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.factory import Factory
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.app import App
Builder.load_file('views/home/home.kv')
class Home(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def open_popup(self):
Factory.SomePopup().open()
class SomePopup(Popup):
def __init__(self, **kw):
super().__init__(**kw)
def modify_home_box(self):
my_app = App.get_running_app().root
my_box = my_app.ids.home.ids.home_box
custom_button = Button(
text = "something"
)
my_box.add_widget(custom_button)
That i´m trying to do is actually modify "home_box" with is store on ids Home dictionary, i also try with ObjectProperty (but that gives and Attribute Error, since i only could read propertys but doesnt modify it), instance of a new Home class doesnt work... searching for current app in App appear doesnt work since Home is store i think on screenManager...
I need add a button or some widget to "home_box" from outside class "SomePopup". I also drop here a repository on github with the whole code. github_repo
I don't know how to solve my issue, and i try with the resources available here on stack as well other net places... any help would be appreciate.
Just a very complicated path to the widget of interest. In your modify_home_box() method, try replacing:
my_app = App.get_running_app().root
my_box = my_app.ids.home.ids.home_box
with:
my_app = App.get_running_app().root
my_box = my_app.ids.scrn_mngr.ids.home.ids.home_box

Wrong screen showing after start with ScreenManager

I am trying to code a simple quiz game. There're supposed to be multiple screens, the first screen (LoginWindow) being a simple login form. After the login and confirmation of the right name and password being entered the second screen (GameWindow) is supposed to show up, but it doesn't. Right from the start the second screen is being loaded.
I'm sure I am missing something super simple and basic but I just don't get it.
.py file:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
import hashlib
Window.size = (512, 512)
user_hash = ""
pass_hash = ""
super_user = "9279F4A7C1C145D5AE930FDA23EF386168F6720B4E0F0D3DEE383C5AD8535737"
super_pass = "EE22032527082315A747781829EF1F9195F6AEAC09C0D52DE06EBF9D8C463918"
# Define screens
class LoginWindow(Screen):
name = ObjectProperty(None)
passw = ObjectProperty(None)
def press(self):
user_hash = hashlib.sha256(self.name.text.encode('utf-8')).hexdigest().upper()
pass_hash = hashlib.sha256(self.passw.text.encode('utf-8')).hexdigest().upper()
if (user_hash == super_user) and (pass_hash == super_pass):
print("Das hat geklappt!")
WindowManager.current = 'game'
else:
print("Du kummst hier net rein!")
class GameWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('box_multiscreen.kv')
class Affenquiz(App):
def build(self):
Window.clearcolor = (0.8, 0.8, 0.8, 1)
WindowManager = ScreenManager()
WindowManager.add_widget(LoginWindow(name='login'))
WindowManager.add_widget(GameWindow(name='game'))
WindowManager.current = 'login'
return kv
if __name__ == "__main__":
Affenquiz().run()
.kv file:
WindowManager:
LoginWindow:
name: "login"
GameWindow:
name: "game"
<LoginWindow>:
name:name
passw:passw
BoxLayout:
orientation: "vertical"
size: root.width, root.height
spacing: 20
padding: 20
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'monkey.png'
AnchorLayout:
anchor_y: 'top'
BoxLayout:
orientation: "horizontal"
size_hint: (1, None)
height: 50
Label:
text: "Der Quizfelsen"
font_size: 50
BoxLayout:
orientation: "horizontal"
size_hint: (1, None)
height: 50
Label:
text: "Benutzer:"
TextInput:
id: name
multiline:False
background_color: (241/255.0,241/255.0,241/255.0,0.9)
BoxLayout:
orientation: "horizontal"
size_hint: (1, None)
height: 50
Label:
text: "Passwort:"
TextInput:
id: passw
multiline:False
background_color: (241/255.0,241/255.0,241/255.0,0.9)
RoundedButton:
text: "Login"
pos_hint: {'center_x': .5}
size_hint: (1, None)
height: 50
on_press: root.press()
<GameWindow>:
Label:
text: "Der Quizfelsen"
font_size: 50
<Label>
font_size: 32
background_normal: ''
background_color: (0.9,0.9,0.9,0)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
color: (184/255.0,70/255.0,35/255.0,1)
bold: True
outline_color: (1,1,1,1)
outline_width: 2
<RoundedButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba: (184/255.0,70/255.0,35/255.0,0.9)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [25]
Thank you in advance

Pass input value to dialog and send to screen

I have the following code where I would like to be able to click on the navigation drawer, select Status under Users, input the name and then be sent to a given screen with the current_user now populated.
main.py
from kivy.uix.behaviors import CoverBehavior
from kivy import utils
from kivy.properties import ObjectProperty, ListProperty, NumericProperty, StringProperty, BooleanProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager
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.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import MDList
#from models import ServerInfo
from navigation_drawer import navigation_helper
Window.fullscreen = 'auto'
class ItemWidget(BoxLayout):
sid = NumericProperty()
name = StringProperty()
work = NumericProperty()
is_disabled = BooleanProperty()
description = StringProperty()
has_issue = BooleanProperty()
class MainWidget(FloatLayout):
recycleView = ObjectProperty()
items = ListProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.items = [
#ServerInfo(1, "server1", 95, "desc", is_disabled=False, has_issue=False),
]
# Put the servers with issues on top, otherwise sort by name
self.items = sorted((s for s in self.items), key=lambda x: (not(x.has_issue),x.name))
# Load the server information when the recycleView is called
def on_recycleView(self, widget, parent):
self.recycleView.data = [
m.get_dictionary() for m in self.items
]
class Content(BoxLayout):
pass
class DemoApp(MDApp):
class ContentNavigationDrawer(BoxLayout):
pass
class DrawerList(ThemableBehavior, MDList):
pass
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.dialog = None
# set main interface
self.manager = ScreenManager()
self.current_user = ""
# return main interface
#return self.manager
def build(self):
screen = Builder.load_string(navigation_helper)
return screen
def on_start(self):
pass
def dialog_close(self, *args):
self.dialog.dismiss(force=True)
def set_current_user(self,user,sm):
self.current_user = user
# Send over to given screen
# ???? = sm
def show_user_input_dialog(self,user,screen):
#print(sm.current)
if not self.dialog:
self.dialog = MDDialog(
title="Input Username:",
type="custom",
content_cls=Content(),
buttons=[
MDFlatButton(
text="CANCEL",
theme_text_color="Custom",
text_color=self.theme_cls.primary_color,
on_release=self.dialog_close
),
MDFlatButton(
text="OK",
theme_text_color="Custom",
text_color=self.theme_cls.primary_color,
#on_release=self.set_current_user(user,screen)
on_release=self.dialog_close
),
],
)
# Send to user management page with current user now populated
# Fails as sm is a str instead of ScreenManager()
#sm.current = 'user_management'
self.dialog.open()
DemoApp().run()
navigation_drawer.py
navigation_helper = """
Screen:
MDNavigationLayout:
ScreenManager:
id: screenManager
Screen:
name: "monitor"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Administration'
left_action_items: [["menu", lambda x: nav_drawer.set_state('toggle')]]
elevation:5
MainWidget:
Screen:
name: "user_management"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Administration'
left_action_items: [["menu", lambda x: nav_drawer.set_state('toggle')]]
elevation:5
UserManagement:
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: 'vertical'
padding: "2dp"
spacing: "2dp"
ScrollView:
DrawerList:
id: md_list
MDList:
TwoLineIconListItem:
text: "Monitor"
secondary_text: "Monitor servers"
on_release: screenManager.current = 'monitor'
IconLeftWidget:
icon: "monitor"
MDLabel:
padding: dp(10), dp(0)
text: "Users"
bold: True
font_size: dp(22)
size_hint_y: None
OneLineIconListItem:
text: "Status"
on_release: app.show_user_input_dialog('abc999','user_management')
<Content>
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "60dp"
MDTextField:
id: username_input
hint_text: "Username"
<UserManagement#BoxLayout>:
Label:
text: "Users"
<MainWidget>:
id: mainWidgetId2
recycleView: recycleView
CoverImage:
source: 'images/monitor.png'
# Darken the photo
canvas:
Color:
rgba: 0, 0, 0, .6
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
padding: dp(20)
spacing: dp(10)
BoxLayout:
orientation: "horizontal"
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
RecycleView:
id: recycleView
viewclass: 'ItemWidget'
RecycleGridLayout:
cols: 1
default_size: self.parent.width / 5, dp(60)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
spacing: dp(155), dp(0)
BoxLayout:
orientation: "vertical"
spacing: dp(10)
BoxLayout:
spacing: dp(10)
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
Label:
text: "APPS"
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
Label:
text: "OTHER"
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
Label:
text: "MOUNTS"
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
Label:
text: "RECENT ACTIVITY"
<CoverImage#CoverBehavior+Image>:
reference_size: self.texture_size
<ItemWidget>:
BoxLayout:
#size_hint_max_x: dp(360)
size_hint_min_x: dp(150)
orientation: "horizontal"
BoxLayout:
orientation: "horizontal"
Button:
# Use the on_press to print troubleshooting info, otherwise comment out
on_press: print(self.background_color)
padding: dp(10), dp(10)
text_size: self.size
font_size: dp(22) if root.has_issue else dp(18)
background_color: .5,1,1,.6 #utils.get_random_color(alpha=.6)
halign: "left"
valign: "top"
size: 1,1
# Show last 4 of server name
text: str(root.name).upper()[-4:]
bold: True
color: (1,0,0) if root.has_issue else (1,1,1)
Button:
background_color: .5,1,1,.6
text_size: self.size
valign: "center"
halign: "center"
text: str(root.work)
padding: dp(8), dp(8)
bold: True if root.work > 90 else False
color: (1,0,0) if root.work > 90 else (1,1,1) # Red if greater than 90
"""
Questions:
How do I get the value from this so that I can pass the value instead of the hardcoded username of abc999
MDTextField:
id: username_input
How do I send to the given screen (user_management here) from
def set_current_user(self,user,sm):
self.current_user = user
# Send over to given screen
# ???? = sm
You can toggle commenting on the two on_release below to see the issue
MDFlatButton(
text="OK",
theme_text_color="Custom",
text_color=self.theme_cls.primary_color,
#on_release=self.set_current_user(user,screen)
on_release=self.dialog_close
You can do what you want by modifying set_current_user() to:
def set_current_user(self, button):
self.current_user = self.dialog.content_cls.ids.username_input.text
self.dialog_close()
self.root.ids.users.add_widget(Label(text=self.current_user))
sm = self.root.ids.screenManager
sm.current = 'user_management'
The above code requires the addition of an id to the UserManagerment in the kv:
UserManagement:
id: users
This just adds a new Label with the name of the user.

How do I add a rectangle graphic behind all my buttons and labels?

I would like to add a rounded rectangle behind each row of widgets containing 3 buttons and two labels all horizontally layout. Each group contents are added dynamically through the input_text and '+' button on the bottom. I have all the major parts working but I can't get the rounded rectangle graphic.
Here is what I've got so far:
I was hoping to create something like this:
Please let me know where I went wrong and how to fix it I'm pretty new in Kivy so I'm just learning.
Thanks.
class Trackers(Screen):
storage = {}
path = ''
def on_pre_enter(self):
self.path = App.get_running_app().user_data_dir + '/'
self.loadData()
for tracker, num in self.storage.items():
self.ids.track.add_widget(Tracker(text=tracker, number=num, data=self.storage))
def addWidget(self):
text_input = self.ids.text_input.text
num = '0'
if text_input not in self.storage.keys():
self.ids.track.add_widget(Tracker(text=text_input, number=num, data=self.storage))
self.storage[text_input] = '0'
self.ids.text_input.text = ''
self.saveData()
class Tracker(BoxLayout):
def __init__(self, text='', number='', data={}, **kwargs):
super().__init__(**kwargs)
self.ids.label.text = text
self.ids.count_add.text = number
class Pess(App):
def build(self):
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '800')
from kivy.core.window import Window
Window.clearcolor = get_color_from_hex('#262829')
return ScreenGenerator()
##### --> .kv file
<Trackers>:
BoxLayout:
orientation: 'vertical'
ActionBar:
height: 45
size_hint_y: None
background_image: ''
background_color: rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]TRACKERS[/b]'
font_size: 21
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'menu'
ActionButton:
text: 'SEND'
color: rgba('#AFB7BA')
on_release: root.send()
ScrollView:
BoxLayout:
id: track
orientation: 'vertical'
font_size: 15
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint_y: None
height: 45
TextInput:
id: text_input
hint_text: 'Add Trackers'
multiline: False
Button:
text: '+'
size_hint_x: None
width: 60
on_release: root.addWidget()
background_color: rgba('#1D7332')
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 4
Button:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').delete_storage(root)
Label:
id: label
font_size: 20
Label:
id: count_add
font_size: 20
text: '0'
Button:
text: '[b]-[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').subtract_num(root)
Button:
text: '[b]+[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').add_num(root)
In your 'kv' file, you can add graphics to the Canvas of your Tracker like this:
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 20, 4, 20, 4 # to keep widgets a bit away from the sides
canvas.before: # use before to keep this under any widgets
Color:
rgba: 1, 0, 0, 1 # any color you want
Rectangle:
pos: self.pos[0] + self.height/2, self.pos[1]
size: self.size[0] - self.height, self.height
Ellipse:
pos: self.pos[0], self.pos[1]
size: self.height, self.height
Ellipse:
pos: self.pos[0] + self.width - self.height, self.pos[1]
size: self.height, self.height
You might want to add some spacing to your track id BoxLayout so that the Tracker widgets don't appear connected.
Here is the entire version of your code that I ran. There are a few lines commented out, since you did not provide all the code:
from kivy.config import Config
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import get_color_from_hex
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
class Trackers(Screen):
storage = {}
path = ''
def on_pre_enter(self):
self.path = App.get_running_app().user_data_dir + '/'
#self.loadData()
for tracker, num in self.storage.items():
self.ids.track.add_widget(Tracker(text=tracker, number=num, data=self.storage))
def addWidget(self):
text_input = self.ids.text_input.text
num = '0'
if text_input not in self.storage.keys():
self.ids.track.add_widget(Tracker(text=text_input, number=num, data=self.storage))
self.storage[text_input] = '0'
self.ids.text_input.text = ''
#self.saveData()
class Tracker(BoxLayout):
def __init__(self, text='', number='', data={}, **kwargs):
super().__init__(**kwargs)
self.ids.label.text = text
self.ids.count_add.text = number
Builder.load_string('''
<Trackers>:
BoxLayout:
orientation: 'vertical'
ActionBar:
height: 45
size_hint_y: None
background_image: ''
background_color: rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]TRACKERS[/b]'
font_size: 21
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'menu'
ActionButton:
text: 'SEND'
color: rgba('#AFB7BA')
on_release: root.send()
ScrollView:
BoxLayout:
id: track
orientation: 'vertical'
spacing: 5
font_size: 15
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint_y: None
height: 45
TextInput:
id: text_input
hint_text: 'Add Trackers'
multiline: False
Button:
text: '+'
size_hint_x: None
width: 60
on_release: root.addWidget()
background_color: rgba('#1D7332')
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 20, 4, 20, 4
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
pos: self.pos[0] + self.height/2, self.pos[1]
size: self.size[0] - self.height, self.height
Ellipse:
pos: self.pos[0], self.pos[1]
size: self.height, self.height
Ellipse:
pos: self.pos[0] + self.width - self.height, self.pos[1]
size: self.height, self.height
Button:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').delete_storage(root)
Label:
id: label
font_size: 20
Label:
id: count_add
font_size: 20
text: '0'
Button:
text: '[b]-[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').subtract_num(root)
Button:
text: '[b]+[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').add_num(root)
''')
class Pess(App):
def build(self):
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '800')
from kivy.core.window import Window
Window.clearcolor = get_color_from_hex('#262829')
# Don't have `ScreenGenerator` so just set up `ScreenManager`
sm = ScreenManager()
sm.add_widget(Trackers(name='trackers'))
return sm
#return ScreenGenerator()
Pess().run()

converting static widget tree to dynamic using python and .kv file

I am working on an application where I want to add n image frames in a vertical BoxLayout. The number of n frames depend on the desktop screen size. Next to this the frames will be filled dynamically with images. I was able to develop this in a static manner with a fixed number of frames.
Now I am trying to convert this to a dynamic solution where n frame widgets will be created depending on the height of the screen (in the example below 7 widgets). And I am lost..... :(
The frames should 'sit' between a top bar and a bottom bar. In the .kv file this is indicated by the # Ilist: line.
I have the following questions:
1) How could I add these widgets dynamically using a .kv file?
2) How could I reference to these individual frame widgets for assigning images dynamically? For example: frame[idx] = swid?
Thanks very much for your time and shared knowledge in advance.
The Python file pplay.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.properties import StringProperty
class IListItem(Widget):
sid = StringProperty('')
image = StringProperty('')
label = StringProperty('')
pass
class IList(Widget):
pass
class pplayHome(BoxLayout):
def init_player(self):
global swid
self.Ilayout = IList()
for idx in range (1, 7):
swid = IListItem(
sid = "s" + str(idx),
image = 'empty_image.png',
label = 'Image' + str(idx)
)
self.Ilayout.add_widget(swid)
class pplayApp(App):
def build(self):
Window.clearcolor = (1,1,1,1)
Window.borderless = True
Window.size = 275, 1080
homeWin = pplayHome()
homeWin.init_player()
return homeWin
if __name__ == "__main__":
pplayApp().run()
and the Kivy file pplay.kv
# File: pplay.kv
<IList#BoxLayout>
pid: self.pid
source: self.source
label: self.label
size_hint_y: None
height: "120dp"
BoxLayout:
orientation: "vertical"
Label:
size_hint: None, 1
text: root.label
Image:
size_hint: None, 1
source: root.source
<pplayHome>:
orientation: "vertical"
ActionBar:
font_size: 8
size: (275,25)
# background color in Kivy acts as a tint and not just a solid color.
# set a pure white background image first.
background_image: 'white-bg.png'
background_color: 0,.19,.34,1
ActionView:
ActionPrevious:
with_previous: False
app_icon: 'trButton.png'
ActionOverflow:
ActionButton:
icon: 'butt_exit.png'
on_press: root.exit_player()
# Ilist:
BoxLayout:
height: "10dp"
size_hint_y: None
pos_x: 0
canvas.before:
Color:
rgb: 0.55,0.77,0.25 # groen
Rectangle:
pos: self.pos
size: self.size
You were actually pretty close.
Here is the slightly changed kv file, with added colored rectangles for illustration of sizes:
# File: pplay.kv
<IListItem#Widget>
source: ''
label: ''
size_hint_y: None
height: "120dp"
canvas.before:
Color:
rgb: 0.55,0.77*self.idx/7,0.25 # groen
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: "vertical"
size: root.size
pos: root.pos
Label:
size_hint: None, 1
text: root.label
canvas.before:
Color:
rgb: 0.77*root.idx/7,0.55,0.25 # groen
Rectangle:
pos: self.pos
size: self.size
Image:
size_hint: None, 1
source: root.source
<pplayHome>:
orientation: "vertical"
ActionBar:
font_size: 8
size: (275,25)
# background color in Kivy acts as a tint and not just a solid color.
# set a pure white background image first.
background_image: 'white-bg.png'
background_color: 0,.19,.34,1
ActionView:
ActionPrevious:
with_previous: False
app_icon: 'trButton.png'
ActionOverflow:
ActionButton:
icon: 'butt_exit.png'
on_press: root.exit_player()
IList:
id: ilist
orientation: 'vertical'
BoxLayout:
height: "10dp"
size_hint_y: None
pos_x: 0
canvas.before:
Color:
rgb: 0.55,0.77,0.25 # groen
Rectangle:
pos: self.pos
size: self.size
In pplay.py, the essential part is to retrieve the IList widget using self.ids['ilist']. It also shows how its children (the IListItems) can be retrieved via a differentiating property.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.properties import StringProperty, NumericProperty
class IListItem(Widget):
idx = NumericProperty(1)
sid = StringProperty('')
image = StringProperty('')
label = StringProperty('')
pass
class IList(BoxLayout):
pass
class pplayHome(BoxLayout):
def init_player(self):
#global swid
print self.ids
ilayout = self.ids['ilist']
for idx in range (0, 7):
swid = IListItem(
sid = "s" + str(idx),
image = 'empty_image.png',
label = 'Image' + str(idx),
idx=idx
)
ilayout.add_widget(swid)
children_ids = [il.sid for il in ilayout.children]
print children_ids
print ilayout.children[children_ids.index('s3')]
class pplayApp(App):
def build(self):
# Window.clearcolor = (1,1,1,1)
Window.borderless = True
Window.size = 275, 1080
homeWin = pplayHome()
homeWin.init_player()
return homeWin
if __name__ == "__main__":
pplayApp().run()

Categories

Resources