【问题标题】:update multiple views on multiple dialogs connected to a single data model更新连接到单个数据模型的多个对话框上的多个视图
【发布时间】:2013-03-18 08:32:15
【问题描述】:

我有两个表单,其中两个视图连接到同一个 dataModel 类,但是当我更改一个表单上的数据时,另一个表单上的数据没有变化。

我正在尝试在几个不同的对话框/表单上获取一个组合框,以便在基础数据从另一个对话框/表单更改时得到更新。

这是我的代码:

class Model(QStringListModel):

    def __init__(self, parent=None):
        super(Model, self).__init__(parent)
        data = QStringList()
        data << "one" << "two" << "three" << "four" << "five"
        self.setStringList(data)


class Form_2(QDialog):

    def __init__(self, parent=None):
        super(Form_2, self).__init__(parent)
        self.model = Model()
        self.combo = QListView()
        self.combo.setModel(self.model)

        layout = QVBoxLayout()
        layout.addWidget(self.combo)
        self.setLayout(layout)


class Form_1(QDialog):

    def __init__(self, parent=None):
        super(Form_1, self).__init__(parent)
        self.model = Model()
        self.listView = QListView()
        self.listView.setModel(self.model)
        self.combo = QComboBox()
        self.combo.setModel(self.model)
        self.form2_button = QPushButton("Open Form_2")

        layout = QVBoxLayout()
        layout.addWidget(self.listView)
        layout.addWidget(self.combo)
        layout.addWidget(self.form2_button)
        self.setLayout(layout)

        self.connect(self.form2_button, SIGNAL("clicked()"), self.form_2)

    def form_2(self):
        self.ft = Form_2()
        self.ft.show()


app = QApplication(sys.argv)
form = Form_1()
form.show()
app.exec_()

【问题讨论】:

  • 基于同一模型的不同视图在任何视图修改模型数据时应该显示相同的值,您可能错误地使用模型/视图框架,请发布您的代码的简化版本帮助确定您的问题所在。
  • QStandardItemModel 已经有一个名为setData 的方法。您的 setData 方法可能会导致某种冲突。要获得进一步的帮助,您还应该发布您实际使用模型和视图的代码部分。由于您正在使用数据库,请考虑改用QSqlQueryModelQSqlTableModel
  • 我知道 setData 没有正确实现,但我这样做只是因为我尝试没有它,模型被填充,但我无法重新填充它。而且我还尝试了其他几个模型,例如 QAbstractTableModel、QSqlTableModel QSqlQueryModel,我直接在两种表单上都尝试了它们,而不是通过创建我自己的类.. 获取初始数据一切正常,但我现在可以刷新组合以获得新数据。我在这里不知所措..任何帮助将不胜感激。
  • 您认为您可以构建一个有效的简单示例吗?这个想法是 2 个独立的形式,使用相同的模型,并且当模型只被一个改变时,两者都得到模型的变化。
  • 模型是否有可能只更新同一个实例的视图而不更新另一个实例的视图?我在帖子底部添加了我尝试过的内容,请看上方。

标签: python model-view-controller model pyqt qcombobox


【解决方案1】:

感谢 ccc.larc 给我答案。我们基本上只能使用模型的一个实例,如果模型有多个实例,它就不起作用。因此,您始终必须将模型的相同实例传递给您希望它使用的任何形式。

如果我理解正确,这就是@X.Jacobs 所说的,我只是展示了我的新代码,它更简单一些,可以更好地理解它与我以前的代码的对比(那不起作用)

所以我上面的代码只需要一个小的改动。

class Model(QStringListModel):

    def __init__(self, parent=None): 
        super(Model, self).__init__(parent)
        data = QStringList()
        data << "one" << "two" << "three" << "four" << "five"
        self.setStringList(data)


class Form_2(QDialog):

    def __init__(self, model, parent=None): #get the model from the calling form
        super(Form_2, self).__init__(parent)
        self.model = model
        self.combo = QListView()
        self.combo.setModel(self.model)

        layout = QVBoxLayout()
        layout.addWidget(self.combo)
        self.setLayout(layout)


class Form_1(QDialog):

    def __init__(self, parent=None):
        super(Form_1, self).__init__(parent)
        self.model = Model()
        self.listView = QListView()
        self.listView.setModel(self.model)
        self.combo = QComboBox()
        self.combo.setModel(self.model)
        self.form2_button = QPushButton("Open Form_2")

        layout = QVBoxLayout()
        layout.addWidget(self.listView)
        layout.addWidget(self.combo)
        layout.addWidget(self.form2_button)
        self.setLayout(layout)

        self.connect(self.form2_button, SIGNAL("clicked()"), self.form_2)

    def form_2(self):
        self.ft = Form_2(self.model) #pass the same model to the new form
        self.ft.show()


app = QApplication(sys.argv)
form = Form_1()
form.show()
app.exec_()

【讨论】:

    【解决方案2】:

    下面是一个基本示例,说明基于同一模型的多个视图在修改任何视图时如何自我更新:

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    from PyQt4 import QtGui, QtCore
    
    class MyDialog(QtGui.QWidget):
        def __init__(self, modelSource, parent=None):
            super(MyDialog, self).__init__(parent)
    
            self.tableView = QtGui.QTableView(self)
            self.tableView.horizontalHeader().setStretchLastSection(True)
            self.tableView.setModel(modelSource)
    
            self.listView = QtGui.QListView(self)
            self.listView.setModel(modelSource)
            self.listView.setModelColumn(0)
    
            self.comboBox = QtGui.QComboBox(self)
            self.comboBox.setModel(modelSource)
            self.comboBox.setModelColumn(1)
    
            self.layoutGrid = QtGui.QGridLayout(self)
            self.layoutGrid.addWidget(self.comboBox, 0, 0, 1, 2)
            self.layoutGrid.addWidget(self.listView, 1, 0, 1, 1)
            self.layoutGrid.addWidget(self.tableView, 1, 1, 1, 1)
    
    class MyWindow(QtGui.QWidget):
        _dialogs = []
        def __init__(self, parent=None):
            super(MyWindow, self).__init__(parent)
    
            self.modelSource = QtGui.QStandardItemModel(self)
    
            for rowNumber in range(3):
                items = []
                for columnNumber in range(3):
                    item = QtGui.QStandardItem()
                    item.setText("row: {0} column {1}".format(rowNumber, columnNumber))
    
                    items.append(item)
    
                self.modelSource.appendRow(items)
    
            self.labelDialogs = QtGui.QLabel(self)
            self.labelDialogs.setText("Select a number of dialogs to create:")
    
            self.spinBoxDialogs = QtGui.QSpinBox(self)
            self.spinBoxDialogs.setValue(3)
    
            self.pushButtonShow = QtGui.QPushButton(self)
            self.pushButtonShow.setText("Show Dialogs!")
            self.pushButtonShow.clicked.connect(self.on_pushButtonShow_clicked)
    
            self.pushButtonClose = QtGui.QPushButton(self)
            self.pushButtonClose.setText("Close Dialogs")
            self.pushButtonClose.clicked.connect(self.on_pushButtonClose_clicked)
    
            self.layoutHorizontal = QtGui.QHBoxLayout(self)
            self.layoutHorizontal.addWidget(self.labelDialogs)
            self.layoutHorizontal.addWidget(self.spinBoxDialogs)
            self.layoutHorizontal.addWidget(self.pushButtonShow)
            self.layoutHorizontal.addWidget(self.pushButtonClose)
    
        @QtCore.pyqtSlot()
        def on_pushButtonShow_clicked(self): 
            self._dialogs = []
            dialogsNumber = self.spinBoxDialogs.value()
    
            for dialogNumber in range(dialogsNumber):  
                dialog = MyDialog(self.modelSource)
                dialog.show()
                dialog.move(100, 100)
    
                self._dialogs.append(dialog)
    
        @QtCore.pyqtSlot()
        def on_pushButtonClose_clicked(self): 
            for dialog in self._dialogs:
                dialog.close()
    
            self._dialogs = []
    
    if __name__ == "__main__":
        import sys
    
        app = QtGui.QApplication(sys.argv)
        app.setApplicationName('MyWindow')
    
        main = MyWindow()
        main.show()
    
        sys.exit(app.exec_())
    

    【讨论】:

    • 感谢@X.Jacobs。但这是在同一个文件上,是否可以有一个包含两个单独文件的示例,甚至是同一个文件但有两个单独的对话框?请看我最后的评论。
    • 这是你可以自己做的事情。在我的示例中,只需使用tableviewlistviewcomboboxgridlayout 创建尽可能多的对话框。然后在您创建的对话框上调用dialog.show()。如果它们在同一个小部件中,它仍然没有什么不同,但它可能会帮助您学习。如果您仍然无法解决问题,我很乐意为您提供帮助。
    • 我做过,我以前试过,没用。在帖子中查看我的代码。我重发了这篇文章,因为它开始变得丑陋了。
    • @JoeMicro 查看我的updated answer,我将其修改为使用同一模型显示多个小部件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 2020-02-19
    • 1970-01-01
    相关资源
    最近更新 更多