I need to get a kivymd MDDialig dialog box with a list. When setting the type parameter to MDDialog by default or "custom", it displays only the title of the dialog box, but not the items themselves. Setting the type parameter to "simple" causes an error.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import OneLineListItem
main = '''
AnchorLayout:
padding: "25sp"
anchor_x: "center"
anchor_y: "top"
TwoLineListItem:
text: 'key'
secondary_text: 'value_1'
on_press: app.open_dialog()
'''
class Example(MDApp):
def build(self):
return Builder.load_string(main)
def open_dialog(self):
dialog = MDDialog(
title="key",
items=[
OneLineListItem(text="value_1"),
OneLineListItem(text="value_2")
]
)
dialog.open()
Example().run()
When setting type to "simple" an error occurs
File "kivy/properties.pyx", line 961, in kivy.properties.ObservableDict.__getattr__
KeyError: '\_left_container'
File "kivy/properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
An example of using the widget was taken from the kivyMD documentation. The buttons display correctly, but the elements do not. Any hints will help.
Below is an image that shows the problem.
enter image description here
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import OneLineAvatarListItem
KV = '''
<Item>
ImageLeftWidget:
source: root.source
MDFloatLayout:
MDFlatButton:
text: "ALERT DIALOG"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: app.show_simple_dialog()
'''
class Item(OneLineAvatarListItem):
divider = None
source = StringProperty()
class Example(MDApp):
dialog = None
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def show_simple_dialog(self):
if not self.dialog:
self.dialog = MDDialog(
title="Set backup account",
type="simple",
items=[
Item(text="user01#gmail.com", source="kivymd/images/logo/kivymd-icon-128.png"),
Item(text="user02#gmail.com", source="data/logo/kivy-icon-128.png"),
],
)
self.dialog.open()
Example().run()
https://kivymd.readthedocs.io/en/1.1.1/components/dialog/#kivymd.uix.dialog.dialog.MDDialog.items
My code is listed below. While running the application, I want to get the text size dynamically bigger and smaller when you "zoom" in/out the application window (dragging window bigger and smaller). Just like the button as an example (white square). Right now the text size stays the same size.
Note:
If you copy my code for testing, download also blue.png for in the same folder as the .py file.
Any help would be appreciated!
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class FirstScreen(Screen):
pass
class myScreenManager(ScreenManager):
pass
class ImageButton(ButtonBehavior, Image):
pass
root_widget = Builder.load_string('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
myScreenManager:
transition: FadeTransition()
FirstScreen:
<FirstScreen>:
name: 'first'
FloatLayout:
orientation: 'vertical'
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'blue.png'
ImageButton:
pos_hint: {'x': 0.25, 'y': 0.18}
size_hint: 0.5, 0.3
Label:
text: 'THIS\\nIS\\nA\\nTEST'
text_size: root.width, None
font_size: 40
pos_hint: {'x': 0, 'y': 0.19}
halign: 'center'
''')
class myScreenManagerApp(App):
def build(self):
return root_widget
myScreenManagerApp().run()
You can make the font_size depend on the size of the application window. Try replacing:
font_size: 40
with something like:
font_size: root.height/12
I am looking to add a graph to one of my kivy screen app. Basic App with a StartScreen and the SecondScreen with the graph itself and few buttons. I can't get the graph to show in Kivy. I've tried creating a class for it but I always end up getting this error:
AttributeError: 'Figure' object has no attribute 'set_canvas'
I have tried finding the answer by myself but I always get to an dead end. Here is the code for the graph below as well as the code for my app. If someone could point me in the right direction you would be my HERO!
Yours truly, the coding newbie!
Here is the graph:
import plotly.graph_objects as go
fig = go.Figure(go.Indicator(
mode = "number+gauge+delta",
gauge = {'shape': "bullet"},
delta = {'reference': 300},
value = 220,
domain = {'x': [0.1, 1], 'y': [0.2, 0.9]},
title = {'text': "Avg order size"}))
fig.show()
Here is my main.py:
import plotly.graph_objects as go
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import ButtonBehavior
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.screenmanager import Screen
from kivy.graphics import Rectangle
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from kivy.properties import ObjectProperty
import matplotlib.pyplot as plt
class StartScreen(Screen):
pass
Window.clearcolor = (1, 1, 1, 1)
class GraphScreen(Screen):
pass
class ImageButton(ButtonBehavior, Image):
pass
GUI = Builder.load_file("main.kv")
class Main(App):
def build(self):
return GUI
def change_screen(self, screen_name):
# Get the screen manager from the kv file
screen_manager = self.root.ids['screen_manager']
screen_manager.current = screen_name
if __name__ == '__main__':
Main().run()
Here is my main.kv:
#:include kv/startscreen.kv
#:include kv/graphscreen.kv
GridLayout:
cols: 1
ScreenManager:
id: screen_manager
StartScreen:
name: "start_screen"
id: start_screen
GraphScreen:
name: "graph_screen"
id: graph_screen
Here is my startscreen.kv:
#:import utils kivy.utils
<StartScreen>:
FloatLayout:
GridLayout:
rows: 1
pos_hint: {"top": 1, "left": 1}
size_hint: 1, .5
Label:
rows: 1
text: "Budget Meter"
font_size: 30
font_name: "font/Duldolar.ttf"
color: 0, 0, 0, 1
GridLayout:
rows: 1
pos_hint: {'x':.02, 'y':.6}
size_hint: 1, .1
ImageButton:
source: "images/Ecommerce_203.jpg"
on_release:
app.change_screen("graph_screen")
Here is my graphscreen.kv:
#:import utils kivy.utils
<GraphScreen>:
BoxLayout:
orientation: "vertical"
size_hint: .3, .5
pos_hint: {'x':.35, 'y':0}
ImageButton:
source: "images/ope.jpg"
on_release:
app.change_screen("start_screen")
Am working on a Project that has a RecycleView that contains details of patients.My aim is that when i click on a specific patient on the recycleView row, it should take me to specific dynamic page layout containing specific details of the selected patient in the RecycleView without using the Screen Manager, the switching of dynamic pages.how can i go about this?
i have created a method called change_dynamic_Layout() for switching dynamic pages and it works fine when using the normal button to call it. I have used a print statement in the method to show if the method is executed or not. But when i use the SelectableButton,the print statement is executed but the statement for changing page-layout is not. No errors is shown and the dynamic page does not change. Here is the code try to run it and see what am talking about?
Demo.py
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, ListProperty,
NumericProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.factory import Factory
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
lost = Builder.load_file('Demo.kv')
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
#selectablebutton to call the change_dynamic_Layout() method in patient class
def on_enter(self):
layout=Patient()
layout.change_dynamic_Layout()
class victor(BoxLayout):
pass
class Patient(Screen):
manage_prescription: ObjectProperty(None)
#Method to change the dynamic pagelayout
def change_dynamic_Layout(self):
layout = Factory.victor()
self.manage_prescription.clear_widgets()
self.manage_prescription.add_widget(layout)
print ('pressed')
class DemoApp(App):
title = 'Hospital Management System'
def build(self):
n= Patient()
return n
if __name__ == "__main__":
DemoApp().run()
demo.kv
<Patient>:
manage_prescription:manage_prescription
BoxLayout:
GridLayout :
cols:1
BoxLayout:
id:manage_prescription
orientation:'vertical'
BoxLayout:
size_hint_y:None
height:40
Button:
text:"NO."
font_size: 25
Button:
text:"Date"
font_size: 25
Button:
text:"Patient"
font_size: 25
Button:
text:"Doctor"
font_size: 25
on_press: root.change_dynamic_Layout()
BoxLayout:
RecycleView:
bar_width: 10
bar_color: 1, 0, 0, 1 # red
bar_inactive_color: 0, 0, 1, 1 # blue
#effect_cls: "ScrollEffect"
scroll_type: ['bars']
viewclass: 'SelectableButton'
data:[{'text': str(x)} for x in range(20)]
SelectableRecycleGridLayout:
cols:4
default_size: None, dp(56)
default_size_hint:1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
<victor>:
Label:
text:" Switched to specific page for patient's details"
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
on_press: root.on_enter()
Any insight or help is much appreciated, thanks in advance.
The problem is that your on_enter method of the SelectableButton is creating a new Patient layout (Screen), and calling the change_dynamic_Layout method of that new Patient Screen. That newly created Patient Screen is not the one displayed in your app, so it has no effect on what you see. You actually want to call change_dynamic_Layout on the displayed Patient Screen. One way of doing this is to access it via App.get_running_app().root. So that your on_enter method can be changed to:
def on_enter(self):
#layout=Patient()
layout = App.get_running_app().root
layout.change_dynamic_Layout()
Here is the entire python file:
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, ListProperty, NumericProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.factory import Factory
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
lost = Builder.load_file('Demo.kv')
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
#selectablebutton to call the change_dynamic_Layout() method in patient class
def on_enter(self):
#layout=Patient()
layout = App.get_running_app().root
layout.change_dynamic_Layout()
class victor(BoxLayout):
pass
class Patient(Screen):
manage_prescription: ObjectProperty(None)
#Method to change the dynamic pagelayout
def change_dynamic_Layout(self):
layout = Factory.victor()
self.manage_prescription.clear_widgets()
self.manage_prescription.add_widget(layout)
print ('pressed')
class DemoApp(App):
title = 'Hospital Management System'
def build(self):
n= Patient()
return n
if __name__ == "__main__":
DemoApp().run()
And here is the Demo.kv:
<Patient>:
manage_prescription:manage_prescription
BoxLayout:
GridLayout :
cols:1
BoxLayout:
id:manage_prescription
orientation:'vertical'
BoxLayout:
size_hint_y:None
height:40
Button:
text:"NO."
font_size: 25
Button:
text:"Date"
font_size: 25
Button:
text:"Patient"
font_size: 25
Button:
text:"Doctor"
font_size: 25
on_press: root.change_dynamic_Layout()
BoxLayout:
RecycleView:
bar_width: 10
bar_color: 1, 0, 0, 1 # red
bar_inactive_color: 0, 0, 1, 1 # blue
#effect_cls: "ScrollEffect"
scroll_type: ['bars']
viewclass: 'SelectableButton'
data:[{'text': str(x)} for x in range(20)]
SelectableRecycleGridLayout:
cols:4
default_size: None, dp(56)
default_size_hint:1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
<victor>:
Label:
text:" Switched to specific page for patient's details"
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
on_press: root.on_enter()
i am using kivy BoxLayout with two Buttons, one of the buttons is to display an image. the image displays fine when using the horizontal orientation, but when I use the vertical orientation it will not display my image. windows 10, python 3.6.4, kivy 1.10.0
.py file:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.stacklayout import StackLayout
from kivy.uix.boxlayout import BoxLayout
class ClickerScreen(Screen):
pass
class Manager(ScreenManager):
clicker_screen = ObjectProperty(None)
class ClickerApp(App):
def build(self):
return Manager()
if __name__=='__main__':
ClickerApp().run()
.kv file:
#: import Window kivy.core.window.Window
<Manager>:
id: screen_manager
clicker_screen: clicker_screen
ClickerScreen:
id: clicker_screen
name: 'clicker'
manager: screen_manager
BoxLayout:
orientation: 'vertical'
Button:
background_color: 0,0,0,0
Image:
source: 'Images/button.png'
allow_stretch: False
keep_ratio: True
size: self.parent.size
Button: