I'm new to kivy , I'm trying to write an application using kivy in python, I got struck at one point where i have to read text from textinput whenever it is changed and based on that i want to implement my button's functionality - I have gone through all the documentation but i couldn't figure out how to do it - Can any body tell me how can I resolve this or am I missing something?
from __future__ import print_function
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.core.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
import walascan
from kivy.clock import Clock
import os
kv = """
<KartScan>:
IntroScreen:
<IntroScreen#Screen>:
orientation: 'horizontal'
name: 'introscreen'
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'index.png'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
BoxLayout:
orientation:'horizontal'
size_hint: .5, .1
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
spacing: 20
pos_hint: {'center_x':.8, 'center_y': .8}
AnchorLayout:
anchor_x: 'left'
size_hint_x: .5
TextInput:
id: waybill
width: 20
text: "Enter Waybill No."
multiline: False
height: self.minimum_height
size_hint_y: None
font_size: 30
focus: True
on_text_validate: app.on_waybill()
AnchorLayout:
anchor_x: 'right'
size_hint_x: None
Button:
size_hint: None, None
height: 50
width: self.texture_size[0]
padding: 10, 10
text: "Add"
on_press:app.buttonClicked()
on_release: root.current = 'mainpage'
AnchorLayout:
anchor_x: 'right'
size_hint_x: None
Button:
size_hint: None, None
height: 50
width: self.texture_size[0]
padding: 10, 10
text: "Compare"
on_press:app.buttonClicked()
on_release: root.current = 'mainpage'
"""
Builder.load_string(kv)
waybill = TextInput(text="Enter Waybill No.", multiline=False)
class KartScan(FloatLayout):
def __init__(self, **kwargs):
super(KartScan, self).__init__(**kwargs)
self.register_event_type('on_text_validate')
def on_text(self, *args):
print('new value is ', waybill.text)
def on_text_validate(self):
pass
def on_focus(self, obj, focused):
if not focused:
self.dispatch('on_text_validate')
class KartScanApp(App):
def build(self):
return KartScan()
def buttonClicked(self):
popup = Popup(title='Result',
content=Label(text=self.on_waybill()),
size_hint=(None, None), size=(100, 100))
popup.bind()
popup.open()
def getwlbtstate(self):
return walascan.mainAntennas()
def on_waybill(self):
waybill.bind(text=KartScan.on_text_validate)
# popup = Popup(title='Result',
# content=Label(text=waybill.text),
# size_hint=(None, None), size=(100, 100))
# popup.bind()
# popup.open()
return waybill.text
if __name__ == '__main__':
KartScanApp().run()
kv file
TextInput:
on_text: print(self.text)
You could use on_text to call a function when the text changes. I think it sometimes even triggers when no change has occured.
TextInput has a text property, and in kivy, all properties have associated on_xxx events, that you can bind to to react to them, so when reading the doc, even if it's not explicitly mentionned for them, everytime you see something is defined as a Property (or any subclass of it, like StringPropertyNumericProperty,ObjectProperty,AliasProperty`).
TextInput:
on_text: do_something(self.text)
or in python
t = TextInput(text='', on_text=do_something)
or
t = TextInput(text='')
t.bind(on_text=do_something)
Related
I´m learning kivy, and it has passed 3 weeks since i face this problem without encounter a solution, so i hope any of u guys could help me, i would appreciate it.
I have a main file:
from app import MyProgramApp
if __name__ == "__main__":
winapp = MyProgramApp()
winapp.run()
from where i start my app. Then i have a directory called "app", inside there is the following "init.py" file.
from kivy.app import App
from kivy.utils import QueryDict, rgba
from kivy.core.window import Window
from .view import MainWindow
Window.minimum_width = 500
Window.minimum_height = 650
Window.maximize()
class MyProgramApp(App):
colors = QueryDict()
colors.primary = rgba('#2D9CDB')
colors.secondary = rgba('#16213E')
colors.succes = rgba('#1FC98E')
colors.warning = rgba('#F2C94C')
colors.danger = rgba('#E85757')
colors.grey_dark = rgba('#C4C4C4')
colors.grey_light = rgba('#F5F5F5')
colors.black = rgba('#A1A1A1')
colors.white = rgba('#FFFFFF')
def build(self):
return MainWindow()
Same folder app, i have the following "view.py".
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager
class MainWindow(BoxLayout):
username = StringProperty("Usuario")
def __init__(self, **kw):
super().__init__(**kw)
def on_press_home(self):
self.ids.scrn_mngr.current = "scrn_home"
class ViewManager(ScreenManager):
def __init__(self, **kw):
super().__init__(**kw)
class NavTab(ToggleButtonBehavior, BoxLayout):
text = StringProperty('')
icon = StringProperty('')
def __init__(self, **kw):
super().__init__(**kw)
and finally for that folder i have "myprogram.kv"
#:kivy 2.1.0
#:import Home views.home.Home
<MainWindow>:
spacing: dp(8)
canvas.before:
Color:
rgba: app.colors.white
Rectangle:
pos: self.pos
size: self.size
# NAVIGATION BAR
BoxLayout:
id: nav_menu
size_hint_x: .2
orientation: "vertical"
size_hint_min_x: dp(100)
# LOGO
BoxLayout:
id: logo_nbox
size_hint_y: .1
size_hint_min_y: dp(70)
padding: dp(16)
AnchorLayout:
anchor_x: "right"
size_hint_x: None
width: dp(52)
halign: "left"
Label:
text: "COMPANY"
halign: "center"
BoxLayout:
orientation: "vertical"
Label:
text: "COMPANY"
halign: "center"
Label:
text: "Phrase"
halign: "center"
# OPTIONS
GridLayout:
id: tabs_box
cols: 1
spacing: dp(4)
size_hint_y: .5
canvas.before:
Color:
rgba: app.colors.grey_dark
Rectangle:
pos: self.pos
size: [self.size[0], dp(1)]
NavTab:
text: "Home"
state: "down"
on_press: root.on_press_home()
# BODY
BoxLayout:
size_hint_x: .8
spacing: dp(8)
orientation: "vertical"
padding: [dp(16), dp(8), dp(12), dp(8)]
canvas.before:
Color:
rgba: app.colors.grey_light
Rectangle:
pos: self.pos
size: self.size
# SCREENS
BoxLayout:
ViewManager:
id: scrn_mngr
<ViewManager>:
Screen:
name: "scrn_home"
Home:
id: home
<NavTab>:
background_normal: ""
background_down: ""
background_color: [0,0,0,0]
group: "tabs"
size_hint_y: None
height: dp(45)
spacing: dp(4)
canvas.before:
Color:
rgba: [0,0,0,0] if self.state == "normal" else rgba("#E1F1FF")
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: [0,0,0,0] if self.state == "normal" else app.colors.primary
Rectangle:
pos: [self.pos[0]+self.size[0]-dp(1), self.pos[1]]
size: [dp(8), self.size[1]]
Label:
halign: "left"
valign: "middle"
text: root.text
color: app.colors.grey_dark if root.state == "normal" else app.colors.primary
Then i got another folder called "views" inside i have another folder called "home", inside home we encounter 3 files "init.py", "home.kv", "home.py". the first one "init.py" is the following.
from .home import Home
then we got "home.kv".
#:kivy 2.1.0
<Home>:
orientation: "vertical"
Label:
size_hint_y: .1
text: "Other"
Button:
size_hint_y: .1
text: "popup"
on_press: root.open_popup()
BoxLayout:
size_hint_y: .8
id: home_box
<SomePopup>:
title: "SOME TITLE"
title_align: "center"
title_color: app.colors.primary
size_hint: .25, .8
size_hint_min_x: dp(200)
pos_hint: {"x": .1, "top": .9}
BoxLayout:
orientation: "vertical"
padding: [dp(0), dp(12), dp(0), dp(12)]
Label:
text: "Some text"
Button:
text: "create buttons on box"
on_press: root.modify_home_box()
and finally and the problem that i´m facing is whit the following file "home.py"
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.factory import Factory
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.app import App
Builder.load_file('views/home/home.kv')
class Home(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def open_popup(self):
Factory.SomePopup().open()
class SomePopup(Popup):
def __init__(self, **kw):
super().__init__(**kw)
def modify_home_box(self):
my_app = App.get_running_app().root
my_box = my_app.ids.home.ids.home_box
custom_button = Button(
text = "something"
)
my_box.add_widget(custom_button)
That i´m trying to do is actually modify "home_box" with is store on ids Home dictionary, i also try with ObjectProperty (but that gives and Attribute Error, since i only could read propertys but doesnt modify it), instance of a new Home class doesnt work... searching for current app in App appear doesnt work since Home is store i think on screenManager...
I need add a button or some widget to "home_box" from outside class "SomePopup". I also drop here a repository on github with the whole code. github_repo
I don't know how to solve my issue, and i try with the resources available here on stack as well other net places... any help would be appreciate.
Just a very complicated path to the widget of interest. In your modify_home_box() method, try replacing:
my_app = App.get_running_app().root
my_box = my_app.ids.home.ids.home_box
with:
my_app = App.get_running_app().root
my_box = my_app.ids.scrn_mngr.ids.home.ids.home_box
I've created a Screen with a boxlayout and its children.
I wanna print size of the label "Hello" in the boxlayout, which has id:shadow_label
This size must be relative. But it's [100, 100]
Why?
What could I give more details for this post? Could this behavior be due to AnchorLayout?
Here is my code
kv file:
<WellcomeScreen>:
box_layout: wellcome_box
BoxLayout:
id: wellcome_box
orientation: 'vertical'
pos: self.parent.pos
size: self.parent.size
padding: [30, 30]
spacing: 10
canvas.before:
Rectangle:
source: 'Data\game background.png'
pos: self.pos
size: self.size
Label:
id:shadow_label
size_hint: (1, .6)
font_size: self.height/12
text_size: self.width-10, None
color: 'purple'
halign: "center"
text: "Hello"
AnchorLayout:
size_hint: (1,.3)
Button:
canvas.before:
Rectangle:
source: "Data\Button_start.png"
pos: self.pos
size: self.size
pos_hint: {"center_x":0.5,"center_y":0.5}
size_hint: (None, None)
size: (self.parent.height/4*3, self.parent.height/4*3)
background_color: (1,1,1,0)
font_size: self.height/4
text_size: self.width, None
text: "START"
color: "yellow"
bold: True
halign: 'center'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'login'
python
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.label import MDLabel
from kivy.uix.behaviors import ButtonBehavior
from kivy.properties import ObjectProperty
from kivy.config import Config
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '420')
Config.set('graphics', 'height', '860')
class WellcomeScreen(Screen):
user_name = ObjectProperty()
box_layout = ObjectProperty()
wellcome_label = ObjectProperty()
def __init__(self, **kwargs):
super(WellcomeScreen, self).__init__(**kwargs)
class StartButton(ButtonBehavior, MDLabel):
def __init__(self, **kwargs):
super(StartButton, self).__init__(**kwargs)
self.background_normal = "Data\Button_start.png"
self.text = "START"
self.text_color = "yellow"
self.color = "white"
self.halign = "center"
class FastReadApp(MDApp):
def build(self):
sm = ScreenManager()
screen_wellcome = WellcomeScreen(name='wellcome')
sm.add_widget(screen_wellcome)
print(screen_wellcome.ids.shadow_label.size)
return sm
if __name__ == '__main__':
app = FastReadApp()
app.run()
There is the screen of my app:
You are printing the size of the label before its size is set, so you see the default size of (100,100). Just delay the print until the size is set. Use Clock.schedule_once() or use a Button to trigger the print.
I've tried multiple pieces of code from here, but they all seem to align the text within the label or text box. I want to align the text box and the label vertically and horizontally. I am a beginner at kivy, so please excuse me if the answer is very obvious.
Is there a way to align the label itself and not the text inside?
Is there also a way to align the text box itself and not the text inside?
Thanks in advance!
This is my .kv file firstkivy.kv
#Filename: firskivy.kv
<MyGrid>:
Label:
text: "Writing"
font_size: 80
bold: True
color: 0.204, 0.204, 0.204, 1
size: self.texture_size
text_size: self.size
halign: 'center'
valign:'middle'
canvas.before:
Color:
rgba: 0.549, 1, 0.984, 1
Rectangle:
size: self.size
pos: self.pos
TextInput:
size_hint: (.2, None)
height: 100
width: 360
multiline: True
size_hint: (None, None)
font_size: 30
halign: 'right'
pos_hint: (None, None)
focus: True
This is the .py file firstkivy.py
# setting up and fixing the window size
#to prevent it from being resized
from kivy.config import Config
Config.set('graphics', 'resizable', False)
Config.set('graphics','width', '360')
Config.set('graphics', 'height', '540')
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
# going back to this one...
Window.clearcolor = (0.549, 1, 0.984, 1)
class MyApp(Widget):
pass
#building the app
class FirstKivy(App, BoxLayout):
def build(self):
self.title = 'Arabic Language Learning App'
return MyApp()
# running the app
if __name__ == '__main__':
FirstKivy().run()
Here is the
Output
Try writing your firstkivy.py like this:
from kivy.config import Config
Config.set('graphics', 'resizable', False)
Config.set('graphics','width', '360')
Config.set('graphics', 'height', '540')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
class MyApp(BoxLayout):
pass
class FirstKivy(App):
title = 'Arabic Language Learning App'
def build(self):
return MyApp()
if __name__ == '__main__':
FirstKivy().run
And your firstkivy.kv like:
<MyApp>:
orientation: "vertical"
spacing: 10
space_x: self.size[0]/3
canvas.before:
Color:
rgba: 0.549, 1, 0.984, 1
Rectangle:
size: self.size
pos: self.pos
FloatLayout:
Label:
text: "Writing"
font_size: 80
bold: True
color: 0.204, 0.204, 0.204, 1
pos_hint: {'center_x': .5, 'center_y': .8}
#size: self.texture_size
#text_size: self.size
#halign: 'center'
#valign:'middle'
TextInput:
size_hint: 1, .5
#height: 100
#width: 200
multiline: True
pos_hint: {'center_x': .5}
#size_hint: None, None
#font_size: 30
#halign: 'right'
#pos_hint: None, None
#focus: True
Hope it achieves what you want.
Any assistance is much appreciated.
Here's an example code to show the problem,
when the ('Press me') button is pressed and the widget resized(white box come within view), the TabbedPanel redraws like a glitch (even though its not).
I've tried changing the layout order and toyed a bit with the animation, no
I wish to prevent that blinking behaviour of the tabbedpanel on the left.
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.animation import Animation
from kivy.lang import Builder
Builder.load_string('''
<Main>:
BoxLayout:
orientation:'vertical'
BoxLayout:
id: main_screen
orientation: 'horizontal'
TabbedPanel:
do_default_tab: False
tab_pos: 'left_top'
tab_width: main_screen.height/4
TabbedPanelItem:
text: 'four'
TabbedPanelItem:
text: 'three'
TabbedPanelItem:
text: 'two'
TabbedPanelItem:
text: 'one'
BoxLayout:
id: swidget
slide: 0
size_hint: None, None
height: main_screen.height
width: self.slide
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_y: None
height: '33dp'
text: 'Press me'
on_release: root.display_widget(swidget)
''')
class Main(BoxLayout):
def __init__(self, **kwargs):
super(Main, self).__init__(**kwargs)
def display_widget(self, widget):
swidget = widget
if swidget.slide == 0:
anim = Animation(slide=105, duration=0.6)
anim.start(widget)
else:
anim = Animation(slide=0, duration=0.6)
anim.start(widget)
class TabbedApp(App):
def build(self):
return Main()
TabbedApp().run()
Add AnchorLayout to be the parent of swidget / BoxLayout and when the animation starts, it won't impact the instantiated TabbedPanel.
Snippets
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
size_hint_x: None
width: 0
BoxLayout:
id: swidget
slide: 0
size_hint_x: None
width: self.slide
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
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 ....."