【问题标题】:PySide/PyQt truncate text in QLabel based on minimumSizePySide/PyQt 根据 minimumSize 截断 QLabel 中的文本
【发布时间】:2012-07-11 21:17:26
【问题描述】:

我想知道如何根据 QLabel 的最大宽度/高度来最好地截断文本。 传入的文本可以是任意长度,但为了保持布局整洁,我想截断长字符串以填充最大空间量(小部件的最大宽度/高度)。

例如:

 'A very long string where there should only be a short one, but I can't control input to the widget as it's a user given value'

会变成:

'A very long string where there should only be a short one, but ...'

基于当前字体所需的空间。

我怎样才能做到最好?

这是我所追求的一个简单示例,虽然这是基于字数,而不是可用空间:

import sys
from PySide.QtGui import *
from PySide.QtCore import *


def truncateText(text):
    maxWords = 10
    words = text.split(' ')
    return ' '.join(words[:maxWords]) + ' ...'

app = QApplication(sys.argv)

mainWindow = QWidget()
layout = QHBoxLayout()
mainWindow.setLayout(layout)

text = 'this is a very long string, '*10
label = QLabel(truncateText(text))
label.setWordWrap(True)
label.setFixedWidth(200)
layout.addWidget(label)

mainWindow.show()
sys.exit(app.exec_())

【问题讨论】:

    标签: qt pyqt4 pyside


    【解决方案1】:

    您可以通过使用QFontMetrics 确定宽度来实现这一点,请参阅this answer

    您可能希望使用或创建一些算法来快速找到剪切的位置,除非在一个简单的 for 循环中执行它就足够了。

    【讨论】:

      【解决方案2】:

      更简单 - 使用 QFontMetrics.elidedText 方法并重载paintEvent,这是一个示例:

      from PyQt4.QtCore import Qt
      from PyQt4.QtGui import QApplication,\
                              QLabel,\
                              QFontMetrics,\
                              QPainter
      
      class MyLabel(QLabel):
          def paintEvent( self, event ):
              painter = QPainter(self)
      
              metrics = QFontMetrics(self.font())
              elided  = metrics.elidedText(self.text(), Qt.ElideRight, self.width())
      
              painter.drawText(self.rect(), self.alignment(), elided)
      
      if ( __name__ == '__main__' ):
          app = None
          if ( not QApplication.instance() ):
              app = QApplication([])
      
          label = MyLabel()
          label.setText('This is a really, long and poorly formatted runon sentence used to illustrate a point')
          label.setWindowFlags(Qt.Dialog)
          label.show()
      
          if ( app ):
              app.exec_()
      

      【讨论】:

      • @EricHulser,这是一个非常好的答案。很有用。非常感谢!
      【解决方案3】:

      我发现@Eric Hulser 的回答虽然很棒,但在将标签放入另一个小部件时不起作用。

      我通过将 Eric 的响应和 Qt Elided Label Example 结合起来想出了这个。如此处所写,它允许传入不同的省略模式并垂直保留文本(当然,它是水平省略的!)。

      实现according to the docs 的布局阶段对我来说不是很清楚,所以我不能很好地谈论它。基本上,它会检查标签文本是否没有超出标签的宽度;如果是,它会省略文本。

      也不清楚a "valid" line 是什么意思。删除这些检查会导致应用程序崩溃。我的猜测是,当它没有超出小部件时,这条线是有效的。

      如果你想使用 PySide,

      • PyQt5 -> PySide2
      • pyqtSignal -> 信号

      不管怎样,享受吧!

      import sys
      from PyQt5 import QtCore, QtWidgets, QtGui
      
      
      class EliderLabel(QtWidgets.QLabel):
      
          elision_changed = QtCore.pyqtSignal(bool)
      
          def __init__(self, text='', mode=QtCore.Qt.ElideRight, **kwargs):
              super().__init__(**kwargs)
      
              self._mode = mode
              self.elided = False
      
              self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
              self.setText(text)
      
          def setText(self, text):
              self._contents = text
              # Changing the content require a repaint of the widget (or so
              # says the overview)
              self.update()
      
          def text(self):
              return self._contents
      
          def minimumSizeHint(self):
              metrics = QtGui.QFontMetrics(self.font())
              return QtCore.QSize(0, metrics.height())
      
          def paintEvent(self, event):
      
              super().paintEvent(event)
      
              did_elide = False
      
              painter = QtGui.QPainter(self)
              font_metrics = painter.fontMetrics()
              # fontMetrics.width() is deprecated; use horizontalAdvance
              text_width = font_metrics.horizontalAdvance(self.text())
      
              # Layout phase, per the docs
              text_layout = QtGui.QTextLayout(self._contents, painter.font())
              text_layout.beginLayout()
      
              while True:
      
                  line = text_layout.createLine()
      
                  if not line.isValid():
                      break
      
                  line.setLineWidth(self.width())
      
                  if text_width >= self.width():
                      elided_line = font_metrics.elidedText(self._contents, self._mode, self.width())
                      painter.drawText(QtCore.QPoint(0, font_metrics.ascent()), elided_line)
                      did_elide = line.isValid()
                      break
                  else:
                      line.draw(painter, QtCore.QPoint(0, 0))
      
              text_layout.endLayout()
      
              self.elision_changed.emit(did_elide)
      
              if did_elide != self.elided:
                  self.elided = did_elide
                  self.elision_changed.emit(did_elide)
      
      
      class MyDialog(QtWidgets.QWidget):
      
          def __init__(self):
              super().__init__()
      
              text = 'This is a really, long and poorly formatted runon sentence used to illustrate a point'
              label = EliderLabel(text, parent=self)
      
              label.elision_changed.connect(self.on_elide)
      
              layout = QtWidgets.QVBoxLayout()
              layout.addWidget(label)
      
              self.setLayout(layout)
      
          def on_elide(self, val):
              print('Elided: ', val, flush=True)
      
      
      if __name__ == '__main__':
          app = QtWidgets.QApplication([])
          dia = MyDialog()
          dia.show()
      
          sys.exit(app.exec_())
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-17
        • 1970-01-01
        • 2017-06-11
        • 1970-01-01
        • 1970-01-01
        • 2014-08-08
        相关资源
        最近更新 更多