python日常記賬本源代碼,基于PySide6(Qt for Python 6)的賬本,界面簡(jiǎn)潔、功能強(qiáng)大,支持保存文件、快速查詢、繪制圖表等,是平時(shí)記賬的不錯(cuò)選擇。賬目查詢、賬本編輯、添加/刪除、撤銷/重做、統(tǒng)計(jì)數(shù)據(jù)、生成圖表。




main.py
import sys
from bisect import insort_right
from functools import partial
from os.path import basename
from webbrowser import open_new_tab
from PySide6.QtWidgets import *
from PySide6.QtCore import Slot, QDate
from PySide6.QtGui import QStandardItem, QStandardItemModel
from api import ApiError, openFile, query, saveFile
from dlgAdd import dlgAdd
from dlgCharts import dlgCharts
from dlgSettings import dlgSettings
from ui_dlgHelp import Ui_Dialog as Ui_dlgHelp
from ui_MainWindow import Ui_MainWindow
# Version info
VERSION = '1.2.1'
CHANNEL = 'stable'
BUILD_DATE = '2022-08-25'
FULL_VERSION = f'{VERSION}-{CHANNEL} ({BUILD_DATE}) on {sys.platform}'
app = QApplication(sys.argv)
class AccountBookMainWindow(QMainWindow):
version_str = '賬本 ' + VERSION
unsaved_tip = '*'
SUPPORTED_FILTERS = '賬本文件(*.abf);;文本文件(*.txt);;所有文件(*.*)'
def __init__(self, parent=None):
# Initialize window
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setWindowTitle('賬本 ' + VERSION)
self.labStatus = QLabel(self)
self.ui.statusBar.addWidget(self.labStatus)
# Initialize table
self.model = QStandardItemModel(0, 4, self)
self.model.setHorizontalHeaderLabels(['日期', '事項(xiàng)', '金額', '備注'])
self.ui.table.setModel(self.model)
self.ui.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.__data = []
self.on_actFile_New_triggered()
self.ui.actEdit_Remove.setEnabled(False)
# Connect slots
self.ui.table.selectionModel().selectionChanged.connect(self.__selectionChanged)
self.model.itemChanged.connect(self.__itemChanged)
def __updateTable(self, data):
self.model.itemChanged.disconnect(self.__itemChanged)
self.model.setRowCount(len(data))
for row in range(len(data)):
for col in range(len(data[row])):
self.model.setItem(row, col, QStandardItem(data[row][col]))
self.model.itemChanged.connect(self.__itemChanged)
def __openFile(self, filename):
try:
self.__data = openFile(filename)
except IOError:
QMessageBox.critical(self, '錯(cuò)誤', '文件打開(kāi)失敗。請(qǐng)稍后再試。')
except ApiError:
QMessageBox.critical(self, '錯(cuò)誤', '文件格式錯(cuò)誤。請(qǐng)檢查文件完整性。')
except Exception as e:
QMessageBox.critical(self, '錯(cuò)誤', '未知錯(cuò)誤:' + str(e.with_traceback()))
else:
self.ui.searchEdit.clear()
self.__key = ''
self.__updateTable(self.__data)
self.labStatus.setText(filename)
self.setWindowTitle(self.version_str)
self.__filename = filename
def __saveFile(self, filename):
try:
saveFile(filename, self.__data)
except IOError:
QMessageBox.critical(self, '錯(cuò)誤', '文件保存錯(cuò)誤。請(qǐng)稍后再試。')
except Exception as e:
QMessageBox.critical(self, '錯(cuò)誤', '未知錯(cuò)誤:' + str(e.with_traceback()))
else:
self.labStatus.setText('保存成功:' + filename)
self.setWindowTitle(self.version_str)
self.__filename = filename
@Slot()
def on_actFile_New_triggered(self):
self.__filename = self.__key = ''
self.setWindowTitle(self.unsaved_tip + self.version_str)
self.labStatus.setText('新文件')
self.model.setRowCount(0)
self.__data.clear()
@Slot()
def on_actFile_Open_triggered(self):
filename, _ = QFileDialog.getOpenFileName(self, '打開(kāi)', filter=self.SUPPORTED_FILTERS)
if filename:
self.__openFile(filename)
@Slot()
def on_actFile_Save_triggered(self):
if self.__filename:
self.__saveFile(self.__filename)
else:
filename, _ = QFileDialog.getSaveFileName(self, '保存', filter=self.SUPPORTED_FILTERS)
if filename:
self.__saveFile(filename)
@Slot()
def on_actFile_SaveAs_triggered(self):
filename, _ = QFileDialog.getSaveFileName(self, '另存為', filter=self.SUPPORTED_FILTERS)
if filename:
self.__saveFile(filename)
@Slot()
def on_actFile_Settings_triggered(self):
dlgSettings(self).exec()
@Slot()
def on_actHelp_About_triggered(self):
dialog = QDialog(self)
ui = Ui_dlgHelp()
ui.setupUi(dialog)
for link in (ui.githubLink, ui.giteeLink, ui.licenseLink, ui.readmeLink):
link.clicked.connect(partial(open_new_tab, link.description()))
ui.labVersion.setText('版本號(hào):' + FULL_VERSION)
ui.btnUpdate.clicked.connect(partial(open_new_tab, 'https://github.com/GoodCoder666/AccountBook/releases'))
dialog.exec()
@Slot()
def on_actHelp_AboutQt_triggered(self):
QMessageBox.aboutQt(self, '關(guān)于Qt')
@Slot()
def on_actEdit_Add_triggered(self):
dialog = dlgAdd(self)
if dialog.exec() == QDialog.Accepted:
row = dialog.getRow()
insort_right(self.__data, row)
self.__updateTable(query(self.__data, self.__key))
self.setWindowTitle(self.unsaved_tip + self.version_str)
@Slot()
def on_actEdit_Remove_triggered(self):
rows = list(set(map(lambda idx: idx.row(), self.ui.table.selectedIndexes())))
for row in rows:
self.__data.remove([self.model.item(row, col).text() for col in range(self.model.columnCount())])
self.model.itemChanged.disconnect(self.__itemChanged)
self.model.removeRows(rows[0], len(rows))
self.model.itemChanged.connect(self.__itemChanged)
self.setWindowTitle(self.unsaved_tip + self.version_str)
def __selectionChanged(self):
self.ui.actEdit_Remove.setEnabled(self.ui.table.selectionModel().hasSelection())
def __itemChanged(self, item: QStandardItem):
i, j, new = item.row(), item.column(), item.text()
if (old := self.__data[i][j]) == new: return
if j == 0 and not QDate.fromString(new, 'yyyy/MM/dd').isValid():
QMessageBox.critical(self, '錯(cuò)誤', '日期格式錯(cuò)誤。')
self.model.itemChanged.disconnect(self.__itemChanged)
item.setText(old)
self.model.itemChanged.connect(self.__itemChanged)
return
row = self.__data.pop(i)
row[j] = new
insort_right(self.__data, row)
self.__updateTable(query(self.__data, self.__key))
self.setWindowTitle(self.unsaved_tip + self.version_str)
@Slot()
def on_searchEdit_textChanged(self):
self.__key = self.ui.searchEdit.text()
self.__updateTable(query(self.__data, self.__key))
@Slot()
def on_actStat_Show_triggered(self):
if self.__data:
dlgCharts(self.__data, self).exec()
else:
QMessageBox.information(self, '提示', '請(qǐng)?zhí)砑訑?shù)據(jù)以使用統(tǒng)計(jì)功能。')
def closeEvent(self, event):
if not self.windowTitle().startswith(self.unsaved_tip): return
filename = basename(self.__filename) if self.__filename else '新文件'
messageBox = QMessageBox(
parent=self, icon=QMessageBox.Warning, windowTitle='提示',
text=f'是否要保存對(duì) {filename} 的更改?', informativeText='如果不保存,你的更改將丟失。',
standardButtons=QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel
)
messageBox.setButtonText(QMessageBox.Save, '保存')
messageBox.setButtonText(QMessageBox.Discard, '不保存')
messageBox.setButtonText(QMessageBox.Cancel, '取消')
reply = messageBox.exec()
if reply == QMessageBox.Save:
self.on_actFile_Save_triggered()
event.accept()
elif reply == QMessageBox.Discard:
event.accept()
else:
event.ignore()
def dragEnterEvent(self, event):
event.accept()
def dropEvent(self, event):
self.__openFile(event.mimeData().text()[8:]) # [8:] is to get rid of 'file:///'
mainform = AccountBookMainWindow()
mainform.show()
sys.exit(app.exec())
完整程序下載地址:
https://download.csdn.net/download/weixin_42756970/86845889
-
文件
+關(guān)注
關(guān)注
1文章
579瀏覽量
25353 -
源代碼
+關(guān)注
關(guān)注
96文章
2953瀏覽量
68309 -
python
+關(guān)注
關(guān)注
56文章
4827瀏覽量
86659
發(fā)布評(píng)論請(qǐng)先 登錄
選手SHOW|確認(rèn)過(guò)眼神,是我最想要的記賬APP!
uCOS-II-V280是當(dāng)前UCosII最新版本源代碼
Python微服務(wù)開(kāi)發(fā)的源代碼合集免費(fèi)下載
區(qū)塊高度和記賬本之間有什么關(guān)聯(lián)
區(qū)塊高度與記賬本頁(yè)碼之間的關(guān)系分析
python的html基本結(jié)構(gòu)及常見(jiàn)文本標(biāo)簽源代碼免費(fèi)下載

Python深度學(xué)習(xí)2018的源代碼合集免費(fèi)下載
python實(shí)現(xiàn)目標(biāo)檢測(cè)的源代碼免費(fèi)下載

使用Python按行讀文件的源代碼免費(fèi)下載

Python版警察抓小偷游戲源代碼

評(píng)論