【问题标题】:Add a Widget (QProgressbar) as a childItem within a QTreeView在 QTreeView 中添加一个 Widget (QProgressbar) 作为 childItem
【发布时间】:2020-02-28 06:55:21
【问题描述】:

我制作了一个向 QTreeView 添加数据的模型。我想将一个小部件(例如:QProgressbar)作为子元素添加到该 QTreeView 中的每一行。这样每次如果我们点击每一行,我们都可以看到进度条作为该行的子项

ma​​in.py

import sys
from PySide2.QtWidgets import QApplication, QMainWindow, QHeaderView, QPushButton
from PySide2 import QtCore
from TreeViewUI import Ui_MainWindow
from custom_models.table_model import CustomTableModel


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, data):
        QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        self.table_model = CustomTableModel(data)
        self.treeView.setIconSize(QtCore.QSize(360 / 4, 640 / 4))
        self.treeView.header().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.treeView.setModel(self.table_model)

def get_data():
    content_list = [
        {
            "user_id": 101,
            "user_name": "User_1",
            "user_image": "images/demo.jpg",
            "user_details": "details_1",
            "user_progress": 45,

        },
        {
            "user_id": 102,
            "user_name": "User_2",
            "user_image": "images/demo.jpg",
            "user_details": "details_2",
            "user_progress": 33,

        },
        {
            "user_id": 103,
            "user_name": "User_3",
            "user_image": "images/demo.jpg",
            "user_details": "details_3",
            "user_progress": 80,

        },



    ]
    return content_list


if __name__ == '__main__':
    app = QApplication([])
    data = get_data()
    main_window = MainWindow(data)
    main_window.showMaximized()
    sys.exit(app.exec_())

table_model.py

from PySide2.QtCore import Qt, QAbstractTableModel, QModelIndex
from PySide2.QtGui import QColor, QImage, QIcon, QPixmap

class CustomTableModel(QAbstractTableModel):
    def __init__(self, data):
        QAbstractTableModel.__init__(self)
        self.content_id = []
        self.content_names = []
        self.content_url = []
        self.content_variant = []
        self.content_progress = []
        for content_data in data:
            self.content_id.append(content_data["user_id"])
            self.content_names.append(content_data["user_name"])
            self.content_url.append(content_data["user_image"])
            self.content_variant.append(content_data["user_details"])
            self.content_progress.append(content_data["user_progress"])

        self.row_count = len(self.content_id)
        self.column_count = 4

    def rowCount(self, parent=QModelIndex()):
        return self.row_count

    def columnCount(self, parent=QModelIndex()):
        return self.column_count


    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return ("ID", "NAME", "IMAGE PREVIEW", "DETAILS")[section]


    def data(self, index, role=Qt.DisplayRole):
        column = index.column()
        row = index.row()
        if role == Qt.DisplayRole:
            if column == 0:
                content_id = self.content_id[row]
                return content_id
            elif column == 1:
                return self.content_names[row]
            elif column == 3:
                return self.content_variant[row]




        elif role == Qt.DecorationRole:
            if column == 2:
                image_path = self.content_url[row]
                image = QImage()
                image.load(image_path)
                icon = QIcon()
                icon.addPixmap(QPixmap.fromImage(image))
                return icon


        elif role == Qt.TextAlignmentRole:
            return Qt.AlignLeft

TreeViewUI.py

from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint,
    QRect, QSize, QUrl, Qt)
from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont,
    QFontDatabase, QIcon, QLinearGradient, QPalette, QPainter, QPixmap,
    QRadialGradient)
from PySide2.QtWidgets import *


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(817, 600)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.label = QLabel(self.centralwidget)
        self.label.setObjectName(u"label")

        self.verticalLayout.addWidget(self.label)

        self.treeView = QTreeView(self.centralwidget)
        self.treeView.setObjectName(u"treeView")

        self.verticalLayout.addWidget(self.treeView)


        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.label.setText(QCoreApplication.translate("MainWindow", u"TreeView", None))
    # retranslateUi

这些是我为测试 QTreeView 的示例实现而创建的文件。 Treeview 的基本结构如下:

User_ID  User_Name  User_Image  User_Details
101       ABC       abc.jpg      abc
 QProgressBar widget for the above user(101)# QProgressbar as the childItem for each row.
102       DEF       def.jpg      def
 QProgressBar widget for the above user(102)
103       GHI       ghi.png      ghi
 QProgressBar widget for the above user(103)

【问题讨论】:

  • 你所说的“每一行的子元素”是什么意思,你能不能把你想要得到的图片放在一张图上,因为你说的不清楚吗?
  • 我正在尝试为每个用户添加一个 QProgressbar 作为 childItem。因此,当用户单击一行时,应在其下方出现一个子行,该行将包含一个进度条
  • 我不明白 子行 对您来说是什么,所以我请您提供您想要的图像或方案
  • 我已经更新了这个问题,我正在寻找 QProgressbar 作为每行的 childItem 的结构。你能看一下吗
  • 好的,我明白你想要什么,最后一个问题,QProgressBar 的宽度是多少?

标签: python qt-designer pyside2 qtreeview qprogressbar


【解决方案1】:

如果结构是树类型,则模型必须具有该结构,以便可以使用基于 QAbstractItemModel 的模型,但为了使其更简单,我使用 QStandardItemModel 类实现了它,在该类中我已经在适当的角色中建立了值,并让进度条显示在一个新文件中,因此您必须是该项目的子项。为了显示进度条,我没有设置小部件,但它已通过委托使用 QStyle 绘制:

from PySide2.QtCore import Qt
from PySide2.QtGui import QIcon, QStandardItem, QStandardItemModel


class UserModel(QStandardItemModel):
    def __init__(self, parent=None):
        super(UserModel, self).__init__(parent)
        self.setColumnCount(4)

    def appendUser(self, id_, name, image, details, progress):
        items = []
        row = self.rowCount()
        for text, column in zip((id_, name, details), (0, 1, 3)):
            it = QStandardItem()
            it.setData(text, Qt.DisplayRole)
            self.setItem(row, column, it)
            items.append(it)
        image_item = QStandardItem()
        image_item.setData(QIcon(image), Qt.DecorationRole)
        self.setItem(row, 2, image_item)
        progress_item = QStandardItem()
        progress_item.setData(progress, Qt.UserRole)
        items[0].appendRow(progress_item)
import os
import sys

from PySide2.QtCore import QSize, Qt
from PySide2.QtWidgets import (
    QApplication,
    QMainWindow,
    QHeaderView,
    QStyledItemDelegate,
    QStyleOptionProgressBar,
    QStyle,
)

from TreeViewUI import Ui_MainWindow
from custom_models.table_model import UserModel

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class ProgressDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        if index.parent().isValid():
            r = option.rect
            r.setWidth(200)
            progress = index.data(Qt.UserRole)
            progress_option = QStyleOptionProgressBar()
            progress_option.rect = r
            progress_option.minimum = 0
            progress_option.maximum = 100
            progress_option.progress = progress
            progress_option.text = "{}%".format(progress)
            progress_option.textVisible = True
            QApplication.style().drawControl(
                QStyle.CE_ProgressBar, progress_option, painter
            )
            return
        super(ProgressDelegate, self).paint(painter, option, index)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, data):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.model = UserModel(self)
        for content_data in data:
            self.model.appendUser(
                content_data["user_id"],
                content_data["user_name"],
                os.path.join(CURRENT_DIR, content_data["user_image"]),
                content_data["user_details"],
                content_data["user_progress"],
            )
        self.treeView.setIconSize(QSize(360 / 4, 640 / 4))
        self.treeView.header().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.treeView.setModel(self.model)
        delegate = ProgressDelegate(self.treeView)
        self.treeView.setItemDelegate(delegate)


def get_data():
    content_list = [
        {
            "user_id": 101,
            "user_name": "User_1",
            "user_image": "images/demo.jpg",
            "user_details": "details_1",
            "user_progress": 45,
        },
        {
            "user_id": 102,
            "user_name": "User_2",
            "user_image": "images/demo.jpg",
            "user_details": "details_2",
            "user_progress": 33,
        },
        {
            "user_id": 103,
            "user_name": "User_3",
            "user_image": "images/demo.jpg",
            "user_details": "details_3",
            "user_progress": 80,
        },
    ]
    return content_list


if __name__ == "__main__":
    app = QApplication([])
    data = get_data()
    main_window = MainWindow(data)
    main_window.showMaximized()
    sys.exit(app.exec_())

另一种可能的解决方案是通过委托创建一个持久编辑器:

class ProgressDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        if index.parent().isValid():
            view = option.widget
            if isinstance(view, QTreeView) and index.model() is view.model():
                view.openPersistentEditor(index)
            return
        super(ProgressDelegate, self).paint(painter, option, index)

    def createEditor(self, parent, option, index):
        if index.parent().isValid():
            editor = QProgressBar(parent)
            editor.setFixedWidth(200)
            editor.setContentsMargins(0, 0, 0, 0)
            editor.setValue(index.data(Qt.UserRole))
            return editor
        super(ProgressDelegate, self).createEditor(parent, option, index)

注意:像我在第一个委托中所做的那样绘制 QProgressBar 是一项微不足道的任务,但如果您想放置更复杂的小部件(具有更多状态的小部件,如 QPushButton),那么最好使用第二个选项。

【讨论】:

  • 非常感谢。我也可以使用相同的过程添加其他小部件吗?
  • @PratikTayshete 阅读我的更新、测试和实验。您必须在您的 cmets 中更加精确,因为说:我还可以添加其他小部件 可以通过在 QProgressbar 旁边添加更多小部件或使用另一个小部件而不是 QProgressBar 来解释,例如 QPushButton。在第一种情况下,您可以使用我的第二个委托并将唯一的小部件作为容器放置,并通过布局设置小部件。在第二种情况下,只需使用我的第二个选项。
猜你喜欢
  • 1970-01-01
  • 2013-11-01
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-27
  • 1970-01-01
  • 2022-01-01
相关资源
最近更新 更多