I would like to change font_name property of MDLabel. But I want to add this component dynamically, in .py file, not .kv.
So when I write something like this:
main.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import MDScreen
class MainApp(MDApp):
def build(self):
Builder.load_string(KV)
otherLabel = MDLabel(
text="one more text",
halign="center",
font_name="18328",
font_size="50sp"
)
screen.add_widget(
otherLabel
)
return screen
MainApp().run()
it does not help. How can I implement font applying dynamically?
KV string
KV = '''
Screen:
MDCard:
id: box
orientation: "vertical"
padding: "8dp"
size_hint: None, None
size: "280dp", "180dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDLabel:
text: "Hello"
theme_text_color: "Secondary"
size_hint_y: None
height: self.texture_size[1]
font_name: '18328.ttf'
MDSeparator:
height: "1dp"
MDLabel:
text: "Body"
MDLabel:
text: "Hello"
font_name: 'BebasNeue-Regular.otf'
font_size: "50sp"
'''
Create a reference in the screen itself (also you don't need to use .ttf, the library adds it automatically, just the filename without extension is fine)
class MyScreen(Screen):
my_MD_Label = None
def on_kv_post(self, instance):
self.my_MD_Label = MDLabel(
text="one more text"
font_name="18328"
)
self.ids.box.add_widget(self.my_MD_Label)
And whenever you want to change it, you can simply do this
self.my_MD_Label.font_name = "new_font" # When in same screen
self.manager.get_screen('MyScreen').my_MD_Label.font_name = "new_font" #When in other screen
Related
My problem is when I want to display the value given by the user in the Text input text field.
When I want to get the text value from the input I get an empty value and I cannot display anything in the label field .
Here is my code :
The kv file :
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
text: root.text_input_1
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
Label:
text: root.Display_text
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()
The py file :
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
# different layouts:
class MainGridLayout(GridLayout):
text_input_1 = StringProperty()
Display_text = StringProperty()
def on_button_plus(self):
print(f'{self.text_input_1}')
# run application:
class CalculatorApp(App):
pass
CalculatorApp().run()
I have created a function in MainGridLayout, on_new_text, that takes as a parameter a TextInput and updates text_input_1 with its value.
In the kv file I have set the on_text property of the TextInput to the on_new_text function and gave the TextInput as a parameter. Every time you modify the text input, the on_new_text function will be called, modifying the text_input_1 property.
You can find more properties like on_text in the kivy documentation.
The kv file:
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
on_text: root.on_new_text(self)
Label:
text: root.Display_text
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()
The py file:
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
# different layouts:
class MainGridLayout(GridLayout):
text_input_1 = StringProperty()
Display_text = StringProperty()
def on_new_text(self, text_input):
self.text_input_1 = text_input.text
def on_button_plus(self):
print(f'{self.text_input_1}')
class CalculatorApp(App):
pass
CalculatorApp().run()
Actually, you don't need the variables text_input_1 and Display_text. To display the text from the my_text_input on the label you can add text: my_text_input.text instead of text: root.Display_text. Now, when the text of my_text_input changes, the label's text will change automatically and you don't need any functions. In on_button_plus() method you can do the same and print my_text_input's text using its text property (from all MainGridLayout's ids you take only my_text_input and print its text). The line text: root.text_input_1 unnecessary, too.
Here is my editted version of your code:
The .py file
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
class MainGridLayout(GridLayout):
def on_button_plus(self):
print(f'{self.ids.my_text_input.text}')
class CalculatorApp(App):
pass
CalculatorApp().run()
The .kv file
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
Label:
text: my_text_input.text # change the text automatically
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()
I'm creating an mp3 player using kivy recycleview, the app has a lot of buttons in the playlist screen and whenever you click on a button, icon of that button change from 'play' to 'pause' and vice versa.
I would like to know how to make it be in a way that clicking another button changes all the other buttons icon to 'play' only that selected button should be with icon of 'pause'.
.py file:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.properties import StringProperty, ObjectProperty
from kivymd.theming import ThemableBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.screen import MDScreen
from kivymd.uix.behaviors import RectangularRippleBehavior
from kivy.uix.behaviors import ButtonBehavior
from kivy.clock import Clock
Builder.load_file('playlist.kv')
KV = """
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManager:
transition: FadeTransition()
Playlist:
name: "playlist screen"
"""
class Playlist(ThemableBehavior, MDScreen):
rv = ObjectProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self._finish_init)
def music_list(self):
return ['audio '+str(i) for i in range(1, 121)]
def _finish_init(self, dt):
self.set_list_musics()
def set_list_musics(self):
"""Builds a list of audios for the screen Playlist."""
print(self.ids)
def add_music_item(num, sura, secText, icon):
self.ids.rv.data.append(
{
"viewclass": "MusicListItem",
"number": num,
"text": sura,
"secondary_text": secText,
"icon": icon,
"callback": lambda x:x})
for i in range(len(self.music_list())):
music = self.music_list()
add_music_item(str(i+1), music[i], '00:00:00', 'play')
class MusicListItem(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, MDBoxLayout):
text = StringProperty()
secondary_text = StringProperty()
number = StringProperty()
icon = StringProperty()
def on_release(self, *args):
if self.icon == "play":
self.icon = "pause"
else:
self.icon = "play"
class Mp3Player(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
self.theme_cls.primary_palette = "Purple"
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
if '__main__' == __name__:
Mp3Player().run()
.kv file:
#: import gch kivy.utils.get_color_from_hex
#: import StiffScrollEffect kivymd.effects.stiffscroll.StiffScrollEffect
<Playlist>
md_bg_color: gch("#5D1049")
MDGridLayout:
cols: 1
MDToolbar:
left_action_items: [["menu", lambda x: x]]
right_action_items: [["magnify", lambda x: x]]
elevation: 10
md_bg_color: 75/255, 6/255, 54/255, 1
title: 'Playlist'
pos_hint: {'top':1}
MDBoxLayout:
orientation: 'vertical'
RecycleView:
id: rv
effect_cls: 'ScrollEffect'
viewclass: 'MusicListItem'
RecycleBoxLayout:
padding: dp(10)
default_size: None, dp(60)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
<MusicListItem>
size_hint_y: None
padding: dp(14)
height: dp(60)
canvas:
Color:
rgba:
self.theme_cls.divider_color
Line:
points: (root.x+dp(10), root.y, root.x+self.width-dp(10)-0, root.y)
MDBoxLayout:
orientation: "horizontal"
pos_hint: {"center_x": .5, "center_y": .5}
MDBoxLayout:
orientation: 'horizontal'
MDBoxLayout:
orientation: 'vertical'
size_hint_x: .2
MDLabel:
text: root.number
font_style: "H6"
adaptive_height: True
MDLabel:
size_hint_y: .3
MDBoxLayout:
orientation: 'vertical'
MDLabel:
text: root.text
font_style: "Subtitle2"
adaptive_height: True
MDLabel:
text: root.secondary_text
font_style: "Caption"
theme_text_color: "Hint"
adaptive_height: True
MDIconButton:
icon: root.icon
Thank you
So, as I've understood, you want to set an icon as 'pause' while all other as 'play'. One way of doing this could be like, you have to reload the RecyclView data each time the icon changes.
Now to provide data with icon reference (i.e. 'play' or 'pause') I found the number property suitable, so I change it to NumericProperty. Thus number = NumericProperty().
Also this requires some change in kv,
MDLabel:
text: str(int(root.number))
font_style: "H6"
adaptive_height: True
To let Playlist know about the number reference,
def set_list_musics(self, music_no = 0):
"""Builds a list of audios for the screen Playlist."""
print(self.ids)
self.ids.rv.data = [ ] # Since you are appending data and we need to reload everytime.
Make required changes in data,
for i in range(len(self.music_list())):
new_icon = 'pause' if i+1 == music_no else 'play'
music = self.music_list()
add_music_item(str(i+1), music[i], '00:00:00', new_icon)
Now the final part, trigger the change via the button,
def on_release(self, *args):
if self.icon == "play":
self.icon = "pause"
pl = self.parent.parent.parent.parent.parent # Accessing the Playlist according to your design pattern.
pl.set_list_musics(self.number)
else:
self.icon = "play"
Note that I made this change in 'pause' icon (i.e. in if self.icon == "play"), thus you can also freely toggle this icon. Placing it otherwise could not make it possible.
Perhaps this could have been done more systematically with other design styles. I've found some issues with your design pattern. This (such as calling function in for loop repeatedly etc.) may make it a little bit slower as the data increases.
I would like the user to be able to select multiple items from a list of check boxes, but for some reason checking a second box deselects the first and I cannot understand why. My code is below:
Python:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivymd.uix.list import ILeftBodyTouch
from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.properties import StringProperty
class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
pass
class CreateWorkoutCustomDialog(MDBoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
lifts = ['Bench Press', 'Squat', 'Deadlift', 'Weighted Pull-ups', 'Rows', 'Shoulder Press']
for lift in lifts:
self.ids.box.add_widget(CreateWorkoutLiftRow(lift = lift))
class CreateWorkoutLiftRow(MDBoxLayout):
lift = StringProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.lift = kwargs['lift']
def set_icon(self, instance_check):
instance_check.active = True if instance_check.active == False else instance_check.active == False
class Main2App(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.lift_dialog = None
def build(self):
Builder.load_file('dialog.kv')
return Builder.load_file("scratch.kv")
def show_lift_dialog(self):
if not self.lift_dialog:
self.lift_dialog = MDDialog(
title="Create New Workout",
type="custom",
content_cls = CreateWorkoutCustomDialog(),
buttons=[
MDFlatButton(text="CANCEL"),
MDFlatButton(text="OK"),
],
)
self.lift_dialog.open()
Main2App().run()
scratch.kv:
MDScreen:
MDFlatButton:
text: "ALERT DIALOG"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: app.show_lift_dialog()
dialog.kv:
#:kivy 2.0.0
<CreateWorkoutCustomDialog>:
orientation: 'vertical'
size_hint_y: None
height: '400dp'
MDTextField:
hint_text: "Workout Title"
required: True
id: workout_title
ScrollView:
MDBoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
id: box
spacing: "12dp"
<CreateWorkoutLiftRow>:
orientation: 'horizontal'
size_hint_y: None
height: self.minimum_height
ItemConfirm:
text: root.lift
on_release: root.set_icon(check)
size_hint_x: .7
divider: None
LeftCheckbox:
id: check
group: "check"
active: True
CreateWorkoutSetsInput:
id: input
hint_text: "# sets"
size_hint_x: .3
<ItemConfirm#OneLineAvatarIconListItem>:
<CreateWorkoutSetsInput#MDTextField>:
I've reviewed several tutorials and tried my best to understand the documentation but I cannot see where the interaction between discrete check boxes is even happening. Any help would be greatly appreciated!
That is the result of using group with the CheckBox. See the documentation.
group: "check"
Just remove that line in the kv.
I am a new programmer, working on a Kivy app and I need to use screens (screen manager), the issue is that I am using element cards as but buttons, and it is supposed that when using on_release it will change the screen, however if I include root.manager.transition.direction = "left" I get the error AttributeError: 'MyContentComunes' object has no attribute 'screen'. I don't know if anyone could help me with this.
Here is a piece of code.
from kivy.app import App
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelTwoLine
from kivy.core.window import Window
from kivymd.color_definitions import colors
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.screen import MDScreen
KV = '''
WindowManager:
id: screen_manager
PrincipalWindow:
LenghtWindow:
<PrincipalWindow>:
name: "principal"
BoxLayout:
MDToolbar:
title: "Conversor"
pos_hint: {"top": 1}
ScrollView:
pos_hint: {"center_x": .5, "center_y": .5} #UbicaciĆ³n
size_hint: 0.90, 0.75
GridLayout:
halign: 'center'
cols: 1
adaptive_height: True
id: box
<LenghtWindow>:
name: "Lenght"
md_bg_color: 0.34,0.024,0.292,1
MDBoxLayout:
orientation: "vertical"
MDToolbar:
title: "Conversor"
pos_hint: {"top": 1}
Button:
text: "Back"
font_size: 32
on_release:
app.root.current = "principal"
root.manager.transition.direction = "right"
<MyContentComunes>:
orientation: 'vertical'
padding: dp(10)
spacing: dp(10)
size_hint_y: None
height: self.minimum_height
ElementCard:
image:"1490820814-13_82405.png"
text:"Longitud"
id:longitud
on_release:
app.root.current = "Lenght"
root.manager.transition.direction = "left"
<ElementCard#MDCard>:
md_bg_color: app.theme_cls.primary_color
padding: dp(15)
spacing: dp(15)
size_hint: 1, None
ripple_behavior: True
# on_release: print("worked")
image:''
text:""
items_count:""
subtext:''
orientation: "vertical"
Image:
source:root.image
halign:"center"
padding: dp (4)
spacing: dp(4)
MDBoxLayout:
orientation: "vertical"
MDLabel:
halign:"center"
text:root.text
MDLabel:
halign:"center"
font_style:"Caption"
text:root.subtext
'''
Window.size = 324, 720
class Conversor(MDApp):
def build(self):
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.list_items = [] # Dictionary where the items are stored
self.category_list1 = ['Comunes']
def on_start(self):
for category in self.category_list1:
self.root.get_screen('principal').ids.box.add_widget(
MDExpansionPanel(
icon="3.png",
content=MyContentComunes(),
panel_cls=MDExpansionPanelTwoLine(
text=category,
secondary_text="Ver las unidades"
)
)
)
class MyContentComunes(BoxLayout):
pass
class PrincipalWindow(Screen):
pass
class LenghtWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
Conversor().run()
The element card is inside an expansion panel, which is also inside a screen.
Try adding Screen to class MyContentComunes.
class MyContentComunes(BoxLayout, Screen):
pass
And I recommend you to organize your code like this. It will make your work more eaisier.
from kivy.app import App
from kivymd.app import MDApp
# import libraries ...
KV = '''
# Your KV File
'''
Window.size = 324, 720
class MyContentComunes(BoxLayout, Screen):
pass
class PrincipalWindow(Screen):
pass
class LenghtWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class Conversor(MDApp):
def build(self):
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
def __init__(self, **kwargs):
# Code
.
.
.
def on_start(self):
# Code
.
.
.
Conversor().run()
I am trying create a GUI by implementing the template of the ComicCreator GUI sample as a template for my own project. The code is easy to follow, but I would like to be able to reconfigure the drawingspace.kv, each time a button is pushed, say for example something like this:
Q: How could I configure the drawingspace.kv to have a different layout with different widgets for each button that is pressed?
A neat way to do this is to use screen.
Since I allready have an example of this app from you earlier question, it was easy to implement the screens, and rewrite the classes a bit.
When a button is pressed, you set the screenmanager's current to whatever the name you named the screen you want.
Then you just edit the layouts as you want inside of each screen, in the kv file, or python file.
I choose to make most of the layout stuff in kv language here. Because I find it easier to develop a layout the way I want it this way.
Later I could rewrite it to python if I want that.
So my python file looks like this now:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen,ScreenManager,NoTransition
from kivy.lang import Builder
import time
Builder.load_file("kv.kv")
class MyLayout(BoxLayout):
def __init__(self,**kwargs):
super(MyLayout,self).__init__(**kwargs)
self.orientation = "vertical"
self.padding = 10
class MainScreen(Screen):
pass
class RemoveScreen(Screen):
pass
class GroupScreen(Screen):
pass
class MyLogo(BoxLayout):
your_time = StringProperty()
def __init__(self,**kwargs):
super(MyLogo,self).__init__(**kwargs)
Clock.schedule_interval(self.set_time, 0.1)
def set_time(self,dt):
self.your_time = time.strftime("%m/%d/%Y %H:%M")
class MyApp(App):
def __init__(self,**kwargs):
super(MyApp,self).__init__(**kwargs)
self.sm = ScreenManager(transition=NoTransition())
self.sm.add_widget(MainScreen(name = "main"))
self.sm.add_widget(RemoveScreen(name = "remove"))
self.sm.add_widget(GroupScreen(name = "group"))
self.sm.current = "main"
def build(self):
return self.sm
if __name__ == "__main__":
MyApp().run()
And kv.kv file looks like this:
#:kivy 1.9.1
<MyButtons#BoxLayout>:
padding: 10,10,10,0
spacing: 10
size_hint: 1,0.3
orientation: "horizontal"
Button:
text: "Clear"
on_press: app.sm.current = "main"
Button:
text: "Remove"
on_press: app.sm.current = "remove"
Button:
text: "Group"
on_press: app.sm.current = "group"
Button:
text: "Color"
Button:
text: "Gestures"
<MyLogo>:
spacing: 10
padding: 10,10,10,0
orientation: "horizontal"
BoxLayout:
orientation: "vertical"
size_hint: 0.3,1
canvas:
Rectangle:
pos: self.pos
size: self.size
AsyncImage
source: 'http://lmsotfy.com/so.png'
Label:
size_hint: 1,0.3
text: root.your_time
color: [0,0,0,1]
Label:
size_hint: 1,0.3
text: "NYC, New York, USA"
color: [0,0,0,1]
<MainScreen>:
MyLayout:
MyLogo:
#Button:
# text: "main"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<RemoveScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "horizontal"
Label:
font_size: "40sp"
text: "Remove"
Button:
font_size: "20sp"
text: "Remove this or something"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<GroupScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "vertical"
Label:
font_size: "40sp"
text: "Group"
Button:
font_size: "20sp"
text: "Something groups stuff"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
The layout frame should be a screen manager, and each layout a screen. Screen transitions would be then triggered by pressing the buttons. You can also watch a tutorial here if you don't know how to do this, but the documentation should be enough.