【日常收支账本】【Day05】编辑账本界面增加删除、更新记录功能——提高代码复用性
一、项目地址
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 效果展示
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区分动账类型,避免同一个功能需要实现三个方法
【日常收支账本】【Day05】编辑账本界面增加删除、更新记录功能——提高代码复用性的更多相关文章
- 2016-1-7第一个完整APP 私人通讯录的实现 6:在联系人界面增加删除联系人的功能
一:在viewDidLoad方法中代码添加一个UIBarButtonItem,并将其的类型设置成垃圾桶,代码如下: - (void)viewDidLoad { [super viewDidLoad]; ...
- 使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题
在前篇随笔<使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理>中介绍了Vue-TreeSelect组件的使用,包括使用v-modal绑定值,normalizer ...
- MFC编辑框接收数据动态更新与刷新方法代码示例-如何让编辑框内容实时更新
MFC编辑框接收数据动态更新与刷新方法代码示例-如何让编辑框内容实时更新 关键代码: //发送数据通知 //from txwtech@163.com LRESULT CCommSampleDlg::O ...
- C# 增加 删除 更新 方法
/// <summary> /// 增加一条数据 /// </summary> public int Add(string 表名,string 参数,string 参数值) { ...
- HAproxy增加日志记录功能和自定义日志输出内容、格式
http://blog.51cto.com/eric1/1854574 一.增加haproxy日志记录功能 1.1 由于数据分析的需要,我们必须打开haproxy日志,记录相关信息. 在配置前,我 ...
- PR 审批界面增加显示项方法
PR 审批界面增加显示项 解决方法 Step 1: 进入审批界面: Step 2: 在上图中,点击左下角'About this Page'查看数据源 点击上图中'Expand ...
- UITableView 编辑模式(增加-删除-移动---自定义左滑 title)
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...
- 小程序实践(十):textarea实现简单的编辑文本界面
textarea是官方的原生组件,用于多行输入 简单的例子,监听文本内容.长度,以及设置最大可输入文本长度 wxml <view class='textarea-Style'> <t ...
- UITableView 编辑模式(增加-删除-移动---自定义左滑 title) xib cell
参考: http://www.open-open.com/lib/view/open1430008922468.html - (void)viewDidLoad { [super viewDidLo ...
- Android 高仿微信(QQ)滑动弹出编辑、删除菜单效果,增加下拉刷新功能
不可否认,微信.QQ列表的滑动删除.编辑功能着实很经典(从IOS那边模仿过来的),然.Android这边,对列表的操作,其实大多还停留上下文菜单来实现. Android如何实现list item的滑动 ...
随机推荐
- [自然语言处理] 自然语言处理库spaCy使用指北
spaCy是一个基于Python编写的开源自然语言处理库.基于自然处理领域的最新研究,spaCy提供了一系列高效且易用的工具,用于文本预处理.文本解析.命名实体识别.词性标注.句法分析和文本分类等任务 ...
- Linux下定时清空某个文件
问题 在一台单点机器部署完成且运行一段时间后,发现页面接口报错,登上机器发现磁盘满了.通过du -lh --max-depth=1 和 du -sh * 找出是哪个文件. 发现是 项目中 stdout ...
- Vue报错:Invalid handler for event "changeUI": got undefined
解决方案 错误代码如下所示: <router-view @hideBox="hideLoginRegisterBox" @changeUI="changeLogin ...
- 配置oracle DG
主库名称:prod1 使用asm存储数据 11.2.03 同一机器备库名称:dg 使用file存储数据 11.2.03 配置备库的参数文件cd $ORACLE_HOME/dbsvi initdg.or ...
- ASP.NET WebForm中在TextBox输入框回车时会触发其他事件,如何处理?
一.TextBox在输入框回车时会触发其他事件,如何解决? 前台代码: <ul> <li><span>名称:</span><asp:TextBox ...
- 【工具】-Reverse-DIE(Detect-It-Easy)
关于 Detect It Easy,或缩写为"DIE"是一个用于确定文件类型的程序.Detect It Easy 是一个多功能的 PE 检测工具,基于 QT 平台编写,主要用于 P ...
- 文心一言 VS 讯飞星火 VS chatgpt (77)-- 算法导论7.3 2题
二.如果用go语言,在 RANDOMIZED-QUICKSORT 的运行过程中,在最坏情况下,随机数生成器 RANDOM 被调用了多少次?在最好情况下呢?以θ符号的形式给出你的答案? 文心一言: 在 ...
- SpringSecurity简明教程
SpringSecurity主要实现UserDetailsService来验证登录的用户信息,和Security的配置类来对登录方式和资源进行限制. 案例包含利用数据库进行登录验证.URL访问限制.自 ...
- SQL取上一条, 下一条记录方法
如果我们需要取id为3的前后的1条记录. 就可以用以下方法 取上一条记录: select * from `表名` where `id`<3 order by `id` desc limit ...
- 【krpano】密码插件
密码插件可以在浏览场景或者执行action之前弹出密码输入框,要求用户输入密码.当密码输入成功了才可以进行下一步操作. 下载地址:http://pan.baidu.com/s/1gfOKKKF 给场景 ...