Kivy add widgets on different sides of the Layout - python

I have a chat app that uses a widget to print out messages. I want to print these on different sides, so the user input goes on the right and the answer goes on the left. Furthermore, I want the chat box to scroll to the new message. Here is my code, where I tried to use a StackLayout, only to realise it doesn't work:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
class Message(Widget):
pass
class KatApp(App):
def post(self):
msg = self.root.ids.usrinp.text
if len(msg) > 0:
self.root.ids.chatbox.orientation = 'tb-rl'
msgbox = Message()
msgbox.ids.mlab.text = msg
self.root.ids.chatbox.add_widget(msgbox)
self.root.ids.scrlv.scroll_to(msgbox)
self.root.ids.usrinp.text = ''
def resp(self,msg):
if len(msg) > 0:
ansr = msg
self.root.ids.chatbox.orientation = 'tb-lr'
ansrbox = Message()
ansrbox.ids.mlab.text = str(ansr)
self.root.ids.chatbox.add_widget(ansrbox)
self.root.ids.scrlv.scroll_to(ansrbox)
self.root.ids.usrinp.text = ''
def build(self):
return Builder.load_string('''
<Message#Widget>:
size_hint: None, None
height: mlab.height
width: mlab.width
canvas:
Color:
rgba: 0, 1, 0, 0.7
Rectangle:
pos: self.pos
size: self.size
Label:
id: mlab
center: root.center
padding: 10, 10
markup: True
text_size: (None, None)
text: ''
haligh: 'left'
valign: 'top'
size_hint: (1, None)
size: self.texture_size
color: 0, 0, 0
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
ScrollView:
canvas.before:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
StackLayout:
id: chatbox
padding: 10, 10
orientation: 'tb-rl'
BoxLayout:
orientation: 'horizontal'
padding: 10, 10, 10, 10
size_hint: 1, None
height: 50
BoxLayout:
id: inpbox
height: max(40, scrlv.height)
size_hint: 0.9, None
ScrollView:
id: scrlv
width: inpbox.width - 15
x: inpbox.x + 10
y: inpbox.y
height:
(len(usrinp._lines)+1) * usrinp.line_height - 5 \
if (len(usrinp._lines)+1 <= 5) \
else 5 * usrinp.line_height - 5
TextInput:
id: usrinp
valign: 'middle'
halign: 'left'
font_size: 16
multiline: True
size_hint: scrlv.size_hint_x, None
padding: 10, 0, 10, 0
Button:
id: post
border: 0, 0, 0, 0
size: 40, 40
size_hint: None, None
on_press:
root.inp = usrinp.text
app.post()
on_release:
app.resp(root.inp)
''')
if __name__ == "__main__":
KatApp().run()
For the sake of this example, the button on the bottom right sends the user input on_press and answers with the same input on_release.
Also, is it possible to make a maximum width for the message widget, like, if it reaches the middle of the page, it should go on the next line?
One more thing that I'm having a hard time figuring out would be the TextInput. It seems that, with the multiline option, when a word is long enough to go on the next line and I try to delete it, some space remains there and it keeps the box from resizing. To reproduce this, just type "aaaaaaaaaa" until it is on line 3 and try to remove it.

To wrap the width of the widget try this:
Function to read text and create label
def Sender_chat_bubble():
Measure the length of the unwrapped text
Measure = Label(text=self.chatinputfield.text)
Measure.texture_update()
if Measure.texture_size[0]== 0 or self.chatinputfield.text=='':
return 0
if the text is not long, keep same width + 10 for the padding I added
elif Measure.texture_size[0]<250:
xsize = Measure.texture_size[0]
chatbubble = ChatBubble_Send(text=self.chatinputfield.text, width=xsize+10, padding_y=10, padding_x=10)
If the unwrapped text is longer than your limit(250 here) , lets wrap it to 260 (250 + 10 padding)
else:
chatbubble = ChatBubble_Send(text=self.chatinputfield.text, width=250+10, padding_y=10, padding_x=10)
Class to make a color behing the label
class ColorLabelSEND(Label):
bgcolor = ListProperty([0.7, 0.7, 0.7, 0.7])
def __init__(self, **kwargs):
super(ColorLabelSEND, self).__init__(**kwargs)
with self.canvas.before:
r, g, b, a = self.bgcolor
Color(r, g, b, a)
self.rect = Rectangle(
size=self.size,
pos=self.pos)
self.bind(size=self._update_rect,
pos=self._update_rect)
def _update_rect(self, instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
Class to wrap the text and label
class ChatBubble_Send(ColorLabelSEND):
def __init__(self, **kwargs):
super(ChatBubble_Send, self).__init__(**kwargs)
self.size_hint = (None, None)
#Constrain horizontally to size of label and free vertically
self.text_size = (self.width, None)
self.width = self.width + 15
def on_texture_size(self,*args):
self.texture_update()
self.height = self.texture_size[1]

Writing on each side can be done using a BoxLayout.
def post(self):
msg = self.root.ids.usrinp.text
if len(msg) > 0:
msgbox = Message()
msgbox.ids.mlab.text = msg
msgbox.pos_hint = {'right': 1}
self.root.ids.chatbox.add_widget(msgbox)
self.root.ids.scrlv.scroll_to(msgbox)
self.root.ids.usrinp.text = ''
def resp(self, msg):
if len(msg) > 0:
ansr = msg
ansrbox = Message()
ansrbox.ids.mlab.text = str(ansr)
ansrbox.pos_hint = {'x': 0}
self.root.ids.chatbox.add_widget(ansrbox)
self.root.ids.scrlv.scroll_to(ansrbox)
self.root.ids.usrinp.text = ''
And in the builder:
ScrollView:
canvas.before:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
id: chatbox
padding: 10, 10
spacing: 5
After adding pos_hint: {'right': 1} to the input widget, the text now goes on the right side, like this:
The problem now remains with the width of the widget:
I tried setting the width of the widget to max(root.width, mlab.width), but it doesn't work. Also, now, scrolling up doesn't work.

Related

How to recalculate texture_size in Kivy after condition reached

I'm trying to optimize the chat bubble mechanism, but still can't figure out the values that I need to set for my texture_size.
As you can see in the picture below, the first chat bubble seems to be okay, but when the second one has more words and reach the width limit then down the line, the label's texture_size[0] will be replaced as its max-width (the orange one) which means the box containing the label (the green one) that has its size attach to the label's texture_size will have its width set to the max-width and won't be able to track the label's texture_size anymore and cause some gaps as I showed below (the red one).
The gaps should be removed like this:
Here's a small app that I convert from the issue code.
.py file
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import ListProperty,BooleanProperty, StringProperty
from datetime import datetime
class HistoryBox(BoxLayout):
chat_logs = ListProperty()
def send(self, text):
now = datetime.now()
current_time = now.strftime("%H:%M")
self.create_chatbubble(text,True,current_time)
self.ids.field.text = ""
def create_chatbubble(self,message,send_by_user,time):
self.chat_logs.append(
{
"text":message,
"send_by_user": send_by_user,
"time": time,
}
)
class ChatBubble(BoxLayout):
send_by_user = BooleanProperty()
text = StringProperty()
time = StringProperty()
class App(App):
def build(self):
self.root = Builder.load_file("my.kv")
if __name__ == "__main__":
App().run()
.kv file
HistoryBox:
<HistoryBox>:
orientation: "vertical"
RecycleView:
data: root.chat_logs
viewclass: "ChatBubble"
RecycleBoxLayout:
id: box
padding: dp(10)
spacing: dp(15)
orientation: "vertical"
height: self.minimum_size[1]
default_size_hint: 1, None
default_size: None, None
TextInput:
id: field
hint_text: "Write your message"
multiline: False
focus: True
padding: dp(7)
size_hint_y: .6
size_hint_max_y: (len(self._lines)+1)*self.line_height
on_text_validate:
root.send(self.text)
<ChatBubble>:
id: chtbld
md_bg_color: [0, 0, 0, 0]
size_hint_y: None
height: wrapped.height
pos_hint: {'right': 1} if chtbld.send_by_user == True else {'x': 0}
#adaptive_height: True
width: root.width
padding: [10, 0, 10, 0]
orientation: 'vertical'
BoxLayout:
id: wrapped
height: msg_content.height + timed.height + 10
width: msg_content.width + wid1.width + wid2.width
size_hint: None, None
pos_hint: {'right': 1} if chtbld.send_by_user == True else {'x': 0}
canvas.before:
Color:
rgba: 1,1,1,1
RoundedRectangle:
pos: self.pos
size: self.size
radius: [10, 10, (1, -5), 10] if self.pos_hint == {'right': 1} else [10, 10, 10, (1, -5)]
Spacer:
id: wid1
BoxLayout:
orientation: 'vertical'
height: msg_content.height + tc.height + wid3.height
width: msg_content.width
Label:
id: msg_content
text: root.text
width: tc.width if self.texture_size[0] < tc.width else self.texture_size[0]
height: self.texture_size[1]
size_hint_y: None
text_size: chtbld.width-dp(100) if self.width >= chtbld.width-dp(100) else None,None
halign: 'left'
color: 0, 0, 0, 1
BoxLayout:
id: tc
size_hint: None, None
height: timed.height
width: timed.width + 3
pos_hint: {'right': 1}
spacing: 3
Label:
id: timed
text: root.time
size_hint: None, None
size: self.texture_size
font_size: 9
bold: True
text_size: None,None
color: [.8, .8, .8, 1]
Spacer:
id: wid3
height: 5
Spacer:
id: wid2
<Spacer#Widget>:
id: wid
width: 5
size_hint: None, None
Just type anything like "welcomeeeeee toooooooooooooo" then minimize the window till the sentence down the line and you will notice the problem. Any help or advice would be helpful.

Getting text input from the user and print it python using kivy

I am trying to print an input given by a user but all I get is: < ObjectProperty name=input >
I can't use Text Input in my py because python quits if I try to run a program with it installed. I have tried putting the popup in the 'test' class but it just comes up with a different error.
Any help is appreciated,
Thank you.
Here is my code:
In my py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
class MyPopup(Popup):
pass
class Test(Widget):
pass
class TestApp(App):
def build(self):
return Test()
def Process(self):
text = MyPopup.input
print(text)
if __name__ == '__main__':
TestApp().run()
and in my kv:
#:import Factory kivy.factory.Factory
<MyPopup#Popup>
input: text
auto_dismiss: True
size_hint: 0.4, 0.4
TextInput:
id: text
hint_text: 'insert text'
multiline: False
on_text_validate: app.Process()
<Test>:
canvas:
Color:
rgba: 0, 0, 0, 0
Rectangle:
pos: 0, 0
size: self.width, self.height - self.height/6
Color:
rgba: 1, 1, 1, 0.1
Rectangle:
pos: 0, 0
size: self.width/2 + self.width/10, self.height - self.height/6
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: 0, self.height - self.height/6
size: self.width, self.height/6
Button:
id: GL
text: 'In here'
pos: 0 , root.height - root.height/6
on_parent: GLdropdown.dismiss()
on_release: GLdropdown.open(self)
size_hint_y: None
height: root.height/6
width: root.width/7
DropDown:
id: GLdropdown
on_select: btn.text = '{}'.format(args[1])
Button:
id: 'AV'
text: 'press me'
size_hint_y: None
height: 50
on_release: Factory.MyPopup().open()
If you change:
on_text_validate: app.Process()
to:
on_text_validate: app.Process(self.text)
And change the Process() method to:
def Process(self, text):
print(text)
I think it will work as you want.
The problem is that the line:
text = MyPopup.input
makes text a reference to the ObjectProperty of the class MyPopup. What you really want is a reference to the text of the TextInput, which is simply self.text in the TextInput.

How do I add a rectangle graphic behind all my buttons and labels?

I would like to add a rounded rectangle behind each row of widgets containing 3 buttons and two labels all horizontally layout. Each group contents are added dynamically through the input_text and '+' button on the bottom. I have all the major parts working but I can't get the rounded rectangle graphic.
Here is what I've got so far:
I was hoping to create something like this:
Please let me know where I went wrong and how to fix it I'm pretty new in Kivy so I'm just learning.
Thanks.
class Trackers(Screen):
storage = {}
path = ''
def on_pre_enter(self):
self.path = App.get_running_app().user_data_dir + '/'
self.loadData()
for tracker, num in self.storage.items():
self.ids.track.add_widget(Tracker(text=tracker, number=num, data=self.storage))
def addWidget(self):
text_input = self.ids.text_input.text
num = '0'
if text_input not in self.storage.keys():
self.ids.track.add_widget(Tracker(text=text_input, number=num, data=self.storage))
self.storage[text_input] = '0'
self.ids.text_input.text = ''
self.saveData()
class Tracker(BoxLayout):
def __init__(self, text='', number='', data={}, **kwargs):
super().__init__(**kwargs)
self.ids.label.text = text
self.ids.count_add.text = number
class Pess(App):
def build(self):
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '800')
from kivy.core.window import Window
Window.clearcolor = get_color_from_hex('#262829')
return ScreenGenerator()
##### --> .kv file
<Trackers>:
BoxLayout:
orientation: 'vertical'
ActionBar:
height: 45
size_hint_y: None
background_image: ''
background_color: rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]TRACKERS[/b]'
font_size: 21
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'menu'
ActionButton:
text: 'SEND'
color: rgba('#AFB7BA')
on_release: root.send()
ScrollView:
BoxLayout:
id: track
orientation: 'vertical'
font_size: 15
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint_y: None
height: 45
TextInput:
id: text_input
hint_text: 'Add Trackers'
multiline: False
Button:
text: '+'
size_hint_x: None
width: 60
on_release: root.addWidget()
background_color: rgba('#1D7332')
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 4
Button:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').delete_storage(root)
Label:
id: label
font_size: 20
Label:
id: count_add
font_size: 20
text: '0'
Button:
text: '[b]-[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').subtract_num(root)
Button:
text: '[b]+[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').add_num(root)
In your 'kv' file, you can add graphics to the Canvas of your Tracker like this:
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 20, 4, 20, 4 # to keep widgets a bit away from the sides
canvas.before: # use before to keep this under any widgets
Color:
rgba: 1, 0, 0, 1 # any color you want
Rectangle:
pos: self.pos[0] + self.height/2, self.pos[1]
size: self.size[0] - self.height, self.height
Ellipse:
pos: self.pos[0], self.pos[1]
size: self.height, self.height
Ellipse:
pos: self.pos[0] + self.width - self.height, self.pos[1]
size: self.height, self.height
You might want to add some spacing to your track id BoxLayout so that the Tracker widgets don't appear connected.
Here is the entire version of your code that I ran. There are a few lines commented out, since you did not provide all the code:
from kivy.config import Config
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import get_color_from_hex
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
class Trackers(Screen):
storage = {}
path = ''
def on_pre_enter(self):
self.path = App.get_running_app().user_data_dir + '/'
#self.loadData()
for tracker, num in self.storage.items():
self.ids.track.add_widget(Tracker(text=tracker, number=num, data=self.storage))
def addWidget(self):
text_input = self.ids.text_input.text
num = '0'
if text_input not in self.storage.keys():
self.ids.track.add_widget(Tracker(text=text_input, number=num, data=self.storage))
self.storage[text_input] = '0'
self.ids.text_input.text = ''
#self.saveData()
class Tracker(BoxLayout):
def __init__(self, text='', number='', data={}, **kwargs):
super().__init__(**kwargs)
self.ids.label.text = text
self.ids.count_add.text = number
Builder.load_string('''
<Trackers>:
BoxLayout:
orientation: 'vertical'
ActionBar:
height: 45
size_hint_y: None
background_image: ''
background_color: rgba('#0B3242')
ActionView:
ActionPrevious:
title: '[b]TRACKERS[/b]'
font_size: 21
color: rgba('#AFB7BA')
markup: True
on_release: app.root.current = 'menu'
ActionButton:
text: 'SEND'
color: rgba('#AFB7BA')
on_release: root.send()
ScrollView:
BoxLayout:
id: track
orientation: 'vertical'
spacing: 5
font_size: 15
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint_y: None
height: 45
TextInput:
id: text_input
hint_text: 'Add Trackers'
multiline: False
Button:
text: '+'
size_hint_x: None
width: 60
on_release: root.addWidget()
background_color: rgba('#1D7332')
<Tracker>:
count_add: count_add
size_hint_y: None
height: 45
padding: 20, 4, 20, 4
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
pos: self.pos[0] + self.height/2, self.pos[1]
size: self.size[0] - self.height, self.height
Ellipse:
pos: self.pos[0], self.pos[1]
size: self.height, self.height
Ellipse:
pos: self.pos[0] + self.width - self.height, self.pos[1]
size: self.height, self.height
Button:
text: '[b]X[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').delete_storage(root)
Label:
id: label
font_size: 20
Label:
id: count_add
font_size: 20
text: '0'
Button:
text: '[b]-[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').subtract_num(root)
Button:
text: '[b]+[/b]'
markup: True
size_hint_x: None
width: 60
on_release: app.root.get_screen('track').add_num(root)
''')
class Pess(App):
def build(self):
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '800')
from kivy.core.window import Window
Window.clearcolor = get_color_from_hex('#262829')
# Don't have `ScreenGenerator` so just set up `ScreenManager`
sm = ScreenManager()
sm.add_widget(Trackers(name='trackers'))
return sm
#return ScreenGenerator()
Pess().run()

Kivy ToggleButtons did not adjust according to different window sizes

I want my CustomLabels and CustomToggleButtons, which I have created, to change their sizes according to different Window sizes. So this was what I did.
lbl = CustomLabel(text=text, width=self.grid_layout.width, >height=self.grid_layout.height*.5)
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + >len(config_type[i]) * 20, height=self.grid_layout.height * .5)
What I did was set the above widgets' heights and widths above proportionate to a GridLayout containing them. The GridLayout's size is relative to the MainScreen. So if I change the Window size, the GridLayout would follow, followed by the widgets.
However, it did not work. Whenever I change the Window size, the CustomLabels and ToggleButtons would remain the same in size. Would appreciate some help, thanks!
This is the full code:
Builder.load_string('''
#:import hex kivy.utils.get_color_from_hex
<CustomButton>
font_size: self.width * .1
background_color: hex('#669999')
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: None, None
# height: self.parent.parent.height * .1
<CustomLabel>:
font_size: self.height * .5
size_hint: None, None
text_size: self.size
halign: 'left'
# width: self.parent.parent.width
# height: self.parent.parent.height * .1
<CustomBoxLayout>:
orientation: 'vertical'
<CustomStackLayout>:
size_hint_y: None
height: self.minimum_height
spacing: 10
<TempBoxLayout>:
spacing: 10
CustomBoxLayout:
spacing: 10
CustomButton:
text: 'Temp Up'
CustomButton:
text: 'Temp Down'
Label:
text: '20'
font_size: self.width * .1
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
pos: self.pos
size: self.size
<MainScreen>:
grid_layout: grid_layout
CustomBoxLayout:
padding: 10
spacing: 10
canvas.before:
Color:
rgba: hex('#669999')
Rectangle:
size: self.size
pos: self.pos
GridLayout:
id: grid_layout
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_y: .4
BoxLayout:
size_hint_x: .25
TempBoxLayout:
BoxLayout:
size_hint_x: .25
''')
class CustomButton(Button):
pass
class CustomToggleButton(ToggleButton):
pass
class CustomLabel(Label):
pass
class CustomBoxLayout(BoxLayout):
pass
class CustomStackLayout(StackLayout):
pass
class TempBoxLayout(BoxLayout):
pass
class MainScreen(Screen):
store = JsonStore('remote_config.json')
power = str(store['power'][0])
mode = str(store['modes'][0])
fan_speed = str(store['fan_speed'][0])
swing = str(store['swing'][0])
louver = str(store['louver'][0])
min_temp = store['min_temp']
max_temp = store['max_temp']
curr_temp = min_temp
temp_interval = store['interval']
config = [store['power'], store['modes'], store['fan_speed'], store['swing'], store['louver']]
titles = ['Power', 'Mode', 'Fan', 'Swing', 'Louver']
grid_layout = ObjectProperty()
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.grid_layout.rows = 0
print(self.power, self.mode, self.fan_speed, self.swing, self.louver)
for i in range(len(self.config)):
self.populate_controls(self.config[i], self.titles[i])
def populate_controls(self, config_type, text):
if len(config_type) is not 1:
if config_type != 'not available':
stack_layout = CustomStackLayout()
self.grid_layout.rows += 1
lbl = CustomLabel(text=text, width=self.grid_layout.width, height=self.grid_layout.height*.5)
stack_layout.add_widget(lbl)
for i in range(len(config_type)):
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + len(config_type[i]) * 20,
height=self.grid_layout.height * .5)
if i is 0:
btn.state = 'down'
stack_layout.add_widget(btn)
self.grid_layout.add_widget(stack_layout)
class TestApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
TestApp().run()
This is the JSON file:
{
"power": ["off", "on"],
"min_temp": 18,
"max_temp": 32,
"interval": 1,
"modes": ["cool", "fan", "dry"],
"fan_speed": ["auto", "low", "med-low", "med", "med-high", "high"],
"swing": ["off", "auto"],
"louver": ["off", "auto"]
}
I think the easiest fix is to use size_hint. Try changing your CustomLabel and CustomTogglebutton definitions in your kv to:
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: 0.1, 0.5
<CustomLabel>:
font_size: self.height * .5
size_hint: 0.1, 0.5
text_size: self.size
halign: 'left'
And you no longer need width and heightspeifications in your Python code for these objects. Also, change CustomStackLayout to:
<CustomStackLayout>:
size_hint_y: 1.0
spacing: 10

Python : How to remove widget in kivy

I have two file demo.py and demo.kv.
when i run demo.py after click on menu then shows +Add more button.When i click on +Add more button then three row add dynamic because i am using loop there.Every time add three row dynamic
But can anyone tell me when i add new row then how to remove previous three row?
Every time should be show only 3 new row and previous row should be delete.I am using code
def add_more(self):
self.remove_widget(Row())
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
demo.py
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.uix.popup import Popup
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 400)
class User(Popup):
total_value = ObjectProperty(None)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
def add_more(self):
self.ids.rows.add_more()
class Row(BoxLayout):
col_data = ListProperty(["?", "?", "?", "?", "?"])
name = ObjectProperty(None)
button_text = StringProperty("")
col_data3 = StringProperty("")
col_data4 = StringProperty("")
def __init__(self, **kwargs):
super(Row, self).__init__(**kwargs)
class Rows(BoxLayout):
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_more()
def add_more(self):
self.remove_widget(Row())
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
class rv(BoxLayout):
data_items = ListProperty([])
mode = StringProperty("")
def __init__(self, **kwargs):
super(rv, self).__init__(**kwargs)
def add(self):
self.mode = "Add"
popup = User()
popup.open()
class MainMenu(BoxLayout):
content_area = ObjectProperty()
def display(self):
self.rv = rv()
self.content_area.add_widget(self.rv)
class demo(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
demo().run()
demo.kv
<Row>:
size_hint_y: None
height: self.minimum_height
height: 40
Button:
text: root.button_text
size_hint_x: None
top: 200
TextInput:
id : name
text: root.col_data3
width: 300
TextInput:
id: number_input
text: root.col_data4
width: 300
input_filter: 'int'
<Rows>:
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
<User>:
id: user
BoxLayout:
orientation: "vertical"
padding : 20, 5
BoxLayout:
orientation: "horizontal"
#padding : 10, 10
spacing: 10, 10
size: 450, 40
size_hint: None, None
Label:
size_hint_x: .2
text: "Number"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "name"
text_size: self.size
valign: 'bottom'
halign: 'center'
Label:
size_hint_x: .4
text: "Value"
text_size: self.size
valign: 'bottom'
halign: 'center'
ScrollView:
Rows:
id: rows
BoxLayout:
orientation: "horizontal"
size_hint_x: .2
size_hint_y: .2
Button:
text: "+Add More"
on_press: root.add_more()
<rv>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: .25, .03
text: "+Add"
on_press: root.add()
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
BoxLayout:
orientation: "vertical"
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (100, 40)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
content_area: content_area
BoxLayout:
orientation: 'vertical'
spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 2
MenuButton:
text: 'Menu'
size : (50, 12)
on_release: root.display()
BoxLayout:
id: content_area
size_hint_y: 30
remove_widget must receive as argument the instance of the child widget to be removed. Since you can get widget's children using its children attribute, to remove the previous three rows you can do the following:
def add_more(self):
if self.children:
for child in self.children[:3]:
self.remove_widget(child)
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
However, it's simpler to use clear_widgets method:
def add_more(self):
self.clear_widgets(self.children[:3])
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
Since you actually delete all the rows in the BoxLayout, you can do:
def add_more(self):
self.clear_widgets()
for x in range(0, 3):
self.row_count += 1
self.add_widget(Row(button_text=str(self.row_count)))
Edit:
To reset the index simply disregard self.row_count and use the value returned by range:
def add_more(self):
self.clear_widgets()
for x in range(1, 4):
self.add_widget(Row(button_text=str(x)))

Categories

Resources