I am trying to simplify the code that generates rows with the same content multiple times by using dynamic classes as shown in the simplified example below.
So far so good, code is simpler but I'm trying to find solutions to access from python for example Label in the second row. In my old solution, I have a unique ID for each widget but now buttons and labels are defined as only ones for all rows, and they have the same ID.
Is there any possibility to access them individually?
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
Builder.load_file("test.kv")
class MyLayout(Widget):
pass
class MyNewApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyNewApp().run()
test.kv
<RowTemplate#GridLayout>:
cols: 2
Label:
id: row_label
text: 'test'
Button:
id: row_button
text: 'button'
<MyLayout>
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
size: root.width, root.height
cols: 1
canvas.before:
Color:
rgba: 0, 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
RowTemplate: #fist row
RowTemplate: #second row
RowTemplate: #third row
from kivy.properties import StringProperty
class RowTemplate(GridLayout):
button_text = StringProperty('')
label_text = StringProperty('')
test.kv
<RowTemplate>:
cols: 2
Label:
id: row_label
text: root.label_text
Button:
id: row_button
text: root.button_text
Now you can change text dynaminally as bellow.
<MyLayout>:
RowTemplate:
label_text: 'label one'
button_text: 'button one'
RowTemplate:
label_text: 'label two'
button_text: 'button two'
Related
Problem:
I have a dropdown button that produces a label. This label overlaps another button below it. Picture of what is going wrong.
What I Want:
I want the button that is being overlapped by the label from the dropdown to be moved downwards, preferably by same height as the label from the drop down. I then want the button to move back up when the drop down is "pulled up"
MRE
KV File:
#:import utils kivy.utils
#:import Factory kivy.factory.Factory
<CustomDropdown#DropDown>:
id: dropdown
on_select:
app.root.ids.btn.text = '{}'.format(args[1])
self.dismiss()
Label:
id: btn1
text: ' Information '
size_hint_y: None
height: 200
background_color: (1, 0, 0, .9)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
<HomeScreen>:
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#FFFFFF")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 8
cols: 1
spacing: 10
size_hint_y: None
height: 1200
width: self.minimum_width
Button:
text:"stuff1"
color: "black"
size_hint: 1,.18
on_press: Factory.CustomDropdown().open(self)
Button:
text:"stuff2"
color: "black"
size_hint: 1,.18
Main.py
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
Window.size = (286.110236, 570.33070866)
class HomeScreen(Screen):
pass
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
MainApp().run()
I am trying to print an input given by a user but all I get is: < ObjectProperty name=input >
I can't use Text Input in my py because python quits if I try to run a program with it installed. I have tried putting the popup in the 'test' class but it just comes up with a different error.
Any help is appreciated,
Thank you.
Here is my code:
In my py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
class MyPopup(Popup):
pass
class Test(Widget):
pass
class TestApp(App):
def build(self):
return Test()
def Process(self):
text = MyPopup.input
print(text)
if __name__ == '__main__':
TestApp().run()
and in my kv:
#:import Factory kivy.factory.Factory
<MyPopup#Popup>
input: text
auto_dismiss: True
size_hint: 0.4, 0.4
TextInput:
id: text
hint_text: 'insert text'
multiline: False
on_text_validate: app.Process()
<Test>:
canvas:
Color:
rgba: 0, 0, 0, 0
Rectangle:
pos: 0, 0
size: self.width, self.height - self.height/6
Color:
rgba: 1, 1, 1, 0.1
Rectangle:
pos: 0, 0
size: self.width/2 + self.width/10, self.height - self.height/6
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: 0, self.height - self.height/6
size: self.width, self.height/6
Button:
id: GL
text: 'In here'
pos: 0 , root.height - root.height/6
on_parent: GLdropdown.dismiss()
on_release: GLdropdown.open(self)
size_hint_y: None
height: root.height/6
width: root.width/7
DropDown:
id: GLdropdown
on_select: btn.text = '{}'.format(args[1])
Button:
id: 'AV'
text: 'press me'
size_hint_y: None
height: 50
on_release: Factory.MyPopup().open()
If you change:
on_text_validate: app.Process()
to:
on_text_validate: app.Process(self.text)
And change the Process() method to:
def Process(self, text):
print(text)
I think it will work as you want.
The problem is that the line:
text = MyPopup.input
makes text a reference to the ObjectProperty of the class MyPopup. What you really want is a reference to the text of the TextInput, which is simply self.text in the TextInput.
I am trying to make an aap for MCQ's. Here i want a function, if anyone even click on the label corresponding to a checkbox, that check box must also be checked.. Is it possible in Kivy? Because Kivy doesn't provide any text association with checkbox directly.
Here is a portion of kv.
<MCQCheckBox#CheckBox>:
color:0,0,0,1
size_hint: 0.15, 1
group: 'opts'
<MCQLabel#Label>:
text_size: self.size
valign: 'center'
font_size: '13sp'
color: 0,0,0,1
<MCQsGUI>:
BoxLayout:
orientation:'vertical'
size_hint: 0.95, 0.7
spacing: 2
pos_hint: {'center_x': .5, 'center_y': .5}
MCQBoxLayout:
MCQCheckBox:
MCQLabel:
text:"option 1"
MCQBoxLayout:
MCQCheckBox:
MCQLabel:
text:"option 2"
MCQBoxLayout:
MCQCheckBox:
MCQLabel:
text:"option 3"
MCQBoxLayout:
MCQCheckBox:
MCQLabel:
text:"option 4"
You can do it using only kv languaje and dynamic classes:
To allow the label to behave like a button, you just have to make MCQLabel inherit from Label and ButtonBehavior classes.
To keep the group's own behavior you can call the _do_press () method of the ToggleButton class (CheckBox inherits from it) when the asociated label is pressed.
test.kv:
<MCQCheckBox#CheckBox>:
color: 0, 0, 0, 1
size_hint: 0.15, 1
<MCQLabel#ButtonBehavior+Label>:
text_size: self.size
valign: 'center'
font_size: '13sp'
color: 0, 0, 0, 1
<MCQLabelCheckBox#BoxLayout>:
text: ''
group: ''
MCQCheckBox:
id: cb
group: root.group
MCQLabel:
on_press: cb._do_press()
text: root.text
<MCQsGUI>:
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
MCQLabelCheckBox:
text:"option 1"
group: 'opts'
MCQLabelCheckBox:
text:"option 2"
group: 'opts'
MCQLabelCheckBox:
text:"option 3"
group: 'opts'
MCQLabelCheckBox:
text:"option 4"
group: 'opts'
main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MCQsGUI(BoxLayout):
pass
class TestApp(App):
def build(self):
return MCQsGUI()
if __name__ == '__main__':
TestApp().run()
I don't know if there is a direct/'built-in' way to do that. But here is an improvised example without using main.kv file.
When you create a CheckBox and a Label object, you can manually connect the CheckBox pressing this way :
import kivy
from kivy.uix.checkbox import CheckBox
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
class Answer(Label):
def __init__(self, text, associate):
Label.__init__(self);
self.text = text;
self.associate = associate;
def on_touch_down(self, touch):
Label.on_touch_down(self, touch);
if self.collide_point(touch.pos[0], touch.pos[1]):
self.associate.active = not self.associate.active;
class Page(GridLayout):
def __init__(self):
GridLayout.__init__(self, rows = 2, cols = 2);
self.check = [CheckBox(), CheckBox()];
self.ans = [Answer(text = 'Choice 1', associate = self.check[0]),\
Answer(text = 'Choice 2', associate = self.check[1])];
for i in self.ans:
self.add_widget(i);
for i in self.check:
self.add_widget(i);
class Example(App):
def build(self):
return Page()
So every time you press the Label, it will do : self.associate.active = not self.associate.active which works as the switch for the corresponding CheckBox.
*This is only one way, you can improvise or even find a better way. Is this okay?
I trying to create a one screen app with one root rule set. by pressing a button i should see a scrollable text in the grid next to the button. In all the example solutions I see that scrollview is working in similar KV files that I have seen in other questions. Could someone please identify what I have missed in KV file.
my .py file:
import kivy
import string
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
class RootContainer(BoxLayout):
instance = ObjectProperty(None)
def __init__(self, **kwargs):
super(RootContainer, self).__init__(**kwargs)
def clickAction1(self, instance):
#identify the button pressed
buttonText = instance.text
self.lbl1.text = instance.text + " some text goes here ... "
myresult = " this is scrolling text.\n " * 30
self.lbl5.text = myresult
class MBApp(App):
def build(self):
return RootContainer()
if __name__ == '__main__':
MBApp().run()
my KV file:
#:kivy 1.0.9
<RootContainer>:
id: theRoot
lbl1: my_labelC
lbl5: my_labelCS
BoxLayout:
orientation: 'vertical'
spacing: 20
padding: 20
canvas:
Color:
rgb: 0, .33, 0
Rectangle:
pos: self.pos
size: self.size
Button:
text: "This is 1st button"
text_size: self.size
size_hint: (.5,1)
on_press: theRoot.clickAction1(self)
Button:
text: "This is 2nd button"
text_size: self.size
size_hint: (.5,1)
on_press: root.clickAction1(self)
GridLayout:
rows: 2
cols: 1
spacing: 10
padding: 10
canvas:
Color:
rgb: .7, .63, 0
Rectangle:
pos: self.pos
size: self.size
Label:
id: my_labelC
canvas.before:
Color:
rgb: 0,0,0
Rectangle:
pos: self.pos
size: self.size
text: "Header text for button clicked ......."
text_size: self.size
ScrollView:
GridLayout:
cols:1
rows:1
height: self.minimum_height
Label:
id: my_labelCS
text: "Scrolling text goes here ....."
I hope this is not a duplicate. Any other suggestions to code are also welcome. Thank you.
You don't set the size of your Label, so the default applies, as any widget, the defaults are
size: 100, 100
size_hint: 1, 1
since size_hintis 1, 1, and the parent is a layout, size itself is overriden by the parent's available space
since you set size: minimum_size in the parent layout, it'll give the minimum size its children require, but the Label doesn't ask for any space, it's size_hint of 1, 1 means that it's happy to take all the available space. Kivy solve this situation by not giving it any space, so the Label size ends up being 0, 0, and the GridLayout's size as well.
So you want to disable size_hint (at least for the height, of the Label, and instead set it to the texture heights
size_hint_y: None
height: self.texture_size[1]
Which is usually sided with setting the texture width to the available width, by setting text_size.
text_size: self.width, None
size_hint_x: 1 # this is the default, so this line is not required, but you want to be sure not to disable this default
Do you really need the GridLayout inside your scrollview? This works for me:
ScrollView:
Label:
id: my_labelCS
size_hint: 1, None
text_size: self.width, None
height: self.texture_size[1]
text: "Scrolling text goes here ....."
I am new to programming with Kivy, I'm trying to develop a program that collects the number of people in a room.
And my difficulty is to pass values between KV file and the main. I need to get the value of the slider which is in KV file and use it in main.py program
How could it? already I tried several ways that were posted on different topics here on the site but could not. Perhaps because as I have no knowledge in the area did not know apply it right.
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty, ObjectProperty
from kivy.lang import Builder
class ThemeBackground(Screen):
pass
class myApp(App):
def build(self):
root = ScreenManager()
root.add_widget(ThemeBackground(name='Screen'))
return root
if __name__ == '__main__':
myApp().run()
And Kv file
#:import random random.random
<ThemeBackground>:
orientation: 'vertical'
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
source: 'data/images/background.jpg'
size: self.size
BoxLayout:
padding: 10
spacing: 10
size_hint: 1, None
pos_hint: {'top': 1}
height: 44
Image:
size_hint: None, None
size: 24, 24
source: 'data/logo/kivy-icon-24.png'
Label:
height: 24
text_size: self.size
color: (1, 1, 1, .8)
text: 'Kivy 1.9.0.'
valign: 'middle'
GridLayout:
cols: 2
Label:
text: 'Please enter \nthe number of occupants?'
bold: True
font_name: 'data/fonts/DejaVuSans.ttf'
font_size: 22
halign: 'center'
Slider:
id: slider
min: 0.0
max: 15.0
value: 1.0
step: 1.0
orientation: "horizontal"
width: "38dp"
Label
text: ''
Label
text: '{}'.format(slider.value)
halign: 'center'
valign: 'top'
bold: True
text_size: self.size
font_size: 18
Button:
text: 'Enter'
size_hint_y: None
height: '50sp'}
You should load the kv file in the build of your myApp:
class myApp(App):
def build(self):
self.load_kv("main.kv")
return ThemeBackground()
You have unneeded } in the bottom of kv file,the last character, remove it.
height: '50sp'}
Preview:
In order to access the values of the slider, add a variable myslider to both of python and kv files like this:
kv:
<ThemeBackground>:
orientation: 'vertical'
myslider: slider
python:
class ThemeBackground(Screen):
myslider = ObjectProperty(None)
Now you can access the value , min or max by:
class myApp(App):
def build(self):
self.load_kv("kivy.3.kv")
tb = ThemeBackground()
print "value =",tb.myslider.value # <---- value here
print "min =",tb.myslider.min # <--- min here
return tb