QListView中的自定义项

6 投票
2 回答
9358 浏览
提问于 2025-04-17 06:56

我刚接触PyQT和QT,得快速设计一个用户界面,想要做成类似现代邮件应用的样子:左边是邮件列表,右边是编辑器。我希望在QListView中显示的不仅仅是字符串,而是更丰富的信息——比如,项目名称用粗体显示,下面有两行描述用不同的样式显示,左上角还有一组像标签一样的标记。此外,列表需要每隔几秒更新一次(可能只会有少量项目发生变化),所以我不想每次都重写数据。

根据我在各种手册和教程中看到的,有不同的方法可以实现这个功能,但我不太确定最常用的方法是什么(因为其他人也需要在我草拟的核心应用上工作)——你会使用哪些对象和方法呢?是QListView还是QListWidget,然后是子类化QAbstractListModel还是QStandardItemModel,等等?

2 个回答

2

如果用户不需要手动更改邮件列表中的数据,那么你可以很简单地使用一个模型类,配合自定义的 QStyledItemDelegate(或者 QAbstractItemDelegate)。你可以看看上面链接的 QAbstractItemDelegate 文档中的示例,还有 星形代理 示例。

如果用户需要在邮件列表中直接更改数据,而且这个邮件列表和标准的控件差别很大,那么确保编辑器看起来和展示视图相似就会变得比较困难。这并不是不可能,但这是比较棘手的部分。

你可以使用 QStandardItemModel 来解决这个问题。不过……我一般建议为任何不简单的情况创建一个带有 Qt 包装的领域模型(在你的情况下是 QAbstractListModel)。

4

如果你不想花太多时间考虑你的模型,或者只是想在不同的视图之间共享数据,那么 QListWidget 就是为这个目的设计的。你只需要直接处理这个列表,数据会存储在它自己的底层模型中。

对于 QListWidget,你可以使用:QListWidget.setItemWidget(QListWidgetItem item, QWidget widget)。这意味着你需要创建一个自己想要样子的控件,里面可以有 QLabels 来显示文本和图片。然后你可以通过以下方式将它们添加到 QListWidget 中:

# create item widget
item = QListWidgetItem()
w = CustomItemWidget()
w.setTitle = "Title"
w.setDescription = "Blah blah"
# would have a QPixmap already cached
w.setBadgeImage = preCreatedPixmaps['thisBadge']  
listWidget.insertItem(item)
listWidget.setItemWidget(item, w)

这样做的好处是,你可以很简单地控制每个项目的外观,而不需要写一个更复杂的代理。

不过,这种方法的缺点是,你不能和其他视图共享模型,而且当需要添加新项目时,你得自己管理创建控件。而且这种方法假设控件的显示是静态的,一旦设置后不喜欢被更改。如果你有成千上万个项目,这种方法可能会变得比较慢。

在 QListView 中为你的项目创建一个代理,从性能的角度来看是更快的做法,但相对来说技术上会复杂一些……

这里有一个例子(虽然是 C++ 的,但很容易理解):http://www.qtcentre.org/threads/27777-Customize-QListWidgetItem-how-to?p=131746#post131746

还有一个 Python 的例子,虽然代码没有缩进:http://www.qtcentre.org/archive/index.php/t-31029.html

撰写回答