如何使用 QCombobox 选择更新 QTableView 单元格? [英] How to update a QTableView cell with a QCombobox selection?

查看:49
本文介绍了如何使用 QCombobox 选择更新 QTableView 单元格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向某些 QTableView 行中的特定单元格添加一个委托 QComboBox 委托.我找到了几篇关于如何添加委托的帖子,但没有一个包含使用 QComboBox 选择更新单元格的示例.

I want to add a delegate QComboBox delegate to specific cells in some of the QTableView rows. I've found several posts on how to add the delegate, but none with examples for updating a cell with the QComboBox selection.

这是我目前所拥有的:

ma​​in.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>350</width>
    <height>239</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QWidget" name="formLayoutWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>341</width>
     <height>231</height>
    </rect>
   </property>
   <layout class="QFormLayout" name="formLayout">
    <item row="0" column="1">
     <widget class="QPushButton" name="btnPopulate">
      <property name="text">
       <string>Populate Table</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QTableView" name="tableView"/>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
from PyQt5 import uic, QtWidgets
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QDialog, QComboBox, QApplication

class GUI(QDialog):

    def __init__(self):
        super(GUI, self).__init__()
        dirname = os.path.dirname(os.path.abspath(__file__))
        uic.loadUi(os.path.join(dirname,'main.ui'), self)
        # button
        self.btnPopulate.clicked.connect(self.populate)
        # table model
        self.header = ['col1', 'col2', 'col3']
        self.QSModel = QStandardItemModel()
        self.QSModel.setColumnCount(3)
        self.QSModel.setHorizontalHeaderLabels(self.header)
        self.tableView.setModel(self.QSModel)
        # combobox delegate
        self.cbDelegate = QComboBox()
        self.cbDelegate.addItems(['choice1', 'choice2'])

    def populate(self):
        row = self.QSModel.rowCount()
        for x in range(0, 7):
            self.QSModel.insertRow(row)
            self.QSModel.setData(self.QSModel.index(row, 0), 'data')
            self.QSModel.item(row, 0).setEditable(True)
            self.QSModel.setData(self.QSModel.index(row, 1), 'data')
            self.QSModel.item(row, 1).setEditable(True)
            # add combobox delegate to even rows
            if x % 2 == 0:
                print('Delegate added.')
                index = self.tableView.model().index(row, 1)
                self.tableView.setIndexWidget(index, self.cbDelegate)
            self.QSModel.setData(self.QSModel.index(row, 2), 'data')
            self.QSModel.item(row, 1).setEditable(True)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = GUI()
    window.show()
    sys.exit(app.exec_())

但是,当我单击填充表格按钮时,只有第一行中的第二个单元格显示为 QComboBox.

However, when I click the Populate Table button only the second cell in the very first row is displayed with a QComboBox.

  1. 我需要如何更改代码以在第 0、2、4 和 6 行或任何任意行中显示 QComboBox.(是否需要显示QComboBox取决于到达行第一个单元格的值.)

  1. How do I need to change the code to display the QComboBox in rows 0, 2, 4 and 6 or any arbitrary row for that matter. (Whether or not the QComboBox needs to be displayed depends on the value of the first cell in reach row.)

我需要使用什么样的方法将单元格内容替换为 QComboBox 选择?

What kind of method do I need to use to replace the cell contents with the QComboBox selection?

推荐答案

如何更改代码以在第 0 行显示 QComboBox,2、4 和 6 或任何与此相关的任意行.(无论是否QComboBox 需要显示取决于第一个单元格的值在到达行.)

How do I need to change the code to display the QComboBox in rows 0, 2, 4 and 6 or any arbitrary row for that matter. (Whether or not the QComboBox needs to be displayed depends on the value of the first cell in reach row.)

导致您只能看到 QComboBox 的问题是因为您只创建了一个 QComboBox,要解决它,您必须为要在其中建立它们的每个单元格创建一个 QComboBox.

the problem so you can only see a QComboBox is caused because you have only created a QComboBox, to solve it you must create a QComboBox for each cell in which you want to establish them.

我需要使用什么样的方法来替换单元格内容QComboBox 选择?

What kind of method do I need to use to replace the cell contents with the QComboBox selection?

您必须将适当的信号连接到模型的 setData() 方法,我们可以使用 QModelIndex 但这很危险,因为它可以在您删除、移动或插入项目时更改,使用 QPersistentModelIndex 是合适的,在这种情况下,您必须使用信号 currentIndexChanged

You must connect the appropriate signal to the setData () method of the model, we could use the QModelIndex but this is dangerous because it can be changed when you delete, move or insert an item, it is appropriate to use QPersistentModelIndex, in this case you must use the signal currentIndexChanged

在这个例子中,我将使用 QModelIndex:

In this example I will use the QModelIndex:

def populate(self):
    row = self.QSModel.rowCount()
    for x in range(7):
        self.QSModel.insertRow(row)
        self.QSModel.setData(self.QSModel.index(row, 0), 'data')
        self.QSModel.item(row, 0).setEditable(True)
        self.QSModel.setData(self.QSModel.index(row, 1), 'data')
        self.QSModel.item(row, 1).setEditable(True)
        # add combobox delegate to even rows
        if x % 2 == 0:
            index = self.tableView.model().index(row, 1)
            cbDelegate = QComboBox()
            pix = QPersistentModelIndex(index)
            cbDelegate.currentIndexChanged[str].connect(lambda txt, pix=pix:self.tableView.model().setData(QModelIndex(pix), txt))
            cbDelegate.addItems(['choice1', 'choice2'])
            self.tableView.setIndexWidget(index, cbDelegate)
        self.QSModel.setData(self.QSModel.index(row, 2), 'data')
        self.QSModel.item(row, 1).setEditable(True)

在这个例子中,我将使用 QStandartItem:

In this example I will use the QStandartItem:

def populate(self):
    row = self.QSModel.rowCount()
    for x in range(7):
        self.QSModel.insertRow(row)
        self.QSModel.setData(self.QSModel.index(row, 0), 'data')
        self.QSModel.item(row, 0).setEditable(True)
        self.QSModel.setData(self.QSModel.index(row, 1), 'data')
        self.QSModel.item(row, 1).setEditable(True)
        if x % 2 == 0:
            item = self.tableView.model().item(row, 1)
            cbDelegate = QComboBox()
            cbDelegate.currentIndexChanged[str].connect(item.setText)
            cbDelegate.addItems(['choice1', 'choice2'])
            self.tableView.setIndexWidget(item.index(), cbDelegate)
        self.QSModel.setData(self.QSModel.index(row, 2), 'data')
        self.QSModel.item(row, 1).setEditable(True)

<小时>

另一种做类似事情的方法是使用委托,为此我们创建了一个继承自 QStyledItemDelegate 的类:

class ComboBoxDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        if index.row()%2 == 0:
            opt = QStyleOptionComboBox()
            opt.rect = option.rect 
            opt.currentText = index.data()
            QApplication.style().drawComplexControl(QStyle.CC_ComboBox, opt, painter)
            QApplication.style().drawControl(QStyle.CE_ComboBoxLabel, opt, painter)
        else:
            QStyledItemDelegate.paint(self, painter, option, index)

    def createEditor(self, parent, option, index):
        if index.row()%2 == 0:
            combobox = QComboBox(parent)
            options = ['choice1', 'choice2']
            if index.data() not in options:
                combobox.addItem(index.data())
            combobox.addItems(options)
            return combobox
        return QStyledItemDelegate.createEditor(self, parent, option, index)

    def setEditorData(self, editor, index):
        if isinstance(editor, QComboBox):
            text = index.data()
            ix = editor.findText(text)
            if ix > 0:
                editor.setCurrentIndex(ix)
            else:
                index.model().setData(index, editor.currentText())
        else:
            QStyledItemDelegate.setEditorData(self, editor, index)

    def setModelData(self, editor, model, index):
        if isinstance(editor, QComboBox):
            model.setData(index, editor.currentText())
        else:
            QStyledItemDelegate.setModelData(self, editor, model, index)

class GUI(QDialog):
    def __init__(self):
        super(GUI, self).__init__()
        dirname = os.path.dirname(os.path.abspath(__file__))
        uic.loadUi(os.path.join(dirname,'main.ui'), self)
        self.btnPopulate.clicked.connect(self.populate)
        self.header = ['col1', 'col2', 'col3']
        self.QSModel = QStandardItemModel()
        self.QSModel.setColumnCount(3)
        self.QSModel.setHorizontalHeaderLabels(self.header)
        self.tableView.setModel(self.QSModel)
        self.tableView.setItemDelegateForColumn(1, ComboBoxDelegate(self.tableView))
        self.populate()

    def populate(self):
        row = self.QSModel.rowCount()
        for x in range(7):
            for i, value in enumerate(['data1', 'data2', 'data3']):
                self.QSModel.setItem(row+x, i, QStandardItem(value))
                self.QSModel.item(row+x, i).setEditable(True)

这篇关于如何使用 QCombobox 选择更新 QTableView 单元格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆