Can I load .kv file multiple times when the app is running? - python

I have two different .kv files:
file defining main interface --> PriceTrackerUI.kv
file defining popup window --> PopupWindow.kv
I want to "refresh" content of popup window, every time I close it.
In PopupWindow.kv the program opens an image by loading file which already exists in a directory. This file is overwritten every time in latter stage of running the app. The problem is, .kv files are loaded at the sheer initialisation of the program and not getting loaded again later. And as it makes sense with the main UI window, it doesn't with popup, which content changes with every click of the button in main UI window
Below is a minimal code
PopupWindow.kv:
<PopupWindow>
orientation: 'vertical'
size_hint: 1, .9
BoxLayout:
orientation: 'horizontal'
cols: 2
AsyncImage:
source: root.daily # loading image stored under that variable
allow_stretch: True
size_hint: .9, 1
pos_hint: {'x': 0, 'center_y': .5}
(...)
PriceTrackerUI:
<SearchPerformer>
GridLayout:
size: root.size
cols: 2
rows: 3
(...)
FloatLayout:
Button:
text: 'Search'
size_hint: .5, .4
pos_hint: {"x": .75, "top": .9}
border: 20, 20, 20, 20
on_press: root.input_grabber(root.dt)
on_release: root.clear()
on_release: root.hit_enter()
main.py:
import UI
UI.PriceTrackerUIApp().run()
UI.py:
import kivy
import database
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
from kivy.lang import Builder
kivy.require('1.11.1')
user_input = []
Builder.load_file('PopupWindow.kv')
class PopupWindow(BoxLayout):
daily = StringProperty('./daily.png')
def popup_show():
pop = PopupWindow()
pop_win = Popup(title="Analysis", content=pop, size_hint=(.9, .9))
pop_win.open()
class SearchPerformer(BoxLayout):
dt = database
def hit_enter(self):
popup_show()
def input_grabber(self, database):
specs = [self.ids.crmk.text, self.ids.crmd.text, self.ids.cryr.text, self.ids.crft.text]
(...)
user_input.extend(specs)
database.add_to_database()
database.query_database()
database.run_plot() # daily.png image gets updated after running that method
class PriceTrackerUIApp(App):
def build(self):
return SearchPerformer()

If you are trying to open a new Popup after changing the daily.png file, your current code should reflect the changed daily.png in the new Popup. Reloading the kv will not affect that.
If you are trying to update the AsyncImage in an already open Popup, then reloading the kv will have no effect. In that case, you just need to call the reload() method of the AsnycImage. Of course, that means that you must retain a reference to the PopupWindow and probably add an id to the AsyncImage. So, to add an id, a slightly modified kv:
<PopupWindow>
orientation: 'vertical'
size_hint: 1, .9
BoxLayout:
orientation: 'horizontal'
cols: 2
AsyncImage:
id: img # id to be used for calling reload()
source: root.daily # loading image stored under that variable
allow_stretch: True
size_hint: .9, 1
pos_hint: {'x': 0, 'center_y': .5}
And use that in your code (along with some small modifications):
def popup_show():
pop = PopupWindow()
pop_win = Popup(title="Analysis", content=pop, size_hint=(.9, .9))
pop_win.open()
return pop # save a reference to the `PopupWindow`
class SearchPerformer(BoxLayout):
dt = database
pop = ObjectProperty(None)
def hit_enter(self):
self.pop = popup_show() # retain reference to `PopupWindow`
def input_grabber(self, database):
specs = [self.ids.crmk.text, self.ids.crmd.text, self.ids.cryr.text, self.ids.crft.text]
(...)
user_input.extend(specs)
database.add_to_database()
database.query_database()
database.run_plot() # daily.png image gets updated after running that method
if self.pop is not None:
self.pop.ids.img.reload() # reload the updated daily.png

You can load a kv file at any point using Builder.load_file or Builder.load_string. When you instantiate a widget, any previously-loaded rules are applied.

Related

Kivy: How can I recode Scrollview and Gridlayout in pure Python?

I have an example code and it works nice.
But in this code Scrollview and Gridlayout are created in KV File.
I have a scroll bug problem so i want to create them in pure python.
There are 350 boxlayouts and they are created in Scrollview and each boxlayout has 5 widgets (buttons label etc) So this causes some bugs in Scrollview when clearing screen and recreating results. There are no problem for 80 boxlayout, but they are created dynamically and some times there are 300+ boxlayouts in Scrollview.
I thought if i can create Scrollview and Gridlayout, i can fix this issue.
So i need your help.
How can i do that.
Test code:
PY File:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.metrics import dp
from kivy.uix.behaviors import ButtonBehavior
from kivy.clock import Clock, mainthread
import json
import threading
class Test(BoxLayout):
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
self.data = self.datas()
# Homepage Screen
def homepage(self, screenmanager):
screenmanager.current = 'homepage_screen'
Clock.schedule_once(self.clear_widgets)
# Clear Widgets
def clear_widgets(self, *args):
for child in [child for child in self.ids.gridsonuc.children]:
self.ids.gridsonuc.remove_widget(child)
#Second screen
def second(self,screenmanager):
screenmanager.current = 'second_screen'
Clock.schedule_once(self.clear_widgets)
Clock.schedule_once(self.datas) # Before calculation, each time app pulls data again, but Kivy Does Not Update The Refreshed Data in The Screen!
Clock.schedule_once(self.calculate)
# or, if i can use threading system as well but this time i must add #mainthread above def calculate(self, *args): to make code work.
# in both scenario, Kivy Does Not Update The Refreshed Data in The Screen While APP is Running.
# mythread1 = threading.Thread(target=self.clear_widgets)
# mythread1.start()
# mythread2 = threading.Thread(target=self.datas)
# mythread2.start()
# mythread3 = threading.Thread(target=self.calculate)
# mythread3.start()
# Calculation
##mainthread
def calculate(self, *args):
for i in self.data['home']:
box = BoxLayout(size_hint_y = None, height = dp(50))
hometeams = Label(text = f'{[i]}', font_name = 'Roboto', font_size = dp(15), size_hint = (0.225, 1), halign='center', bold = True )
box.add_widget(hometeams)
self.ids.gridsonuc.add_widget(box)
def datas(self, *args):
# PLEASE CHANGE THE LOCATION!!!!!!!!!!!!!!!!!
with open ("C:\\Users\\Messi\\Desktop\\Python\\Projects\\Football Tips\\Kivy\\Testing Bugs\\Test1\\data.json", "r") as dosya:
dataApi = json.load(dosya)
print('datas updated')
self.data = dataApi # update the self.data
return dataApi
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()
KV File:
#:import NoTransition kivy.uix.screenmanager.NoTransition
<Test>:
ScreenManager:
transition: NoTransition()
id: sm
size: root.width, root.height
Screen:
name: 'homepage_screen'
BoxLayout:
size_hint: 1, 0.10
Button:
text: 'Calculate'
id: underOver_button_homepage
on_press: root.second(sm)
background_color: 0, 0, 0, 0
Screen:
name: 'second_screen'
BoxLayout:
spacing: '20dp'
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.80
ScrollView:
scroll_type: ['bars', 'content']
bar_margin: '5dp'
bar_color: 1, 0.4, 0.769, 1
bar_width: '5dp'
bar_inactive_color: 1, 0.4, 0.769, 1
GridLayout:
id: gridsonuc
cols: 1
spacing: '50dp'
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint: 1, 0.10
Button:
text: 'Home'
id: home_button_underOver
on_press: root.homepage(sm)
background_color: 0, 0, 0, 0
For example:
I don't want this structure in KV file
BoxLayout:
size_hint: 1, 0.80
ScrollView:
scroll_type: ['bars', 'content']
bar_margin: '5dp'
bar_color: 1, 0.4, 0.769, 1
bar_width: '5dp'
bar_inactive_color: 1, 0.4, 0.769, 1
GridLayout:
id: gridsonuc
cols: 1
spacing: '50dp'
size_hint_y: None
height: self.minimum_height
My Goal:
BoxLayout:
size_hint: 1, 0.80
Newscroll: # New Scrollview Class and have also Gridlayout in it
GridLayout and Scrollview must have same settings and i want to use like below. I think scroll_type: ['bars', 'content'], bar_margin: '5dp', bar_color: 1, 0.4, 0.769, 1, bar_width: '5dp', bar_inactive_color: 1, 0.4, 0.769, 1, cols: 1, spacing: '50dp', size_hint_y: None, height: self.minimum_height should code in Python
And a new clear def() for cleaning full scrollview class, when clear and create Scrollview in Pure Python, there are created dynamically so I can fix my Scroll bug issue.
Thanks for your help.
I hope one day I can be at a level where I can help other people in Kivy.
Kivy: How can I recode Scrollview and Gridlayout in pure Python?
The shortest answer to your question is:
You can't.
See Pure python gui library? here on stackoverflow to read:
Notion of "pure python gui library" is wrong because ultimately you will be using system level calls and widgets, may be thru ctypes but that doesn't change the fact that if you start implementing your idea you will eventually end with using wxPython or some other module.
along with the statement in the accepted answer:
The path of least effort and best results would be to learn what it takes to deploy an app using some of the existing GUI libraries.
Kivy is a Python module you can use to create GUIs (Graphical User Interfaces) and comes with the possibility to create a Scrollview and a Gridlayout objects/widgets for by it created window with an user interface.
Your goal is to use "pure Python" to replace the objects/widgets, but it is not possible to use "pure Python" for this task, because Python requires usage of a module for GUIs.
Most native GUI module that comes with the standard Python installation and is nearest to the notion of "pure Python" is tkinter, but it needs GTK to be already installed on the system, else it won't be available and you need to learn how to use it properly like you need it when using Kivy.
In other words it will be a good idea to find out what actually causes the problems you experience while using Kivy and solve them instead of learning how to use another GUI library to recreate your application.
And if your idea is to create own widgets within Kivy you have to learn how to write own extensions to Kivy which can take you much more effort compared to finding out the reason for why you face problems while using it.

Python Kivy self.add_widget() doesn't update while code running

The idea is to create a texting app that works like Messenger. I am having a problem with the chat history which is a "BoxLayer (or GridLayer)" containing all previous text. I want when I insert a new text, it's will appear as a new label or a box and stay below the previous text like this, but when I run the code and insert input text, it's not appearing. I spent hours to find the answer both myself and on the internet, but it's kind of hard for a beginner like me.
.Py file
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.image import Image
from kivy.properties import StringProperty
from kivy.core.window import Window
from kivy.graphics.context_instructions import Color
class MainWidget(Widget):
request = StringProperty("This is a previous text, don't mind")
insert_text = StringProperty("Insert Here")
window_size = (305,400)
refresh_key = False
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.Window_Minimum()
def on_size(self,*args):
print(self.width,self.height)
def on_text_validate(self,widget): #<<<<<<<<<<<<<<<<<<<<<<<<<<< input text
request=widget.text
Chat_history_update().chat_history(request)
def Window_Minimum(self):
Window.minimum_width,Window.minimum_height=self.window_size
class Chat_history_update(BoxLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
l = Label(text="This is a previous text, don't mind",size_hint=(1, None),height=("30dp"))
self.add_widget(l)
def chat_history(self,request): # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Add Label Function
l = Label(text=request, size_hint=(1, None),height=("30dp"))
self.add_widget(l) # <<<<<<<<<<<<< This won't update my app screen
class Assistant(App):
pass
if __name__ == "__main__":
Assistant().run()
Kv file
MainWidget:
<MainWidget>:
BoxLayout:
size: root.size
orientation: "vertical"
GridLayout:
cols: 3
size_hint: 1,None
height: "50dp"
spacing: "10dp"
padding: "10dp"
Label:
text:"Erza Assistant"
Button:
text:"Edit Path"
Button:
text:"Setting"
GridLayout:
size: self.size
rows: 2
spacing: "10dp"
padding: "10dp"
ScrollView: #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Here my text display
Chat_history_update:
orientation: "vertical"
size_hint: 1, None
height: self.minimum_height
TextInput:
size_hint: 1, None
height: "40dp"
text: root.insert_text
multiline: False
on_text_validate: root.on_text_validate(self)
Your code:
Chat_history_update().chat_history(request)
is creating a new instance of Chat_history_update, and calling chat_history() for that new instance. That new instance is not part of your GUI, so you will see no effect. The fix is to access the correct instance of Chat_history_update (the one that is in your GUI). To do that, you can add an id in your kv:
ScrollView: #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Here my text display
Chat_history_update:
id: chu
orientation: "vertical"
size_hint: 1, None
height: self.minimum_height
And then use that id in your py code:
def on_text_validate(self,widget): #<<<<<<<<<<<<<<<<<<<<<<<<<<< input text
request=widget.text
self.ids.chu.chat_history(request)
I think this here might help. You have to reference widgets in the kivy language by using id or ids.
If you do not yet i strongly suggest you learn how to reference widgets by their ids.

Kivy updating label when using function via button fails

I'm trying to build an App thats uses certain input Parameters and when hitting a submit button it uses a logic to generate output paramters. I managed to build the app and the input and the triggering via a submit button. Now i want to generate the output, for beginning with an easy logic. I looked up several similar solutions, but somehow they don't work for me.
For some reason my .kv file doen't get the updated value for the label text with the error: "ValueError: Label.text accept only str" Eventough everything is declared as a string in the .py. If i change it in the kv to str("...") I get some code line which i guess is the intern id of the attribute but not the assigned value i want to get.
I hope you can help. Pls don't be too harsh, I#M new to python and kivy...
main .py, shuldn't be part of the problem
Peenomat.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.anchorlayout import AnchorLayout
from kivy.core.text import LabelBase
Builder.load_file('Statusbar.kv')
Builder.load_file('Inputparameters.kv')
Builder.load_file('Outputparameters.kv')
#Layout
class Peenomat(AnchorLayout):
pass
class PeenomatApp(App):
def build(self):
return Peenomat()
if __name__=="__main__":
PeenomatApp().run()
.py with the classes and methods for the logic
StatusBar.py
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.app import App
class InputParameters(GridLayout):
verfahren = ObjectProperty(None)
def on_state(self, togglebutton):
tb = togglebutton
if tb.state == 'down':
self.verfahren = tb.text
self.verfahren = tb.text
print(self.verfahren)
return self.verfahren
class StatusBar(BoxLayout):
#InputGrößen
group_mode = False
prozess = ObjectProperty(None)
vorbehandlung = ObjectProperty(None)
material = ObjectProperty(None)
haerte = ObjectProperty(None)
rauheit = ObjectProperty(None)
#OutputGrößen
frequenz = StringProperty(None)
def btn_submit(self):
ip = App.get_running_app().root.ids._input_parameters
print("Haerte:", ip.haerte.value, "Rauheit:", ip.rauheit.value, "Material:", ip.material.text, "Vorbehandlung:", ip.vorbehandlung.text)
if ip.haerte.value < 50:
self.frequency = str(180)
elif ip.haerte.value < 60:
self.frequency = str(200)
else:
self.frequency = str(220)
#control to see if right value is taken
print(self.frequency, "Hz")
def btn_clear(self):
np = App.get_running_app().root.ids._input_parameters
np.pro1.state = "normal"
np.pro2.state = "normal"
np.pro3.state = "normal"
np.material.text = "Auswahl treffen"
np.haerte.value = 55
np.rauheit.value = 5.5
the .kv file that can't get the label text:
outputparameters.kv
#: import statusbar StatusBar
<OutputParameters#GridLayout>
#Initialisierung .py zu .kv
frequenz: _frequenz
Label:
text:'Frequenz:'
font_size:
Label:
id: _frequenz
text: root.frequenz
font_size: 20
the .kv file with the submit button, shouldn't be part of the problem either, worked perfectly fine before implementing the part ehre i try to update the text
statusbar.kv
#: import statusbar StatusBar
<StatusBar#BoxLayout>
orientation:'horizontal'
Button:
text: 'Clear'
on_press: root.btn_clear()
Button:
text: 'Submit'
on_press: root.btn_submit()
the file where i put in all the inputparameters, rather important:
Inputparameters.kv
#: import statusbar StatusBar
<InputParameters#GridLayout>
#Initialisierung .py zu .kv Ids
prozess: _prozess
pro1: _prozess1
pro2: _prozess2
pro3: _prozess3
vorbehandlung: _vorbehandlung
material: _material
haerte: _haerte
rauheit: _rauheit
#Prozess
Label:
text:'Prozess:
BoxLayout:
orientation: 'horizontal'
id: _prozess
ToggleButton:
id:_prozess1
text:'P-MOH'
group: "proc_group"
on_state: root.on_state(self)
ToggleButton:
id:_prozess2
text:'E-MOH'
group: "proc_group"
on_state: root.on_state(self)
ToggleButton:
id:_prozess3
text:'PE-MOH'
group: "proc_group"
on_state: root.on_state(self)
#Material
Label:
text: 'Material:'
Spinner:
id: _material
text: ""
values:
# Herstellschritte
Label:
text:'Fertigungsschritte:'
Spinner:
id: _vorbehandlung
text:
values:
# Haerte
Label:
text:'Haerte:'
BoxLayout:
orientation: 'vertical'
Label:
text: str(_haerte.value)
Slider:
id: _haerte
# Rauheit
Label:
text:'Rauheit:
BoxLayout:
orientation: 'vertical'
Label:
text:
Slider:
id: _rauheit
and the file where my layout is embedded (also rather necessary)
peenomat.kv
<Peenomat>
AnchorLayout:
anchor_x: 'left'
anchor_y: 'bottom'
GridLayout:
cols: 1
canvas.before:
Color:
Rectangle:
pos: self.pos
size: self.size
InputParameters:
id:_input_parameters
StatusBar:
id:_status_bar
OutputParameters:
id:_output_parameters
I really hope you can help, have been struggeling with this for a while and it should rather be easy...thanks in advance!
In your kv rule for <OutputParameters#GridLayout> you have a line:
frequenz: _frequenz
which sets frequenz to be a reference to the Label with the id of _frequenz. Then in that Label you are setting text using:
text: root.frequenz
So, you are trying to set the text of the Label to a reference to that Label
I suggest trying something like this:
<OutputParameters#GridLayout>
#Initialisierung .py zu .kv
frequenz: _frequenz
frequency: ''
And change the Label to:
Label:
id: _frequenz
text: root.frequency
font_size: 20
But to actually change the value shown in the label, you will need a reference to the instance of OutputParameters, using something like:
App.get_running_app().root.ids._output_parameters.frequency = str(500)

Kivy function scope on button release (widget tree)

I am new to Kivy and need some help in understanding function scope. I have built a simple app with two screens. The first screen has two buttons and the second screen has a text label at the centre. On the first screen, I have used app.root.current='new_screen_name' with the on_release attribute for one button and it works fine. It takes me to the next screen which is the intended function. For the second button, I have used a function call which has been defined in the Python file under the class definition of the first screen (the root widget of the button). However, this method does not work and the app window simply closes. I guess I am making a mistake in the function scope and call But I cannot figure out what. Any help would be greatly appreciated.
Python file:
from kivy.config import Config
# Config.set should be used before importing any other Kivy module.
Config.set('kivy','window_icon','sivaicon.png')
# Config set for resizing image button
Config.set('graphics', 'resizable', True)
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.lang.builder import Builder
class SivaLoginScreen(Screen):
def func_authentication(self):
app.root.current='tabbed_screen'
class SivaTabbedScreen(Screen):
pass
class SivaScreenManager(ScreenManager):
pass
class ImageButton(ButtonBehavior, Image):
pass
# Tell Kivy to directly load a file. If this file defines a root widget, it will be returned by the method.
root_widget = Builder.load_file('siva.kv')
class SivaApp(App):
def build(self):
# Initialize root widget
return root_widget
if __name__ == '__main__':
# Run application
SivaApp().run()
Kivy file (.kv):
SivaScreenManager:
SivaLoginScreen:
SivaTabbedScreen:
<ImageButton>:
keep_ratio: True
<SivaLoginScreen>:
name: 'login_screen'
canvas.before:
Color:
rgba: 195/255, 60/255, 35/255, 1
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
size: root.width, root.height
Image:
id: login_logo_siva
source: 'images/sivalogo4.png'
keep_ratio: True
size_hint: 0.2, 0.2
pos_hint: {'center_x':0.5, 'center_y':0.75}
Label:
id: login_label_siva
pos: self.x*0.5-4, self.y*0.5+15
markup: True
font_name: 'roboto/Roboto-Medium.ttf'
text: '[color=#FDFD98]S.[/color][color=#B29DD9]I[/color][color=#FDFD98].[/color][color=#77DD77]V[/color][color=#FDFD98].[/color][color=#779ECB]A[/color]'
font_size: '50sp'
Label:
id: login_label_slogan1
pos: self.x*0.5-3, self.y*0.5-6
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]SLOGAN TEXT[/color]'
font_size: '15sp'
Label:
id: login_label_slogan2
pos: self.x*0.5-3, self.y*0.5-20
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]HEADLINE TEXT[/color]'
font_size: '15sp'
BoxLayout:
id:login_button_layout
orientation: 'horizontal'
size_hint: 0.2, 0.2
pos_hint: {'center_x':0.5, 'center_y':0.25}
ImageButton:
id: first_button
source: {'normal': 'images/first.png', 'down': 'images/first-down.png'} [self.state]
on_release: app.root.current='tabbed_screen'
ImageButton:
id: second_button
source: {'normal': 'images/second.png', 'down': 'images/second-down.png'} [self.state]
on_release: app.root.func_authentication()
<SivaTabbedScreen>:
name: 'tabbed_screen'
FloatLayout:
size: root.width, root.height
Label:
pos: self.x*0.5, self.y*0.5
text: 'SECOND SCREEN'
font_size: '50sp'
In your case, app.root link to SivaScreenManager which is the root widget of your application. And in these class, there is not a func_authenticationfunction, why you app crashed.
To refer a class itself in a KV definition, you must just use root, so right code must be :
on_release: root.func_authentication()
see Kivy Language - Reserved Keywords
Definition of func_authentication is not correct also, app is unknown. Use either :
App.get_running_app().root.current='tabbed_screen' or
self.manager.current='tabbed_screen'

Scroll contents of GridLayout in ScrollView - Kivy

I will say first off I have tried every single example on the web involving kv lang. Not once have I had any success.
The idea is pretty simple: As I swipe up/down/scroll the contents of GridLayout() within ScrollView() are scrolled up or down.
The best I have been able to do is have the scroll bar fade into view when running the program. Not able to scroll unfortunately.
<Root>
grid_layout: grid_layout
ScreenManager:
...
Screen:
...
ScrollView:
GridLayout:
id: grid_layout
size_hint_y: None
cols: 1
height: self.minimum_height
<list of buttons>
Binding minimum_heightin the __init__ method of the root class (RelativeLayout):
grid_layout = ObjectProperty(None)
self.grid_layout.bind(minimum_height=self.grid_layout.setter('height'))
I have followed https://github.com/kivy/kivy/blob/master/examples/widgets/scrollview.py converting it to kv lang - scroll bar visible, unable to scroll. Also tried every example on Google Groups and here related to using kv lang. Still no scroll :\
Compiling using buildozer and running on Android fails for an unknown reason.
I would appreciate any assistance that can be given.. I am completely clueless at this point
This:
height: self.minimum_height
should be:
minimum_height: self.height
This is unnecessary:
grid_layout = ObjectProperty(None)
self.grid_layout.bind(minimum_height=self.grid_layout.setter('height'))
It also won't scroll unless the contents are larger than the scrollview's height:
Full code:
from kivy.lang.builder import Builder
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<Root>:
ScrollView:
size_hint: 1, .1
# setting the width of the scrollbar to 50pixels
bar_width: 50
# setting the color of the active bar using rgba
bar_color: 5, 10, 15, .8
# setting the color of the inactive bar using rgba
bar_inactive_color: 5, 20, 10, .5
# setting the content only to scroll via bar, not content
scroll_type: ['bars']
GridLayout:
size_hint_y: None
cols: 1
minimum_height: self.height
Button
text: 'one'
Button:
text: 'two'
Button:
text: 'three'
Button:
text: 'four'
''')
class Root(FloatLayout):
pass
class DemoApp(App):
def build(self):
return Root()
if __name__ == '__main__':
DemoApp().run()
Being unable to scroll was due to a misunderstanding of Kivy's touch handlers. Completely unrelated to the code mentioned in my question.
The key is to have GridLayout be larger than ScrollView, so GridLayout can be panned within ScrollView.
For those wanting to use ScrollView inside ScreenManager using kvlang only:
ScreenManager:
id: screen_manager
Screen:
manager: screen_manager
id: main_screen
name: 'main'
ScrollView:
bar_width: 4
# pos_hint defaults to 1,1 so no need to declare it
GridLayout:
size_hint_y: None
cols: 1
# you do not need to manually bind to setter('height') in
# python - perfectly possible with kv lang
# this allows for height to update depending on the
# collective heights of its child widgets
height: self.minimum_height
<----- widgets here ----->
# for scroll to show/work there must be more widgets
# then can fit root.height. If not there is no need
# for scrollview :)

Categories