Prevent TabbedPanel from redrawing during animation - python

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

Related

Kivy: How to move other buttons down/up when dropdown is down

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()

Add widget dynamically from outside class (error)

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

Kivy Nested ScreenManager inside BoxLayout

Something seen with a different flavor each week, Here we go again with more ScreenManager shenanigans!
Screens won't change unless buttons are part of the screen itself, I wanted a universal navbar along the top and then a "display" under it. Both screens work, the buttons to switch between them don't.
(Bonus points if you can tell me how to make each screen its own KV file and still link with the screenmanager)
anyways: CODE
QCManager.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
kivy.require('1.9.1')
class MOTD(Screen):
print("MOTD Screen!")
pass
class Search(Screen):
print("Search Screen!")
pass
class ScreenManagement(ScreenManager):
pass
class ClassAllScreen(BoxLayout):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.manager = ScreenManagement()
class ClassApp(App):
def build(self):
self.root = ClassAllScreen()
return self.root
if __name__ == '__main__':
Builder.load_file('./kvfiles/main.kv')
ClassApp().run()
main.kv
#: import NoTransition kivy.uix.screenmanager.NoTransition
<MOTD>:
name: 'motd'
BoxLayout:
orientation:'vertical'
padding:20
spacing:10
Label:
text:"The Cake Is a Lie"
<Search>:
name: 'search'
BoxLayout:
orientation:'vertical'
padding:20
spacing:10
GridLayout:
spacing:10
cols:2
Button:
text:'Left'
Button:
text:'Right'
Button:
text:'bottom'
<ScreenManagement>:
transition: NoTransition()
MOTD:
Search:
<ClassAllScreen>:
orientation:'vertical'
BoxLayout:
size_hint_y: None
height: 60
spacing: 5
padding: 5
canvas:
Color:
rgba: .1,.1,.1,1
Rectangle:
pos: self.pos
size: self.size
Button:
text:'Menu'
size_hint_x: None
width: 120
on_release: root.manager.current = 'motd'
Button:
text:'Search'
size_hint_x: None
width: 120
on_release: root.manager.current = 'search'
Button:
text:'Add to DB'
size_hint_x: None
width: 120
on_press: print("Button Working")
ScreenManagement:
You __init__() method in the ClassAllScreen class is creating an instance of ScreenManagement. That instance is saved as self.manager, but is not added to your GUI.
In your kv file, the line:
ScreenManagement:
is creating another, different instance of ScreenManagement. This instance of ScreenManagement is the one that is in your GUI.
So anything your do to self.manager in the ClassAllScreen will have no effect on the ScreenManagement that is in your GUI.
The fix is to make sure you are referencing the correct instance of ScreenManagement (and not bother to create any other instances). To do this you can add an ObjectProperty to ClassAllScreen in the kv file, like this:
<ClassAllScreen>:
manager: scr_manager # added ObjectProperty that references the scr_manager id
orientation:'vertical'
BoxLayout:
size_hint_y: None
height: 60
spacing: 5
padding: 5
canvas:
Color:
rgba: .1,.1,.1,1
Rectangle:
pos: self.pos
size: self.size
Button:
text:'Menu'
size_hint_x: None
width: 120
on_release: root.manager.current = 'motd'
Button:
text:'Search'
size_hint_x: None
width: 120
on_release: root.manager.current = 'search'
Button:
text:'Add to DB'
size_hint_x: None
width: 120
on_press: print("Button Working")
ScreenManagement:
id: scr_manager # new id to enable reference to this ScreenManagement instance
And the ClassAllScreen class can then be simplified to:
class ClassAllScreen(BoxLayout):
pass
Just to help out anyone trying to do the same. The fixed code is below
App.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
kivy.require('1.9.1')
class MOTD(Screen):
print("MOTD Screen!")
pass
class Search(Screen):
print("Search Screen!")
pass
# class ScreenManagement(ScreenManager):
# pass # Removed, Instanced in kv
class ClassAllScreen(BoxLayout):
pass # Removed code, Done in kv
class ClassApp(App):
def build(self):
self.root = ClassAllScreen()
return self.root
if __name__ == '__main__':
Builder.load_file('./kvfiles/main.kv')
ClassApp().run()
main.kv
#: import NoTransition kivy.uix.screenmanager.NoTransition
<MOTD>:
name: 'motd'
BoxLayout:
orientation:'vertical'
padding:20
spacing:10
Label:
text:"The Cake Is a Lie"
<Search>:
name: 'search'
BoxLayout:
orientation:'vertical'
padding:20
spacing:10
GridLayout:
spacing:10
cols:2
Button:
text:'Left'
Button:
text:'Right'
Button:
text:'bottom'
<ClassAllScreen>:
manager:scr_manager
orientation:'vertical'
BoxLayout:
size_hint_y: None
height: 60
spacing: 5
padding: 5
canvas:
Color:
rgba: .1,.1,.1,1
Rectangle:
pos: self.pos
size: self.size
Button:
text:'Menu'
size_hint_x: None
width: 120
on_release: root.manager.current = 'motd'
Button:
text:'Search'
size_hint_x: None
width: 120
on_release: root.manager.current = 'search'
Button:
text:'Add to DB'
size_hint_x: None
width: 120
on_press: print("Button Working")
ScreenManager:
transition: NoTransition()
id: scr_manager
MOTD:
Search:

Horizontally aligning buttons in kivy

This is how my program looks right now.
How can I position my button "Log in" to always be horizontally aligned with center? I've tried looking on Stack Overflow about similar stuff but nothing worked for me... If anyone can help me, I would be really thankful.
Here's my python code:
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
import kivy.properties as kyprops
from kivy.uix.widget import Widget
from kivy.uix.image import Image
Builder.load_file("main.kv")
Window.clearcolor = (1,1,1,1)
# Declare both screens
class LoginScreen(Screen):
#txt_inpt = kyprops.ObjectProperty(None)
#def __init__(self):
pass
class InfoScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(LoginScreen(name='Login'))
sm.add_widget(InfoScreen(name='Info'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
Here is my .kv code:
#:import C kivy.utils.get_color_from_hex
<LoginScreen>:
RelativeLayout:
txt_inpt: txt_inpt
canvas:
Color:
rgba: C('#336699')
Line:
width: 2
rectangle: (0,self.height-50,self.width,0)
id: linija
Ellipse:
pos: self.width- 35, self.height-15
size: 7 , 7.0000000001
angle_start: 0
angle_end: 360
Ellipse:
pos: self.width- 35, self.height-27
size: 7 , 7.0000000001
angle_start: 0
angle_end: 360
Ellipse:
pos: self.width- 35, self.height-39
size: 7 , 7.0000000001
angle_start: 0
angle_end: 360
TextInput:
id: txt_inpt
password: True
multiline: False
hint_text: 'Username'
hint_text_color: C('#b3ccff')
size_hint_x: 0.9
size_hint_y: None
pos_hint: {"x":0.05, "top":0.8}
background_color: (1,1,1,0.2)
on_text_validate: root.manager.current = 'Info'
height: 30
pos: 300,60
TextInput:
id: txt_inpt
password: True
multiline: False
hint_text: 'Password'
hint_text_color: C('#b3ccff')
size_hint_x: 0.9
size_hint_y: None
pos_hint: {"x":0.05, "top":0.7}
background_color: (1,1,1,0.2)
on_text_validate: root.manager.current = 'Info'
height: 30
pos: 300,60
BoxLayout:
width: 1
pos: self.parent.pos # important!
orientation: 'vertical'
halign: 'center'
Button:
on_press: root.manager.current = 'Info'
background_color: C('#336699')
pos: self.pos
size: self.size
size: 80,30
size_hint: None, None
## NOTE: pos_hint: {"x":0.45, "top":0.6}
font_name: 'Droid.otf'
text: 'Log in'
<InfoScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'Login'
Your line in kv:
pos: self.parent.pos # important!
is positioning the BoxLayout in the lower left corner of the RelativeLayout
You can center it by using pos_hint and minimum_width:
BoxLayout:
# width: 1
# pos: self.parent.pos # important!
pos_hint: {'center_x':0.5, 'y':0}
size_hint_x: None
width: self.minimum_width
orientation: 'vertical'

Read the text from Textinput dynamically when text changed in text box?

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)

Categories

Resources