一、項目地址 https://github.com/LinFeng-BingYi/DailyAccountBook 二、新增 1. 增加刪除記錄功能 1.1 功能詳述 點擊刪除按鈕後,獲取對應行的數據組成字典,用字典的鍵值對匹配到對應日期的記錄元素; 接著用該字典數據沖正存款賬戶餘額(實現思路為新增 ...
一、項目地址
https://github.com/LinFeng-BingYi/DailyAccountBook
二、新增
1. 增加刪除記錄功能
1.1 功能詳述
- 點擊刪除按鈕後,獲取對應行的數據組成字典,用字典的鍵值對匹配到對應日期的記錄元素;
- 接著用該字典數據沖正存款賬戶餘額(實現思路為新增記錄時的反向操作),同時刪除記錄元素;
- 最後再更新表格。
1.2 代碼實現
def deleteTableRow(self, triggeredBtn, tableWidget):
print("觸發了刪除按鈕")
# 獲取觸發信號的控制項所在行號
current_row = tableWidget.indexAt(triggeredBtn.parent().pos()).row()
if tableWidget == self.tableWidget_expense:
const_class = expenseConst
action = 'expense'
elif tableWidget == self.tableWidget_income:
const_class = incomeConst
action = 'income'
elif tableWidget == self.tableWidget_movement:
const_class = movementConst
action = 'movement'
else:
print('未知控制項觸發新增按鈕!')
return
# 獲取待刪除行的數據
old_data_dict = self.getExistTableCell(tableWidget, current_row, const_class)
if old_data_dict is None:
print("獲取待刪除數據失敗!!")
return
print("待刪除記錄內容為: \n", old_data_dict)
if self.file_processor.deleteRecord(old_data_dict, self.dateEdit.text().replace('/', ''), action):
print("刪除成功!")
# 把刪除結果寫入文件
self.file_processor.writeXMLFile(self.lineEdit_file_path.text())
# 更新self.file_parse_result以及記錄表
records_list = self.file_parse_result[action + 's']
records_list.pop(current_row)
self.updateRecordTable(tableWidget, records_list, const_class)
其中處理xml文件的方法代碼如下:
def deleteRecord(self, old_record_dict, date_str, action):
e_date = self.getSpecificDateElement(date_str)
if isinstance(e_date, int):
print("未找到這一天的數據!")
return False
if action == 'expense':
action_path = ".//expenses"
record_path = """.//expense[@necessity='{}'][@associatedFund='{}'][value='{}'][category='{}'][detail='{}'][describe='{}'][from='{}']""".format(
old_record_dict['necessity'],
old_record_dict['associatedFund'],
old_record_dict['value'],
old_record_dict['category'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['from'])
elif action == 'income':
action_path = ".//incomes"
record_path = """.//income[@associatedFund='{}'][value='{}'][category='{}'][detail='{}'][describe='{}'][to='{}']""".format(
old_record_dict['associatedFund'],
old_record_dict['value'],
old_record_dict['category'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['to'])
elif action == 'movement':
action_path = ".//movements"
record_path = """.//movement[value='{}'][detail='{}'][describe='{}'][from='{}'][to='{}']""".format(
old_record_dict['value'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['from'],
old_record_dict['to'])
else:
print("未知的動賬操作!!")
return False
# print(record_path)
e_action = e_date.find(action_path)
e_record = e_action.find(record_path)
if e_record is None:
print("未找到待刪除的記錄")
return False
e_action.remove(e_record)
if action == 'movement':
self.modifyBalance(old_record_dict['from'], Decimal(old_record_dict['value']))
self.modifyBalance(old_record_dict['to'], Decimal(old_record_dict['value']) * (-1))
else:
self.reversalVariation(old_record_dict, e_date)
return True
def reversalVariation(self, change_dict, e_date):
"""
Describe: 刪除某條記錄時,需要衝正原來的記錄,將回退對應的存款賬戶數值變化、以及餘額
Args:
change_dict: dict
記錄字典
e_date: Element
指定日期的day元素
"""
e_variation = e_date.find(".//variation")
if e_variation is None:
print("沖正記錄時異常!!該記錄不存在餘額變化")
return
if 'from' in change_dict:
e_fund_variety = e_variation.find(".//fund[category='{}']/out".format(change_dict['from']))
if e_fund_variety is None:
print("沖正記錄時異常!!該記錄不存在餘額變化")
return
e_fund_variety.text = str((Decimal(e_fund_variety.text) - Decimal(change_dict['value'])).quantize(Decimal('0.00')))
self.modifyBalance(change_dict['from'], Decimal(change_dict['value']))
self.reversalAssociatedFund(e_variation, change_dict, 'from')
if 'to' in change_dict:
e_fund_variety = e_variation.find(".//fund[category='{}']/in".format(change_dict['to']))
if e_fund_variety is None:
print("沖正記錄時異常!!該記錄不存在餘額變化")
return
e_fund_variety.text = str((Decimal(e_fund_variety.text) - Decimal(change_dict['value'])).quantize(Decimal('0.00')))
self.modifyBalance(change_dict['to'], Decimal(change_dict['value'])*(-1))
self.reversalAssociatedFund(e_variation, change_dict, 'to')
def reversalAssociatedFund(self, e_variation, change_dict, from_or_to):
"""
Describe: 沖正關聯賬戶
Args:
e_variation: Element
change_dict: dict
from_or_to: ['from', 'to']
"""
# print(change_dict['associatedFund'])
if 'associatedFund' in change_dict and change_dict['associatedFund'] != 'None':
print('執行了associatedFund沖正,操作為', from_or_to)
if e_variation.find(".//fund[category='{}']".format(change_dict['associatedFund'])) is None:
print("沖正記錄時異常!!該記錄不存在關聯賬戶餘額變化")
return
if from_or_to == 'from':
e_fund_variety = e_variation.find(".//fund[category='{}']/out".format(change_dict['associatedFund']))
flag = 1
elif from_or_to == 'to':
e_fund_variety = e_variation.find(".//fund[category='{}']/in".format(change_dict['associatedFund']))
flag = -1
else:
print('未知的收支動作!')
return
e_fund_variety.text = str((Decimal(e_fund_variety.text) - Decimal(change_dict['value'])).quantize(Decimal('0.00')))
self.modifyBalance(change_dict['associatedFund'], Decimal(change_dict['value'])*flag)
2. 增加更新記錄功能
2.1 功能詳述
- 點擊更新按鈕後,獲取對應行的數據組成新記錄字典;
- 同時根據行號獲取編輯賬本界面的self.file_parse_result屬性對應的舊記錄字典(每次更新xml文件時,該屬性都會同步);
- 接著用舊字典數據沖正存款賬戶餘額(實現思路為新增記錄時的反向操作),再用新字典數據更新賬戶餘額,>- 最後再更新self.file_parse_result屬性。
2.2 代碼實現
def updateTableRow(self, triggeredBtn, tableWidget):
print("觸發了新增按鈕")
# 獲取觸發信號的控制項所在行號
current_row = tableWidget.indexAt(triggeredBtn.parent().pos()).row()
if tableWidget == self.tableWidget_expense:
const_class = expenseConst
action = 'expense'
elif tableWidget == self.tableWidget_income:
const_class = incomeConst
action = 'income'
elif tableWidget == self.tableWidget_movement:
const_class = movementConst
action = 'movement'
else:
print('未知控制項觸發新增按鈕!')
return
# 獲取被更新的舊數據(文件解析後,記錄順序與表格順序相同)
old_data_dict = self.file_parse_result[action+'s'][current_row]
print("舊記錄內容為: \n", old_data_dict)
# 獲取更新後的新數據
new_data_dict = self.getExistTableCell(tableWidget, current_row, const_class)
if new_data_dict is None:
print("獲取更新後的數據失敗!!")
return
print("更新後的記錄內容為: \n", new_data_dict)
if self.file_processor.updateRecord(old_data_dict, new_data_dict, self.dateEdit.text().replace('/', ''), action):
print("更新成功!")
# 把刪除結果寫入文件
self.file_processor.writeXMLFile(self.lineEdit_file_path.text())
# 更新self.file_parse_result
self.file_parse_result[action+'s'][current_row] = new_data_dict
# print(self.file_parse_result)
其中處理xml文件的方法代碼如下:
def updateRecord(self, old_record_dict, new_record_dict, date_str, action):
e_date = self.getSpecificDateElement(date_str)
if isinstance(e_date, int):
print("未找到這一天的數據!")
return False
if action == 'expense':
action_path = ".//expenses"
record_path = """.//expense[@necessity='{}'][@associatedFund='{}'][value='{}'][category='{}'][detail='{}'][describe='{}'][from='{}']""".format(
old_record_dict['necessity'],
old_record_dict['associatedFund'],
old_record_dict['value'],
old_record_dict['category'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['from'])
elif action == 'income':
action_path = ".//incomes"
record_path = """.//income[@associatedFund='{}'][value='{}'][category='{}'][detail='{}'][describe='{}'][to='{}']""".format(
old_record_dict['associatedFund'],
old_record_dict['value'],
old_record_dict['category'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['to'])
elif action == 'movement':
action_path = ".//movements"
record_path = """.//movement[value='{}'][detail='{}'][describe='{}'][from='{}'][to='{}']""".format(
old_record_dict['value'],
old_record_dict['detail'],
old_record_dict['describe'],
old_record_dict['from'],
old_record_dict['to'])
else:
print("未知的動賬操作!!")
return False
# print(record_path)
e_action = e_date.find(action_path)
e_record = e_action.find(record_path)
if e_record is None:
print("未找到待刪除的記錄")
return False
# 修改了數值則需要衝正
if old_record_dict['value'] != new_record_dict['value']:
# 先沖正原記錄數據
# 在用新數據修改賬戶變化和餘額
if action == 'movement':
self.modifyBalance(old_record_dict['from'], Decimal(old_record_dict['value']))
self.modifyBalance(old_record_dict['to'], Decimal(old_record_dict['value']) * (-1))
self.modifyBalance(new_record_dict['from'], Decimal(new_record_dict['value']) * (-1))
self.modifyBalance(new_record_dict['to'], Decimal(new_record_dict['value']))
else:
self.reversalVariation(old_record_dict, e_date)
self.organizeVariation(new_record_dict, e_date)
# 修改記錄數據
for key in new_record_dict.keys():
if key == 'necessity':
e_record.attrib['necessity'] = new_record_dict['necessity']
elif key == 'associatedFund':
e_record.attrib['associatedFund'] = new_record_dict['associatedFund']
else:
e_record.find(".//"+key).text = str(new_record_dict[key])
return True
3. 優化界面控制項(內置spinBox、增加按鈕切換日期)
3.1 功能詳述
將記錄表格數值(value)列內置QSpinBox,以避免存於文件的數值小數點位不一致;增加按鈕來控制日期的切換
3.2 效果展示
數值(value)列內置QSpinBox
增加按鈕來控制日期的切換
3.3 代碼實現
# 內置QDoubleSpinBox
spinBox = QDoubleSpinBox(decimals=2)# 設置保留小數後2位
# 設置範圍,預設為[0.0, 100.0)。必須在調整數值前設置,否則大於等於100.0時會變成99.99
spinBox.setRange(0.0, 100000000.0)
spinBox.setSingleStep(0.1) # 設置步長
spinBox.setValue(value) # 調整數值
tableWidget.setCellWidget(current_row, keys_list.index(key), spinBox)
# 日期切換
# 利用QDate類的addDays(int)方法
self.pushButton_prev_day.clicked.connect(lambda: self.dateEdit.setDate(self.dateEdit.date().addDays(-1)))
self.pushButton_post_day.clicked.connect(lambda: self.dateEdit.setDate(self.dateEdit.date().addDays(1)))
三、開發總結
1. 提高代碼復用性
最近幾篇都沒有技術含量,就不總結了。唯一值得一提的就是提高代碼復用性。
- 對於支出、收入、轉移三種動賬類型,欄位大量重覆,於是創建表格時,將所有列的初始化集中到一個函數中,根據列名執行對應初始化方式。
- 通過設置ExpenseConst、IncomeConst、MovementConst三個具有同名常量的類,更好地支持代碼復用
- 第二章刪除和新增記錄時修改xml文件的方法
deleteRecord(old_record_dict, date_str, action)
和updateRecord(self, old_record_dict, new_record_dict, date_str, action)
是通過action區分動賬類型,避免同一個功能需要實現三個方法
本文來自博客園,作者:林風冰翼,轉載請註明原文鏈接:https://www.cnblogs.com/LinfengBingyi/p/17756104.html