如何扩展默认情况下没有模型支持的Qt Widgets

时间:2015-01-27 05:31:32

标签: python qt model pyqt qtableview

CustomMenu类继承自QMenu。它的自定义setData()方法接受一个参数并将其设置为类变量model。我这样做是因为QToolButtonQToolMenuQAction不支持模型/视图框架。除了QList-QTable-QTree Views and Trees之外,我所知道的只有QComboBox支持model。 所以问题是:是否可以扩展其他non-model widgets的功能,以便它们也可以用作driven-by-model小部件?

enter image description here

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os

class CustomMenu(QMenu):
    def __init__(self):
        super(CustomMenu, self).__init__()
        self.model=None

    def setModel(self, model):
        self.model=model
        self.pupulate()
    def pupulate(self):
        for item in self.model.items:
            self.addAction(item)

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
    def rowCount(self, QModelIndex):
        return len(self.items)
    def columnCount(self, QModelIndex):
        return 1

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        if role == Qt.DisplayRole:
            return QVariant(self.items[index.row()])
        return QVariant()
    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():            
            if role == Qt.EditRole:                
                self.items[index.row()]=value  
                return True
        return False
class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        layout=QVBoxLayout(self)
        self.setLayout(layout)

        tablemodel=Model(self)

        tableView=QTableView() 
        tableView.horizontalHeader().setStretchLastSection(True)
        tableView.setModel(tablemodel)         
        layout.addWidget(tableView)      

        combo=QComboBox()
        combo.setModel(tablemodel)
        layout.addWidget(combo)

        toolButton=QToolButton(self)
        toolButton.setText('Tool Button')
        toolButton.setPopupMode(QToolButton.InstantPopup)
        toolButton.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))

        menu=CustomMenu()
        menu.setModel(tablemodel)
        toolButton.setMenu(menu)
        layout.addWidget(toolButton)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

稍后编辑:尝试实现QDataWidgetMapper():

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os

class CustomMenuButton(QWidget):
    def __init__(self, parent):
        super(CustomMenuButton, self).__init__(parent)
        self.dataMapper=QDataWidgetMapper()
        layout=QVBoxLayout()
        self.setLayout(layout)

        toolButton=QToolButton(self)
        toolButton.setText('Tool Button')
        toolButton.setPopupMode(QToolButton.InstantPopup)

        self.menu=QMenu(toolButton)
        toolButton.setMenu(self.menu)

    def setModel(self, model):
        self.dataMapper.setModel(model)

        for row in range(model.rowCount()):
            action=self.menu.addAction('Item')

            self.dataMapper.addMapping(action, row)

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
    def rowCount(self, parent=QModelIndex()):
        return len(self.items)
    def columnCount(self, parent=QModelIndex()):
        return 1

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        if role == Qt.DisplayRole:
            return QVariant(self.items[index.row()])
        return QVariant()
    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():            
            if role == Qt.EditRole:                
                self.items[index.row()]=value  
                self.dataChanged.emit(index, index)
                return True
        return False

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        layout=QVBoxLayout(self)
        self.setLayout(layout)

        tablemodel=Model(self)

        tableView=QTableView() 
        tableView.horizontalHeader().setStretchLastSection(True)
        tableView.setModel(tablemodel)         
        layout.addWidget(tableView)      

        combo=QComboBox()
        combo.setModel(tablemodel)
        layout.addWidget(combo)

        menuButton=CustomMenuButton(self)
        layout.addWidget(menuButton)

        menuButton.setModel(tablemodel)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

编辑2:使用dataChanged = pyqtSignal(QModelIndex,QModelIndex)定义了一个CustomAction类(QAction)......

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os

class CustomAction(QAction):
    dataChanged = pyqtSignal(QModelIndex,QModelIndex)
    def __init__(self, name, parent):
        super(CustomAction, self).__init__(name, parent)

class CustomMenuButton(QWidget):
    def __init__(self, parent):
        super(CustomMenuButton, self).__init__(parent)
        self.dataMapper=QDataWidgetMapper()
        layout=QVBoxLayout()
        self.setLayout(layout)

        toolButton=QToolButton(self)
        toolButton.setText('Tool Button')
        toolButton.setPopupMode(QToolButton.InstantPopup)

        self.menu=QMenu(toolButton)
        toolButton.setMenu(self.menu)

    def setModel(self, model):
        self.dataMapper.setModel(model)
        for row in range(model.rowCount()):
            index=model.index(row,0)
            itemName=model.data(index, Qt.DisplayRole).toPyObject()

            actn=CustomAction(itemName, self.menu)
            self.menu.addAction(actn)

            self.dataMapper.addMapping(actn, row)

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
    def rowCount(self, parent=QModelIndex()):
        return len(self.items)
    def columnCount(self, parent=QModelIndex()):
        return 1

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        if role == Qt.DisplayRole:
            return QVariant(self.items[index.row()])
        return QVariant()
    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():            
            if role == Qt.EditRole:                
                self.items[index.row()]=value  
                self.dataChanged.emit(index, index)
                return True
        return False

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        layout=QVBoxLayout(self)
        self.setLayout(layout)

        tablemodel=Model(self)

        tableView=QTableView() 
        tableView.horizontalHeader().setStretchLastSection(True)
        tableView.setModel(tablemodel)         
        layout.addWidget(tableView)      

        combo=QComboBox()
        combo.setModel(tablemodel)
        layout.addWidget(combo)

        menuButton=CustomMenuButton(self)
        layout.addWidget(menuButton)

        menuButton.setModel(tablemodel)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

这是QDataWidgetMapper课程的设计目标。以下博客有一个很好的教程,涵盖了如何实现它:http://www.yasinuludag.com/blog/?p=98

编辑:我应该补充说QDataWidgetMapper适用于QWidget及其子类,因此QAction不适用。对于非QWidget或其子类的类,您可能必须实现自己的自定义模型视图绑定。