python日常記賬本源代碼,基于PySide6(Qt for Python 6)的賬本,界面簡潔、功能強大,支持保存文件、快速查詢、繪制圖表等,是平時記賬的不錯選擇。賬目查詢、賬本編輯、添加/刪除、撤銷/重做、統(tǒng)計數(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(['日期', '事項', '金額', '備注'])
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, '錯誤', '文件打開失敗。請稍后再試。')
except ApiError:
QMessageBox.critical(self, '錯誤', '文件格式錯誤。請檢查文件完整性。')
except Exception as e:
QMessageBox.critical(self, '錯誤', '未知錯誤:' + 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, '錯誤', '文件保存錯誤。請稍后再試。')
except Exception as e:
QMessageBox.critical(self, '錯誤', '未知錯誤:' + 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, '打開', 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('版本號:' + 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, '關于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, '錯誤', '日期格式錯誤。')
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, '提示', '請?zhí)砑訑?shù)據(jù)以使用統(tǒng)計功能。')
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'是否要保存對 {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
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
文件
+關注
關注
1文章
565瀏覽量
24727 -
源代碼
+關注
關注
96文章
2945瀏覽量
66730 -
python
+關注
關注
56文章
4792瀏覽量
84627
發(fā)布評論請先 登錄
相關推薦
選手SHOW|確認過眼神,是我最想要的記賬APP!
。不僅如此,圈子賬本還考慮到日常記賬習慣,開發(fā)出了圈子功能,讓商業(yè)伙伴、家庭成員、結伴出行的小伙伴都可以在同一賬本記賬。不僅拉近了彼此之間的
發(fā)表于 07-02 11:48
uCOS-II-V280是當前UCosII最新版本源代碼
uCOS-II-V280是當前UCosII最新版本源代碼
/*********************************************************************************************************** &n
發(fā)表于 02-24 14:24
?0次下載
區(qū)塊高度和記賬本之間有什么關聯(lián)
區(qū)塊鏈就像是一個記賬本,而區(qū)塊就像是這個記賬本里面的一頁頁記賬紙,區(qū)塊高度就是記賬紙的頁碼,當同時出現(xiàn)兩個相同頁碼時就會發(fā)生分叉。
發(fā)表于 10-15 14:09
?598次閱讀
區(qū)塊高度與記賬本頁碼之間的關系分析
區(qū)塊高度顧名思義就是區(qū)塊的高度,準確地說是連接在區(qū)塊鏈上的塊數(shù)。因此想要明白什么是區(qū)塊高度,我們得首先搞明白什么是區(qū)塊鏈。如果說區(qū)塊鏈是記賬本的話,那么一個區(qū)塊就像是記賬本的每一頁一樣。
發(fā)表于 10-16 10:20
?670次閱讀
python的html基本結構及常見文本標簽源代碼免費下載
本文檔的主要內(nèi)容詳細介紹的是python的html基本結構及常見文本標簽源代碼免費下載。
發(fā)表于 12-04 08:00
?0次下載
20個解決日常問題的Python代碼片段!
在本文中,將分享20 個 Python 代碼片段,以幫助你應對日常編程挑戰(zhàn)。你可能已經(jīng)知道其中一些片段,但有些其他片段對你來說可能是新的。趕緊使用這些有用的 Python
評論