[英]Is it necessary to reload the whole window when refreshing a widget in a window in PyQt5?
我创建了一个 PyQt5 窗口,其中 SQL 表的数据显示在一个框架中(QtSql.QSqlTableModel、QTableView)和一个用于插入新数据的按钮( InsertButton
)。 为了刷新显示的表格,我使用了self.MonthTab.InsertButton.clicked.connect(self.startMonth)
,并使用QSortFilterProxyModel
和setFilterFixedString
按组合框中选择的年份过滤了值,到目前为止效果很好。 但是,当我过滤条目(例如仅显示 2020 条目)并插入一个新条目时,表格会通过重建窗口进行更新,并且组合框被设置回默认值。 因此,我不再看到过滤后的 2020 年条目。 我想在表格更新时保留组合框设置,因此我尝试仅更新表格框架( update()
、 hide()
/ show()
、调用 Month 类( createView()
和handle_db
)而不是 Month 窗口),但更改始终不可见,直到(手动)重新加载“月”窗口。 据我了解,startMonth 将 Month 类元素放在 Month 窗口中,并且组合框必须在 Month 类中才能在 Month 窗口中看到,这在尝试更新框架而不是组合框时会出现困境,这使得没有意义。 所以可能我对 PyQt 窗口和 QWidgets 有什么误解。 是否可以在运行时只更新一个小部件而不重新加载整个窗口? 是否可以在 Month 窗口中显示不在 Month 类中的小部件? 我对 PyQt 和 Qt 很陌生,我用谷歌搜索并尝试了很多,但直到现在都没有成功,所以我希望你能给我一个提示是什么问题或如何解决它。
class Month(Menu):
def __init__(self, parent=Menu):
super(Month, self).__init__(parent)
self.x = datetime.datetime.now()
self.year = QtWidgets.QComboBox(self)
self.year.setGeometry(100, 80, 100, 24)
self.year.setMouseTracking(False)
self.year.addItem(self.x.strftime("%G"))
self.year.addItem("2019")
self.year.addItem("2020")
self.year.setEditable(False)
self.year.currentTextChanged.connect(self.date_filter)
self.InsertButton = QtWidgets.QPushButton(self)
self.InsertButton.setText("Insert")
self.InsertButton.clicked.connect(self.clicked) # inserts values into sql database table
self.handle_db()
self.createView("Table Model (View 1)", self.model)
def createDB(self): ... # provides sql-connection, creates database
def initializeModel(self, model): ...
def createView(self, title, model): ...
def handle_db(self): ... # creates model, proxymodel, view, layout and frame for showing table
def date_filter(self):
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setGeometry(200, 50, 900, 650)
print("MainWindow")
self.startMonth()
def startMonth(self):
self.MonthTab = Month(self)
self.setWindowTitle("Month")
self.setCentralWidget(self.MonthTab)
self.MonthTab.InsertButton.clicked.connect(self.startMonth) # rebuilds Month window -> table is updated
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
Month().createDB()
w = MainWindow()
sys.exit(app.exec_())
我使用的是 Python 3.8、PyQt5 5.15.0、PyCharm 2020.2 和 Linux Mint 19.3。
我担心“最小可重复示例”非常大:
import sys
from PyQt5 import QtWidgets, QtSql, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, \
QVBoxLayout, QTableView, QPushButton, \
QMessageBox, qApp, QFrame
from PyQt5.QtCore import QSortFilterProxyModel
import datetime
class Menu(QWidget): # die allgemeine Fenster-Parent-Class
def __init__(self, parent=None):
super(Menu, self).__init__()
self.MonatBTN = QPushButton("Monat", self)
self.MonatBTN.move(20, 30)
class Monat(Menu):
def __init__(self, parent=Menu):
super(Monat, self).__init__(parent)
self.x = datetime.datetime.now()
self.jahr = QtWidgets.QComboBox(self)
self.jahr.setGeometry(100, 80, 100, 24)
self.jahr.setMouseTracking(False)
self.jahr.addItem(self.x.strftime("%G"))
self.jahr.addItem("2019")
self.jahr.addItem("2020")
self.jahr.setEditable(False)
self.jahr.currentTextChanged.connect(self.date_filter)
self.date_frame = QFrame(self)
self.date_frame.setFrameShape(QFrame.StyledPanel)
self.date_frame.setLineWidth(1)
self.date_frame.setGeometry(100, 500, 161, 50)
self.date_picker = QtWidgets.QDateEdit(calendarPopup=True)
self.date_picker.setDateTime(QtCore.QDateTime.currentDateTime())
self.date_layout = QVBoxLayout()
self.date_layout.addWidget(self.date_picker)
self.date_frame.setLayout(self.date_layout)
self.date_frame.show()
self.posten = QtWidgets.QComboBox(self)
self.posten.setGeometry(300, 513, 161, 24)
self.posten.setMouseTracking(False)
self.posten.addItem("")
self.posten.addItem("Apple")
self.posten.addItem("Peach")
self.posten.addItem("Orange")
self.posten.setEditable(True)
self.wert = QtWidgets.QComboBox(self)
self.wert.setGeometry(500, 513, 161, 24)
self.wert.setMouseTracking(False)
self.wert.addItem("")
self.wert.addItem("20")
self.wert.addItem("300")
self.wert.addItem("-15")
self.wert.setEditable(True)
self.InsertButton = QtWidgets.QPushButton(self)
self.InsertButton.setText("Einfügen")
self.InsertButton.move(700, 513)
self.InsertButton.clicked.connect(self.clicked)
self.handle_db()
self.createView("Table Model (View 1)", self.model)
def createDB(self):
print("creating")
self.cash_db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
self.cash_db.setDatabaseName('cash.db')
if not self.cash_db.open():
QMessageBox.critical(None, qApp.tr("Cannot open database"),
qApp.tr("Unable to establish a database connection.\n"
"Click Cancel to exit."),
QMessageBox.Cancel)
return False
query = QtSql.QSqlQuery()
# query.exec_("create table cash(id int primary key, "
query.exec_("create table cash( "
"date varchar(20), datum varchar(20), posten varchar(40), wert varchar(20))")
return True
def initializeModel(self, model):
self.model.setTable('cash')
self.model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
self.model.select()
self.model.setHeaderData(0, QtCore.Qt.Horizontal, "Date")
self.model.setHeaderData(1, QtCore.Qt.Horizontal, "Datum")
self.model.setHeaderData(2, QtCore.Qt.Horizontal, "Posten")
self.model.setHeaderData(3, QtCore.Qt.Horizontal, "Wert")
def createView(self, title, model):
self.view = QTableView()
self.view.setModel(model)
self.view.setWindowTitle(title)
return self.view
def handle_db(self):
print("handling")
self.model = QtSql.QSqlTableModel()
self.delrow = -1
self.initializeModel(self.model)
self.proxyModel = QSortFilterProxyModel()
self.proxyModel.setSourceModel(self.model)
self.view = self.createView("Table Model (View 1)", self.model)
self.view.setModel(self.proxyModel)
self.view.setSortingEnabled(True)
self.view.hideColumn(0)
self.view.header = self.view.horizontalHeader()
self.view.header.resizeSection(1, 100)
self.view.header.resizeSection(2, 466)
self.view.header.resizeSection(3, 100)
self.view.resizeRowsToContents()
self.proxyModel.setSourceModel(self.model)
self.view.setModel(self.proxyModel)
self.frame = QFrame(self)
self.frame.setFrameShape(QFrame.StyledPanel)
self.frame.setLineWidth(1)
self.frame.setGeometry(100, 120, 700, 300)
self.layout = QVBoxLayout()
self.layout.addWidget(self.view)
self.frame.setLayout(self.layout)
self.frame.show()
def date_filter(self):
jahr = self.jahr.currentText()
filter = jahr
self.proxyModel.setFilterFixedString(filter)
self.view.resizeRowsToContents()
def clicked(self):
d = self.date_picker.date()
date = d.toPyDate()
datum = (date.strftime("%d.%m.%Y"))
posten = self.posten.currentText()
v = self.wert.currentText()
val = ('%10.2f') % float(v)
wert = str(val)
query = QtSql.QSqlQuery()
query.exec_(
"insert into cash (date, datum, posten, wert) "
"values('%s', '%s', '%s', '%s')" % (date, datum, posten, wert))
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setGeometry(200, 50, 900, 650)
print("MainWindow")
self.startMonat()
def startMonat(self):
self.MonatTab = Monat(self)
self.setWindowTitle("Cash - Monat")
self.setCentralWidget(self.MonatTab)
self.MonatTab.InsertButton.clicked.connect(self.startMonat)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
Monat().createDB()
w = MainWindow()
sys.exit(app.exec_())
如果要将数据插入表中,则必须使用与模型关联的 QSqlRecord:
def clicked(self):
d = self.date_picker.date()
date = d.toPyDate()
datum = date.strftime("%d.%m.%Y")
posten = self.posten.currentText()
v = self.wert.currentText()
val = ("%10.2f") % float(v)
wert = str(val)
record = self.model.record()
record.setValue("date", date)
record.setValue("datum", datum)
record.setValue("posten", posten)
record.setValue("wert", wert)
self.model.insertRecord(-1, record)
注意:删除self.MonatTab.InsertButton.clicked.connect(self.startMonat)
您可以通过专门调用widget.update()
来告诉 Qt 随时刷新任何小部件。 例如, self.MonthTab.update()
。
但是,如果您以正确的方式使用模型和过滤模型,则显示它们的小部件将在模型更改时自动刷新。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.