Essentially, I have multiple screens, being controlled by the screen manager (primarily for logins), however on the main screen, I have it broken up with a header, nav bar, and a section for the body. In the body section is where I want to be able to call different layouts that I have classes for, and add and remove these as buttons on the nav bar are pressed.
Im using kivy to control all aspects of the gui, but am rather new to it. At the moment I have:
Builder.load_string('''
<MainMenu>:
FloatLayout:
canvas.before:
Color:
rgba: 0.235, 0.271, 0.302, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
rows: 4
Label:
size_hint: 1,0.12
text: "ProductName"
text_size: self.size
halign: 'left'
valign: 'middle'
font_size: 32
color: [0.114,0.18,0.224,1]
StackLayout:
size_hint: 1,0.10
orientation: 'lr-tb'
#Purchase Order System
Button:
id: butpos
text: "Purchase Order"
size_hint: 0.166,1
on_press: spaceholder.add_widget(pos)
#Asset Assignment System
Button:
id: butaas
text: "Asset Assignment"
size_hint: 0.166,1
#Review and Revise System
Button:
id: butrrs
text: "Review"
size_hint: 0.166,1
#Administrative System
Button:
id: butadm
text: "Administration"
size_hint: 0.166,1
#Analytics and Reporting System
Button:
id: butars
text: "Analytics"
size_hint: 0.166,1
#Placeholder, possibly documentation
Button:
id: butbut
text: "Placeholder"
size_hint: 0.166,1
Label:
canvas.before:
Color:
rgba: 0.259, 0.643, 0.937, 1
Rectangle:
pos: self.pos
size: self.size
size_hint: 1,0.005
Widget:
id: spaceholder
<PurchaseOrder>
id: pos
orientation: 'lr-tb'
#Asset Details
Label:
BoxLayout:
orientation: 'vertical'
Label:
text: "Asset Requirements"
Label:
text: "Asset1: "
TextInput:
id: as1count
Label:
text: "Asset2: "
TextInput:
id: as2count
''')
class MainMenu(Screen):
pass
class PurchaseOrder(StackLayout):
pass
class MainApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainMenu(name='mainmenu'))
return sm
if __name__ == '__main__':
MainApp().run()
PurchaseOrder is a class that Id like to be added or removed, much like classes I intend to set up for the other navigation options. Ive tried a number of methods, but I think im missing something. Im either being thrown with 'pos' is not defined, or that 'spaceholder' has wrong attributes when ive tried different combinations.
You can make that work by modifying the Purchase Order Button:
on_press: spaceholder.add_widget(Factory.PurchaseOrder())
That requires an addition to your kv to import Factory:
#:import Factory kivy.factory.Factory
I would recommend using a Layout for your spaceholder to take advantage of their sizing and positioning capabilities. For example, using an AnchorLayout automatically centers its child (but is limited to a single child). Like this:
AnchorLayout:
id: spaceholder
Related
I want to update MDRectangleFlatIconButton's text. It changes with a new text but when the new text is longer than previous text, then the text fits in two lines.
When i use a normal button, the new text fits in one line with proper adjustment.
but Since there is a Icon in MDRectangleFlatIconButton, when a new text is longer than previous text, the text fits in a two line.
To run the program,
Add a new app name which is longer than "Info" inside "Info" button's popup window, then click "Update Top Bar's name". Then, it updated title and the text of "Info" button at the front main App.
I have tried to change this by adding button's text_size: self.width, valign:"center", haling: "center", or manually adding text_size: cm(10), cm(10).
Also, i tried with on_release: "app.root.ids.bt_information.text_size = self.width, None
but nothing works so far.
I greatly appreciate your help.
Python code
'''
from kivy.uix.widget import Widget
'''Setting the size of first window for program'''
from kivy.config import Config #another way of setting size of window
Config.set('graphics', 'width', '600') # from kivy.core.window import Window
Config.set('graphics', 'height', '750') # Window.size = ("600", "750")
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.factory import Factory
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
Builder.load_file('new_window_popup.kv')
class Dex(Popup):
pass
class Remi(Popup):
pass
class Info(Popup):
pass
class MyLayout(Widget):
pass
class AwesomeApp(MDApp):
def build(self):
self.title = "My house"
return MyLayout()
if __name__ == '__main__':
AwesomeApp().run()
'''
kivyfile: new_window_popup.kv
'''
#:import Factory kivy.factory.Factory
#:import MDRaisedButton kivymd.uix.button
<Dex>:
auto_dismiss: False
size_hint: 1, 1
title: "Weight-Based Dose Calculator "
canvas.before:
Color:
rgba: (0,1,0,1)
Rectangle:
pos:self.pos
size:self.size
BoxLayout:
orientation: "vertical"
size:root.width, root.height
Label:
text: "Dex 1"
Button:
text: "Close"
font_size: 24
on_release: root.dismiss()
<Remi>:
auto_dismiss: False
size_hint: 1, 1
title: "Weight-Based Dose Calculator "
canvas.before:
Color:
rgba: (0,1,0,1)
Rectangle:
pos:self.pos
size:self.size
BoxLayout:
orientation: "vertical"
size:root.width, root.height
Label:
text: "Remi"
Button:
text: "Close"
font_size: 24
on_release: root.dismiss()
<Info>:
appName:appName
auto_dismiss: False
size_hint: 1, 1
title: "Change Info"
canvas.before:
Color:
rgba: (0,1,0,1)
Rectangle:
pos:self.pos
size:self.size
BoxLayout:
orientation: "vertical"
size:root.width, root.height
Label:
text: "What is your App name?"
BoxLayout:
orientation: "horizontal"
MDTextField:
id: appName
hint_text: "App Name"
color_mode: 'primary'
current_hint_text_color: 1,1,1,1
hint_text_color_focus: 1,1,1,.9
line_color_focus: 1,1,1,1
font_size: '25sp'
text_color_normal: 1,1,1,.9
text_color_focus: 0,0,1,.9
focus: True
write_tab: False
Button:
text: "Update Top Bar\'s name"
font_size: 24
size_hint: .8, .2
# on_release: root.updateName()
on_release:
app.title = appName.text
app.root.ids.bt_information.text = appName.text
Button:
text: "Close"
font_size: 24
on_release: root.dismiss()
<MyLayout>
MDBoxLayout:
orientation:"vertical"
size: root.width, root.height
MDRaisedButton:
text: "Dex"
font_size: 32
text_color: 0,0,0,.9
size_hint: 1,.5
on_press: Factory.Dex().open()
MDRaisedButton:
text: "Remi"
font_size: 32
size_hint: 1,.5
on_press: Factory.Remi().open()
MDRectangleFlatIconButton:
id: bt_information
text: "Info"
icon: "youtube-studio"
font_size: 32
size_hint: 1,.2
text_size: self.width, None
md_bg_color: 0.95,0.61,0.73,1
on_press: Factory.Info().open()
'''
I'm creating a kivy app right now. I'm quite new to Kivy and kv lang and there doesn't seam to be much rumour about it although i find it great to seperate code logic and layout, especially after some pygame development.
So to my actuall problem: I have a wiki-style screen for screenmanager, consisting out of a BoxLayout:
Title as Label
Scrollable Label for the Text (later , there shall be displayed a nested kv file)
Buttons for Navigation (scroll up and go back to main screen)
Now I'm recreating the Navigation buttons to be floating type as known from many webpages and apps. Problem is, I suddendly cant reference my ScrollView anymore. Any help or suggestions?
<Wiki>:
name: "wiki"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "picture.jpg"
BoxLayout:
id: box
orientation: "vertical"
padding: 10
spacing: 10
Label:
font_size: 20
size_hint_y: .1
text: root.country_text
ScrollView:
id: scrlvw
BackgroundLabel:
background_color: 220,220,220, 0.5
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
halign: "left"
valign: "top"
text: root.wiki_text
FloatLayout:
size_hint_y: .1
Button:
size_hint_x: .2
pos_hint: {"center_x": .25, "center_y": .5}
text: "Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
FloatButton:
size_hint_x: .2
pos_hint: {"center_x": .75, "center_y": .5}
text: "Up"
on_release:
widget = BoxLayout()
widget.ids.scrlvw.scroll_y = 0
Before, when it worked, it was:
BoxLayout:
FloatLayout:
size_hint_y: .1
Button:
size_hint_x: .2
pos_hint: {"center_x": .25, "center_y": .5}
text: "Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
Button:
size_hint_x: .2
pos_hint: {"center_x": .75, "center_y": .5}
text: "Up"
on_release:
scrlvw.scroll_y = 0
Well as its just a design question, I guess i temporary have to dismiss the floating design. But I would be so pleased if you could help me understand this language better.
As long as the 'kv' code described as "when it worked" is still in the same <Wiki> rule, it should still work. The newer kv code will never work as you are trying to create a new BoxLayout and reference an id in it. That has two problems:
The newly created BoxLayout is not the BoxLayout instance that appears in your GUI, so any changes to it will have no effect on what appears in the display.
Unless you have a <BoxLayout> rule in your kv, the newly created BoxLayout will not have a scrlvw id.
The ids defined within a kv rule are available for use only within that rule. See the documntation.
I am looking to add a border to the main screen of my application but I'm not sure how.
I tried to take some tips from this question:
Kivy-how can i make my canvas height smaller than the parent height
But I can't seem to figure it out.
The issue is that I am also using a KivyMD's Navigation Drawer, I would like the border be separate from the top bar, enclosing everything below the bar. Please let me know if I'm not being clear.
Here is some sample code that replicates my setup.
Perhaps I could add some random rectangles to act as a border?
EDIT:
Okay almost there, I got the 'border' but I now need the size_hint added in the AnchorLayout to ignore the top portion of the screen where the menu bar is. Here is the updated code.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
kv = '''
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
Widget:
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
source: "image.jpg"
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
'''
class ContentNavigationDrawer(BoxLayout):
pass
class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)
MyApp().run()
I think you will get what you want if you indent the FloatLayout so that it is in the BoxLayout. Like this:
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
# Widget: # not needed
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
# source: "image.jpg"
source: 'tester.png'
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
I am working with a FileChooser module in Kivy which is black by default.
But for the rest of my app I used this to define Labels and Buttons style :
<Label>
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
and
<Button>
font_size:20
color: 1,1,1,1
background_color: (0.55,0.55,0.47,1.0)
size_hint:0.9,0.2
This is efficient and time saver BUT it breaks the FileChooserIconView I use :
The filechooser contains Labels and buttons. They are all in the same class, so do you know how to NOT affect this button and label stuyle to one class ?
I already tried to change the filechooser style instead but it's not working
The filechooser class
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserIconView:
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)
I have an App with three toggle buttons in a fixed header that is an outside indented layout for screen manager. On initialisation, the Import screen must show i.e. self.ids.scrn_man.current = 'import_scn" and when a toggle button is pushed a next screen should show i.e. on_state: scrn_man.current = "settings_scrn".
But for some reason, only the header is showing and the screens do not want to transition. I don't get any errors.
I tried different layouts as my Apps main class inheritance including, FloatLayout, StackLayout and BoxLayout. I also made the header fixed with AnchorLayout and use a different layout as the inline layout for ScreenManager. If I remove the ScreenManager I see my widgets, but of course, I cannot transition. I did at first try using TabbedPanel to house my different widgets but I encountered a constant RefError: weak object reference if I added too many widgets (but that's not for now). So I re-designed with something I knew worked on a previous App albeit less complex.
Here is my faulty code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import StringProperty, ObjectProperty
Builder.load_string("""
<RoundedButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (1,.6,0,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<RoundedCancelButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (1,.2,.2,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<RoundedAcceptButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (.2,1,.6,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<TabbedContainer#ToggleButton>:
background_color: (1, .5, 0, 1)
background_normal: ''
size_hint_y: None
height: 50
size_hint_x: (1 / 3)
spacing: 30
<Tab>:
canvas.before:
Color:
rgba: (.89, .89, .89, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: 'lr-tb'
BoxLayout:
orientation: 'horizontal'
size_hint_y: None
height: 30
canvas.before:
Color:
rgba: (1, .3, 0, 1)
Rectangle:
size: self.size
pos: self.pos
Label:
text: 'Test'
color: (1, 1, 1, 1)
size_hint_x: 1
StackLayout:
orientation: 'lr-tb'
Label:
text: ''
size_hint_x: 1
size_hint_y: None
height: 10
TabbedContainer:
id: import_tog
text: 'Import'
state: 'down'
group: 'admin_navs'
on_state: root.change_screen(self)
TabbedContainer:
id: calculate_tog
text: 'Calculate'
group: 'admin_navs'
on_state: root.change_screen(self)
TabbedContainer:
id: settings_tog
text: 'Settings'
group: 'admin_navs'
on_state: root.change_screen(self)
BoxLayout:
id: ui_content
padding: 10
ScreenManager: #Problem here I think
id: scrn_man
Screen:
id: import_scrn
name: 'import_scrn'
StackLayout:
orientation: 'lr-tb'
Label:
text: ''
size_hint_x: 1
Label:
text: ''
size_hint_x: 0.2
RoundedButton:
text: 'Choose File'
size_hint_x: 0.2
TextInput:
id: get_file
readonly: True
size_hint_x: 0.5
Label:
text: ''
size_hint_x: 0.1
Label:
text: ''
size_hint_x: 0.2
RoundedButton:
text: 'Import'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.6
StackLayout:
id: import_data_content
orientation: 'lr-tb'
size_hint_y: None
height: 90
Screen:
id: calculate_scrn
name: 'calculate_scrn'
Screen:
id: settings_scrn
name: 'settings_scrn'
StackLayout:
orientation: 'lr-tb'
size_hint_x: 0.5
Label:
text: ''
size_hint_x: 0.1
Button:
text: 'Add Employee'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.2
Button:
text: 'CSV'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.3
BoxLayout:
orientation: 'horizontal'
size_hint_x: 0.5
Label:
text: 'In Time'
size_hint_x: 0.7
TextInput:
size_hint_x: 0.3
Label:
text: 'Out Time'
size_hint_x: 0.7
TextInput:
size_hint_x: 0.3
""")
class TabbedContainer(ToggleButton):
pass
class FileChoosePopup(Popup):
load = ObjectProperty()
class RoundedButton(Button):
pass
class RoundedCancelButton(Button):
pass
class RoundedAcceptButton(Button):
pass
class Tab(StackLayout):
file_path = StringProperty("No file chosen")
the_popup = ObjectProperty(None)
def __init__(self, **kwargs):
super().__init__(**kwargs)
#load import window on initialisation
import_window = self.ids.import_scrn
self.ids.scrn_man.current = 'import_scrn'
def change_screen(self, instance):
if instance.text == 'Import':
self.ids.scrn_man.current = 'import_scrn'
elif instance.text == 'Calculate':
self.ids.scrn_man.current = 'calculate_scrn'
else:
self.ids.scrn_man.current = 'settings_scrn'
class TestApp(App):
def build(self):
return Tab()
if __name__ == '__main__':
TestApp().run()
I expect that the import screen must show on initialisation and screens transition on toggle button state: down. Can someone please give me some advice on how to make my App act as explained above?
Your screens are loading correctly according to your settings. You need to review your entire kv string looking at your size_hint settings. Check each item that contains children and make sure that the total of size_hint_x for its children is less than or equal to 1.0 and the same for size_hint_y.