【问题标题】:QListView/QListWidget with custom items and custom item widgets带有自定义项目和自定义项目小部件的 QListView/QListWidget
【发布时间】:2010-10-31 05:04:32
【问题描述】:

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

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

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

【问题讨论】:

    标签: qt pyqt qitemdelegate qlistview qlistwidget


    【解决方案1】:

    我认为你需要继承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 绘制自定义小部件,我相信它包含您可能需要的所有信息。

    【讨论】:

    • 感谢您的帖子,明天我会进一步研究。您能否详细说明我将如何用自定义小部件替换 QStyleOption 绘图?
    • 这只是使用 QItemDelegate 的绘制方法中提供的 QPainter 绘制小部件的问题。我已经编辑了我的帖子以包含一个有用的链接。
    • 嗯,我可以使用这种技术得到一些粗略的工作。但问题在于“任意小部件”方面——我有一个复合小部件,其中包含交互式按钮等——因此它们需要物理放置在列表中,否则用户无法点击它们。如果我错了,请纠正我,但这只会绘制一个不活动的小部件。
    • 确实如此。但这就是你有“编辑模式”的原因,那是列表应该是交互式的,而不是显示静态数据的时候。
    • 好吧,我不需要为自己辩护,但我有理由想要这样做。控件不是编辑数据,而是基于它产生动作。有很多很好的 UI 示例……在浏览器中打开“下载”窗口。
    【解决方案2】:

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

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

    要做到这一点,需要两个步骤。

    使用自定义小部件实现行

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

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

    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)
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        Assist 说:

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

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

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

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

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

        【讨论】:

        • 不幸的是,这些功能仅适用于QTableWidgetQTreeWidgetQListWidget。当使用带有自定义模型的视图时,它们不可用。
        • 来自docs"这个函数应该只用于在列表小部件项的地方显示静态内容。如果要显示自定义动态内容或实现自定义编辑器小部件,请使用QListView并改为子类 QItemDelegate。"
        【解决方案5】:

        您可以在 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);
        

        后来你也可以使用信号/槽来改变项目属性..

        希望对您有所帮助..!

        【讨论】:

        • 谁在项目销毁时删除 myList?我在此示例中看不到任何与所有权相关的代码。
        • 好吧,我是 Java 开发人员,而 JAVA 负责垃圾收集 :) 那是我对 C++ 的一点了解
        猜你喜欢
        • 2014-07-20
        • 2017-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多