具有自定义项目和自定义项目小部件的 QListView/QListWidget

发布于 2024-07-23 07:32:27 字数 211 浏览 6 评论 0原文

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

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

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

I'm writing a PyQt application and am having some trouble creating a custom list view. I'd like the list to contain arbitrary widgets (one custom widget in particular). How would I go about this?

It seems that the alternative would be to create a table or grid view wrapped in a scrollbar. However, I'd like to be able to take advantage of the model/view approach as well as the nesting (tree-view) support the built-ins handle.

To clarify, the custom widgets are interactive (contain buttons), so the solution requires more than painting a widget.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

眼泪也成诗 2024-07-30 07:32:27

我认为您需要子类 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 的项目委托

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

I think you need to subclass QItemDelegate.

QItemDelegate can be used to provide
custom display features and editor
widgets for item views based on
QAbstractItemView subclasses. Using a
delegate for this purpose allows the
display and editing mechanisms to be
customized and developed independently
from the model and view.

This code is taken from Qt's examples, the torrent application.

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);
    }
};

Basically as you can see it checks if the column to be painted is of a specific index, if so it paints a progress bar. I think you could tweak it a little and instead of using a QStyleOption you could use your own widget.

edit: don't forget to setup your item delegate with your QListView using setItemDelegate.

While investigating your question I've stumbled upon this thread, which elaborates how to paint a custom widget using a QItemDelegate, I believe it has all the info you might need.

绻影浮沉 2024-07-30 07:32:27

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

在此处输入图像描述

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

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

使用自定义小部件实现该行

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

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

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)

If I understand your question correctly, you want something like this:

enter image description here

where each row contains a custom set of widgets.

To achieve this, two steps.

Implement the row with a custom Widget

First, implement a custom widget that contains all the widgets needed per list row.

Here I am using a label and two buttons per row, with an horizontal layout.

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)

Add rows to the list

Instanciating multiple rows is then just a matter of creating a widget item, and associate the custom widget to the item's 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)
浅听莫相离 2024-07-30 07:32:27

@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));

@Idan's answer works well, but I'll post a simpler example I came up with. This item delegate just draws a black rectangle for each item.

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);
    }
};

And then you just need to set it for the list widget:

ui->listWidget->setItemDelegate(new ItemDelegate(ui->listWidget));
梦过后 2024-07-30 07:32:27

Assist 表示:

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

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

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

仅当您希望编辑器小部件仅在单击 EditTrigger 时才出现在视图中时,您才必须对 Q***Delegate 进行子类化,然后消失并让委托以某种方式呈现视图项。

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

Assist says, that:

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

Sets the given widget to be displayed in the cell in the given row and column, passing the ownership of the widget to the table. If cell widget A is replaced with cell widget B, cell widget A will be deleted.

And there is analogs to this method in the most of QAbstractItemView descendants.

You have to subclass Q***Delegate only when you want editor widget to appear in View only when you hit EditTrigger, then vanish and let delegate render the view item in some way.

If I correct, you wanted to see control in item view all the time and be able to hit controls without the need to enter editing mode and wait while delegate creates editor and set its state, so you do not need to make specific delegate, just set widget into the view's item.

幼儿园老大 2024-07-30 07:32:27

另一种方法是在 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);

然后你还可以使用信号/槽更改项目属性..

希望它对你有帮助..!

another way you can add custom items in listWidget. for this purpose you need to add new class. name it as you want i just give it "myList" i hope you know how to add new items in project. :)

then in this new frame add your control as many as u want. like QLabels,QlineEdit etc

then in main class u have to add a listWidget name list or as you want and the write the following code

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);

latter u can also change items properties using signals/slots ..

hope its help you ..!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文