I have a ListView containing customized buttons for the listitems. How can I format the scrollbar in such a way that it is always visible (in case there is something to scroll...), make it wider (10 pts instead of the default 2) and give it a different color?
The DoScroll.py file:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.listview import ListItemButton
class ShowItems(BoxLayout):
def get_list(self):
self.results.item_strings = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}
def show_capital(self, capital):
print capital
class CapitalButton(ListItemButton):
pass
class DoScrollApp(App):
pass
if __name__ == '__main__':
DoScrollApp().run()
And here is the DoScroll.kv file.
#: import DoScroll DoScroll
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
<CapitalButton>:
text_size: self.width - 50, None
halign: 'left'
valign: 'middle'
font_size: 16
on_press: app.root.show_capital(self.text)
ShowItems:
<ShowItems>:
results: results_list
orientation: "vertical"
BoxLayout:
height: "40dp"
size_hint_y: None
Button:
text: "Get the list"
on_press: root.get_list()
ListView:
id: results_list
adapter:
ListAdapter(data=[], args_converter=lambda row_index,
an_obj: {'text': an_obj,'size_hint_y': None,'height': 40}, cls=DoScroll.CapitalButton)
ListView contains a ScrollView, which in turn holds the GridView holding the list items. The corresponding kv rules are these (from listview.py):
<ListView>:
container: container
ScrollView:
pos: root.pos
on_scroll_y: root._scroll(args[1])
do_scroll_x: False
GridLayout:
cols: 1
id: container
size_hint_y: None
ScrollView has properties bar_width, bar_color, bar_inactive_color. These could be accessed through lv.container.parent.bar_width etc., for lv = ListView().
Related
well I'm entirely new to kivy, it's a bit complicated but I'm trying to get on
so I'm stuck on something, I'm trying to get a text from a TextInput, but i can't, it just refuse to do it, can anyone crack it?
KV code:
<Signin>:
title:"Telegram Checker"
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
BoxLayout:
width : 600
orientation: 'vertical'
size_hint: None, None
Label:
text:"Telegram Sign-In"
TextInput:
id : tel
input_type:'tel'
width:600
multiline: False
hint_text: '+XXXXXXXXXXXXX'
size_hint: None, None
height: 50
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
padding: 20
spacing: 100
width : 600
orientation: 'vertical'
size_hint: None, None
Button:
text: "Next ->"
#size_hint: 0.5,6
height : 100
pos:self.pos
on_release : app.send_code_request()
the function that's not getting the text :
class MyApp(App):
def build(self):
self.title="Telegram Checker"
return screen_manager
def send_code_request(self):
phone = self.root.ids.tel.text
print(phone)
The code at the bottom is runnable and it passes the argument you requested. It shows this being done two ways. I suggest not using the .ids property because you can link the items at the top of the .kv class and assign type hints to the object like this:
tel: TextInput
full code:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
Builder.load_string('''
<Signin>:
# match the python object to the kivy id
# python on the left: kivy id on the right
tel: tel
title:"Telegram Checker"
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
BoxLayout:
width : 600
orientation: 'vertical'
size_hint: None, None
Label:
text:"Telegram Sign-In"
TextInput:
id : tel
input_type:'tel'
width:600
multiline: False
hint_text: '+XXXXXXXXXXXXX'
size_hint: None, None
height: 50
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
padding: 20
spacing: 100
width : 600
orientation: 'vertical'
size_hint: None, None
Button:
text: "Next ->"
#size_hint: 0.5,6
height : 100
pos:self.pos
on_release : app.send_code_request(tel.text, self)
'''
)
class Signin(Screen):
# python objects mapped in the .kv file. this is a type hint which will help with auto-complete
tel: TextInput
def __init__(self, **kwargs):
super().__init__(**kwargs)
print(f" hint text is {self.tel.hint_text}")
class MyApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_top_widget = ScreenManager()
self.signin_screen = Signin(name="sign_in")
def send_code_request(self, phone: str, your_button, *args) -> None:
# this is one way
print(f" by id {self.signin_screen.ids.tel.text}")
print(f"vale passed={phone} \nyour button {your_button} other args {args}")
def build(self):
self.title = "Telegram Checker"
self.my_top_widget.add_widget(self.signin_screen, name="sign_in")
self.my_top_widget.current = "sign_in"
return self.my_top_widget
my_app = MyApp()
my_app.run()
I need to create an autofill app, I have a label and text input on the top, and recycle view on the bottom. However, when I run the program, the recycle view disappears, even though I have set in the string. This app will facilitate searching content by typing the name in the text input and the relevant content will appear in the recycle view, so the user is not required to view through the long list of content.
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.recycleview import RecycleView
from kivy.uix.boxlayout import BoxLayout
Window.size = (350, 600)
Builder.load_string('''
<MyLayout>:
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
Label :
text : 'Favourite Pizza'
TextInput :
font_size: 30
focus: True
multiline : False
<RV>:
RecycleBoxLayout:
viewclass: 'TextInput'
default_size: None, 30
default_size_hint: 1, None
size_hint_y: .8
height: self.minimum_height
orientation : 'vertical'
''')
class MyLayout(BoxLayout):
pass
class RV(RecycleView):
def __init__(self, **kwrgs):
super(RV, self).__init__(**kwrgs)
content = ["Pepperoni", "Cheese","Papper", "Hawaii", "Seafood",
"Ham", "Taco", "Onion"]
self.data = [{'text':item} for item in content]
print(content)
class MainApp(App):
title='Search App'
def build(self):
Window.clearcolor = (51/255, 153/255, 1, 1)
return MyLayout()
MainApp().run()
What should I do in order to get a complete view (label, text input & recycle view)? I want to type an input text, the relevant content will appear in the recycle view, can I use recycle view to achieve this purpose? Can I use both BoxLayout and the RecycleBoxLayout at the same time, since it refers to the different widgets?
First of all, dynamic classes must be in the same level as root.
Secondly in order to make RecycleView grow vertically, here, you have to set size_hint_y of RecycleBoxLayout to None. Thus your kvlang should now look like,
<MyLayout>:
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
Label :
text : 'Favourite Pizza'
TextInput :
font_size: 30
focus: True
multiline : False
RV:
<RV>:
viewclass: 'TextInput'
RecycleBoxLayout:
default_size: None, 30
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation : 'vertical'
I want to remove a Boxlayout in my widget, but I cant.
There is a Boxlayout at the begining of the app called "Speca". After my sellections it must be removed.
When you run the app, sellect something in "Home" Spinner and click any of the new Toggle buttons.
Wtih the press of any of the Toggle buttons "Speca" must disappear.
Please help.
Here is main.py:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.spinner import Spinner
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import ObjectProperty, StringProperty, BooleanProperty
from kivy.properties import ListProperty
from collections import OrderedDict
from kivy.uix.togglebutton import ToggleButton
data1=["mother","father","son"]
data2=["uncle","aunt","grandfather"]
data3=["jack","mike","simon"]
data4=["1898","1975","1985","1885"]
amd="0dp"
class MainWidget(Widget):
def remove_layout(self, *ignore):
self.remove_widget(self.layout)
global amd
an0=tuple(list(OrderedDict.fromkeys(data1)))
cal5= ObjectProperty()
cal6= ObjectProperty()
def btn10(self,text):
if self.cal5:
self.cal5.parent.remove_widget(self.cal5)
self.cal5 =ModelSpecifications()
a=data2
b=data3
c=data4
mi=[]
n=0
while n < len(a):
aba=n
mi.append(aba)
n+=1
for i in mi:
self.b1=MyTButton(text=str(i),size_hint=(1,None),height="100dp",group="selections")
self.cal5.add_widget(self.b1)
self.ids.scd.add_widget(self.cal5, index=3)
def on_state(self, togglebutton): #<----THIS IS THE TUGGLEBUTTON I WANT USE
global amd
tb = togglebutton
text1=tb.text
if text1=="0":
amd="50dp"
elif text1=="1":
amd="100dp"
else:
amd="200dp"
if self.cal6:
self.cal6.parent.remove_widget(self.cal6)
self.cal6 =Spec()
self.ids.scd.add_widget(self.cal6, index=2)
class SecondPage(ScrollView):
pass
class Speca(BoxLayout): #<------ THIS IS THE BOXLAYOUT I WANT TO REMOVE
pass
class Spec(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint=(1,None)
self.height=amd
class MyTButton(ToggleButton):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class ModelSpecifications(BoxLayout): #this is the class I want add after my spinner selection
pass
class Calculation(GridLayout):
pass
class MyApp(App):
pass
MyApp().run()
here is my.kv :
MainWidget:
<MainWidget>:
hideable: hideable
ScreenManager:
id: scmanager
size: root.width, root.height
Screen:
id: scndpage
name: "second"
SecondPage:
Calculation:
id:scd
cols:1
height: self.minimum_height
row_default_height: "70dp"
size_hint_y: None
spacing:"10dp"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint: 1, None
height: "50dp"
pading:"10dp"
spacing:"10dp"
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
Label:
text:"Name:"
color: 0,0,0,1
TextInput:
text:"---"
color: 0,0,0,1
Label:
text:"Surname:"
color: 0,0,0,1
TextInput:
text:"-----"
color: 0,0,0,1
BoxLayout:
id:scdd
size_hint: 1, 1
height: "100dp"
orientation: "vertical"
BoxLayout:
size_hint: 1, None
height: "50dp"
orientation: "horizontal"
Label:
text: " Sellection:"
color: 0,0,0,1
Spinner:
text: 'Home'
values: root.an0
on_text: app.root.btn10(self.text)
Speca: #<------ THIS IS THE BOXLAYOUT I WANT TO REMOVE
Button:
text:" Calculate"
Button:
text:"Sellect"
Button:
text:"Back"
<ModelSpecifications>:
id:anss
pading:"10dp"
spacing:"10dp"
size_hint: 1, None
height: "100dp"
orientation: "horizontal"
<MyTButton#ToggleButton>: #<----THIS IS THE TUGGLEBUTTON I WANT USE
on_state:
app.root.on_state(self)
<Speca>: #<------ THIS IS THE BOXLAYOUT I WANT TO REMOVE
orientation:"vertical"
Label:
color: (1,1,0,1)
text:"I WANT TO REMOVE THIS PART WHEN I PRESS ANY OF TOGGLE BUTTONS"
Please run the app and see it.
Looks to me like speca is a child of the calculation widget with ID scd. So give speca an ID and then Remove speca via ids in on_srate python function.
Kv
SecondPage:
Calculation:
id:scd
speca:
id: speca
py
def on_state():
self.root.ids.scd.remove_widget(self.root.ids.speca)
YES.
When I make those changes;
Kv
SecondPage:
Calculation:
id:scd
speca:
id: speca
py
def on_state():
self.ids.scd.remove_widget(self.ids.speca)
It works.
I want to catch a value from my first screen into my thirdscreen.
In the first, I write my name in an input field.
I go to the next window.
And I try to show my name in this last window.
So I share the code with you and I hope I will find an issue.
Python code :
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
#define ou different screens
class FirstWindow(Screen):
def envoyer(self):
name = self.ids.nom_input.text
self.ids.my_name.text = name
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
#PROBLEM HERE
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
class WindowManager(ScreenManager):
pass
class MonWidget(Widget):
pass
kv = Builder.load_file('new_window.kv')
class AwesomeApp(App):
def build(self):
Window.clearcolor = (0,0,0,0)
return kv
if __name__ == '__main__':
AwesomeApp().run()
My KV CODE :
WindowManager:
FirstWindow:
SecondWindow:
ThirdWindow:
<FirstWindow>:
name: "romain"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
id: my_name
text: "Entrez votre nom"
font_size: 32
TextInput:
id: nom_input
multiline: False
size_hint: (1, .5)
Button:
text: "Next screen"
font_size: 32
on_press: root.envoyer()
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "Mickael"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Entre votre ville"
font_size: 32
TextInput:
id: ville_input
multiline: False
size_hint: (1, .5)
Button:
text: "VĂ©rifier les infos"
font_size: 32
on_release:
app.root.current = "foncier"
root.manager.transition.direction = "left"
Button:
text: "go back first screen"
font_size: 32
on_release:
app.root.current = "romain"
root.manager.transition.direction = "right"
<ThirdWindow>:
name: "foncier"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Verifier : "
font_size: 32
Label:
id: recup_infos
text: ""
font_size: 32
color: 'white'
Button:
text: "On press"
font_size: 32
#Problem HERE
on_press: root.on_press()
Button:
text: "Précedent"
font_size: 32
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "right"
Could you help me ?
Thank you
Romain
In your on_press method:
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
self.root.get_screen('FirstWindow').ids.my_name.text isn't the correct way to get access to widgets outside of the class that you are in right now, or in this situation, screen. The correct way is to use the App.get_running_app() method:
self.ids.recup_infos.text = App.get_running_app().root.ids.First.ids.my_name.text
But before doing that, you have to give ids to the screens of your app, so that the First argument of the method demonstrated above actually makes sense:
WindowManager:
FirstWindow:
id: First
# "First" is the id of the FirstWindow class
# which can also explain why there was a "First" arg
# inside "App.get_running_app().root.ids.First.ids.my_name.text"
SecondWindow:
id: Second
ThirdWindow:
id: Third
Still confused to why this works? Let's divide the attributes of App.get_running_app().root.ids.First.ids.my_name.text into 3 parts:
App.get_running_app(): this method returns the location of your running App class, in this case AwesomeApp. This also acts as self if you were to get the variable inside the App object itself
.root.ids.First: if you read the Kivy documentation, or just simply watched Kivy course videos online, carefully, you should know that self.root.ids inside the App object returns a list of ids of the widgets inside your root widget. In this case, App.get_running_app().root.ids is doing the same thing here, and your screens are passed in the ScreenManager root widget, hence make First an available attribute in App.get_running_app().root.ids
.ids.my_name.text: same as above, App.get_running_app().root.ids.First acts the same as self if you were to run it in your FirstWindow class, which gives you the opportunity to get access to variables outside of your working classes/screens
I am making a selection app. I am using a spinner for multiple choises. After spinner selection I want to add 3 different buttons, which are related to spinner selection. In every selection in spinner those old buttons replace with new ones.
So far I can add different buttons after every selection. However, the buttons are keep adding. I need to clear the old buttons first after every spinner selection.
My class, which contains buttons is "ModelSpecifications".
Long story short, there is something wrong in clear_widgets(). It cant reach "ModelSpecifications".
Here is my main.py;
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.spinner import Spinner
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import ObjectProperty, StringProperty, BooleanProperty
from kivy.properties import ListProperty
from collections import OrderedDict
data1=["mother","father","son"]
data2=["uncle","aunt","grandfather"]
data3=["jack","mike","simon"]
data4=["1898","1975","1985","1885"]
class MainWidget(Widget):
an0=tuple(list(OrderedDict.fromkeys(data1)))
cal5= ObjectProperty()
def btn10(self,text):
#----------here is the part I want to clear the buttons first:
#ModelSpecifications.clear_widgets(ModelSpecifications)
# or
#self.ids["anss"].clear_widgets()
# after that I will add new buttons:
self.cal5 =ModelSpecifications()
a=data2
b=data3
c=data4
mi=[]
n=0
while n < len(a):
aba=(str(a[n])+"\n"+str(b[n])+"\n"+str(c[n]))
mi.append(aba)
n+=1
for i in mi:
self.b1=Button(text=str(i),size_hint=(1,None),height="100dp")
self.cal5.add_widget(self.b1)
self.ids.scd.add_widget(self.cal5, index=3) #here id.scd is the class that ModelSpecifications class is added. And it works fine.
class SecondPage(ScrollView):
pass
class ModelSpecifications(BoxLayout): #this is the class I want add after my spinner selection
pass
class Calculation(GridLayout):
pass
class MyApp(App):
pass
MyApp().run()
And here is my.kv ;
MainWidget:
<MainWidget>:
ScreenManager:
id: scmanager
size: root.width, root.height
Screen:
id: scndpage
name: "second"
SecondPage:
Calculation:
id:scd
cols:1
height: self.minimum_height
row_default_height: "70dp"
size_hint_y: None
spacing:"10dp"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint: 1, None
height: "50dp"
pading:"10dp"
spacing:"10dp"
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
Label:
text:"Name:"
color: 0,0,0,1
TextInput:
text:"---"
color: 0,0,0,1
Label:
text:"Surname:"
color: 0,0,0,1
TextInput:
text:"-----"
color: 0,0,0,1
BoxLayout:
id:scdd
size_hint: 1, 1
height: "100dp"
orientation: "vertical"
BoxLayout:
size_hint: 1, None
height: "50dp"
orientation: "horizontal"
Label:
text: " Sellection:"
color: 0,0,0,1
Spinner:
text: 'Home'
values: root.an0
on_text: app.root.btn10(self.text)
Button:
text:" Calculate"
Button:
text:"Sellect"
Button:
text:"Back"
<ModelSpecifications>:
id:anss #HERE IS MY CLASS THAT I WANT TO CLEAR AND ADD AFTER EVERY SPINNER SELECTION
pading:"10dp"
spacing:"10dp"
size_hint: 1, None
height: "100dp"
orientation: "horizontal"
When you run this code sellect something in spinner. You will see in every selection, app keeps add more buttons;
In your btn10() method, just add:
if self.cal5:
self.cal5.parent.remove_widget(self.cal5)
before the line:
self.cal5 = ModelSpecifications()