Итак, я делаю приложение для составления бюджета, его код довольно большой, поэтому я просто покажу вам основной класс приложения (кстати, у меня нет большого опыта в кодировании). Моя проблема в том, что у меня есть некоторые данные вфайл, который необходимо обновить в моем счетчике и перезапустить. Я действительно не знаю, есть ли лучшее решение для обновления этих виджетов, но сейчас я использую метод Clock для обновления данных.
Так что у меня есть эта функция on_start (), которая должна запускаться мгновеннокогда я запускаю приложение и обновляю прядильщик и перезаписываю элементы новыми обновленными данными в моем файле. Самое смешное, что это иногда работает, а иногда нет, я не понял, что заставляет его работать, а иногда нет.
Я сделал кнопку, которая делает то же самое, когда я нажимаю на нее, все работаеткак очарование, но моя главная цель в том, чтобы всякий раз, когда я запускаю приложение, я не хотел беспокоиться о том, чтобы всегда нажимать кнопку, потому что я должен, иначе мои списки не обновляются ..
Так что вы думаете, чтопроблема с кодом?
add.kv
<SelectableLabel>:
id:selectlabel
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (.5, .5, .5, .2)
Rectangle:
pos: self.pos
size: self.size
<AddWindow>:
orientation:'vertical'
padding: 5
spacing: 10
id: addwindow
FloatLayout:
id:actionid
size_hint_y:None
size: 384, 50
ActionBar:
pos_hint: {'top': 1}
size_hint_x: None
size: 384, 50
ActionView:
padding: 5
ActionPrevious:
title:'GoToMenu'
on_release: root.changescreen('MainWindow')
RecycleView:
id:teft
data: [{'text': str(x).strip('\n')} for x in open('proba.txt')]
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
touch_multiselect: True
BoxLayout:
size_hint_y:None
height: 30
TextInput:
id:termeknev
height: 30
size_hint:(.7, 1)
focus:False
hint_text:'Product name...'
halign:'center'
TextInput:
id:kiadas
size_hint:(.3, 1)
focus:False
hint_text:'Expense'
halign:'center'
BoxLayout:
size_hint_y:None
height: 30
TextInput:
id:vendegszam
size_hint:(.35, 1)
focus:False
hint_text:'Guests'
halign:'center'
Label:
id:currentmonthlabel
text:'<-(Optional)->'
size_hint:(.47, 1)
TextInput:
id:bevetel
size_hint:(.35, 1)
focus:False
hint_text:'Income'
halign:'center'
Button:
text:'Submit'
size_hint:(1, .5)
background_color: .2, .8, .3, 1
on_release:root.appendfile()
BoxLayout:
size_hint:1,None
spacing: 5
Button:
text:'Delete'
size_hint: .2, 1
background_color: .8, .2, .3, 1
on_release:root.delfile()
on_release:root.refresh()
Button:
id:refresh
text:'Refresh'
size_hint:(.8, 1)
on_release:root.refresh()
Button:
id:gotoview
text:'GoToView'
size_hint:(1, .5)
on_release: root.changescreen('ViewWindow')
<PopupWarning>:
id:popwarning
orientation:'vertical'
Label:
text:'Please select a file from the list above.'
Button:
size_hint: 1, .4
text:'OK'
on_release:root.dismiss()
menu.kv
<MainWindow>:
orientation: 'vertical'
padding: 5
spacing: 10
Label:
text:'Track Your Budget'
font_size: 40
size_hint: 1, .3
bold: True
outline_color: .6, .2, .1
outline_width: 2
Button:
id:new
text:'New'
on_release: root.newpopup()
Button:
id:modify
text:'Modify'
on_release: root.changescreen('AddWindow')
Button:
id:view
text:'View'
on_release:root.changescreen('ViewWindow')
Label:
text:''
size_hint:1,.2
Button:
id:exit
text:'Save and exit'
on_release: root.exitapp()
<PopupContent>:
orientation: 'vertical'
spacing: 5
TextInput:
id:popinput
multiline: False
size_hint: 1, .05
hint_text: 'Month Name'
halign: 'center'
font_size: 30
password: False
Button:
id:create
text:'Create'
size_hint: 1, .05
background_color: .2, .8, .3, 1
on_release: root.createfile(popinput.text)
on_release: root.dismiss()
Button:
id:cancel
text:'Cancel'
size_hint: 1, .04
background_color: .8, .2, .3, 1
on_release: root.dismiss()
TesterApp.py
import os, sys
import csv
import time
# os.environ['KIVY_NO_CONSOLELOG'] = '1'
from kivy.config import Config
Config.set('graphics', 'width', '384') # 768
Config.set('graphics', 'height', '683') # 1366
Config.set('graphics', 'resizable', '0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.properties import ObjectProperty, BooleanProperty, StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.label import Label
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview import RecycleViewBehavior
from kivy.clock import Clock
from kivy.lang import Builder
Builder.load_file('menu.kv')
Builder.load_file('add.kv')
Builder.load_file('view.kv')
# FŐ ABLAK
class MainWindow(BoxLayout, Screen):
# ADD WINDOWRA VÁLT
def changescreen(self, screenname):
self.manager.current = screenname
def newpopup(self):
global popup
popup = Popup(title='Create New Month', content=PopupContent(), size_hint=(None,None), size=(350, 200))
popup.open()
def exitapp(self):
sys.exit()
# POPUP
class PopupContent(BoxLayout):
# CSV filet létrehozza
def createfile(self, name):
with open(name + '.csv', 'w', encoding='utf-8') as f:
fieldnames = ['val1', 'val2', 'val3', 'val4', 'val5']
dictwriter = csv.DictWriter(f, fieldnames=fieldnames, delimiter='/')
dictwriter.writeheader()
with open('proba.txt', 'a', encoding='utf-8') as f:
f.write(name+'\n')
# MAGÁT A POUP ABLAKOT ELTŰNTETI
def dismiss(self): # KILÉPIK A MAINWINDOW newpopup()POPUP-ból
Popup.dismiss(popup)
class PopupWarning(BoxLayout):
def dismiss(self):
Popup.dismiss(AddWindow.selectedpopup)
class AddWindow(BoxLayout, Screen, RecycleViewBehavior):
def __init__(self, **kwargs):
super(AddWindow, self).__init__(**kwargs)
self.addwindowdata = self.ids.teft.data
selectedpopup = Popup(title='No file selected !', content=PopupWarning(), size_hint=(None, None), size=(350, 200))
def refresh(self):
Clock.schedule_interval(self.refreshData, 1) # CSAK AKKOR MŰKÖDIK HA FUNKCIÓT ADOK NEKI
# ÉS AZ A FUNKCIÓ VALAMI ÉRTÉKET MEGVÁLTOZTAT
def refreshData(self, *args):
self.ids.teft.data = [{'text': str(x).strip('\n')} for x in open('proba.txt')]
# FŐOLDALRA VISSZA VÁLT
def changescreen(self, screenname):
self.manager.current = screenname
def appendfile(self):###################### EZTMÉG ÁTNÉZNI ÉS CSISZOLNI
try:
with open(selectedvalue + '.csv', 'a', encoding='utf-8', newline='') as f:
writer = csv.writer(f, delimiter='/')
termek = self.ids.termeknev.text
kiadas = self.ids.kiadas.text
vendegszam = self.ids.vendegszam.text
bevetel = self.ids.bevetel.text
datum = time.strftime('%Y-%m-%d')
if termek == '':
termek = ' . . . '
if kiadas == '':
kiadas = 0
if vendegszam == '':
vendegszam = 0
if bevetel == '':
bevetel = 0
lista = termek, kiadas, vendegszam, bevetel, datum
writer.writerow(lista)
self.ids.termeknev.text = ''
self.ids.kiadas.text = ''
self.ids.vendegszam.text = ''
self.ids.bevetel.text = ''
except NameError:
self.selectedpopup.open()
def delfile(self):
try:
os.remove(selectedvalue + '.csv')
with open('proba.txt', 'r+') as f:
r = f.read()
l = list(r.split('\n'))
l.remove(selectedvalue)
o = str('\n'.join(l))
with open('proba.txt', 'w') as f:
f.write(o)
except:
self.selectedpopup.open()
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableLabel(RecycleDataViewBehavior, RecycleViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
global selectedvalue # EZ AZ ALÁBBI IF STATEMENTBŐL
# KISZEDI AZ ÉRTÉKET AMIT VISSZA FOG ADNI az ADDWINDOW CLASSNAK
# ÉS AZON BELÜL AZ APPEND FUNKCIÓNAK
if is_selected:
print("selection changed to {0}".format(rv.data[index].get('text')))
selectedvalue = rv.data[index].get('text')
else:
print("selection removed for {0}".format(rv.data[index]))
class ViewPopup(BoxLayout):
def dismiss(self):
Popup.dismiss(ViewWindow.viewpopup)
class ViewWindow(BoxLayout, Screen):
def __init__(self, **kwargs):
super(ViewWindow, self).__init__(**kwargs)
self.viewwindowdata = self.ids.filespinner.values
viewpopup = Popup(title='INFO', content=ViewPopup(), size_hint=(None, None), size=(350, 200))
def getHonap(*args):
global honapok
honapok = []
with open('proba.txt', 'r', encoding='utf-8') as f:
for file in f:
honapok.append(file.strip('\n'))
return honapok
def showdata(self):
filename = self.ids.filespinner.text
if filename == '':
pass
else:
with open(filename + '.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f, delimiter='/')
nevkiadas = []
kiadasbevetel = []
bevetelvendeg = []
for sor in reader:
val1 = str(sor['val1'])
val2 = str(sor['val2'])
val3 = str(sor['val3'])
val4 = str(sor['val4'])
val5 = str(sor['val5'])
nevkiadas.append(val1.ljust(20)+' '+val2.center(10) + ' ' + val5)
kiadasbevetel.append(val2.ljust(20)+' '+val4.center(10) + ' ' + val5)
bevetelvendeg.append(val4.ljust(20)+' '+val3.center(10) + ' ' + val5)
# EZTMAJD LE EGYSZERŰSÍTENI HA LEHETSÉGES
with open('temp.txt', 'w', encoding='utf-8') as f:
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
f.write(' Product ' + ' Expense ' + ' Date ' + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
for teszt1 in nevkiadas:
f.write(teszt1 + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
with open('temp.txt', 'r', encoding='utf-8') as f:
content1 = f.read()
self.ids.productexpense.text = content1
# ---------------------------------------------------------
with open('temp2.txt', 'w', encoding='utf-8') as f:
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
f.write(' Expense ' + ' Income ' + ' Date ' + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
for teszt2 in kiadasbevetel:
f.write(teszt2 + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
with open('temp2.txt', 'r', encoding='utf-8') as f:
content2 = f.read()
self.ids.expenseincome.text = content2
# ---------------------------------------------------------
with open('temp3.txt', 'w', encoding='utf-8') as f:
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
f.write(' Income ' + ' Guests ' + ' Date ' + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
for teszt3 in bevetelvendeg:
f.write(teszt3 + '\n')
f.write('=' * 20 + ' ' + '=' * 10 + ' ' + '=' * 10 + '\n')
with open('temp3.txt', 'r', encoding='utf-8') as f:
content3 = f.read()
self.ids.incomeguests.text = content3
# ---------------------------------------------------------
# FORCED REFRESH IF THE on_start REFRESH NOT WORKING
def refresh(self, *args):
Clock.schedule_interval(self.refreshData, 1)
try:
self.showdata()
except:
self.ids.productexpense.text = ''
self.ids.expenseincome.text = ''
self.ids.incomeguests.text = ''
pass
def refreshData(self, *args):
self.ids.filespinner.values = self.getHonap()
def changescreen(self, screenname):
self.manager.current = screenname
# ALKALMAZÁS FUTTATÓ
class TesterApp(App):
title = 'Budget App'
def on_start(self):
Clock.schedule_interval(self.update_data, 1)
def update_data(self, *args):
AddWindow.addwindowdata = [{'text': str(x).strip('\n')} for x in open('proba.txt')]
ViewWindow.viewwindowdata = ViewWindow.getHonap() # TALÁN BUGOL
def build(self):
# PÉLDA A SCREEN VÁLTÁSRA
transition = FadeTransition(duration=.06)
screenmanager = ScreenManager(transition=transition)
mainscreen = MainWindow(name='MainWindow')
addscreen = AddWindow(name='AddWindow')
viewscreen = ViewWindow(name='ViewWindow')
screenmanager.add_widget(mainscreen)
screenmanager.add_widget(addscreen)
screenmanager.add_widget(viewscreen)
return screenmanager
if __name__ == '__main__':
TesterApp().run()
view.kv
<ViewWindow>:
orientation:'vertical'
padding: 5
spacing: 10
id: viewwindow
FloatLayout:
id:actionid
size_hint_y:None
size: 384, 50
ActionBar:
pos_hint: {'top': 1}
size_hint_x: None
size: 384, 50
ActionView:
padding: 5
ActionPrevious:
title:'GoToMenu'
on_release: root.changescreen('MainWindow')
Spinner:
id:filespinner
text:'Choose a file'
values:root.getHonap()
text_autoupdate:False
on_text:root.showdata()
on_text:root.refresh()
size_hint: 1, .1
BoxLayout:
# TextInput:
# id:showstat
# readonly:True
# text:''
TabbedPanel:
title:'Asd'
do_default_tab:False
tab_width: 150
tab_height: 30
TabbedPanelItem:
text:'Product/Expense'
RstDocument:
id:productexpense
readonly:True
text:''
line_spacing:5
scroll_y:1
TabbedPanelItem:
text:'Expense/Income'
RstDocument:
id:expenseincome
readonly:True
text:''
scroll_y:1
TabbedPanelItem:
text:'Income/Guests'
RstDocument:
id:incomeguests
readonly:True
text:''
scroll_y:1
Button:
text:'Refresh'
size_hint_y: .1
on_release:root.refresh()
<ViewPopup>:
id:viewwarning
orientation:'vertical'
Label:
text:'Choose a file.'
Button:
size_hint: 1, .4
text:'OK'
on_release:root.dismiss()