【问题标题】:QDataWidgetMapper and validationQDataWidgetMapper 和验证
【发布时间】:2014-05-16 16:16:33
【问题描述】:

我有一个包含几列的树视图。我使用 QDataWidgetMapper 将每一列与侧边栏上的几个小部件之一连接起来。可以通过双击树视图中的单元格或使用侧边栏上的小部件来更改数据。

我的一个专栏包含需要验证的字符串数据。我创建了一个自定义委托,我将它附加到树视图和数据小部件映射器。它有一个 QRegExpValidator,以防止用户在输入时出现无效输入。此外,在 setModelData() 中,一旦用户按下“Enter”,它就会进行不同的验证检查。对于树视图,此委托工作正常。对于映射的QLineEdit,有两个问题:

  1. 没有调用 QRegExpValidator(可能是因为 createEditor() 没有用于侧边栏小部件);因此用户可以在 QLineEdit 中输入错误的输入。
  2. 如果数据在 setModelData() 期间检查失败,QLineEdit 中的文本不会切换回原始文本。因此,当用户单击 QLineEdit 以外的其他内容时,错误消息会再次打印出来。

我是不是走错路了?

这是一个简化的例子。为简单起见,我用列表视图替换了树视图:

class TestWidgetMapperValidate(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(TestWidgetMapperValidate, self).__init__(parent)

        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        self.mainLayout = QtGui.QVBoxLayout(self.centralWidget)

        # Set up the list view
        self.listView = QtGui.QListView()
        self.listModel = QtGui.QStringListModel(['aaa', 'bbb', 'ccc', 'ddd'])
        self.listView.setModel(self.listModel)

        # Set up the delegate
        self.testDelegate = TestDelegate()
        self.listView.setItemDelegateForColumn(0, self.testDelegate)

        self.lineEdit = QtGui.QLineEdit()

        self.mainLayout.addWidget(self.listView)
        self.mainLayout.addWidget(self.lineEdit)

        # Set up the QDataWidgetMapper
        self.mapper = QtGui.QDataWidgetMapper()
        self.mapper.setModel(self.listModel)
        self.mapper.addMapping(self.lineEdit, 0)
        self.mapper.setItemDelegate(self.testDelegate)

        self.listView.selectionModel().currentChanged.connect(self.mapper.setCurrentModelIndex)

class TestDelegate(QtGui.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(TestDelegate, self).__init__(parent)

    def createEditor(self, parentWidget, option, qModelIndex):
        editor = QtGui.QLineEdit(parentWidget)
        nameRegex = QtCore.QRegExp('[a-zA-Z][a-zA-Z0-9_]+')
        editor.setValidator(QtGui.QRegExpValidator(nameRegex))
        return editor

    def setEditorData(self, editor, qModelIndex):
        value = qModelIndex.data(QtCore.Qt.DisplayRole)
        editor.setText(value)

    def setModelData(self, editor, model, qModelIndex):
        if not editor.hasAcceptableInput():
            return False

        oldValue = qModelIndex.data(QtCore.Qt.DisplayRole)
        newValue = editor.text()

        if oldValue != newValue:
            if newValue in model.stringList():
                print 'That name already exists: {0}'.format(newValue)
                return False
            else:
                return model.setData(qModelIndex, newValue)
        else:
            return True

(注意:我使用的是 PySide 和 Python 2.7)

【问题讨论】:

    标签: python qt pyside


    【解决方案1】:

    这是我想出的。我不知道这是否是最好的解决方案,但它适用于我的情况。

    1. 我最终将 QRegExpValidator 直接添加到我的行编辑中,因为我无法让它从委托中读取。以下是来自 __init__() 的更新行:

      class TestWidgetMapperValidate(QtGui.QMainWindow):
          def __init__(self, parent=rsui.getMayaMainWindow()):
              # some code omitted here
              self.lineEdit = QtGui.QLineEdit()
              nameRegex = QtCore.QRegExp('[a-zA-Z][a-zA-Z0-9_]+')
              self.lineEdit.setValidator(QtGui.QRegExpValidator(nameRegex))
      
    2. 如果数据未能通过委托中的检查,我会使用原始值调用 setEditorData() 以将其强制恢复为旧值。这可以防止错误消息被打印两次。下面是来自 TestDelegate 类的更新后的 setModelData():

      def setModelData(self, editor, model, qModelIndex):
          if not editor.hasAcceptableInput():
              return False
      
          oldValue = qModelIndex.data(QtCore.Qt.DisplayRole)
          newValue = editor.text()
      
          if oldValue != newValue:
              if newValue in model.stringList():
                  # The new value is not valid.  Set the data back to the original value.
                  self.setEditorData(editor, qModelIndex)
                  print 'That name already exists: {0}'.format(newValue)
                  return False
              else:
                  return model.setData(qModelIndex, newValue)
          else:
              return True
      

    【讨论】:

      【解决方案2】:

      据我了解:

      1. QDataWidgetMapper 用于将模型数据映射到现有的小部件。因此,正如您所提到的,委托方法 createEditor 永远不会被调用。换一种说法:QDataWidgetMapper 用于而不是将委托方法createEditor 与视图结合使用。另一种方法是为您的侧边栏创建一个视图,向它注册您的委托(以便该视图调用createEditor)并共享tableView 的选择机制。见http://qt-project.org/doc/qt-5/model-view-programming.html#sharing-selections-among-views
      2. 如果您要按照上面的建议创建侧边栏视图,您可以通过恢复编辑器值来处理 setModelData 返回 false 的事件。

      我不得不承认,我对模型视图比较陌生。我有兴趣听取其他人的意见。这是一个很好的问题!

      【讨论】:

        猜你喜欢
        • 2013-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多