一、项目地址

https://github.com/LinFeng-BingYi/DailyAccountBook

二、新增

1. 解析xml文件

1.1 功能详述

解析所设计的xml文件格式,并将所得数据存入变量。

→→→点击查看xml格式←←←
<DailyAccountBook>
<balance>
<fund>
<value>5000.00</value>
<category>0</category>
<fundName>微信零钱</fundName>
</fund>
<fund>
<value>999.00</value>
<category>1</category>
<fundName>中国银行卡</fundName>
</fund>
<fund>
<value>90.00</value>
<category>2</category>
<fundName>羊城通</fundName>
</fund>
<fund>
<value>1700.07</value>
<category>3</category>
<fundName>支付宝余额宝</fundName>
</fund>
<fund>
<value>5000.00</value>
<category>4</category>
<fundName>代管存款</fundName>
</fund>
</balance>
<year value="2023">
<month value="09">
<day value="11">
<expenses>
<expense necessity="True" associatedFund="None">
<value>5.00</value>
<category>1</category>
<detail>地铁</detail>
<describe>早上上班。羊城通卡余额=100-5=95元</describe>
<from>2</from>
</expense>
<expense necessity="True" associatedFund="None">
<value>5.00</value>
<category>1</category>
<detail>地铁</detail>
<describe>晚上下班。羊城通卡余额=95-5=90元</describe>
<from>2</from>
</expense>
<expense necessity="False" associatedFund="None">
<value>1.00</value>
<category>12</category>
<detail>业务手续费</detail>
<describe>微信零钱提现1000的手续费</describe>
<from>0</from>
</expense>
</expenses>
<incomes>
<income associatedFund="4">
<value>3000.00</value>
<category>5</category>
<!-->代管存款的收支,应属于“非本人相关”类别<-->
<detail>转账</detail>
<describe>托管人转给本人3000,帮忙存放。本人微信零钱余额=3000+3000=6000元;同时代管存款余额=2000+3000=5000元</describe>
<to>0</to>
</income>
<income associatedFund="None">
<value>0.07</value>
<category>2</category>
<detail>理财</detail>
<describe>昨日余额宝收益。余额=1700+0.07=1700.07</describe>
<to>3</to>
</income>
</incomes>
<movements>
<!-->存款账户之间的资金转移不记录在收支变化量中,仅修改账户余额。由于两个账户余额一增一减,而总量不变,记录下来反而影响个人收支统计<-->
<movement>
<value>999.00</value>
<detail>提现</detail>
<describe>从微信零钱向中国银行卡提现1000元。完成后微信零钱余额=6000-999-1=5000;中国银行卡余额=0+999=999;被收取0.1%的手续费</describe>
<from>0</from>
<to>1</to>
</movement>
</movements>
<variation>
<fund>
<category>0</category>
<out>1.00</out>
<in>3000.00</in>
</fund>
<fund>
<category>1</category>
<out>0.00</out>
<in>0.00</in>
</fund>
<fund>
<category>2</category>
<out>10.00</out>
<in>0.00</in>
</fund>
<fund>
<category>3</category>
<out>0.00</out>
<in>0.07</in>
</fund>
<fund>
<category>4</category>
<out>0.00</out>
<in>3000.00</in>
</fund>
</variation>
</day>
</month>
</year>
</DailyAccountBook>

解析目的:

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

1.2 代码实现

解析balance元素:

    def parseBalance(self):
e_balance = self.e_dailyAccountBook.find(".//balance")
balance_list = []
for e_fund in list(e_balance):
balance_dict = {"value": float(e_fund.find('.//value').text),
"category": int(e_fund.find('.//category').text),
"fundName": e_fund.find('.//fundName').text}
balance_list.append(balance_dict)
return balance_list

解析day元素:

    def getSpecificDateElement(self, date_str):
"""
Describe: 根据日期字符串获取指定的day元素
Args:
date_str: str
格式为"yyyyMMdd"
Returns:
若找到指定日期的元素,则返回Element类型的day元素.
若未找到指定year,则返回int类型的0;若未找到指定month,则返回int类型的1;若未找到指定day,则返回int类型的2。
int型返回值用于控制从何处开始初始化日期元素。
"""
e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
if e_year is None:
return 0
e_month = e_year.find(".//month[@value='{}']".format(date_str[4:6]))
if e_month is None:
return 1
e_day = e_month.find(".//day[@value='{}']".format(date_str[6:]))
if e_day is None:
return 2
return e_day def parseSpecificDateElement(self, date_str):
e_date = self.getSpecificDateElement(date_str)
if isinstance(e_date, int):
print("未找到这一天的数据!")
return None parse_dict = dict()
for child_node in list(e_date):
print(child_node.tag)
if child_node.tag == 'expenses':
e_expenses = e_date.find(".//expenses")
expenses_list = [self.parseExpense(e_expense) for e_expense in list(e_expenses)]
parse_dict['expenses'] = expenses_list
elif child_node.tag == 'incomes':
e_incomes = e_date.find(".//incomes")
incomes_list = [self.parseIncome(e_income) for e_income in list(e_incomes)]
parse_dict['incomes'] = incomes_list
elif child_node.tag == 'movements':
e_movements = e_date.find(".//movements")
movements_list = [self.parseMovement(e_movement) for e_movement in list(e_movements)]
parse_dict['movements'] = movements_list
elif child_node.tag == 'variation':
e_variation = e_date.find(".//variation")
variation_list = [self.parseVariation(e_fund) for e_fund in list(e_variation)]
parse_dict['variation'] = variation_list
else:
print("未知类型的节点名") return parse_dict def parseExpense(self, e_expense):
expense_dict = {
'necessity': True if (e_expense.attrib['necessity'].lower() == 'true') else False,
'value': float(e_expense.find('.//value').text),
'category': int(e_expense.find('.//category').text),
'detail': e_expense.find('.//detail').text,
'describe': e_expense.find('.//describe').text,
'from': int(e_expense.find('.//from').text),
'associatedFund': int(e_expense.attrib['associatedFund']) if (
('associatedFund' in e_expense.attrib) and e_expense.attrib['associatedFund'] != 'None') else None
} return expense_dict def parseIncome(self, e_income):
pass def parseMovement(self, e_movement):
pass def parseVariation(self, e_fund):
pass

2. 编辑账本界面-新增行

2.1 功能详述

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

  • 对于已存在记录的行:包含修改、删除按钮;
  • 对于空白行:包含新增按钮。点击新增后,该行变成已存在记录的行,故而操作控件也相应地变化,同时表格再新增一行空白行

2.2 代码实现

    def responseSelectedDateChanging(self):
if not self.lineEdit_file_path.text():
print("还未选择文件!")
return
self.file_processor = AccountBookXMLProcessor(self.lineEdit_file_path.text())
self.file_parse_result = self.file_processor.parseSpecificDateElement(self.dateEdit.text().replace('/', ''))
print(self.file_parse_result)
if self.file_parse_result is None:
self.file_parse_result = {} if 'expenses' not in self.file_parse_result:
self.file_parse_result['expenses'] = []
if 'incomes' not in self.file_parse_result:
self.file_parse_result['incomes'] = []
if 'movements' not in self.file_parse_result:
self.file_parse_result['movements'] = []
if 'variation' not in self.file_parse_result:
self.file_parse_result['variation'] = [] self.updateExpenseTable(self.file_parse_result['expenses'])
self.updateIncomeTable(self.file_parse_result['incomes'])
self.updateMovementTable(self.file_parse_result['movements']) def updateExpenseTable(self, expenses_list):
self.tableWidget_expense.setRowCount(0)
self.tableWidget_expense.setRowCount(len(expenses_list)+1) current_row = 0
for expense_dict in expenses_list:
self.tableWidget_expense.setItem(current_row, 0, QTableWidgetItem(str(expense_dict['necessity'])))
self.tableWidget_expense.setItem(current_row, 1, QTableWidgetItem(str(expense_dict['value'])))
self.tableWidget_expense.setItem(current_row, 2, QTableWidgetItem(str(expense_dict['category'])))
self.tableWidget_expense.setItem(current_row, 3, QTableWidgetItem(str(expense_dict['detail'])))
self.tableWidget_expense.setItem(current_row, 4, QTableWidgetItem(str(expense_dict['describe'])))
self.tableWidget_expense.setItem(current_row, 5, QTableWidgetItem(str(expense_dict['from'])))
self.tableWidget_expense.setItem(current_row, 6, QTableWidgetItem(str(expense_dict['associatedFund'])))
self.tableWidget_expense.setCellWidget(current_row, 7, self.buttonsForExistRow(self.tableWidget_expense))
current_row += 1 self.tableWidget_expense.setItem(current_row, 4, QTableWidgetItem(' '))
self.tableWidget_expense.setCellWidget(current_row, 7, self.buttonsForNewRow(self.tableWidget_expense)) def updateIncomeTable(self, incomes_list):
pass def updateMovementTable(self, movements_list):
pass def buttonsForExistRow(self, tableWidget):
widget = QWidget()
# 更新
updateBtn = QPushButton('更新')
updateBtn.clicked.connect(lambda: self.updateTableRow(tableWidget))
# 删除
deleteBtn = QPushButton('删除')
deleteBtn.clicked.connect(lambda: self.deleteTableRow(tableWidget)) hLayout = QHBoxLayout(widget)
hLayout.addWidget(updateBtn)
hLayout.addWidget(deleteBtn)
hLayout.setContentsMargins(5, 2, 5, 2)
return widget def buttonsForNewRow(self, tableWidget):
widget = QWidget()
# 新增
newBtn = QPushButton('新增')
newBtn.clicked.connect(lambda: self.newTableRow(newBtn, tableWidget)) hLayout = QHBoxLayout(widget)
hLayout.addWidget(newBtn)
hLayout.setContentsMargins(5, 2, 5, 2)
return widget def updateTableRow(self, toggledBtn, tableWidget):
pass def deleteTableRow(self, toggledBtn, tableWidget):
pass def newTableRow(self, toggledBtn, tableWidget):
print('触发了新增按钮')
# 获取触发信号的控件所在行号
row = tableWidget.indexAt(toggledBtn.parent().pos()).row()
new_data_dict = dict()
if tableWidget == self.tableWidget_expense:
current_column_head = TABLEWIDGET_EXPENSE_COLUMN_HEAD
elif tableWidget == self.tableWidget_income:
current_column_head = TABLEWIDGET_INCOME_COLUMN_HEAD
elif tableWidget == self.tableWidget_movement:
current_column_head = TABLEWIDGET_MOVEMENT_COLUMN_HEAD
else:
print('未知控件触发新增按钮!')
return
# 用新增行数据构建字典
for i in range(tableWidget.columnCount()-1):
new_data_dict[current_column_head[tableWidget.horizontalHeaderItem(i).text()]] = tableWidget.item(row, i).text()
print(new_data_dict) # 插入新空行
insert_pos = tableWidget.rowCount()
tableWidget.insertRow(insert_pos)
# 新空行"操作"列初始化按钮
tableWidget.setCellWidget(insert_pos, tableWidget.columnCount()-1, self.buttonsForNewRow(tableWidget))
# 新增行"操作"列初始化按钮
tableWidget.setCellWidget(insert_pos-1, tableWidget.columnCount()-1, self.buttonsForExistRow(tableWidget)) if tableWidget == self.tableWidget_expense:
# 将"描述"字段预置空格
tableWidget.setItem(insert_pos, 4, QTableWidgetItem(' '))
# 用新增行的数据组织文件结构
self.file_processor.organizeExpense(new_data_dict, self.dateEdit.text().replace('/', ''))
elif tableWidget == self.tableWidget_income:
tableWidget.setItem(insert_pos, 3, QTableWidgetItem(' '))
self.file_processor.organizeIncome(new_data_dict, self.dateEdit.text().replace('/', ''))
elif tableWidget == self.tableWidget_movement:
tableWidget.setItem(insert_pos, 2, QTableWidgetItem(' '))
self.file_processor.organizeMovement(new_data_dict, self.dateEdit.text().replace('/', ''))
# 将结果文件暂时存放在工作目录
self.file_processor.writeXMLFile(self.cwd+'\\AccountBookXMLFile.xml')

3. 将新增行写入xml文件

3.1 功能详述

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

  1. 判断当前日期是否存在,四种情况:存在年/月/日、只存在年/月、只存在年、均不存在。判断方法:在方法getSpecificDateElement(date_str)中,通过int型返回值作为标志,再结合方法switch_caseInitStartDate(init_start, date_str)确定日期元素新增起始点,即判断从年/月/日开始新增。
  2. 根据新增行字典内容,修改各存款账户的余额
  3. 根据新增行字典内容,新增对应动账记录
  4. 若收支记录关联了其他存款账户,则同时修改关联账户

3.2 代码实现

    def createChildElement(self, e_parent, child_name, child_text, chile_attr=None):
if chile_attr is None:
chile_attr = {}
e_child = et.SubElement(e_parent, child_name, attrib=chile_attr)
e_child.text = child_text
return e_child def switch_caseInitStartDate(self, init_start, date_str):
# 模拟C++中switch-case控制语句,不使用break的情况
if init_start == 0:
self.createChildElement(self.e_dailyAccountBook, 'year', None, {'value': date_str[:4]})
init_start += 1
if init_start == 1:
e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
self.createChildElement(e_year, 'month', None, {'value': date_str[4:6]})
# init_start += 1
# if init_start == 2:
e_year = self.e_dailyAccountBook.find(".//year[@value='{}']".format(date_str[:4]))
e_month = e_year.find(".//month[@value='{}']".format(date_str[4:6]))
e_date = self.createChildElement(e_month, 'day', None, {'value': date_str[6:]})
return e_date def organizeExpense(self, expense_dict: dict, date_str):
e_date = self.getSpecificDateElement(date_str) if isinstance(e_date, int):
print("未找到这一天的数据!") e_date = self.switch_caseInitStartDate(e_date, date_str) e_expenses = e_date.find(".//expenses") if e_date.find(".//expenses") is not None else self.createChildElement(e_date, 'expenses', None)
e_expense = et.SubElement(e_expenses, 'expense') self.organizeVariation(expense_dict, e_date) if 'necessity' in expense_dict:
e_expense.set('necessity', expense_dict['necessity'])
del expense_dict['necessity']
if 'associatedFund' in expense_dict:
e_expense.set('associatedFund', expense_dict['associatedFund'])
del expense_dict['associatedFund']
for key, value in expense_dict.items():
self.createChildElement(e_expense, key, value) def organizeVariation(self, change_dict, e_date):
e_variation = e_date.find(".//variation") if e_date.find(".//variation") is not None else self.createChildElement(e_date, 'variation', None)
if 'from' in change_dict:
if e_variation.find(".//fund[category='{}']".format(change_dict['from'])) is None:
e_fund = self.createChildElement(e_variation, 'fund', None)
self.createChildElement(e_fund, 'category', change_dict['from'])
self.createChildElement(e_fund, 'out', '0.0')
self.createChildElement(e_fund, 'in', '0.0')
e_fund_variety = e_variation.find(".//fund[category='{}']/out".format(change_dict['from']))
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'])*(-1)) self.organizeAssociatedFund(e_variation, change_dict, 'from')
if 'to' in change_dict:
if e_variation.find(".//fund[category='{}']".format(change_dict['to'])) is None:
e_fund = self.createChildElement(e_variation, 'fund', None)
self.createChildElement(e_fund, 'category', change_dict['to'])
self.createChildElement(e_fund, 'out', '0.0')
self.createChildElement(e_fund, 'in', '0.0')
e_fund_variety = e_variation.find(".//fund[category='{}']/in".format(change_dict['to']))
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'])) self.organizeAssociatedFund(e_variation, change_dict, 'to') def modifyBalance(self, fund_category, increment_value: Decimal):
"""
Describe: Args:
fund_category: int or str
存款账户类型
increment_value: Decimal
余额增量,为正或负
"""
e_value = self.e_dailyAccountBook.find(".//balance").find(".//fund[category='{}']".format(fund_category)).find(".//value")
e_value.text = str((Decimal(e_value.text) + increment_value).quantize(Decimal('0.00'))) def organizeAssociatedFund(self, e_variation, change_dict, from_or_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:
e_associated_fund = self.createChildElement(e_variation, 'fund', None)
self.createChildElement(e_associated_fund, 'category', change_dict['associatedFund'])
self.createChildElement(e_associated_fund, 'out', '0.0')
self.createChildElement(e_associated_fund, 'in', '0.0')
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)

三、开发总结

1. ElementTree模块基本使用方法

//Element基本构成

<tag attrib1=1>text</tag>tail

<元素名 属性1=1>文本</元素名>尾部

//解析文件

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号基本开支(necessity=True)中用于饮食(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写入,问题解决

def pretty_xml(element, indent, newline='\n', level=0):  # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
if element: # 判断element是否有子元素
if (element.text is None) or element.text.isspace(): # 如果element的text没有内容
element.text = newline + indent * (level + 1)
else:
element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
# else: # 此处两行如果把注释去掉,Element的text也会另起一行
# element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
temp = list(element) # 将element转成list
for sub_element in temp:
if temp.index(sub_element) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
sub_element.tail = newline + indent * (level + 1)
else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
sub_element.tail = newline + indent * level
pretty_xml(sub_element, indent, newline, level=level + 1) # 对子元素进行递归操作

3. QTableWidget单元格内置控件

核心方法:

def setCellWidget(row: int, column: int, widget: QWidget) -> None

获QTableWidget中发出信号的控件所在行号的槽函数:

def get_triggeredObj_pos():
triggeredObj = self.sender() # 获取信号发出者
# 假设层次关系为triggeredObj放在widget中,而widget放在QTableWidget的单元格中
widget = triggeredObj.parent()
table_widget = widget.parent()
row = table_widget.indexAt(widget.pos()).row()
print(f"The row number of the button is {row}")

【日常收支账本】【Day03】完成编辑账本界面的新增动账记录功能——通过ElementTree加XPath实现的更多相关文章

  1. 小程序实践(十):textarea实现简单的编辑文本界面

    textarea是官方的原生组件,用于多行输入 简单的例子,监听文本内容.长度,以及设置最大可输入文本长度 wxml <view class='textarea-Style'> <t ...

  2. Android:日常学习笔记(8)———开发微信聊天界面

    Android:日常学习笔记(8)———开发微信聊天界面 只做Nine-Patch图片 Nine-Patch是一种被特殊处理过的PNG图片,能够指定哪些区域可以被拉升,哪些区域不可以.

  3. 使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题

    在前篇随笔<使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理>中介绍了Vue-TreeSelect组件的使用,包括使用v-modal绑定值,normalizer ...

  4. HBuilderX配置外部服务器(tomcat)查看编辑jsp界面

    HBuilderX配置外部服务器(tomcat)查看编辑jsp界面 一.第一种方法,通过启动本地tomcat,查看jsp 在tomcat的webapps目录下创建文件夹HBuilderX 打开HBui ...

  5. php+redis实现注册、删除、编辑、分页、登录、关注等功能

    本文实例讲述了php+redis实现注册.删除.编辑.分页.登录.关注等功能.分享给大家供大家参考,具体如下: 主要界面 ​ 连接redis redis.php <?php //实例化 $red ...

  6. swing实现QQ登录界面1.0( 实现了同一张图片只加载一次)、(以及实现简单的布局面板添加背景图片控件的标签控件和添加一个关闭按钮控件)

    swing实现QQ登录界面1.0( 实现了同一张图片只加载一次).(以及实现简单的布局面板添加背景图片控件的标签控件和添加一个关闭按钮控件) 代码思路分析: 1.(同一张图片仅仅需要加载一次就够了,下 ...

  7. 家庭记账本app实现登录注册界面以及仿微信操作界面(共4个实现一个)遇到了麻烦

    今天学习了数据的创建,以及关于数据库的相关操作. 今天主要是实现了对于数据库的增加和查找. 具体的代码如下: 首先是数据库的创建: DBOpenMessage.java package com.exa ...

  8. 家庭版记账本app开发进度相关界面的规划

    总的app界面包括四个页面,页面可以来回滑动.设计的时候就和微信的四个页面类似. 由于没有找到合适的图标进行替换,在此仍应用微信对应的四个图标. 总的四个页面是: 1.增加收入或者支出的小账单.当点击 ...

  9. 第15.11节 PyQt(Python+Qt)入门学习:Qt Designer(设计师)组件Property Editor(属性编辑)界面中主窗口QMainWindow类相关属性详解

    概述 主窗口对象是在新建窗口对象时,选择main window类型的模板时创建的窗口对象,如图: 在属性编辑界面中,主窗口对象与QMainWindow相关的属性包括:iconSize.toolButt ...

  10. DirectUI界面编程(三)从XML文件中加载界面

    Duilib支持xml界面布局,使得界面设计与逻辑处理相分离,本节介绍如何从xml文件中加载界面元素. 我们需要以下几个步骤: 创建并初始化CPaintManagerUI对象. 创建CDialogBu ...

随机推荐

  1. [Spring+SpringMVC+Mybatis]框架学习笔记(九):Mybatis主配置文件和映射文件

    第9章 Mybatis主配置文件和映射文件 9.1 用Mybatis进行开发的两种方式 在正式的开发环境中用Mybatis进行开发有两种方式: 1)原始的接口和实现类的方式 缺点: 重复代码太多,sq ...

  2. 【pandas小技巧】--修改列的名称

    重命名 pandas 数据中列的名称是一种常见的数据预处理任务.这通常是因为原始数据中的列名称可能不够清晰或准确.例如,列名可能包含空格.大写字母.特殊字符或拼写错误. 使用 pandas 的 ren ...

  3. 2023-08-02:给定一棵树,一共有n个点, 每个点上没有值,请把1~n这些数字,不重复的分配到二叉树上, 做到 : 奇数层节点的值总和 与 偶数层节点的值总和 相差不超过1。 返回奇数层节点分配

    2023-08-02:给定一棵树,一共有n个点, 每个点上没有值,请把1~n这些数字,不重复的分配到二叉树上, 做到 : 奇数层节点的值总和 与 偶数层节点的值总和 相差不超过1. 返回奇数层节点分配 ...

  4. 2023-08-06:小青蛙住在一条河边, 它想到河对岸的学校去学习 小青蛙打算经过河里 的石头跳到对岸 河里的石头排成了一条直线, 小青蛙每次跳跃必须落在一块石头或者岸上 给定一个长度为n的数组ar

    2023-08-06:小青蛙住在一条河边, 它想到河对岸的学校去学习 小青蛙打算经过河里 的石头跳到对岸 河里的石头排成了一条直线, 小青蛙每次跳跃必须落在一块石头或者岸上 给定一个长度为n的数组ar ...

  5. react中使用动画 react-transition-group

    在React中通过react-transition-group使用过渡.动画,首先要有CSS3中的过渡和动画的相关知识储备,可以参考 过渡和2D变换.动画和3d变换. 我们自己通过css设置过渡.动画 ...

  6. 利用IPV6随时访问家中影音Jellyfin

    本文章主要记录通过ipv6实现家庭影音中心在互联网上的访问. 之前很多方案都是通过第三方进行内网穿透,实际体验不是很好.目前ipv6发展迅速,完全可以取代这种以ipv4为中心的内网资源外网访问的方式. ...

  7. 1.JDK的安装与卸载

    1.卸载: 卸载或更改程序,找到相应的JDK程序,删除 2.安装: 官网下载JDK程序:jdk-8u25-windows-i586.exe 双击安装程序,同意协议,更改安装路径:C:\jdk1.8.0 ...

  8. Java Maven POM配置参考

    介绍 什么是POM? POM代表"项目对象模型".它是一个名为pom.XML的文件中保存的Maven项目的XML表示. 快速概览 这是一个直接位于POM项目元素下的元素列表.请注意 ...

  9. 小白python和pycharm安装大佬勿扰

    编程语言发展和Python安装 计算机语言的发展 机器语言 1946年2月14日,世界上第一台计算机ENIAC诞生,使用的是最原始的穿孔卡片.这种卡片上使用的语言是只有专家才能理解的语言,与人类语言差 ...

  10. Java实践项目 - 购物车模块

    Smiling & Weeping ----世界上美好的东西不太多,立秋傍晚从河对岸吹来的风, 加入购物车 1.数据创建--创建t_cart CREATE TABLE t_cart( cid ...