QStyledItemDelegate 水平截断文本并且不添加水平滚动条 [英] QStyledItemDelegate truncates text horizontally and doesn't add a horizontal scroll bar

查看:48
本文介绍了QStyledItemDelegate 水平截断文本并且不添加水平滚动条的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我得到了以下代码,我稍微修改了一下,作为关于

I got the following code, which I slightly modified, as an answer on how to use HTML formatted text in a QListWidget.

main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>341</width>
    <height>161</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QWidget" name="verticalLayoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>321</width>
     <height>141</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QListWidget" name="lwOptions"/>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

test.py

import os
import html
from PyQt5 import uic
from PyQt5.Qt import (QApplication, QDialog, QListWidget, 
    QListWidgetItem, QStyleOptionViewItem, 
    QStyledItemDelegate, QStyle)
from PyQt5.QtGui import QPalette, QAbstractTextDocumentLayout, QTextDocument
from PyQt5.QtCore import QSize

class HTMLDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HTMLDelegate, self).__init__(parent)
        self.doc = QTextDocument(self)

    def paint(self, painter, option, index):
        painter.save()
        options = QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setHtml(options.text)
        options.text = ""
        style = QApplication.style() if options.widget is None \
            else options.widget.style()
        style.drawControl(QStyle.CE_ItemViewItem, options, painter)

        ctx = QAbstractTextDocumentLayout.PaintContext()
        if option.state & QStyle.State_Selected:
            ctx.palette.setColor(QPalette.Text, option.palette.color(
                QPalette.Active, QPalette.HighlightedText))
        else:
            ctx.palette.setColor(QPalette.Text, option.palette.color(
                QPalette.Active, QPalette.Text))
        textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options, None)
        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)
        constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)
        painter.restore()

    def sizeHint(self, option, index):
        return QSize(self.doc.idealWidth(), self.doc.size().height())

class GUI(QDialog):
    def __init__(self):
        super(GUI, self).__init__()
        dirname = os.path.dirname(os.path.abspath(__file__))
        uic.loadUi(os.path.join(dirname,'main.ui'), self)

        delegate = HTMLDelegate(self.lwOptions)
        self.lwOptions.setItemDelegate(delegate)

        for ordinal in ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth']:
            item = QListWidgetItem('This is the <b>{}</b> word. This is the <b>{}</b> word. This is the <b>{}</b> word.'.format(ordinal, ordinal, ordinal))
            self.lwOptions.addItem(item)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = GUI()
    window.show()
    sys.exit(app.exec_())

The code works fine, however, text that is longer than the width of the QListWidget is truncated and no horizontal scroll bar is displayed. (The vertical scroll bar is automatically added when needed.)

I tried forcing the display via ScrollBarAlwaysOn, which only displayed a non-working horizontal scroll bar.

How do I need to change the code to automatically add a horizontal scroll bar when needed?

解决方案

The calculation I made in my previous answer was incorrect since the size that returns sizeHint() is relative to the previous item. A simple solution is to use the Qt::SizeHintRole role to set the size.

import os
from PyQt5 import QtCore, QtGui, QtWidgets, uic

class HTMLDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HTMLDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)

    def paint(self, painter, option, index):
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setHtml(options.text)
        options.text = ""
        style = QApplication.style() if options.widget is None \
            else options.widget.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option.state & QtWidgets.QStyle.State_Selected:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
        else:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.Text))
        textRect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options, None)
        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)
        constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)
        painter.restore()
        s = QtCore.QSize(self.doc.idealWidth(), self.doc.size().height())
        index.model().setData(index, s, QtCore.Qt.SizeHintRole)

class GUI(QtWidgets.QDialog):
    def __init__(self):
        super(GUI, self).__init__()
        dirname = os.path.dirname(os.path.abspath(__file__))
        uic.loadUi(os.path.join(dirname,'main.ui'), self)

        delegate = HTMLDelegate(self.lwOptions)
        self.lwOptions.setItemDelegate(delegate)

        for ordinal in ['first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth']:
            item = QtWidgets.QListWidgetItem('This is the <b>{}</b> word. This is the <b>{}</b> word. This is the <b>{}</b> word.'.format(ordinal, ordinal, ordinal))
            self.lwOptions.addItem(item)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = GUI()
    window.show()
    sys.exit(app.exec_())

这篇关于QStyledItemDelegate 水平截断文本并且不添加水平滚动条的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆