Kivy: horizontal scrollable labels inside a GridLayout - python

I am trying to adapt the code from the ScrollView doc to have get scrollable labels on the horizontal axis inside a GridLayout. The GridLayout shouldn't be scrollable it, just the labels within it.
For my app, I can't use kv language (either in .kv or the builder), so the code has to be in python.
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.app import runTouchApp
layout = GridLayout(cols=1, spacing=10)
for i in range(10):
label = Label(text="abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz", height = 30, size_hint_x=None, width=400)
label.bind(minimum_width=label.setter('width'))
root = ScrollView(size_hint=(None, 1), size=(label.width, label.height))
root.add_widget(label)
layout.add_widget(root)
runTouchApp(layout)

So far, this is working:
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
class Test(App):
def build(self):
layout = GridLayout (cols=3)
for i in range(3):
l = Label(font_size=15, size_hint_x= None, width=300, text="This is a very looooooooooooooooooooonnnnnnnnnnnnnnnnnnnng text. Indeed it is a very loooooooooooooooooooooonnnnnnnnnnnnnnnng text")
l.bind(size_hint_min_x=l.setter('width'))
scroll = ScrollView(size_hint=(None, None), size=(100, 400), pos_hint={'center_x':.5, 'center_y':.5})
scroll.add_widget(l)
layout.add_widget(scroll)
return layout
Test().run()

Related

Not getting ScrollView for kivy

Iam creating an app so that my code is given below but why Iam not getting ScrollView What's wrong with this code can anybody explain me.
from kivy.uix.button import Button
from kivy.app import runTouchApp
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
root1 = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root2 = FloatLayout()
def c(a):
root1.remove_widget(root2)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout1 = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout1.bind(minimum_height=layout1.setter('height'))
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout1.add_widget(btn)
layout2=GridLayout(cols=1, spacing=10, size_hint_y=None)
b1=Button(text='hi')
layout2.add_widget(b1)
layout.add_widget(layout2)
layout.add_widget(layout1)
root1.add_widget(layout)
b=Image(source='/storage/emulated/0/Photo Editor/Polish_20210216_162256244.png')
root2.add_widget(b)
root1.add_widget(root2)
Clock.schedule_once(c, 2)
runTouchApp(root1)
Not sure why you are using a GridLayout inside another GridLayout, but that is the problem. If you use two of them, each must be using minimum_height. Just add the line:
layout.bind(minimum_height=layout.setter('height'))

Kivy Button on_press function=Popup not calling function

Here's the code that has the problem:
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.app import runTouchApp
from kivy.uix.popup import Popup
import arabic_reshaper
import bidi.algorithm
file = open("/sdcard/ls.txt","r")
li = [i for i in open("/sdcard/code_pinal.txt").read().split('\n\n\n')]
class MessageBox(Popup):
message = StringProperty()
def message_box(self, message):
p = MessageBox()
p.message = message
p.open()
layout = GridLayout(cols=1, spacing=1, size_hint_y=None)
# Make sure the height is such that there is something to scroll.
layout.bind(minimum_height=layout.setter('height'))
for x in li:
ttl = bidi.algorithm.get_display(arabic_reshaper.reshape(x.split(':')[0]))
txt = bidi.algorithm.get_display(arabic_reshaper.reshape(x.split(':')[1]))
btn = Button(text=str(title), font_name='/storage/emulated/0/Download/fonts/DejaVuSans.ttf', size_hint_y=None, height=90, on_press=message_box(text))
layout.add_widget(btn)
root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root.add_widget(layout)
runTouchApp(root)
https://i.stack.imgur.com/u2ePj.jpg
i'm getting errors:
TypeError: message_box() missing 1 required positional argument: 'message'
and
AssertionError: None is not callable
i want to get a popup with the title = "ttl" and text = "txt" varibles when any button pressed for every element on the list "li"
please take it easy with me, i'm Beginner
your trying to get text of button on press
why don't you just get the text from button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.app import runTouchApp
from kivy.uix.popup import Popup
import arabic_reshaper
import bidi.algorithm
file = open("/sdcard/ls.txt","r")
li = [i for i in open("/sdcard/code_pinal.txt").read().split('\n\n\n')]
class MessageBox(Popup):
message = StringProperty()
def message_box(self, btn):
message = btn.text
p = MessageBox()
p.message = message
p.open()
layout = GridLayout(cols=1, spacing=1, size_hint_y=None)
# Make sure the height is such that there is something to scroll.
layout.bind(minimum_height=layout.setter('height'))
for x in li:
ttl = bidi.algorithm.get_display(arabic_reshaper.reshape(x.split(':')[0]))
txt = bidi.algorithm.get_display(arabic_reshaper.reshape(x.split(':')[1]))
btn = Button(text=str(title), font_name='/storage/emulated/0/Download/fonts/DejaVuSans.ttf', size_hint_y=None, height=90, on_press=message_box)
layout.add_widget(btn)
root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root.add_widget(layout)
runTouchApp(root)

How to get access to widgets in kivy? I need to remove TextInput by pressing a Button

How to get access to different widgets in python kivy?
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
class kxApp(App):
def build(self):
gl_main = GridLayout(rows=2,padding=5, spacing=5)
gl_left = GridLayout(padding=5, spacing=5)
gl_middle = GridLayout(padding=5, spacing=5)
gl_right = GridLayout(padding=5, spacing=5)
gl_main.add_widget(gl_left)
gl_main.add_widget(gl_middle)
gl_main.add_widget(gl_right)
gl_left.add_widget(TextInput(text='Input Here'))
gl_middle.add_widget(Label(text='Just Label'))
gl_right.add_widget(Button(text='Remove Input Field', on_press killFunc))
def killFunc(self,obj):
#how to get access to TextInput() and remove it?
kxApp().run()
What is the natural way to 'get' widget to manipulate it?
By saving a reference to the TextInput, you can simply use remove_widget:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
class kxApp(App):
def build(self):
gl_main = GridLayout(rows=2,padding=5, spacing=5)
gl_left = GridLayout(cols=1, padding=5, spacing=5)
gl_middle = GridLayout(cols=1, padding=5, spacing=5)
gl_right = GridLayout(cols=1, padding=5, spacing=5)
gl_main.add_widget(gl_left)
gl_main.add_widget(gl_middle)
gl_main.add_widget(gl_right)
self.text_input = TextInput(text='Input Here')
gl_left.add_widget(self.text_input)
gl_middle.add_widget(Label(text='Just Label'))
gl_right.add_widget(Button(text='Remove Input Field', on_press=self.killFunc))
return gl_main
def killFunc(self,obj):
self.text_input.parent.remove_widget(self.text_input)
kxApp().run()

Adding spacing between dropdown items in kivy

My problem is in accessing container property of DropDown, which is a GridLayout by default and contains it's children.
Simple app:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.label import Label
class TestApp(App):
def build(self):
root = BoxLayout(orientation='vertical')
dropdown = DropDown()
for i in range(3):
dropdown.add_widget(Button(
text=str(i),
size_hint_y=None
)) # add 3 buttons to dropdown
dropdown.container.bind(spacing=8) # this line does not work
dropdown_button = Button(size_hint_y=.2, text='Open DropDown')
dropdown_button.bind(on_release=dropdown.open)
root.add_widget(dropdown_button)
root.add_widget(Label()) # empty space under button
return root
TestApp().run()
I tried using bind method for this, but there is no result. No indentation is set. I also would like to see the solution in kivy language because I want to use dp() function for setting spacing and it's not very convenient to pass the parameter to python file for this. Thanks in advance for any help.
Instead using bind you should just set the value directly:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.widget import Widget
class TestApp(App):
def build(self):
root = BoxLayout(orientation='vertical')
dropdown = DropDown()
for i in range(3):
dropdown.add_widget(Button(
text=str(i),
size_hint_y=None
)) # add 3 buttons to dropdown
dropdown.container.spacing = 10
dropdown.container.padding = (0, 10, 0, 0)
dropdown_button = Button(size_hint_y=.2, text='Open DropDown')
dropdown_button.bind(on_release=dropdown.open)
root.add_widget(dropdown_button)
root.add_widget(Widget()) # empty space under button
return root
TestApp().run()
Using a custom container class is not supported directly. You can do it like this, but its hacky and ugly:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_string('''
<MyContainer>:
# copied from kivy.uix.dropdown._grid_kv
size_hint_y: None
height: self.minimum_size[1]
cols: 1
# custom settings
spacing: 10
padding: (0, 10, 0, 0)
''')
class MyContainer(GridLayout):
pass
class TestApp(App):
def build(self):
root = BoxLayout(orientation='vertical')
container = MyContainer()
dropdown = DropDown(container=container)
super(DropDown, dropdown).add_widget(container)
dropdown.on_container(dropdown, container)
for i in range(3):
dropdown.add_widget(Button(
text=str(i),
size_hint_y=None
)) # add 3 buttons to dropdown
dropdown_button = Button(size_hint_y=.2, text='Open DropDown')
dropdown_button.bind(on_release=dropdown.open)
root.add_widget(dropdown_button)
root.add_widget(Widget()) # empty space under button
return root
TestApp().run()
So I'd say it'd more clean to make custom spacing class as a subclass of Widget to fill space between buttons:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_string('''
<DropDownSpacing>:
size_hint_y: None
height: 20
''')
class DropDownSpacing(Widget):
pass
class TestApp(App):
def build(self):
root = BoxLayout(orientation='vertical')
dropdown = DropDown()
for i in range(3):
dropdown.add_widget(DropDownSpacing())
dropdown.add_widget(Button(
text=str(i),
size_hint_y=None
)) # add 3 buttons to dropdown
dropdown_button = Button(size_hint_y=.2, text='Open DropDown')
dropdown_button.bind(on_release=dropdown.open)
root.add_widget(dropdown_button)
root.add_widget(Widget()) # empty space under button
return root
TestApp().run()
This is the same you're doing in your main BoxLayout, except I prefer to use Widget class directly instead of Label with no text.

Kivy scrollable label: impossible to read the beginning and the end of the label

I have these scrollable labels but I can't read the very beginning and the very end of them(the alphabet starting with 1 and the one starting with 8).
Another issue is that the scrollview starts in the center and jumps back automatically to the center when the scroll is released. It would be better to have it display the left part and let the label where I have stop to scroll.
I use python 3.6 and Kivy 1.9.2.dev0 and my code has to be in python (no .kv file or builder)
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
# from kivy.properties import StringProperty
from kivy.uix.scrollview import ScrollView
class Test(App):
def build(self):
layout_pop = GridLayout (cols=3)
for i in range(3):
l = Label(
text="1abcdefghijklmnopqrstuvwxyz_2abcdefghijklmnopqrstuvwxyz_3abcdefghijklmnopqrstuvwxyz_4abcdefghijklmnopqrstuvwxyz_5abcdefghijklmnopqrstuvwxyz_6abcdefghijklmnopqrstuvwxyz_7abcdefghijklmnopqrstuvwxyz_8abcdefghijklmnopqrstuvwxyz",
font_size=15,
color=(1,1,3,1),
size_hint_x= None,
width=600)
l.bind(size_hint_min_x=l.setter('width'))
scroll = ScrollView(size_hint=(None, None), size=(200, 30))
scroll.add_widget(l)
layout_pop.add_widget(scroll)
return layout_pop
Test().run()
I simply had to use l.bind(texture_size=l.setter('size')). That fixed the 2 issues.
This is the updated def function:
def build(self):
layout_pop = GridLayout (cols=3)
for i in range(3):
l = Label(
text="1abcdefghijklmnopqrstuvwxyz_2abcdefghijklmnopqrstuvwxyz_3abcdefghijklmnopqrstuvwxyz_4abcdefghijklmnopqrstuvwxyz_5abcdefghijklmnopqrstuvwxyz_6abcdefghijklmnopqrstuvwxyz_7abcdefghijklmnopqrstuvwxyz_8abcdefghijklmnopqrstuvwxyz \n1abcdefghijklmnopqrstuvwxyz_2abcdefghijklmnopqrstuvwxyz_3abcdefghijklmnopqrstuvwxyz_4abcdefghijklmnopqrstuvwxyz_5abcdefghijklmnopqrstuvwxyz_6abcdefghijklmnopqrstuvwxyz_7abcdefghijklmnopqrstuvwxyz_8abcdefghijklmnopqrstuvwxyz",
font_size=15,
color=(1,1,3,1),
size_hint_x= None)
l.bind(texture_size=l.setter('size'))
l.bind(size_hint_min_x=l.setter('width'))
scroll = ScrollView(size_hint=(None, None), size=(200, 30))
scroll.add_widget(l)
layout_pop.add_widget(scroll)
return layout_pop

Categories