翼度科技»论坛 编程开发 python 查看内容

【日常收支账本】【Day03】完成编辑账本界面的新增动账记录功能——通过Ele

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
一、项目地址

https://github.com/LinFeng-BingYi/DailyAccountBook
二、新增

1. 解析xml文件

1.1 功能详述

解析所设计的xml文件格式,并将所得数据存入变量。
→→→点击查看xml格式←←←
  1. <DailyAccountBook>
  2.     <balance>
  3.         <fund>
  4.             <value>5000.00</value>
  5.             <category>0</category>
  6.             <fundName>微信零钱</fundName>
  7.         </fund>
  8.         <fund>
  9.             <value>999.00</value>
  10.             <category>1</category>
  11.             <fundName>中国银行卡</fundName>
  12.         </fund>
  13.         <fund>
  14.             <value>90.00</value>
  15.             <category>2</category>
  16.             <fundName>羊城通</fundName>
  17.         </fund>
  18.         <fund>
  19.             <value>1700.07</value>
  20.             <category>3</category>
  21.             <fundName>支付宝余额宝</fundName>
  22.         </fund>
  23.         <fund>
  24.             <value>5000.00</value>
  25.             <category>4</category>
  26.             <fundName>代管存款</fundName>
  27.         </fund>
  28.     </balance>
  29.     <year value="2023">
  30.         <month value="09">
  31.             <day value="11">
  32.                 <expenses>
  33.                     <expense necessity="True" associatedFund="None">
  34.                         <value>5.00</value>
  35.                         <category>1</category>
  36.                         <detail>地铁</detail>
  37.                         <describe>早上上班。羊城通卡余额=100-5=95元</describe>
  38.                         <from>2</from>
  39.                     </expense>
  40.                     <expense necessity="True" associatedFund="None">
  41.                         <value>5.00</value>
  42.                         <category>1</category>
  43.                         <detail>地铁</detail>
  44.                         <describe>晚上下班。羊城通卡余额=95-5=90元</describe>
  45.                         <from>2</from>
  46.                     </expense>
  47.                     <expense necessity="False" associatedFund="None">
  48.                         <value>1.00</value>
  49.                         <category>12</category>
  50.                         <detail>业务手续费</detail>
  51.                         <describe>微信零钱提现1000的手续费</describe>
  52.                         <from>0</from>
  53.                     </expense>
  54.                 </expenses>
  55.                 <incomes>
  56.                     <income associatedFund="4">
  57.                         <value>3000.00</value>
  58.                         <category>5</category>
  59.                         
  60.                         <detail>转账</detail>
  61.                         <describe>托管人转给本人3000,帮忙存放。本人微信零钱余额=3000+3000=6000元;同时代管存款余额=2000+3000=5000元</describe>
  62.                         <to>0</to>
  63.                     </income>
  64.                     <income associatedFund="None">
  65.                         <value>0.07</value>
  66.                         <category>2</category>
  67.                         <detail>理财</detail>
  68.                         <describe>昨日余额宝收益。余额=1700+0.07=1700.07</describe>
  69.                         <to>3</to>
  70.                     </income>
  71.                 </incomes>
  72.                 <movements>
  73.                     
  74.                     <movement>
  75.                         <value>999.00</value>
  76.                         <detail>提现</detail>
  77.                         <describe>从微信零钱向中国银行卡提现1000元。完成后微信零钱余额=6000-999-1=5000;中国银行卡余额=0+999=999;被收取0.1%的手续费</describe>
  78.                         <from>0</from>
  79.                         <to>1</to>
  80.                     </movement>
  81.                 </movements>
  82.                 <variation>
  83.                     <fund>
  84.                         <category>0</category>
  85.                         <out>1.00</out>
  86.                         <in>3000.00</in>
  87.                     </fund>
  88.                     <fund>
  89.                         <category>1</category>
  90.                         <out>0.00</out>
  91.                         <in>0.00</in>
  92.                     </fund>
  93.                     <fund>
  94.                         <category>2</category>
  95.                         <out>10.00</out>
  96.                         <in>0.00</in>
  97.                     </fund>
  98.                     <fund>
  99.                         <category>3</category>
  100.                         <out>0.00</out>
  101.                         <in>0.07</in>
  102.                     </fund>
  103.                     <fund>
  104.                         <category>4</category>
  105.                         <out>0.00</out>
  106.                         <in>3000.00</in>
  107.                     </fund>
  108.                 </variation>
  109.             </day>
  110.         </month>
  111.     </year>
  112. </DailyAccountBook>
复制代码
解析目的:

  • 将balance元素中各项fund子元素存入列表,列表中每一项都是一个代表fund元素的字典;
  • 将对应日期的day元素中各种动账类型记录集合存入字典,该字典内容格式如下:
  1. day_dict = {
  2.     'expenses': [expense_dict1, expense_dict2, ...],
  3.     'incomes': [income_dict1, ...],
  4.     'movements': [movement_dict1, ...],
  5.     'variation': [fund_dict1, ...]
  6. }
复制代码
1.2 代码实现

解析balance元素:
  1.     def parseBalance(self):
  2.         e_balance = self.e_dailyAccountBook.find(".//balance")
  3.         balance_list = []
  4.         for e_fund in list(e_balance):
  5.             balance_dict = {"value": float(e_fund.find('.//value').text),
  6.                             "category": int(e_fund.find('.//category').text),
  7.                             "fundName": e_fund.find('.//fundName').text}
  8.             balance_list.append(balance_dict)
  9.         return balance_list
复制代码
解析day元素:
  1.     def getSpecificDateElement(self, date_str):
  2.         """
  3.         Describe: 根据日期字符串获取指定的day元素
  4.         Args:
  5.             date_str: str
  6.                 格式为"yyyyMMdd"
  7.         Returns:
  8.             若找到指定日期的元素,则返回Element类型的day元素.
  9.             若未找到指定year,则返回int类型的0;若未找到指定month,则返回int类型的1;若未找到指定day,则返回int类型的2。
  10.             int型返回值用于控制从何处开始初始化日期元素。
  11.         """
  12.         e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
  13.         if e_year is None:
  14.             return 0
  15.         e_month = e_year.find(".//month[@value='{}']".format(date_str[4:6]))
  16.         if e_month is None:
  17.             return 1
  18.         e_day = e_month.find(".//day[@value='{}']".format(date_str[6:]))
  19.         if e_day is None:
  20.             return 2
  21.         return e_day
  22.     def parseSpecificDateElement(self, date_str):
  23.         e_date = self.getSpecificDateElement(date_str)
  24.         if isinstance(e_date, int):
  25.             print("未找到这一天的数据!")
  26.             return None
  27.         parse_dict = dict()
  28.         for child_node in list(e_date):
  29.             print(child_node.tag)
  30.             if child_node.tag == 'expenses':
  31.                 e_expenses = e_date.find(".//expenses")
  32.                 expenses_list = [self.parseExpense(e_expense) for e_expense in list(e_expenses)]
  33.                 parse_dict['expenses'] = expenses_list
  34.             elif child_node.tag == 'incomes':
  35.                 e_incomes = e_date.find(".//incomes")
  36.                 incomes_list = [self.parseIncome(e_income) for e_income in list(e_incomes)]
  37.                 parse_dict['incomes'] = incomes_list
  38.             elif child_node.tag == 'movements':
  39.                 e_movements = e_date.find(".//movements")
  40.                 movements_list = [self.parseMovement(e_movement) for e_movement in list(e_movements)]
  41.                 parse_dict['movements'] = movements_list
  42.             elif child_node.tag == 'variation':
  43.                 e_variation = e_date.find(".//variation")
  44.                 variation_list = [self.parseVariation(e_fund) for e_fund in list(e_variation)]
  45.                 parse_dict['variation'] = variation_list
  46.             else:
  47.                 print("未知类型的节点名")
  48.         return parse_dict
  49.     def parseExpense(self, e_expense):
  50.         expense_dict = {
  51.             'necessity': True if (e_expense.attrib['necessity'].lower() == 'true') else False,
  52.             'value': float(e_expense.find('.//value').text),
  53.             'category': int(e_expense.find('.//category').text),
  54.             'detail': e_expense.find('.//detail').text,
  55.             'describe': e_expense.find('.//describe').text,
  56.             'from': int(e_expense.find('.//from').text),
  57.             'associatedFund': int(e_expense.attrib['associatedFund']) if (
  58.                     ('associatedFund' in e_expense.attrib) and e_expense.attrib['associatedFund'] != 'None') else None
  59.         }
  60.         return expense_dict
  61.     def parseIncome(self, e_income):
  62.         pass
  63.     def parseMovement(self, e_movement):
  64.         pass
  65.     def parseVariation(self, e_fund):
  66.         pass
复制代码
2. 编辑账本界面-新增行

2.1 功能详述

在选择文件或不同的日期后,解析xml文件中对应日期的收支记录,将其展示在QTableWidget中。此外,表格中最后一列增加两种操作控件:

  • 对于已存在记录的行:包含修改、删除按钮;
  • 对于空白行:包含新增按钮。点击新增后,该行变成已存在记录的行,故而操作控件也相应地变化,同时表格再新增一行空白行
2.2 代码实现
  1.     def responseSelectedDateChanging(self):
  2.         if not self.lineEdit_file_path.text():
  3.             print("还未选择文件!")
  4.             return
  5.         self.file_processor = AccountBookXMLProcessor(self.lineEdit_file_path.text())
  6.         self.file_parse_result = self.file_processor.parseSpecificDateElement(self.dateEdit.text().replace('/', ''))
  7.         print(self.file_parse_result)
  8.         if self.file_parse_result is None:
  9.             self.file_parse_result = {}
  10.         if 'expenses' not in self.file_parse_result:
  11.             self.file_parse_result['expenses'] = []
  12.         if 'incomes' not in self.file_parse_result:
  13.             self.file_parse_result['incomes'] = []
  14.         if 'movements' not in self.file_parse_result:
  15.             self.file_parse_result['movements'] = []
  16.         if 'variation' not in self.file_parse_result:
  17.             self.file_parse_result['variation'] = []
  18.         self.updateExpenseTable(self.file_parse_result['expenses'])
  19.         self.updateIncomeTable(self.file_parse_result['incomes'])
  20.         self.updateMovementTable(self.file_parse_result['movements'])
  21.     def updateExpenseTable(self, expenses_list):
  22.         self.tableWidget_expense.setRowCount(0)
  23.         self.tableWidget_expense.setRowCount(len(expenses_list)+1)
  24.         current_row = 0
  25.         for expense_dict in expenses_list:
  26.             self.tableWidget_expense.setItem(current_row, 0, QTableWidgetItem(str(expense_dict['necessity'])))
  27.             self.tableWidget_expense.setItem(current_row, 1, QTableWidgetItem(str(expense_dict['value'])))
  28.             self.tableWidget_expense.setItem(current_row, 2, QTableWidgetItem(str(expense_dict['category'])))
  29.             self.tableWidget_expense.setItem(current_row, 3, QTableWidgetItem(str(expense_dict['detail'])))
  30.             self.tableWidget_expense.setItem(current_row, 4, QTableWidgetItem(str(expense_dict['describe'])))
  31.             self.tableWidget_expense.setItem(current_row, 5, QTableWidgetItem(str(expense_dict['from'])))
  32.             self.tableWidget_expense.setItem(current_row, 6, QTableWidgetItem(str(expense_dict['associatedFund'])))
  33.             self.tableWidget_expense.setCellWidget(current_row, 7, self.buttonsForExistRow(self.tableWidget_expense))
  34.             current_row += 1
  35.         self.tableWidget_expense.setItem(current_row, 4, QTableWidgetItem(' '))
  36.         self.tableWidget_expense.setCellWidget(current_row, 7, self.buttonsForNewRow(self.tableWidget_expense))
  37.     def updateIncomeTable(self, incomes_list):
  38.         pass
  39.     def updateMovementTable(self, movements_list):
  40.         pass
  41.     def buttonsForExistRow(self, tableWidget):
  42.         widget = QWidget()
  43.         # 更新
  44.         updateBtn = QPushButton('更新')
  45.         updateBtn.clicked.connect(lambda: self.updateTableRow(tableWidget))
  46.         # 删除
  47.         deleteBtn = QPushButton('删除')
  48.         deleteBtn.clicked.connect(lambda: self.deleteTableRow(tableWidget))
  49.         hLayout = QHBoxLayout(widget)
  50.         hLayout.addWidget(updateBtn)
  51.         hLayout.addWidget(deleteBtn)
  52.         hLayout.setContentsMargins(5, 2, 5, 2)
  53.         return widget
  54.     def buttonsForNewRow(self, tableWidget):
  55.         widget = QWidget()
  56.         # 新增
  57.         newBtn = QPushButton('新增')
  58.         newBtn.clicked.connect(lambda: self.newTableRow(newBtn, tableWidget))
  59.         hLayout = QHBoxLayout(widget)
  60.         hLayout.addWidget(newBtn)
  61.         hLayout.setContentsMargins(5, 2, 5, 2)
  62.         return widget
  63.     def updateTableRow(self, toggledBtn, tableWidget):
  64.         pass
  65.     def deleteTableRow(self, toggledBtn, tableWidget):
  66.         pass
  67.     def newTableRow(self, toggledBtn, tableWidget):
  68.         print('触发了新增按钮')
  69.         # 获取触发信号的控件所在行号
  70.         row = tableWidget.indexAt(toggledBtn.parent().pos()).row()
  71.         new_data_dict = dict()
  72.         if tableWidget == self.tableWidget_expense:
  73.             current_column_head = TABLEWIDGET_EXPENSE_COLUMN_HEAD
  74.         elif tableWidget == self.tableWidget_income:
  75.             current_column_head = TABLEWIDGET_INCOME_COLUMN_HEAD
  76.         elif tableWidget == self.tableWidget_movement:
  77.             current_column_head = TABLEWIDGET_MOVEMENT_COLUMN_HEAD
  78.         else:
  79.             print('未知控件触发新增按钮!')
  80.             return
  81.         # 用新增行数据构建字典
  82.         for i in range(tableWidget.columnCount()-1):
  83.             new_data_dict[current_column_head[tableWidget.horizontalHeaderItem(i).text()]] = tableWidget.item(row, i).text()
  84.         print(new_data_dict)
  85.         # 插入新空行
  86.         insert_pos = tableWidget.rowCount()
  87.         tableWidget.insertRow(insert_pos)
  88.         # 新空行"操作"列初始化按钮
  89.         tableWidget.setCellWidget(insert_pos, tableWidget.columnCount()-1, self.buttonsForNewRow(tableWidget))
  90.         # 新增行"操作"列初始化按钮
  91.         tableWidget.setCellWidget(insert_pos-1, tableWidget.columnCount()-1, self.buttonsForExistRow(tableWidget))
  92.         if tableWidget == self.tableWidget_expense:
  93.             # 将"描述"字段预置空格
  94.             tableWidget.setItem(insert_pos, 4, QTableWidgetItem(' '))
  95.             # 用新增行的数据组织文件结构
  96.             self.file_processor.organizeExpense(new_data_dict, self.dateEdit.text().replace('/', ''))
  97.         elif tableWidget == self.tableWidget_income:
  98.             tableWidget.setItem(insert_pos, 3, QTableWidgetItem(' '))
  99.             self.file_processor.organizeIncome(new_data_dict, self.dateEdit.text().replace('/', ''))
  100.         elif tableWidget == self.tableWidget_movement:
  101.             tableWidget.setItem(insert_pos, 2, QTableWidgetItem(' '))
  102.             self.file_processor.organizeMovement(new_data_dict, self.dateEdit.text().replace('/', ''))
  103.         # 将结果文件暂时存放在工作目录
  104.         self.file_processor.writeXMLFile(self.cwd+'\\AccountBookXMLFile.xml')
复制代码
3. 将新增行写入xml文件

3.1 功能详述

用从编辑账本界面获取的新增行字典,写入xml文件。具体过程如下:

  • 判断当前日期是否存在,四种情况:存在年/月/日、只存在年/月、只存在年、均不存在。判断方法:在方法getSpecificDateElement(date_str)中,通过int型返回值作为标志,再结合方法switch_caseInitStartDate(init_start, date_str)确定日期元素新增起始点,即判断从年/月/日开始新增。
  • 根据新增行字典内容,修改各存款账户的余额
  • 根据新增行字典内容,新增对应动账记录
  • 若收支记录关联了其他存款账户,则同时修改关联账户
3.2 代码实现
  1.     def createChildElement(self, e_parent, child_name, child_text, chile_attr=None):
  2.         if chile_attr is None:
  3.             chile_attr = {}
  4.         e_child = et.SubElement(e_parent, child_name, attrib=chile_attr)
  5.         e_child.text = child_text
  6.         return e_child
  7.     def switch_caseInitStartDate(self, init_start, date_str):
  8.         # 模拟C++中switch-case控制语句,不使用break的情况
  9.         if init_start == 0:
  10.             self.createChildElement(self.e_dailyAccountBook, 'year', None, {'value': date_str[:4]})
  11.             init_start += 1
  12.         if init_start == 1:
  13.             e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
  14.             self.createChildElement(e_year, 'month', None, {'value': date_str[4:6]})
  15.         #     init_start += 1
  16.         # if init_start == 2:
  17.         e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
  18.         e_month = e_year.find(".//month[@value='{}']".format(date_str[4:6]))
  19.         e_date = self.createChildElement(e_month, 'day', None, {'value': date_str[6:]})
  20.         return e_date
  21.     def organizeExpense(self, expense_dict: dict, date_str):
  22.         e_date = self.getSpecificDateElement(date_str)
  23.         if isinstance(e_date, int):
  24.             print("未找到这一天的数据!")
  25.             e_date = self.switch_caseInitStartDate(e_date, date_str)
  26.         e_expenses = e_date.find(".//expenses") if e_date.find(".//expenses") is not None else self.createChildElement(e_date, 'expenses', None)
  27.         e_expense = et.SubElement(e_expenses, 'expense')
  28.         self.organizeVariation(expense_dict, e_date)
  29.         if 'necessity' in expense_dict:
  30.             e_expense.set('necessity', expense_dict['necessity'])
  31.             del expense_dict['necessity']
  32.         if 'associatedFund' in expense_dict:
  33.             e_expense.set('associatedFund', expense_dict['associatedFund'])
  34.             del expense_dict['associatedFund']
  35.         for key, value in expense_dict.items():
  36.             self.createChildElement(e_expense, key, value)
  37.     def organizeVariation(self, change_dict, e_date):
  38.         e_variation = e_date.find(".//variation") if e_date.find(".//variation") is not None else self.createChildElement(e_date, 'variation', None)
  39.         if 'from' in change_dict:
  40.             if e_variation.find(".//fund[category='{}']".format(change_dict['from'])) is None:
  41.                 e_fund = self.createChildElement(e_variation, 'fund', None)
  42.                 self.createChildElement(e_fund, 'category', change_dict['from'])
  43.                 self.createChildElement(e_fund, 'out', '0.0')
  44.                 self.createChildElement(e_fund, 'in', '0.0')
  45.             e_fund_variety = e_variation.find(".//fund[category='{}']/out".format(change_dict['from']))
  46.             e_fund_variety.text = str((Decimal(e_fund_variety.text) + Decimal(change_dict['value'])).quantize(Decimal('0.00')))
  47.             self.modifyBalance(change_dict['from'], Decimal(change_dict['value'])*(-1))
  48.             self.organizeAssociatedFund(e_variation, change_dict, 'from')
  49.         if 'to' in change_dict:
  50.             if e_variation.find(".//fund[category='{}']".format(change_dict['to'])) is None:
  51.                 e_fund = self.createChildElement(e_variation, 'fund', None)
  52.                 self.createChildElement(e_fund, 'category', change_dict['to'])
  53.                 self.createChildElement(e_fund, 'out', '0.0')
  54.                 self.createChildElement(e_fund, 'in', '0.0')
  55.             e_fund_variety = e_variation.find(".//fund[category='{}']/in".format(change_dict['to']))
  56.             e_fund_variety.text = str((Decimal(e_fund_variety.text) + Decimal(change_dict['value'])).quantize(Decimal('0.00')))
  57.             self.modifyBalance(change_dict['to'], Decimal(change_dict['value']))
  58.             self.organizeAssociatedFund(e_variation, change_dict, 'to')
  59.     def modifyBalance(self, fund_category, increment_value: Decimal):
  60.         """
  61.         Describe:
  62.         Args:
  63.             fund_category: int or str
  64.                 存款账户类型
  65.             increment_value: Decimal
  66.                 余额增量,为正或负
  67.         """
  68.         e_value = self.e_dailyAccountBook.find(".//balance").find(".//fund[category='{}']".format(fund_category)).find(".//value")
  69.         e_value.text = str((Decimal(e_value.text) + increment_value).quantize(Decimal('0.00')))
  70.     def organizeAssociatedFund(self, e_variation, change_dict, from_or_to):
  71.         print(change_dict['associatedFund'])
  72.         if 'associatedFund' in change_dict and change_dict['associatedFund'] != 'None':
  73.             print('执行了associatedFund,操作为', from_or_to)
  74.             if e_variation.find(".//fund[category='{}']".format(change_dict['associatedFund'])) is None:
  75.                 e_associated_fund = self.createChildElement(e_variation, 'fund', None)
  76.                 self.createChildElement(e_associated_fund, 'category', change_dict['associatedFund'])
  77.                 self.createChildElement(e_associated_fund, 'out', '0.0')
  78.                 self.createChildElement(e_associated_fund, 'in', '0.0')
  79.             if from_or_to == 'from':
  80.                 e_fund_variety = e_variation.find(".//fund[category='{}']/out".format(change_dict['associatedFund']))
  81.                 flag = -1
  82.             elif from_or_to == 'to':
  83.                 e_fund_variety = e_variation.find(".//fund[category='{}']/in".format(change_dict['associatedFund']))
  84.                 flag = 1
  85.             else:
  86.                 print('未知的收支动作!')
  87.                 return
  88.             e_fund_variety.text = str((Decimal(e_fund_variety.text) + Decimal(change_dict['value'])).quantize(Decimal('0.00')))
  89.             self.modifyBalance(change_dict['associatedFund'], Decimal(change_dict['value'])*flag)
复制代码
三、开发总结

1. ElementTree模块基本使用方法

//Element基本构成
texttail
文本尾部
//解析文件
xml_tree = ElementTree.parse("AccountBookFile.xml")
//获取根元素
root = xml_tree.getroot()
//查找子元素:按元素名查找,返回匹配到的第一个元素
//举例:查找root元素的第一个year子元素
//情景含义:找到xml文件的第一个年份的动账记录
year = root.find(".//year")
//查找子元素:按元素名查找,返回所有匹配到的元素
//举例:查找year元素的所有month元素
//情景含义:找到年份中所有月份的动账记录
month_list = year.findall(".//month")
//查找子元素:查找具有特定属性值的子元素
//举例:查找month元素直属子元素中,符合该条件的子元素——具有属性value=10
//情景含义:找到第一个月份中10号日期的动账记录
day = month_list[0].find(".//day[@value='10']")
//查找子元素:查找具有特定子元素值的子元素
//举例:查找variation元素直属子元素中,符合该条件的子元素——包含文本值为0的category子元素
//情景含义:找到10号微信零钱(category=0)的收支总和
variation = day.find(".//variation")
fund = variation.find(".//fund[category='0']")
//查找子元素:查找具有特定属性值,同时有特定子元素值的子元素
//举例:查找expenses元素直属子元素中,符合该条件的子元素——具有属性necessity=True,同时包含文本值为0的category子元素
//情景含义:找到10号基本开支中用于饮食(category=0)的花销记录
expenses = day.find(".//expenses")
expense = expenses.find(".//expense[@necessity='True'][category='0']")
//查找非直属子元素:根据路径查找子元素
//举例:查找root元素下,具有属性value=2023的year元素下,具有属性value=09的month元素下,具有属性value=11的day元素下,所有expenses元素下,包含文本值为1的category子元素的expense元素
//情景含义:找到2023/09/11这一天用于出行(category=1)的花销记录
expense = root.findall(".//year[@value='2023']/month[@value='09']/day[@value='11']/expenses/expense[category='1']")
//创建子元素
//举例:为e_parent元素创建子元素e_child,子元素名(tag)为child_name,子元素属性(attrib)键值对包含在字典attr_dict中,子元素文本值(text)为child_text
e_child = ElementTree.SubElement(e_parent, child_name, attrib=attr_dict)
e_child.text = child_text
//添加子元素
//举例:将现有的e_child元素设置为e_parent元素的子元素
e_parent.append(e_child)
//修改element元素的名称和文本
element.tag = "new_tag"
element.text = "new_text"
//新增或修改element元素中名为key的属性(attrib本质上是字典)
element.attrib[key] = "new_value"
//删除element元素中名为key的属性,并返回对应的值value。若不存在该属性,则返回defalt_value
value = element.attrib.pop(key, defalt_value)
//写入xml文件
xml_tree.write(file_path, encoding='utf-8', xml_declaration=True)
2. 修改xml文件后,出现原有内容与新增内容格式不一致的情况

参考:https://blog.csdn.net/u012692537/article/details/101395192
通过该函数美化一下,再调用write写入,问题解决
  1. def pretty_xml(element, indent, newline='\n', level=0):  # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
  2.     if element:  # 判断element是否有子元素
  3.         if (element.text is None) or element.text.isspace():  # 如果element的text没有内容
  4.             element.text = newline + indent * (level + 1)
  5.         else:
  6.             element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
  7.             # else:  # 此处两行如果把注释去掉,Element的text也会另起一行
  8.             # element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
  9.     temp = list(element)  # 将element转成list
  10.     for sub_element in temp:
  11.         if temp.index(sub_element) < (len(temp) - 1):  # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
  12.             sub_element.tail = newline + indent * (level + 1)
  13.         else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
  14.             sub_element.tail = newline + indent * level
  15.         pretty_xml(sub_element, indent, newline, level=level + 1)  # 对子元素进行递归操作
复制代码
3. QTableWidget单元格内置控件

核心方法:
  1. def setCellWidget(row: int, column: int, widget: QWidget) -> None
复制代码
获QTableWidget中发出信号的控件所在行号的槽函数:
  1. def get_triggeredObj_pos():
  2.     triggeredObj = self.sender() # 获取信号发出者
  3.     # 假设层次关系为triggeredObj放在widget中,而widget放在QTableWidget的单元格中
  4.     widget = triggeredObj.parent()
  5.     table_widget = widget.parent()
  6.     row = table_widget.indexAt(widget.pos()).row()
  7.     print(f"The row number of the button is {row}")
复制代码
来源:https://www.cnblogs.com/LinfengBingyi/p/17716008.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具