2011-12-26 67 views
14

Tengo una QLabel de ancho fijo.
Necesito comprobar (periódicamente) que toda la cadena encaja dentro de QLabel en su ancho actual, por lo que puedo cambiar el tamaño de forma adecuada.Qt - Obtenga la longitud de píxel de una cadena en una QLabel

Para hacer esto, necesito obtener la 'longitud de píxel' de la cadena.
(La cantidad total de píxeles horizontales necesarios para mostrar la cadena).
Se debe tener en cuenta que el tamaño del punto de QLabel nunca cambia.

Example of 'Pixel Width' of a string

no puedo simplemente comprobar la cantidad de caracteres presentes, ya que algunos caracteres son subíndice/superíndice y contribuyen de manera diferente a la anchura de toda la cadena.
(Esto quiere decir que no existe una relación simple entre el ancho de píxel y la cantidad de caracteres)

¿Hay alguna función abstracta y super conveniente para esto?

Especificaciones:
Python 2.7.1
PyQt4
Windows 7

Respuesta

22

Para obtener el píxel de ancho precisa del texto, debe utilizar QFontMetrics.boundingRect.

No utilice QFontMetrics.width, ya que tiene en cuenta el rumbo izquierdo y derecho de los caracteres. Esto a menudo (pero no siempre) dará lugar a resultados que pueden ser varios píxeles más o menos que el ancho de píxel completo.

Por lo tanto, para calcular el píxel de ancho del texto de la etiqueta, usar algo como:

width = label.fontMetrics().boundingRect(label.text()).width() 

EDITAR

Hay tres diferentes QFontMetrics métodos que pueden ser utilizados para calcular el "ancho "de una cadena: size(), width() y boundingRect().

Sin embargo, aunque todos dan resultados ligeramente diferentes, ninguno de ellos parece devolver consistentemente el ancho exacto de píxeles en todas las circunstancias. Cuál es el mejor depende principalmente de la familia de fuentes actual en uso y en qué caracteres particulares se encuentran al principio y al final de la cadena.

He añadido debajo una secuencia de comandos que prueba los tres métodos. Para mí, el método boundingRect ofrece los resultados más consistentes. Los otros dos métodos tienden a ser demasiado anchos o recortar la segunda muestra de texto cuando se utiliza una fuente serif (esto es con PyQt 4.9 y Qt 4.8 en Linux).

from PyQt4 import QtGui, QtCore 

class Window(QtGui.QWidget): 
    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     self.setAutoFillBackground(True) 
     self.setBackgroundRole(QtGui.QPalette.Mid) 
     self.setLayout(QtGui.QFormLayout(self)) 
     self.fonts = QtGui.QFontComboBox(self) 
     self.fonts.currentFontChanged.connect(self.handleFontChanged) 
     self.layout().addRow('font:', self.fonts) 
     for text in (
      u'H\u2082SO\u2084 + Be', 
      u'jib leaf jib leaf', 
      ): 
      for label in ('boundingRect', 'width', 'size'): 
       field = QtGui.QLabel(text, self) 
       field.setStyleSheet('background-color: yellow') 
       field.setAlignment(QtCore.Qt.AlignCenter) 
       self.layout().addRow(label, field) 
     self.handleFontChanged(self.font()) 

    def handleFontChanged(self, font): 
     layout = self.layout() 
     font.setPointSize(20) 
     metrics = QtGui.QFontMetrics(font) 
     for index in range(1, layout.rowCount()): 
      field = layout.itemAt(index, QtGui.QFormLayout.FieldRole).widget() 
      label = layout.itemAt(index, QtGui.QFormLayout.LabelRole).widget() 
      method = label.text().split(' ')[0] 
      text = field.text() 
      if method == 'width': 
       width = metrics.width(text) 
      elif method == 'size': 
       width = metrics.size(field.alignment(), text).width() 
      else: 
       width = metrics.boundingRect(text).width() 
      field.setFixedWidth(width) 
      field.setFont(font) 
      label.setText('%s (%d):' % (method, width)) 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.show() 
    sys.exit(app.exec_()) 
+0

¡Quiero que se tengan en cuenta los rodamientos, pero gracias de todos modos! –

+0

@AntiEarth. Los rodamientos pueden ser negativos, por lo que si se tienen en cuenta para el cambio de tamaño, el texto de la etiqueta puede recortarse en los bordes. Solo se garantiza que el 'boundingRect' proporciona siempre el ancho de píxel completo del texto. – ekhumoro

+0

No tiene en cuenta la subscripción, ¿o sí? Solo punto de tamaño? –

Cuestiones relacionadas