Kivy Button changing values unwantedly (size_hint) - python-3.x

So, i've been studying the kivy library for a couple of days and I did a simple app with some screens simulating a SignIn/Register enviroment. What i noticed is, in my .kv file, when I set "global parameters" to my widgets, the Button parameters are simply not changing. Take a look:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
Gerencia:
transition: FadeTransition()
TelaDeLogin:
TelaDeCadastro:
TelaEsqueci:
TelaEmDesenvolvimento:
<Button>:
size_hint: 1, 0.1
font_size: 40
color: 1, 1, 1, 1
<Label>:
size_hint: 0.5, 0.1
color: 1, 1, 0, 1
font_size: 40
<TextInput>:
multiline: False
size_hint: 0.5, 0.1
<TelaDeLogin>:
name: "Login"
FloatLayout:
Button:
on_release: app.root.current = "Desenvolvimento"
pos_hint: {'x':0, 'y':0.2}
text: 'Logar'
Button:
on_release: app.root.current = "Esqueci"
pos_hint: {'x':0, 'y':0.1}
text: 'Esqueci a senha'
Button:
on_release: app.root.current = "Cadastro"
pos_hint: {'x':0, 'y':0}
text: 'Cadastre-se'
Label:
text: "Usuário"
pos_hint: {'x':0.25, 'y':0.8}
TextInput:
pos_hint: {'x':0.25, 'y':0.7}
Label:
text: "Senha"
pos_hint: {'x':0.25, 'y':0.6}
TextInput:
password: True
pos_hint: {'x':0.25, 'y':0.5}
I'm ommiting some other screens but they are irrelevant, what happened was, I did some tests and changing the size_hint inside of "<"Button">" doesn't affect the size of my Buttons at all, they are apparently just getting some default size. Another weird thing that happened was, just to test, I did some changes to font_size both inside "<"Button">" and inside "<"Label">", and the value I put into Label also affected my Buttons on the screen, same happened with color. So it seems like my Buttons are getting their values from "<"Label">" and not from "<"Button>". Does anyone have any Idea what's going on?

Explanation
You have overwritten the base class Label, and Button is a Label as specified in the following Kivy documentation. In your Kivy App, Button has inherited the size_hint, font_size and color from your customized Label.
Button
The Button is a Label with associated actions that are triggered when
the button is pressed (or released after a click/touch). To configure
the button, the same properties (padding, font_size, etc) and sizing
system are used as for the Label class
Solution
Create dynamic classes for Label and Button.
Create a dynamic class with inheritance from Button. Replace instantied children, Button: with MyButton:
Create a dynamic class with inheritance from Label. Replace instantied children, Label: with MyLabel:
Snippets
<MyButton#Button>:
size_hint: 1, 0.1
font_size: 40
color: 1, 1, 1, 1
<MyLabel#Label>:
size_hint: 0.5, 0.1
color: 1, 1, 0, 1
font_size: 40
...
<TelaDeLogin>:
name: "Login"
FloatLayout:
MyButton:
on_release: app.root.current = "Desenvolvimento"
pos_hint: {'x':0, 'y':0.2}
text: 'Logar'
MyButton:
on_release: app.root.current = "Esqueci"
pos_hint: {'x':0, 'y':0.1}
text: 'Esqueci a senha'
MyButton:
on_release: app.root.current = "Cadastro"
pos_hint: {'x':0, 'y':0}
text: 'Cadastre-se'
MyLabel:
text: "Usuário"
pos_hint: {'x':0.25, 'y':0.8}
TextInput:
pos_hint: {'x':0.25, 'y':0.7}
MyLabel:
text: "Senha"
pos_hint: {'x':0.25, 'y':0.6}
TextInput:
password: True
pos_hint: {'x':0.25, 'y':0.5}
Output

Related

How to get text of a label that lie inside a MDCard without using ids

I want to get the text of a label that is inside a MDCard without using any ids when the MDcard is pressed.
For example:
MDCard:
md_bg_color: 1,1,1,1
size_hint: None, None
size: "320dp","100dp"
pos_hint: {"x": 0.5,"y": 0.5}
on_press: app.function_to_get_text_of_the_label()
MDRelativeLayout:
MDLabel:
text: "Electrostatics"
font_size: "20dp"

Kivy - How to Size Embedded Anchor Layouts?

I would like to build the following simple design in a .kv file.
It is made of 3 parts :
One top-left Anchor Layout which is made up of a Grid Layout of 3 columns. I want its width to be equal to 20% of the window's with and its height to be equal to 75% of the window's height.
One top-right Anchor Layout which is made up of a vertically-oriented Box Layout. I want its width to be equal to 80% of the window's with and its height to be equal to 75% of the window's height.
One bottom-left Anchor Layout which is empty for the moment. I want its height to be 25% of the window's height.
These three parts are themselves included in an AnchorLayout.
I tried to translate this design into a .kv file as follows.
#:kivy 1.11.1
<Example>:
anchor_x: "center"
anchor_y: "center"
AnchorLayout:
anchor_x: "left"
anchor_y: "top"
size_hint: (0.2, 0.75)
GridLayout:
cols: 3
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: "right"
anchor_y: "top"
size_hint: (0.8, 0.75)
BoxLayout:
orientation: "vertical"
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
anchor_x: "left"
anchor_y: "bottom"
size_hint: (1, 0.25)
Label:
text: "FOOTER"
In case it matters, here is the code of my .py file as well.
# Importing Kivy
import kivy
kivy.require("1.11.1")
# Importing kivy libraries
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
# Importing external libraries
# Import kv files
Builder.load_file("example.kv")
# Root widget of the application
class Example(AnchorLayout):
pass
# Application class
class TestApp(App):
def build(self, **kwargs):
return Example()
# Launch the application
if __name__=="__main__":
app = TestApp()
app.run()
The output does not look as I expected as shown on the picture below :
I don't get it. Because the AnchorLayout is a subclass of the Widget class and is itself included within a Layout, its size_hint property should enable me to define its size.
What am I missing here ? Thanks in advance!
Problem - design centered
The design is placed in the center.
Root Cause
The root is an AnchorLayout with value 'center' for both anchor_x and anchor_y. Therefore, all its children (the AnchorLayouts) are placed in respect to the root.
Below is a view of your design in different colours for visualization.
AnchorLayout
The AnchorLayout aligns its children to a border (top, bottom, left, right) or center.
Solution
There are three possible solutions to your design. The preference is method 1.
Method 1 - No AnchorLayouts
This method replace all AnchorLayouts with BoxLayouts. It use one less AnchorLayout widget which makes the app more resource efficient i.e. use less memory and the app is smaller.
Snippets - Method 1
<Example>:
orientation: 'vertical'
BoxLayout:
...
GridLayout: # left box
...
BoxLayout: # right box
...
BoxLayout: # footer
...
Method 2 - BoxLayout as root
This method replace the root widget with BoxLayout and realign the left box.
Snippets - Method 2
<Example>:
orientation: 'vertical'
AnchorLayout:
...
GridLayout: # left box
...
AnchorLayout: # right box
...
AnchorLayout: # footer
...
Method 3
This method add a BoxLayout as a child of the root, and the rest of the AnchorLayout as children of the BoxLayout.
Snippets - Method 3
<Example>:
anchor_x: "center"
anchor_y: "center"
BoxLayout:
orientation: 'vertical'
AnchorLayout:
...
GridLayout: # left box
...
AnchorLayout: # right box
...
AnchorLayout: # footer
...
Example
Method 1 - No AnchorLayouts
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string("""
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.75
GridLayout:
size_hint: 0.2, 1
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
cols: 3
row_force_default: True
row_default_height: 40
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "HELLO..."
Label:
text: "WORLD..."
BoxLayout:
size_hint: 1, 0.25
canvas.before:
Color:
rgba: 0, 0, 1, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "FOOTER"
"""))
Output: Method 1 - No AnchorLayouts
Method 2 - BoxLayout as root
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string("""
BoxLayout:
orientation: 'vertical'
AnchorLayout:
size_hint: 1, 0.75
anchor_x: 'left'
anchor_y: 'top'
GridLayout:
size_hint: 0.2, 1
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
cols: 3
row_force_default: True
row_default_height: 40
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
BoxLayout:
orientation: 'vertical'
size_hint: 0.8, 1
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
size_hint: 1, 0.25
anchor_x: 'left'
anchor_y: 'bottom'
canvas.before:
Color:
rgba: 0, 0, 1, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "FOOTER"
"""))
Output: Method 2 - BoxLayout as root
Changing the Example class to extend FloatLayout instead of AnchorLayout allows more control of its children. With that change to Example, here is a kv that looks more like what you want:
<Example>:
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
size_hint: (0.2, 0.75)
pos_hint: {'x':0, 'top':1}
GridLayout:
cols: 3
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
size_hint: (0.8, 0.75)
pos_hint: {'right':1, 'top':1}
BoxLayout:
orientation: "vertical"
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
anchor_x: "center"
anchor_y: "bottom"
size_hint: (1, 0.25)
pos_hint: {'x':0, 'y':0}
Label:
text: "FOOTER"

python kivy : How to make switch Button work with carousel

I get:
AttributeError: 'Carousel' object has no attribute 'switch_on'
error whenever I try to click on the button
-------main.py----------
class main(App):
def build(self):
class SampBoxLayout(BoxLayout):
# For Switch
def switch_on(self, instance, value):
if value is True:
print("Switch On")
else:
print("Switch Off")
return Carousel()
sample_app = kv_main()
sample_app.run()
----------main.kv--------------
:
Label:
text: "Page 1"
size_hint: 1, .1
width :100
SampBoxLayout:
# ----------Switch ----------
BoxLayout:
BoxLayout:
orientation: "horizontal"
size_hint_x: .25
CustLabel:
text: "On / Off"
Switch:
id: switch_id
on_active: root.switch_on(self, self.active)# <--need help on this
Label:
text: "Page 2"
size_hint: 1, .1
width :100
Button:
text: "Button 2.1"
size_hint: None, None
width :100
Label:
text: "Page 3"
size_hint: 1, .1
width :100
Button:
text: "Button 3.1"
size_hint: None, None
width :100
You are using root.switch_on. As the error indicates, your root class is the carousel. Since SampBoxLayout is not root, you should give SampBoxLayout an id, and call it with it´s id.
Edited from your example:
SampBoxLayout:
id: samp
BoxLayout:
BoxLayout:
orientation: "horizontal"
size_hint_x: .25
CustLabel:
text: "On / Off"
Switch:
id: switch_id
on_active: samp.switch_on(self, self.active)
I don't know if you did something wrong when posting this, or if your code really looks like this. But you should not define classes inside your app class. Keep the classes on top level to access them in kv.
And your kv code is unusual. You have your widgets in a label.

Kivy make a grid layout inside a label or button

Is it possible to have a grid like layout inside a Label or a Button in kivy.
I have an app that takes in a CSV file with product information and I would like to populate MainScreen with rows from a CSV file.
Each row should look like this:
In the end the Label or Button should be pressable to open a pop up window for confirmation screen for quantity of the product and verify.
Is it even possible or am I approaching it from the wrong angle?
I do not have any code yet to populate the MainScreen with rows but this is how it looks so far.
To clarify. At this moment I don't need help with importing CSV files, but with the method to display it, that matches the above criteria(picture)
Code so far is as follows:
ATmain.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import StringProperty
Window.clearcolor = (1,1,1,1)
Window.size = (270, 480)
class LoginScreen(Screen):
input = StringProperty("")
class MainScreen(Screen):
username = StringProperty('')
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("app.kv")
class ATApp(App):
presentation = Builder.load_file("app.kv")
def build(self):
return presentation
if __name__ == '__main__':
ATApp().run()
app.kv:
# File name: main.py
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:kivy 1.10.1
ScreenManagement:
transition: FadeTransition()
LoginScreen:
id: login
MainScreen:
username: login.input
<LoginScreen>:
name: "login"
canvas:
Color:
rgba: [1,1,1]
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
rows:2
cols:1
background_color: 1,1,1,1
Label:
size_hint: 0.3, 0.05
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.4}
text:"Kasutaja"
color: 0,0,0,1
TextInput:
id: input
size_hint: (0.3, None)
height: 30
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.3}
multiline: False
Button:
id: confirm_login
text: "Login"
size_hint: 0.15, 0.07
pos_hint: {"x": 0.5 - 0.15/2, "center_y": 0.2}
background_color: 0.9,0.9,0.9,1
on_press: self.background_color = (1,0,0,1)
on_release: root.input = input.text; app.root.current = "main"
<MainScreen>:
name: "main"
canvas:
Rectangle:
pos: self.pos
size: self.size
Label:
id:name
text: root.username
color: (0,0,0,1)
size_hint_y: None
height: 30
size_hint_x: 1
pos_hint: {"right": 1, "top": 1}
BoxLayout:
orientation: "vertical"
size_hint_y: None
size_hint_x: 1
pos_hint_x: None
pos_hint_y: 1
Button:
text: "Item1"
color: (0,0,0,1)
height: self.height
size_hint_y: None
size_hint_x: 1
pos_hint: {"right": 1, "top": 0}
I would be very greatful if anyone could as much as point me in the right direction!
The kivy hack way will be to simply use a GridLayout or any layout for that matter then give your layout button properties so it is clickable like so :
from kivy.behaviors import ButtonBehavior
#then make a clickable grid
class GridButton(GridLayout, ButtonBehaviour):
def __init__(self, **kwargs):
super().__init__(**kwargs)
#Then do whatever you want to do
Another way to do it I guess would be to use the on_touch_down callback and check if the touch is within the widget's bounds

Access data from Kivy Popoup Input

I was trying to look at different examples online to solve this issue but Still cannot figure out. I have an app that calls a popup class. The popup has an input field that does some manipulation to the text in the input field. The manipulated data is stored in a variable inside of the popup class. Now how can the parent widget access the data obtained from this widget. Here is a short example of the code.
KV
<ScreenManagement>:
ScreenManager:
id: manager
size_hint_y: 93
Screen:
name: "Case_info_screen"
id: sc1
FloatLayout:
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 10
canvas.before:
Color:
rgb: 0.17, 0.17, 0.17 # your color here
Rectangle:
pos: self.pos
size: self.size
Label:
text_size: self.size
font_size: 20
valign: 'middle'
height: "75dp"
size_hint_y: None
color: 1,1,1,1
size_hint_x: 75
text: " Case Info"
RelativeLayout:
size_hint_x: 25
Button:
text_size: self.size
halign: 'center'
valign: 'middle'
size_hint: 0.70, 0.6
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: 'Automatic Filler'
on_press: root.formfiller()
BoxLayout:
size_hint_y: 5
spacing: 35
LabelCases:
text: ' Name: '
width: '125dp'
size_hint_x: None
TextInput:
id: first_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'First Name'
TextInput:
id: last_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'Last Name'
<Formfillerpop>:
title: 'Automatic Filler'
size_hint: None, None
size: 600, 600
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: 20
text: 'Please Paste your text'
markup: True
TextInput:
id: sentence
size_hint_y: 65
BoxLayout:
size_hint_y: 10
orientation: 'horizontal'
Button:
text: 'Analyze'
on_press: root.on_analyze(sentence.text)
Button:
text: 'Close'
on_press: root.closepop()
Python:
class Formfillerpop(Popup):
selection = StringProperty
id = ObjectProperty
def on_analyze(self, selection):
analyze = TextExtractor(selection)
names = analyze.name()
def closepop(self):
self.dismiss()
class ScreenManagement(FloatLayout):
def formfiller(self, *args):
Formfillerpop().open()
class IOApp(App):
def build(self):
return ScreenManagement()
if __name__ == '__main__':
IOApp().run()
Ultimately I want to take the txt from names in the popup and then autopopulate the first name and last name in the main app with the analyzed data
Sorry if this is basic. I am fairly new to Kivy.
You can access popup content using its content property. You can use it to read text property of read underlying TextInput. For example this code binds this property to local popup_text StringProperty, which means that any change in the popup text input will be reflected there:
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string('''
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Hello world'
BoxLayout:
text_input: text_input
orientation: 'vertical'
TextInput:
id: text_input
Button:
text: 'dismiss'
on_press: root.dismiss()
''')
class CustomPopup(Popup):
pass
class TestApp(App):
popup_text = StringProperty()
def build(self):
l = BoxLayout()
l.add_widget(Button(
text='show_popup', on_press=self.show_popup
))
l.add_widget(Button(
text='print popup text', on_press=self.print_popup_text
))
return l
def show_popup(self, *args):
p = CustomPopup()
p.content.text_input.bind(text=self.setter('popup_text'))
p.open()
def print_popup_text(self, *args):
print(self.popup_text)
if __name__ == '__main__':
TestApp().run()

Resources