【问题标题】:Automatically resizing label text in Qt - strange behaviour在 Qt 中自动调整标签文本的大小 - 奇怪的行为
【发布时间】:2012-02-06 10:59:06
【问题描述】:

在 Qt 中,我有一个复合小部件,它由排列在 QBoxLayouts 内的几个 QLabels 组成。当小部件调整大小时,我希望标签文本缩放以填充标签区域,并且我已经在 resizeEvent 中实现了文本大小调整。

这可行,但似乎发生了某种反馈循环。复合小部件与其他一些小部件一起放置在 QBoxLayout 内的主窗口中。当主窗口变小时,复合小部件最初保持其大小,然后分几个步骤(大约 10-15)调整到正确的大小。如果文本高度设置为标签高度的 0.8 倍以上,那么在调整文本大小时,包含的小部件会随着每一步而变大,直到最终应用崩溃。

这是实现此效果的正确方法吗?如果是这样,调整大小可能有什么问题?

下面是resizeEvent的代码。

def resizeEvent(self, evt):
        print("resizeEvent", evt.size().width(), evt.size().height())
        QFrame.resizeEvent(self, evt)

        dataLabels = self.dataPanels.values()

        for label in dataLabels:            
            font = label.font()
            h = label.height()
            h2 = h * 0.8
            font.setPixelSize(h2)
            label.setFont(font)

(使用 PyQt4 4.8、Qt 4.7.4、Win 7 和 OSX 10.6)

【问题讨论】:

    标签: python qt pyqt resize


    【解决方案1】:

    我认为由SizePolicy 引起的调整大小问题。尝试将label 的大小政策设置为Ignored 应该会有所帮助。

    label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
    

    这是实现这种效果的正确方法吗?

    可能是的,在文档中快速搜索没有提供更好的解决方案。但我会创建QLabel 的子类,并在那里进行策略设置和调整大小。示例:

    class StretchedLabel(QLabel):
        def __init__(self, *args, **kwargs):
            QLabel.__init__(self, *args, **kwargs)
            self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
    
        def resizeEvent(self, evt):
            font = self.font()
            font.setPixelSize(self.height() * 0.8)
            self.setFont(font)
    

    如果您不仅需要按高度调整文本,还需要按宽度调整文本,则需要一些额外的代码。

    【讨论】:

    • 这对我不起作用。为我的标签小部件的大小设置动画效果很好,但是一旦我在 resizeEvent 中添加了 setFont,动画的行为就会很奇怪。看起来当字体设置时它以某种方式更新标签大小,因此它正在与调整大小动画作斗争..
    【解决方案2】:

    reclosedev's answer 给了我使用Ignored size policy 的关键线索,但仍有一些细节需要解决。这是一个计算适合标签当前大小的字体大小的示例。

    from PySide2.QtGui import QResizeEvent, QFontMetrics, Qt
    from PySide2.QtWidgets import QLabel
    
    
    class ScaledLabel(QLabel):
        def resizeEvent(self, event: QResizeEvent):
            # This flag is used for pixmaps, but I thought it might be useful to
            # disable font scaling. Remove the check if you don't like it.
            if not self.hasScaledContents():
                return
    
            target_rect = self.contentsRect()
            text = self.text()
    
            # Use binary search to efficiently find the biggest font that will fit.
            max_size = self.height()
            min_size = 1
            font = self.font()
            while 1 < max_size - min_size:
                new_size = (min_size + max_size) // 2
                font.setPointSize(new_size)
                metrics = QFontMetrics(font)
    
                # Be careful which overload of boundingRect() you call.
                rect = metrics.boundingRect(target_rect, Qt.AlignLeft, text)
                if (rect.width() > target_rect.width() or
                        rect.height() > target_rect.height()):
                    max_size = new_size
                else:
                    min_size = new_size
    
            font.setPointSize(min_size)
            self.setFont(font)
    

    不幸的是,当您使用缩放标签时,需要一些属性才能完成这项工作。要么确保始终设置它们,要么覆盖__init__() 以使默认值有用。这是一个设置它们的工作示例:

    from PySide2.QtCore import Qt
    from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QSizePolicy, QLabel
    
    from scaled_label import ScaledLabel
    
    
    def main():
        app = QApplication()
    
        widget = QWidget()
        label1 = ScaledLabel('Lorem ipsum')
        label2 = ScaledLabel('Lorem ipsum')
    
        # Any policy other than Ignored will fight you when you resize.
        size_policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        label1.setSizePolicy(size_policy)
        label2.setSizePolicy(size_policy)
    
        # If you check this flag, don't forget to set it.
        label1.setScaledContents(True)
        label2.setScaledContents(True)
    
        # "Ignored" policy means you have to define your own minimum size.
        label1.setMinimumSize(200, 40)
        label2.setMinimumSize(50, 10)
    
        # Standard label attributes still work.
        label1.setAlignment(Qt.AlignBottom)
        label2.setAlignment(Qt.AlignTop)
    
        # Tell the layout to scale the two fields at different sizes.
        layout = QVBoxLayout(widget)
        layout.addWidget(label1)
        layout.addWidget(label2)
        layout.setStretch(0, 4)
        layout.setStretch(1, 1)
    
        widget.show()
        exit(app.exec_())
    
    
    main()
    

    【讨论】:

      猜你喜欢
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多