Kivy Removing elements from a Stack- / GridLayout - python

I made a pop-up. It is basically some rows of options (max. 5 rows).
If I press the '+' button, there will be a new line of options.
If I press the '-' button the last row should diasappear. Unfortunatelly it doesn't.
I tried already the followings out in root.remove():
--> widget_path.pop(0) :
no visual change, I see n rows instead of n-1 .
--> widget_path.pop() :
It removes the first line instead of the last one.
--> Gridlayout (cols: 4) instead of StackLayout: similar results
Could you help me?
Here is my code:
.kv -file;
<FormPopup>:
size_hint: None, None
size: '361pt', '220pt'
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, None
height: '20pt'
orientation: 'horizontal'
Label:
text: 'column1'
Label:
text: 'column2'
Label:
text: 'column3'
Label:
text: 'column4'
# list of sensors
StackLayout:
padding: 0
spacing: 1
orientation: 'lr-tb'
pos_hint: {'center_x': .5, 'center_y': .5}
height: self.minimum_height
id: measure_stack
BoxLayout:
orientation: 'horizontal'
MyButton:
text: '+'
on_release: root.add()
MyButton:
text: '-'
on_release: root.remove()
my .py class:
class FormPopup(Popup):
"""Class: Popup for comments"""
def __init__(self):
super().__init__()
self.error = 0
self.linenumber = 0
self.add()
def add(self):
"""add a new option-line"""
widget_path = self.ids
if self.linenumber < 5 :
sensor_id = 'sensor_' + str(self.linenumber)
widget_path['measure_stack'].add_widget(Spinner(id = sensor_id, size_hint=(None,None), height='20pt', width='85pt', text = '---', values= ('A','B','C') ))
measurand_id = 'measurand_' + str(self.linenumber)
widget_path['measure_stack'].add_widget(Spinner(id = measurand_id, size_hint=(None,None), height='20pt', width='85pt', text = '---', values= ('A','B','C') ) )
branchwise_id = 'branchwise_' + str(self.linenumber)
widget_path['measure_stack'].add_widget(Spinner(id = branchwise_id, size_hint=(None,None), height='20pt', width='85pt', text = '---', values= ('A','B','C')))
procedure_id = 'procedure_' + str(self.linenumber)
widget_path['measure_stack'].add_widget(Spinner(id = procedure_id, size_hint=(None,None), height='20pt', width='85pt', text = '---', values= ('A','B','C')))
self.linenumber += 1
def remove(self):
"""remove one option-line"""
widget_path = self.ids.measure_stack.children
# do not remove if there is only one line
if len(widget_path) > 4:
self.linenumber -= 1
for i in range(4):
widget_path.pop(0)

Get the widget, and remove it.
An example of that:
from kivy.app import App
from kivy.lang import Builder
root = Builder.load_string('''
BoxLayout:
GridLayout:
id: grid
cols: 1
rows: 5
Label:
text: "label 1"
Label:
text: "label 2"
Label:
text: "label 3"
Label:
text: "label 4"
Button:
text: "Remove last item"
on_release: grid.remove_widget(grid.children[0])
''')
class MyApp(App):
def build(self):
return root
MyApp().run()

Related

How to update RecycleView Kivy

This is my first question, so sorry if butcher it.
I'm making an application, that will allow for a more efficient protocol creation for other people at my job.
The problem is, that I'm trying to update created RecycleView, but for some reason it doesn't work. Some solutions on the web advise using .refresh_from_data() method, but it did not work, and all the other solutions are too complicated (or I'm too dumb).
I have this function - add_entry that adds information from two TextInputs as a dictionary inside protocol list.
At the current moment my RecycleView just shows numbers, because no solution have worked, and I actually really struggled to even make a Recycle View.
Here is relevant part of Python code:
class DrillingInfoPage(Screen):
rod = 1
dist = 3
protocol = ListProperty() # {Rod:_,Distance:_,Proc:_,Depth:_}
def add_entry(self, proc, depth):
self.protocol.append({'Rod': 0, 'Distance': 0, 'Proc': 0, 'Depth': 0})
self.protocol[self.rod-1]['Proc'] = proc
self.protocol[self.rod-1]['Depth'] = depth
self.protocol[self.rod-1]['Rod'] = self.rod
self.protocol[self.rod-1]['Distance'] = self.dist
self.rod += 1
self.dist += 3
print(self.protocol)
return self.protocol
class Profile(Screen):
pass
class WindowManager(ScreenManager):
pass
class ColorsPopup(Screen):
popupWindow = None
class Recycle(RecycleView):
def __init__(self, **kwargs):
super(Recycle, self).__init__(**kwargs)
self.data = [{'text': str(x)} for x in range(50)]
kv = Builder.load_file("my.kv")
class MyApp(App):
def build(self):
return kv
if __name__ == '__main__':
MyApp().run()
And here is a relevant part of KV file:
<DrillingInfoPage>:
name: 'third'
BoxLayout:
orientation: 'vertical'
Label:
size_hint: 1, .4
text: 'Drilling Info Page'
GridLayout:
size_hint: 1, .1
cols:3
GridLayout:
cols:2
Label:
text: 'BG'
TextInput:
id: start
multiline: False
GridLayout:
cols:2
Label:
text: 'BG'
TextInput:
id: end
multiline: False
Button:
text: 'Confirm'
on_release: drilling_holes.text = 'BG' + start.text + ' -----> ' + 'BG' + end.text
GridLayout:
size_hint: 1, .1
cols:3
GridLayout:
cols:2
Label:
text: '%:'
TextInput:
id: proc
multiline: False
GridLayout:
cols:2
Label:
text: 'Depth:'
TextInput:
id: depth
multiline: False
Button:
text: 'Add'
on_release: root.add_entry(proc.text, depth.text)
Label:
id: drilling_holes
size_hint: 1, .2
text: ''
Recycle:
id: drilling_data
data: self.data
viewclass: 'Label'
RecycleBoxLayout:
default_size: None, '25dp'
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
size_hint: 1, .2
text: ''
GridLayout:
size_hint: 1, .17
cols:2
Button:
text: 'Go Back'
on_release:
app.root.current = 'second'
root.manager.transition.direction = 'down'
Button:
text: 'Confirm'
on_release:
app.root.current = 'last'
root.manager.transition.direction = 'up'
I've tried creating some functions inside RecycleView class that would refresh the data, as well as inside the DrillingInfoPage class, but nothing seems to work.
I'm new to Python and especially Kivy, therefore hoping someone wise can guide me in the right direction :)
Here how the screen itself looks right now, ideally it should be empty at first and pressing 'Add' button should add a new line
You just have to add the new information to the data list of the RecycleView. It's not clear exactly what you want to add to the RecycleView, but you can just add a line to your add_entry() method like this:
self.ids.drilling_data.data.append({'text': proc}) # add new entry to data list
And that method does not need a return statement

Kivy expand and collapse a panel to hide the inside itens

I'm new to kivy and I am trying do create a widget to colapse and expand after click in a button. When it is colapsed the inside widgets must be hidden, and when it is extended the height should be minimum heigh possible.
I did this implementation, but when expanded i couldn't set the height properly, and the childrens don't hide when colapse...
I know that already there is a widget that do this in kivyMD library, but I need create a differente layout for the button and the childrens, so if someone could help me...
kivy file: teeeste.kv
#:import C kivy.utils.get_color_from_hex
<CLabel#Label>:
color: 0,0,0,1
size_hint_y: None
height: 40
<CButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: C("#455A64") if self.state == "normal" else (0.26,0.26,0.26,0.85)
RoundedRectangle:
pos: self.pos
size: self.size
radius: 10,10,10,10
size_hint: None,None
size: 300,40
<Box#GridLayout>:
canvas.before:
Color:
rgba: 1,1,1,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: 10,10,10,10
cols: 1
size_hint: None,None
width: 300
height: self.minimum_height
orientation: "tb-lr"
FloatLayout:
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
padding: 0,30,0,0
Box:
id: box
CButton:
text: "Press to expand or colapse"
on_release: box.height = 300 if box.height == 40 else 40
CLabel:
text: "abc"
CLabel:
text: "abc"
CLabel:
text: "abc"
CLabel:
text: "abc"
python file:
# coding: utf-8
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.utils import get_color_from_hex
Window.clearcolor = get_color_from_hex("#424242")
class TesteApp(App):
def build(self):
return aplicativo
aplicativo = Builder.load_file("teeeste.kv")
if __name__ == "__main__":
TesteApp().run()
I did the changes suggested by #JohnAnderson and I tried implement other Box inside each other, but sometimes after click on "NUMBER 3" button the childrens inside the related box stop of expand.
Here is the actual code:
kivy: teeeste.ky
#:import C kivy.utils.get_color_from_hex
<CLabel#Label>:
color: 0,0,0,1
size_hint_y: None
height: 40
<CButton>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: C("#455A64") if self.state == "normal" else (0.26,0.26,0.26,0.85)
RoundedRectangle:
pos: self.pos
size: self.size
radius: 10,10,10,10
size_hint: 1.0,None
height: 40
<Box#GridLayout>:
canvas.before:
Color:
rgba: 1,1,1,1
RoundedRectangle:
size: self.size
pos: self.pos
size_hint: 0.8,None
height: self.minimum_height
FloatLayout:
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
padding: 0,30,0,0
ScrollView:
do_scroll_x: False
size_hint: None, 0.9
width: 300
GridLayout:
cols: 1
spacing: 5
size_hint_y: None
height: self.minimum_height
Box:
id: box
cols: 1
CButton:
text: "NUMBER 1"
on_release: self.exp_or_collapse(box)
CLabel:
text: "aaa"
Box:
id: box2
cols: 1
CButton:
text: "NUMBER 2"
on_release: self.exp_or_collapse(box2)
CLabel:
text: "bbb"
Box:
id: box3
cols: 1
CButton:
text: "NUMBER 03"
on_release: self.exp_or_collapse(box3)
Box:
id: box4
cols: 1
CButton:
text: "CHILD 1"
on_release: self.exp_or_collapse(box4)
CLabel:
text: "111"
Box:
id: box5
cols: 1
CButton:
text: "CHILD 2"
on_release: self.exp_or_collapse(box5)
CLabel:
text: "222"
Box:
id: box6
cols: 1
CButton:
text: "CHILD 3"
on_release: self.exp_or_collapse(box6)
CLabel:
text: "333"
Box:
id: box7
cols: 1
CButton:
text: "CHILD 4"
on_release: self.exp_or_collapse(box7)
CLabel:
text: "444"
Box:
id: box8
cols: 1
CButton:
text: "CHILD 5"
on_release: self.exp_or_collapse(box8)
CLabel:
text: "555"
Box:
id: box9
cols: 1
CButton:
text: "CHILD 6"
on_release: self.exp_or_collapse(box9)
CLabel:
text: "666"
Box:
id: box10
cols: 1
CButton:
text: "CHILD 7"
on_release: self.exp_or_collapse(box10)
CLabel:
text: "777"
Box:
id: box11
cols: 1
CButton:
text: "CHILD 8"
on_release: self.exp_or_collapse(box11)
CLabel:
text: "888"
Box:
id: box12
cols: 1
CButton:
text: "CHILD 9"
on_release: self.exp_or_collapse(box12)
CLabel:
text: "999"
Python file: main.py
import kivy
kivy.require("1.11.0")
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
class CButton(Button):
def exp_or_collapse(self, id):
if id.height == self.height:
# expand:
for child in id.children:
child.height = 40
child.opacity = 1
else:
# collapse
for child in id.children:
if child != self:
child.height = 0
child.opacity = 0
class expApp(App):
def build(self):
return Builder.load_file("exp.kv")
if __name__ == "__main__":
expApp().run()
Imagage of the all box colapsed
One way to do that is to write a method to do it in the CButton class:
class CButton(Button):
def exp_or_collapse(self, box):
if box.height == self.height:
# expand
for child in box.children:
child.height = 40
child.opacity = 1
else:
# collapse
for child in box.children:
if child != self:
child.height = 0
child.opacity = 0
Then use that in the kv file:
FloatLayout:
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
padding: 0,30,0,0
Box:
id: box
CButton:
text: "Press to expand or colapse"
on_release: self.exp_or_collapse(box)
CLabel:
text: "abc"
CLabel:
text: "abc"
CLabel:
text: "abc"
CLabel:
text: "abc"
The opacity fiddling is required to completely hide the CLabels, since a Label will display its text even if its size is 0.
The above code is designed to handle only CLabels and CButtons in a Box. To expand it to handle general children of the Box, the exp_or_collapse() can be modified as:
class CButton(Button):
removedChildren = ListProperty([])
def exp_or_collapse(self, id):
if len(self.removedChildren) > 0:
# expand:
# re-add all children
self.removedChildren.reverse()
for child in self.removedChildren:
id.add_widget(child)
self.removedChildren = []
else:
# collapse
# remove all children (except ourself)
for child in id.children:
if child != self:
self.removedChildren.append(child)
for child in self.removedChildren:
id.remove_widget(child)

Is there a way to let the button color remain unchanged after changing/switching screen?

What I'm trying to achieve here is to change the color button in the SurveyHeader widget after clicking either checkboxes. Example: after checking any checkboxes in question 3, I would like only button number "3" to turn red. Also, after clicking next, I would like the button number "3" to remain red. This is where I'm having a hard time., after switching screens, my button color changes to the original color. Is it because I'm creating a new instance of QuestionsScreen1 everytime? If so, is there any workaround for my case?
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition, WipeTransition, NoTransition, SlideTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivymd.theming import ThemeManager
import re
class NavTray1(BoxLayout):
pass
class SurveyHeader(GridLayout):
pass
class SubjectsLayout(GridLayout):
pass
class MainScreen(Screen):
pass
class BeginScreen(Screen):
pass
class QuestionsScreen1(Screen):
def insert_data_A(self, *args):
if args[1] == True:
pass
def insert_data_B(self, *args):
self.question_text1 = MDApp.get_running_app().root.current
if args[1] == True:
pass
class MyScreenManager(ScreenManager):
# Create new page from 1 to 5.
def new_page(self):
if self.current == 'begin':
s = QuestionsScreen1(name='Question 1')
if "Question 1" in self.screen_names:
self.current = 'Question 1'
else:
self.add_widget(s)
self.current = 'Question 1'
elif self.current =='Question 5':
pass
else:
current_page_number = int(re.search(r'\d+', self.current).group(0))
s = QuestionsScreen1(name='Question {}'.format(str(int(current_page_number +1))))
if "Question {}".format(str(int(current_page_number +1))) in self.screen_names:
self.current = 'Question {}'.format(str(int(current_page_number +1)))
else:
self.add_widget(s)
self.current = 'Question {}'.format(str(int(current_page_number + 1)))
# Switch screens according to number.
def switch_pages(self, instance):
question_button = StringProperty()
self.question_button = instance.text
s = QuestionsScreen1(name='Question {}'.format(self.question_button))
if 'Question {}'.format(self.question_button) in self.screen_names:
self.current = 'Question {}'.format(self.question_button)
else:
self.add_widget(s)
self.current = 'Question {}'.format(self.question_button)
# Switch screens between 1 to 5.
def back_page(self):
current_page = StringProperty()
if self.current == 'Question 1':
pass
else:
current_page_number = int(re.search(r'\d+', self.current).group(0))
s = QuestionsScreen1(name='Question {}'.format(str(int(current_page_number -1))))
if "Question {}".format(str(int(current_page_number -1))) in self.screen_names:
self.current = 'Question {}'.format(str(int(current_page_number - 1)))
else:
self.add_widget(s)
self.current = 'Question {}'.format(str(int(current_page_number - 1)))
main_widget_kv = ('''
#: import ScrollEffect kivy.effects.scroll.ScrollEffect
MyScreenManager:
BeginScreen:
<BeginScreen>:
begin_button:begin_button
name: "begin"
canvas.before:
Color:
rgb: .1, .1, .1
FloatLayout:
id: begin_layout
Button:
id: begin_button
text: 'Begin'
font_size: 24
on_press: app.root.new_page()
size_hint: (.4,.25)
pos_hint: {"center_x":.5, "center_y":.2}
color: [0,0,0,1]
<NavTray1>:
cols: 3
padding: '5dp'
spacing: '5dp'
canvas.before:
Color:
rgb: .1, .1, .1
Rectangle:
size: self.size
pos: self.pos
MDRaisedButton:
size_hint_x: None
color: [0.4, 0.4, 0.4, 1]
font_style: 'Body1'
height: dp(80)
text: 'Back'
on_release : app.root.back_page()
BoxLayout:
size_hint_x: 0.4
orientation: 'vertical'
Label:
font_style: 'Body1'
MDRaisedButton:
size_hint_x: None
color: [6/255, 114/255, 0, 1]
height: dp(80)
text: "Next"
font_style: 'Body1'
background_color: [28/138, 1, 35/138, 0.5]
on_release : app.root.new_page()
<QuestionsScreen1>:
BoxLayout:
orientation: 'vertical'
size: root.size
pos: root.pos
SurveyHeader:
size_hint: (1.0, None)
height: '90dp'
id: header
rows: 2
Button:
text: "1"
background_color: [0,255,255,1]
on_release: app.root.switch_pages(self)
Button:
text: "2"
background_color: [0,255,255,1]
on_release: app.root.switch_pages(self)
Button:
text: "3"
background_color: [0,255,255,1]
on_release: app.root.switch_pages(self)
Button:
text: "4"
background_color: [0,255,255,1]
on_release: app.root.switch_pages(self)
Button:
text: "5"
background_color: [0,255,255,1]
on_release: app.root.switch_pages(self)
ScrollView:
size_hint: (1.0, None)
height: root.height - header.height - navtray.height
SubjectsLayout:
cols: 1
Label:
size_hint_y : 0.25
text: app.root.current
text_size: self.size
valign: 'middle'
halign: 'center'
GridLayout:
cols: 2
rows: 2
size_hint_y : 0.75
Label:
text: 'a'
font_size: "20dp"
size_hint_x : 0.8
CheckBox:
group: 'answer_group'
size_hint_x : 0.2
on_active: root.insert_data_A(*args)
Label:
text: 'b'
font_size: "20dp"
size_hint_x : 0.8
CheckBox:
group: 'answer_group'
size_hint_x : 0.2
on_active: root.insert_data_B(*args)
NavTray1:
id: navtray
size_hint: (1.0, None)
height: '90dp'
''')
class TestApp(MDApp):
def __init__(self,**kwargs):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Red"
super().__init__(**kwargs)
def build(self):
main_widget = Builder.load_string(main_widget_kv)
return main_widget
if __name__ == '__main__':
TestApp().run()

Kivy: Updating a field on a ScreenManager screen from a RecycleView

I am struggling with referring to Labels on ScreenManager screens. I have a RecycleView and the class accumulates a total in the init. I would like to put this total on the screen outside the RecycleView. The id in the .kv file is t_pay. The total is accumulated in the Nq_rv class as self.total_bill. How do I take the total from this class and update the total field on the pay screen?
Note the total field at the bottom of this screenshot:
My main.py file is:
class Nq_rv(RecycleView):
def __init__(self, **kwargs):
super(Nq_rv, self).__init__(**kwargs)
bill_text = []
self.total_bill = 0.0
with open('bill.csv') as bill:
bill_reader = csv.reader(bill)
for row in bill_reader:
for item in range(len(row)):
if item < 2:
item_text = row[item]
else:
item_text = '{0:.2f}'.format(float(row[2]))
self.total_bill += float(row[2]) #total accumulation
text_row = {'text': item_text}
bill_text.append(text_row)
self.data = bill_text
#How do I update the t-pay field in the .kv file?
class Sm(ScreenManager):
total_pay = ObjectProperty() #I don't know if this is needed
def send_survey(self):
mypopup = MyPopup()
mypopup.show_popup('Survey', 'Survey sent!', 'OK!')
def pay(self):
mypopup = MyPopup()
mypopup.show_popup('Pay', 'Please put your card in the card reader and follow the prompts.', 'OK!')
def tip_slider_update(self):
self.ids.pay_screen.tip.text = '{0:.2f}'.format(float(self.ids.pay_screen.total_pay.text) * self.ids.pay_screen.tip_sldr.value)
def close_app(self):
App.get_running_app().stop()
class Pay_screen(Screen):
pass
class Survey_screen(Screen):
pass
class Finish_screen(Screen):
pass
class ImageButton(ButtonBehavior, Image):
pass
class Nq_button(Button):
pass
class MyPopup(Popup):
def show_popup(self, title_text, label_text, button_text):
mytext= label_text
content = BoxLayout(orientation="vertical")
content.add_widget(Label(text=mytext, font_size=20, text_size=(300, None)))
mybutton = Button(text="Ok!", size_hint=(1,.20), font_size=20)
content.add_widget(mybutton)
mypopup = Popup(content = content,
title = title_text,
auto_dismiss = False,
size_hint = (.5, .5))
mybutton.bind(on_press=mypopup.dismiss)
mypopup.open()
class nextqualApp(App):
icon = 'nextqual.png'
title = 'Pay / survey / join'
if __name__ == '__main__':
nextqualApp().run()
my .kv file is nextqual.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
Sm:
id: sm
transition: FadeTransition()
Pay_screen:
id: pay_screen
manager: sm
Survey_screen:
id: survey_screen
manager: sm
<Nq_check_label#Label>:
markup: True
multiline: True
<Nq_check_items#Label>:
color: 0,0,0,1
<Nq_rv>:
viewclass: 'Nq_check_items'
RecycleGridLayout:
cols: 3
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
<Pay_screen>:
name: 'pay'
total_pay: t_pay
BoxLayout:
orientation: "vertical"
padding: 6
font_size: '24'
BoxLayout:
size_hint_y: None
height: "40dp"
Button:
text: "Pay your bill"
on_release: app.root.current = 'pay'
Button:
text: "Tell us how we did"
on_release: app.root.current = 'survey'
Button:
text: "I'm finished"
BoxLayout:
BoxLayout:
padding: 12
orientation: 'vertical'
BoxLayout:
height: "40dp"
size_hint_y: None
Label:
text: 'Table: 4'
Label:
text: 'Server: Julie'
Label:
text: 'Check # 58645'
BoxLayout:
canvas:
Color:
rgb: 255,255,255,255
Rectangle:
size: self.size
pos: self.pos
Nq_rv:
BoxLayout:
height: "30dp"
size_hint_y: None
Label:
text: 'Total check:'
size_hint_x: 75
#This is the field I want to update!
Label:
id: t_pay
text: '0.00'
halign: 'right'
size_hint_x: 25
<Survey_screen>:
name: "survey"
BoxLayout:
orientation: "vertical"
padding: 6
font_size: '24'
BoxLayout:
size_hint_y: None
height: "40dp"
Button:
text: "Pay your bill"
on_release: app.root.current = 'pay'
Button:
text: "Tell us how we did"
on_release: app.root.current = 'survey'
Button:
text: "I'm finished"
BoxLayout:
BoxLayout:
height: "100dp"
size_hint_y: None
Label:
size_hint_x: 40
Button:
size_hint_x: 20
text:"Send survey"
halign: "center"
on_press: app.root.send_survey()
Label:
size_hint_x: 40
embryo asked for some sample data. the file 'bill.csv' looks like this:
1,Seafood Sampler,15.99
1,Tea Smoked Duck,19.95
2,Shredded Duck with Ginger,22
1,Deli Rueben,9.95
1,Sam Adams,3
1,Cotswold Premium,4
1,Btl Pinot Noir,25
The idea of creating custom classes is to give you custom properties, for example Nq_rv is not only a RecycleView but a class that you can new properties, for example you can give the property total_bill that has the information of the total. That property will be accessible from the outside so you can make a binding with the text of t_pay:
*.py
class Nq_rv(RecycleView):
total_bill = NumericProperty(0.00) # <-- new property
def __init__(self, **kwargs):
super(Nq_rv, self).__init__(**kwargs)
self.load_data()
def load_data(self):
bill_text = []
total = 0.0
with open('bill.csv') as bill:
bill_reader = csv.reader(bill)
for row in bill_reader:
for item, val in enumerate(row):
if item < 2:
item_text = val
else:
item_text = '{0:.2f}'.format(float(val))
total += float(val) #total accumulation
text_row = {'text': item_text}
bill_text.append(text_row)
self.data = bill_text
self.total_bill = total # <-- update property
*.kv
BoxLayout:
canvas:
Color:
rgb: 255,255,255,255
Rectangle:
size: self.size
pos: self.pos
Nq_rv:
id: rv # <-- set id
BoxLayout:
height: "30dp"
size_hint_y: None
Label:
text: 'Total check:'
size_hint_x: 75
#This is the field I want to update!
Label:
id: t_pay
text: '{0:.2f}'.format(rv.total_bill) # <--- binding
halign: 'right'
size_hint_x: 25

Python Kivy. My program should append the textfile, but is does not

Textfile should look like this :
e.g
Walking 61.0/2018-09-04 79.0/2018-10-04
Running 24.0/2018-09-04 33.0/2018-10-04
The point of this function is to append the textfile with the new value of the slider or to change one.
There are some names for the slider and each of them can have many values which consist of a slider.value and the current date. If today is not the date of the last value - then we append the file.
If today is the same date as the date of the last value - then it is supposed to change it(I did not do it yet, but this is not a problem, i will do it myself after I solve this problem).
Here is the full Python file and Kivy files, nothing but def save_values matters. Everything else is just to make the program working for you.
Python
from kivy.app import App
import time
import datetime
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.uix.slider import Slider
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.config import Config
screen_width = 450
screen_height = 800
Config.set("graphics", "resizable","1")
Config.set("graphics", "width", screen_width)
Config.set("graphics", "height", screen_height)
languages = ["Reading","Writing","Running","Climbing"]
spawned_List = ["False"]
class MenuScreen(Screen):
pass
class JobChoiceScreen(Screen):
def changing_screen(self, instance, *args):
self.manager.current= "sliderScreen"
screenSlider = self.manager.get_screen('sliderScreen')
text = str(instance.text)
screenSlider.changing_label(text)
def on_pre_enter(self, *args):
if spawned_List[0] == "False":
for x in range(0,len(languages)):
word = languages[x]
word = str(word)
btn = Button(text = word, size_hint=(None, None), size = (140,70),
font_size = 18, bold = True, color = [0,1,1,1], background_color = (.156, .172, .24, 0.7),
on_release = self.changing_screen)
self.ids.container.add_widget(btn)
spawned_List[0] = "True"
self.ids.boxLayBottom.add_widget(Widget(size_hint=(1, .4)))
self.ids.datesContainer.add_widget(Button(text = "Day back", size_hint=(.28, 1), font_size = 18, bold = True, color = [0,1,1,1], background_color = (.176, .192, .44, 0.7)))
self.ids.datesContainer.add_widget(Widget(size_hint=(.44, 1)))
self.ids.datesContainer.add_widget(Button(text = "Day forward", size_hint=(.28, 1), font_size = 18, bold = True, color = [0,1,1,1], background_color = (.176, .192, .44, 0.7)))
class SliderScreen(Screen):
def save_values(self, *args, **kwargs):
date = (datetime.datetime.now().strftime("%y-%m-%d"))
written = (str(self.ids.my_slider.value)+ "/" + date + " ")
print("started save_values")
with open('values.txt', 'r') as fileValues:
lines = fileValues.readlines()
print("opened the file")
with open('values.txt', 'a') as fileValues:
for i, line in enumerate(lines):
if line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = line + ((self.ids.my_label.text) + " " + written)
print(line)
if not line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = (" " + written)
print(line)
print("hello bill")
def changing_label(self, text):
self.ids.my_label.text = text
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("manager.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kivy
ScreenManagement:
#transition: FadeTransition()
MenuScreen:
JobChoiceScreen:
SliderScreen:
<MenuScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "menu"
BoxLayout:
padding: [10,10,10,10]
orientation: "vertical"
Widget:
size_hint: [1,0.2]
BoxLayout:
Button:
bold: True
color: [0,1,1,1]
on_release: app.root.current = "list_of_jobs"
text: "Change"
size_hint: [0.28,1]
font_size: 20
background_color: (.156, .172, .24, 0.7)
Widget:
size_hint: [0.44,1]
Button:
bold: True
color: [.5,0, .8, .7]
text: "View \n Progress"
size_hint: [0.28,1]
font_size: 20
halign: "center"
valign: "center"
background_color: (.156, .172, .24, 0.7)
on_release: app.root.current = "sliderScreen"
Widget:
size_hint: [1,0.2]
<JobChoiceScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "list_of_jobs"
BoxLayout:
orientation: "vertical"
padding: [10,10,10,10]
BoxLayout:
orientation: "vertical"
id: boxLayBottom
size_hint: (1,.1)
BoxLayout:
id: datesContainer
orientation: "horizontal"
size_hint: (1,.6)
AnchorLayout:
anchor_x: "center"
acnhor_y: "top"
size_hint: (1,.8)
GridLayout:
id: container
cols: 3
spacing: 5
BoxLayout:
orientation: "vertical"
id: boxContainer
size_hint: (1,.1)
Button:
text: "Back to Menu"
on_release: app.root.current = "menu"
bold: True
color: [0,1,1,1]
background_color: (.176, .192, .44, 0.7)
<SliderScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "sliderScreen"
BoxLayout:
padding: [10,10,10,10]
orientation: "vertical"
id: my_label_container
Slider:
id: my_slider
min: 0
max: 100
value: 0
orientation: "vertical"
size_hint: [1, 0.7]
step: 1
Label:
id: my_label
size_hint: [1, 0.2]
bold: True
font_size: 40
text: ""
Button:
size_hint: [1, 0.1]
bold: True
on_release: app.root.current = "menu"
text : "Back Home"
font_size: 20
halign: "center"
valign: "center"
background_color: (.156, .172, .24, 0.7)
on_press: root.save_values()
def save_values
def save_values(self, *args, **kwargs):
date = (datetime.datetime.now().strftime("%y-%m-%d"))
written = (str(self.ids.my_slider.value)+ "/" + date + " ")
print("started save_values")
with open('values.txt', 'r') as fileValues:
lines = fileValues.readlines()
print("opened the file")
with open('values.txt', 'a') as fileValues:
for i, line in enumerate(lines):
if line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = line + ((self.ids.my_label.text) + " " + written)
print(line)
if not line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = (" " + written)
print(line)
print("hello bill")
I see two problems with your code:
In your save_values() method, You are opening the values.txt file twice at the same time with the same name, but with different modes. I think you need to unindent the second with open block, remove the second with open statement, and modify the mode in the first with open statement to r+. So your code should look something like:
with open('values.txt', 'r+') as fileValues:
lines = fileValues.readlines()
print("opened the file")
for i, line in enumerate(lines):
You never call any write routine, so nothing gets written. When you want to append line/lines to values.txt, you need to call fileValues.write() or fileValues.writelines().
I have not looked at your code logic, so I will not comment on that.

Categories

Resources