Qt - получает длину строки в QLabel в пикселях - PullRequest
15 голосов
/ 26 декабря 2011

У меня есть QLabel фиксированной ширины.
Мне нужно (периодически) проверять, чтобы вся строка вписывалась в QLabel при его текущей ширине, чтобы я мог соответствующим образом изменить ее размер.

Чтобы сделатьдля этого мне нужно получить «длину в пикселях» строки.
(общее количество горизонтальных пикселей, необходимых для отображения строки).
Следует отметить, что размер точки QLabel никогда не изменяется.

Example of 'Pixel Width' of a string

Я не могу просто проверить количество присутствующих символов, так как некоторые символы являются подстрочными или надстрочными и по-разному влияют на ширину всей строки.
(Этоскажем, нет простой связи между шириной пикселя и количеством символов)

Есть ли какая-нибудь абстрактная, супер удобная функция для этого?

Характеристики:
Python 2.7.1
PyQt4
Windows 7

1 Ответ

23 голосов
/ 26 декабря 2011

Чтобы получить точную ширину текста в пикселях, вы должны использовать QFontMetrics.boundingRect .

Не использовать QFontMetrics.width , потому что оно учитываетучитывать левую и правую несущую символы.Это часто (но не всегда) приводит к результатам, которые могут быть на несколько пикселей больше или меньше полной ширины пикселя.

Итак, чтобы вычислить ширину пикселя в тексте метки, используйте что-то вроде:

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

РЕДАКТИРОВАТЬ

Существует три различных метода QFontMetrics, которые можно использовать для вычисления "ширины" строки: size(), width() и boundingRect().

Однако, хотя все они дают несколько разные результаты, ни один из них , кажется,последовательно возвращайте точную ширину пикселя при любых обстоятельствах.Какой из них лучше, зависит в основном от текущего используемого семейства шрифтов и от того, какие конкретные символы находятся в начале и конце строки.

Я добавил ниже скрипт, который тестирует три метода.Для меня метод boundingRect дает наиболее последовательные результаты.Два других метода имеют тенденцию быть либо слишком широкими, либо обрезать второй образец текста, когда используется шрифт с засечками (это с PyQt 4.9 и Qt 4.8 в 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_())
...