For example we created with kivy language simple BoxLayout1 that contains button1 and another BoxLayout2. When you click button1 it adds a new button in BoxLayout2 but it's written in python.
Is it possible to acces existing layout in kv language, in python code? Or only solution is writting whole window in python?
I couldn't find any info in kivy docs, maybe I've just missed something.
EDIT:
I've something like this
Kv:
<CreateWindow>:
BoxLayout:
Button:
text: "test"
on_release: root.press()
BoxLayout:
Label:
text: "Label"
Python:
class CreateWindow(Screen):
def press(self):
I want to add a new button near Label by activating press function
in python will be like this
class CreateWindow(Screen):
def press(self):
# the first box is the first child in the children list of the CreateWindow widget so
box1=self.children[0]
box2=self.children[1]
# and now you can decide which box you want to use add_widget method with
# in your case it should be
box2.add_widget(Button())
Related
I want to create a Label in my kv-file and the text I want the Label to have is supposed to be collected from my python-file. I have tried to create a function in the python-file that has a variable equal to the string I want the Label to have, but it does not seem to work and I don't know how to do it correctly...
The code below is how my kv-file looks. So it is in the field that says "text:" that I want to collect the data from my python-file.
Hope someone knows how to do!
<FirstScreen>:
GridLayout:
cols: 2
text:
In your class FirstScreen you can add a StringProperty to represent the text.
class FirstScreen(Screen):
mytext = StringProperty('default text')
Then, in your kv you can use it as:
<FirstScreen>:
Label:
text: root.mytext
Can I just put more function in this on release or this wont work. I want to have more pop functions and pictures displayed, maybe some audio, etc. This is .kv file:
<Root>:
orientation: 'vertical'
RecordButton:
id: record_button
background_color: 1,1.01,0.90,1
text: 'Order'
on_release:
self.record()
root.pop1()
height: '100dp'
size_hint_y: None
TextInput:
text: record_button.output
readonly: True
Defining an event callback as sequence of statements.
Inside the KV file
Indentation and thus structuring control-flow readable is limited in a KV file. As inclement commented there are basically 2 ways for defining a callback sequence:
statements per line (same indentation)
semicolon separated statements
on_release:
self.record()
root.pop1()
on_press: print('pressed'); self.insert_text("pressed!")
See Kivy-language syntax Valid expressions inside :
[..] multiple single line statements are valid, including those that escape their newline, as long as they don’t add an indentation level.
Define a function in Python
You have more flexibility to define the a function inside the Python script and declare this callback on the event inside the KV file.
For example the function as method of your RecordButton (assume its a class extending Button) in Python:
class RecordButton(Button):
# callback function tells when button released
# It tells the state and instance of button.
def record_and_pop(self, instance):
print("Button is released")
print('The button <%s> state is <%s>' % (instance.text, instance.state))
self.record()
root.pop1()
then used inside the KV:
RecordButton:
on_release: self.record_and_more()
See also
kivy: firing multiple functions on 1 button click
Kivy API: Button class
I am trying to use TwoLineIconListItem with add_widget in a for loop but I can't figure out how to add the icon. It does not take an Icon parameter because per the docs IconLeftWidget is nested like so:
TwoLineIconListItem:
text: "Two-line item with avatar"
secondary_text: "Secondary text here"
IconLeftWidget:
icon: "language-python"
I know how to do this in the KV language but how do you do it in a python for loop that populates a list. This is the closest I got but it puts the icon above the text
for i, z, n in zip(x[1::2], x[0::2], range(1,10)):
self.root.ids.todays_workout.add_widget(
IconLeftWidget(icon=f"numeric-{n}-box-multiple-outline"))
self.root.ids.todays_workout.add_widget(
TwoLineIconListItem(text=f"{i}", secondary_text=f"{z}"))
Perhaps a nested add_widget()? I'm not sure how to accomplish this
I think your nested add_widget() is along the right track, but you can't actually do that because add_widget() returns None. So you can do it something like this:
for i, z, n in zip(x[1::2], x[0::2], range(1,10)):
icon = IconLeftWidget(icon=f"numeric-{n}-box-multiple-outline"))
listItem = TwoLineIconListItem(text=f"{i}", secondary_text=f"{z}"))
listItem.add_widget(icon)
self.root.ids.todays_workout.add_widget(listItem)
With a second look at the docs and some help from the KivyMD support Discord Channel, I have found the solution.
You need to create a new class that inherits from the TwoLineIconListItem as such:
class ListWithIcon(TwoLineIconListItem):
icon = StringProperty("string")
Then I created a new .kv file called listwithicon.kv with the following (notice the class names match)
<ListWithIcon>:
IconLeftWidget:
icon: root.icon
Finally in my main KV string(or file) I added #: include listwithicon.kv
These steps will allow you to add an icon parameter to your function. Just be sure to pass ListWithIcon (your new class) instead of the KivyMD class TwoLineIconListItem
for i, z, n in zip(x[1::2], x[0::2], range(1,number_workouts)):
self.root.ids.todays_workout.add_widget(
ListWithIcon(text=f"{i}", secondary_text=f"{z}", icon=f"numeric-{n}-box-multiple-outline"))
I'm trying create new TabbedPanelItem with properties already created widget. But i'm getting new empty widget or replace exist.
.py
class MainScreen(Screen):
def add(self, tabbed_item):
new_tabbed_item = TabbedPanelItem()
new_tabbed_item.properties = copy(tabbed_item)
new_tabbed_item.text = "2"
self.ids.tab_panel.add_widget(new_tabbed_item)
.kv
<MainScreen>:
AnchorLayout:
canvas.before:
...
TabbedPanel:
id: tab_panel
...
TabbedPanelItem:
Button:
on_press: root.add(tab_item)
TabbedPanelItem:
id: tab_item
....
When I try to run you're code nothing pops up. You don't have enough code to test. I'm not sure what your goal is, but if you want to have a TabbedPanelItem with stuff already created without having to reproduce the same code (if that's your goal), try using #. An example: MyTabbedPanel#TabbedPanelItem:. Then you can add everything you want it to do, and reuse it instead of retyping out the code everytime.
I've made a rule in my kv for the Button class to have a specific background (provided in an image). When I created an ActionBar that contains ActionPrevious and ActionButton widgets, they both seemed to get the same background.
And I would understand that ActionButton instance got that background, since it inherits from Button and ActionItem classes, but why did the ActionPrevious get the same background? It inherits from BoxLayout and ActionItem, neither of which have anything to do with the Button class. What's the reason behind it?
Also, a side question
The ActionPrevious has a property with_previous which, when set to True, adds a clickable arrow. However, the title of the widget remains unclickable. But the docs say that this property would make the whole widget clickable. While it's not a big deal, I'd rather want the entire ActionPrevious widget background to change on press. Is it possible to achieve this?
So what I mean is that when you press the Back arrow, only the space around it and the app icon turns blue, but the text doesn't, as if it's part of a different widget.
Here is the code to visualize the question:
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.actionbar import ActionBar
Builder.load_string('''
<Button>:
background_normal: 'some_file.png'
<MenuBar>:
ActionView:
ActionPrevious:
title: "Log out"
with_previous: True
ActionButton:
text: "Settings"
''')
class MenuBar(ActionBar):
pass
runTouchApp(MenuBar())
Okay, so the truth was in the style.kv file. Basically, ActionPrevious widget has the following structure:
<ActionPrevious>:
GridLayout:
ActionPreviousButton:
GridLayout:
ActionPreviousImage:
id: prev_icon_image # the "back" arrow
ActionPreviousImage:
id: app_icon_image # the app icon
Widget:
# perhaps something to split the title from the GridLayout
Label:
id: title # the title
And the ActionPreviousButton inherits from Button, so that's why the ActionPrevious arrow part was getting that background.
Here also lies the answer to the side question. Since the clickable part is the ActionPreviousButton, and the title is kept in a Label, that is not a child of it, the text is unclickable. So to fix that, one has to create a custom class and put the Label as a child of the ActionPreviousButton.