【问题标题】:QDataWidgetMapper does not update in all WindowsQDataWidgetMapper 不会在所有 Windows 中更新
【发布时间】:2021-04-27 22:08:57
【问题描述】:

我正在尝试让 PyQt 中的多窗口应用程序工作,它应该以不同的方式在多个窗口中显示数据。现在我遇到了一个我不了解QDataWidgetMapper 的问题。为了解释,我创建了一个示例应用程序。 下面的代码确实创建了

  • 与 SQLite 数据库的连接

  • 创建两个相同的窗口,显示一个 QTable 和一个映射在单元格 0,0 上的 QlineEdit

    import sys
    from PyQt5.QtCore import QSize, Qt
    from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
    from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView, QMessageBox,\
    QLineEdit, QWidget, QVBoxLayout, QDataWidgetMapper
    from Singleton import Singleton
    
    class SqlModel(QSqlTableModel, metaclass=Singleton):
        def __init__(self, parent=None):
            con = QSqlDatabase.addDatabase("QSQLITE")
            con.setDatabaseName("chinook.sqlite")
            con.open()
            super().__init__()
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setMinimumSize(QSize(400, 200))
            widget = QWidget()        
            layout = QVBoxLayout()
            widget.setLayout(layout)
            self.setCentralWidget(widget)
    
            self.table = QTableView()
            layout.addWidget(self.table)
    
            self.inputField = QLineEdit()
            layout.addWidget(self.inputField)
    
            self.model = SqlModel()
            self.model.setTable("Track")
            print(self.model.lastError().text())
    
            self.table.setModel( self.model )
    
            print(self.model.lastError().text())
    
            self.mapper = QDataWidgetMapper()
            self.mapper.setModel(self.model)
    
            self.mapper.addMapping(self.inputField, 0)
    
            self.model.select()
            self.mapper.toFirst()
    
    def createConnection():
        con = QSqlDatabase.addDatabase("QSQLITE")
        con.setDatabaseName("chinook.sqlite")
        if not con.open():
            print('could not open db')
            return False
        return True
    
    
    app = QApplication(sys.argv)
    
    window = MainWindow()
    window.show()
    
    window2 = MainWindow()
    window2.show()
    
    app.exec_()
    

两个窗口都打开了。 两个 QTables 都完美同步。 但只有一个 LineEdit 在其中一个窗口中确实会跟随任何值更改,另一个窗口中的 QLineEdit 只是显示打开时的初始值无需任何进一步的操作。

为了完整起见,单例类的代码:

from PyQt5.QtCore import QObject

class Singleton(type(QObject), type):
    '''
    :class: Parent class used to build the individial singletons across the program. 
    '''
    def __init__(cls, name, bases, dict):  # @NoSelf @ReservedAssignment
        super().__init__(name, bases, dict)
        cls._instance = None

    def __call__(cls, *args, **kwargs):  # @NoSelf
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

【问题讨论】:

  • 你给select()打了两次电话。您需要重新组织您的代码,以便它 separates the concerns 来自 windows 的模型。事实上,模型的设置是在窗口初始化期间执行的,所以所有事情都会完成两次。在它自己的__init__ 中为模型进行所有设置(它只被调用一次,因为它是一个单例)。

标签: python sqlite pyqt5


【解决方案1】:

解释:

这个问题是微不足道的,但很难跟踪,但我将逐步解释它,但在这样做之前你必须了解:

  • 如果您将模型集重置为映射器,则 currentIndex 将为 -1。
  • 使用 select() 重置 QSqlTableModel。

步骤:

  • 在第一个MainWindow中创建模型(SqlModel),在视图(QTableView)和映射器(QDataWidgetMapper)上设置模型,然后使用select()并将映射器的currentIndex设置为0。

  • 在第二个 MainWindow 中不再需要创建模块,因为 Singleton 使用缓存,您在视图和映射器中设置它,您调用 select 会将 currentIndex 设置为 -1 到第一个映射器MainWindow,然后将第二个映射器的 currentIndex 设置为 0。

结论:第一个窗口的映射器的 currentIndex 将为 -1,而第二个映射器的 currentIndex 为 0,因此第一个 QLineEdit 没有更新,因为它没有分配的行。问题是由两次调用 select() 导致的,这会重置先前窗口的映射器。

解决办法:

一种可能的解决方案是只使用一次select()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setMinimumSize(QSize(400, 200))
        widget = QWidget()
        layout = QVBoxLayout()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.table = QTableView()
        layout.addWidget(self.table)

        self.inputField = QLineEdit()
        layout.addWidget(self.inputField)

        self.model = SqlModel()

        if not getattr(self.model, "is_loaded", False):
            self.model.setTable("Track")
            if not self.model.select():
                print(self.model.lastError().text())
            self.model.is_loaded = True

        self.table.setModel(self.model)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model)

        self.mapper.addMapping(self.inputField, 0)

        self.mapper.toFirst()

另一种可能的解决方案是在构造函数中完成信息加载(设置表并使用select())。

【讨论】:

  • 非常感谢!您的两个提案都运行良好。
猜你喜欢
  • 2014-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
相关资源
最近更新 更多