简体   繁体   English

在 PyQt5 中刷新窗口中的小部件时是否需要重新加载整个窗口?

[英]Is it necessary to reload the whole window when refreshing a widget in a window in PyQt5?

I created a PyQt5 window where the data of an SQL table is shown in a frame (QtSql.QSqlTableModel, QTableView) and a Button to insert new data ( InsertButton ).我创建了一个 PyQt5 窗口,其中 SQL 表的数据显示在一个框架中(QtSql.QSqlTableModel、QTableView)和一个用于插入新数据的按钮( InsertButton )。 In Order to refresh the shown table, I used self.MonthTab.InsertButton.clicked.connect(self.startMonth) , and filtered the values with QSortFilterProxyModel and setFilterFixedString by the year chosen in the combobox, which works fine so far.为了刷新显示的表格,我使用了self.MonthTab.InsertButton.clicked.connect(self.startMonth) ,并使用QSortFilterProxyModelsetFilterFixedString按组合框中选择的年份过滤了值,到目前为止效果很好。 But when I filter the entries (showing eg 2020 entries only) and insert a new entry, the table is updated by rebuilding the window and the combobox is set back to default values.但是,当我过滤条目(例如仅显示 2020 条目)并插入一个新条目时,表格会通过重建窗口进行更新,并且组合框被设置回默认值。 Accordingly, I don't see the filtered 2020 entries any more.因此,我不再看到过滤后的 2020 年条目。 I want to keep the combobox settings when the table is updated, so I tried to update the table frame only ( update() , hide() / show() , call Month class( createView() and handle_db ) instead of the Month window), but the changes are always invisible until (manually) reloading the Month window.我想在表格更新时保留组合框设置,因此我尝试仅更新表格框架( update()hide() / show() 、调用 Month 类( createView()handle_db )而不是 Month 窗口),但更改始终不可见,直到(手动)重新加载“月”窗口。 To my understanding, startMonth puts the Month class elements in the Month window, and the comboboxes have to be in the Month class to be seen on Month window, which would be a dilemma when trying to update the frame but not the comboboxes, which makes no sense.据我了解,startMonth 将 Month 类元素放在 Month 窗口中,并且组合框必须在 Month 类中才能在 Month 窗口中看到,这在尝试更新框架而不是组合框时会出现困境,这使得没有意义。 So probably I got something wrong about PyQt windows and QWidgets.所以可能我对 PyQt 窗口和 QWidgets 有什么误解。 Is it possible to update just a widget during runtime without reloading the whole window?是否可以在运行时只更新一个小部件而不重新加载整个窗口? Is it possible to show widgets in the Month window which are not placed in the Month class?是否可以在 Month 窗口中显示不在 Month 类中的小部件? I'm quite new to PyQt and Qt and I googled and tried a lot, but until now without success, so I hope you may give me a hint what's wrong or how to solve it.我对 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_())


I'm using Python 3.8, PyQt5 5.15.0, PyCharm 2020.2 and Linux Mint 19.3.我使用的是 Python 3.8、PyQt5 5.15.0、PyCharm 2020.2 和 Linux Mint 19.3。

I fear the "minimal reproducible example" is quite large:我担心“最小可重复示例”非常大:

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_())

If you want to insert data into the table then you must use the QSqlRecord associated with the model:如果要将数据插入表中,则必须使用与模型关联的 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)

Note: Remove self.MonatTab.InsertButton.clicked.connect(self.startMonat)注意:删除self.MonatTab.InsertButton.clicked.connect(self.startMonat)

You can tell Qt to refresh any widget at any time by specifically calling widget.update() .您可以通过专门调用widget.update()来告诉 Qt 随时刷新任何小部件。 For example, self.MonthTab.update() .例如, self.MonthTab.update()

However, if you use the model and filter model in the correct way, the widgets displaying them will refresh automatically when the model changes.但是,如果您以正确的方式使用模型和过滤模型,则显示它们的小部件将在模型更改时自动刷新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM