35

我正在编写一个 PyQt 应用程序,但在创建自定义列表视图时遇到了一些麻烦。我希望列表包含任意小部件(特别是一个自定义小部件)。我该怎么办?

似乎另一种选择是创建一个包含在滚动条中的表格或网格视图。但是,我希望能够利用模型/视图方法以及嵌套(树视图)支持内置句柄。

澄清一下,自定义小部件是交互式的(包含按钮),因此解决方案需要的不仅仅是绘制小部件。

4

5 回答 5

30

我认为您需要继承 QItemDelegate

QItemDelegate 可用于为基于 QAbstractItemView 子类的项目视图提供自定义显示功能和编辑器小部件。为此目的使用委托允许独立于模型和视图自定义和开发显示和编辑机制。

此代码取自 Qt 的示例,即 torrent 应用程序。

class TorrentViewDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    inline TorrentViewDelegate(MainWindow *mainWindow) : QItemDelegate(mainWindow) {}

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const
    {
        if (index.column() != 2) {
            QItemDelegate::paint(painter, option, index);
            return;
        }

        // Set up a QStyleOptionProgressBar to precisely mimic the
        // environment of a progress bar.
        QStyleOptionProgressBar progressBarOption;
        progressBarOption.state = QStyle::State_Enabled;
        progressBarOption.direction = QApplication::layoutDirection();
        progressBarOption.rect = option.rect;
        progressBarOption.fontMetrics = QApplication::fontMetrics();
        progressBarOption.minimum = 0;
        progressBarOption.maximum = 100;
        progressBarOption.textAlignment = Qt::AlignCenter;
        progressBarOption.textVisible = true;

        // Set the progress and text values of the style option.
        int progress = qobject_cast<MainWindow *>(parent())->clientForRow(index.row())->progress();
        progressBarOption.progress = progress < 0 ? 0 : progress;
        progressBarOption.text = QString().sprintf("%d%%", progressBarOption.progress);

        // Draw the progress bar onto the view.
        QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
    }
};

基本上如您所见,它检查要绘制的列是否具有特定索引,如果是,则绘制进度条。我认为您可以对其进行一些调整,而不是使用 QStyleOption 您可以使用自己的小部件。

编辑:不要忘记使用 setItemDelegate 使用QListView设置您的项目委托。

在调查您的问题时,我偶然发现了这个线程,该线程详细说明了如何使用 QItemDelegate 绘制自定义小部件,我相信它包含您可能需要的所有信息。

于 2009-06-04T07:38:13.713 回答
16

如果我正确理解你的问题,你想要这样的东西:

在此处输入图像描述

其中每一行包含一组自定义小部件。

要实现这一点,需要两个步骤。

使用自定义小部件实现行

首先,实现一个自定义小部件,其中包含每个列表行所需的所有小部件。

在这里,我使用一个标签和每行两个按钮,采用水平布局。

class MyCustomWidget(QWidget):
    def __init__(self, name, parent=None):
        super(MyCustomWidget, self).__init__(parent)

        self.row = QHBoxLayout()

        self.row.addWidget(QLabel(name))
        self.row.addWidget(QPushButton("view"))
        self.row.addWidget(QPushButton("select"))

        self.setLayout(self.row)

将行添加到列表

然后,实例化多行只需创建一个小部件项目,并将自定义小部件与该项目的行相关联。

# Create the list
mylist = QListWidget()

# Add to list a new item (item is simply an entry in your list)
item = QListWidgetItem(mylist)
mylist.addItem(item)

# Instanciate a custom widget 
row = MyCustomWidget()
item.setSizeHint(row.minimumSizeHint())

# Associate the custom widget to the list entry
mylist.setItemWidget(item, row)
于 2018-03-14T08:34:47.883 回答
5

@Idan 的回答效果很好,但我会发布一个我想出的更简单的例子。这个项目委托只是为每个项目绘制一个黑色矩形。

class ItemDelegate : public QItemDelegate
{
public:
    explicit ItemDelegate(QObject *parent = 0) : QItemDelegate(parent) {}
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        painter->fillRect(option.rect.adjusted(1, 1, -1, -1), Qt::SolidPattern);
    }
};

然后你只需要为列表小部件设置它:

ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));
于 2014-03-12T10:39:34.460 回答
2

Assist 说:

void QTableWidget::setCellWidget (int row, int column, QWidget * widget)  

将给定的小部件设置为显示在给定行和列的单元格中,将小部件的所有权传递给表格。如果单元小部件 A 被单元小部件 B 替换,则单元小部件 A 将被删除。

在大多数 QAbstractItemView 后代中都有类似的方法。

只有当您希望编辑器小部件仅在您点击 EditTrigger 时出现在视图中时,您才必须继承 Q***Delegate,然后消失并让委托以某种方式呈现视图项。

如果我更正了,您希望始终在项目视图中看到控件并且能够在无需进入编辑模式并等待委托创建编辑器并设置其状态的情况下点击控件,因此您不需要制作特定委托,只需将小部件设置到视图的项目中。

于 2010-03-19T10:48:58.180 回答
1

您可以在 listWidget 中添加自定义项目的另一种方式。为此,您需要添加新类。随意命名我只是给它“myList”我希望你知道如何在项目中添加新项目。:)

然后在这个新框架中添加你想要的控件。像 QLabels、QlineEdit 等

然后在主类中,您必须添加一个 listWidget 名称列表或根据需要添加并编写以下代码

MyList *myList = new MyList();
QListWidgetItem *item = new QListWidgetItem();
ui->list->insertItem(ui->list->size().height(),item);
item->setSizeHint(QSize(50,30));
ui->list->setItemWidget(item,myList);

后者您还可以使用信号/插槽更改项目属性..

希望它对你有帮助..!

于 2013-04-01T12:11:09.347 回答