如何调整标签的宽度?

How do I resize a Label's width?

一段时间以来,我一直在尝试调整标签的宽度,但这似乎是不可能的,或者至少对我来说是不可理解的...

为了清楚起见,我将用图片解释我的情况。

这是 Window 带有 "Normal" 标签的样子...

这就是 Window 带有大得离谱的文字的样子...

现在,这就是我希望文本大得离谱时的样子

看到了吗?

示例代码如下:

# -*- coding: utf-8 -*-

import gi
import signal
import hashlib
import random
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango

class Test(Gtk.Window):
    def __init__(self):
        def center(a):
            a.props.valign = Gtk.Align.CENTER
            a.props.halign = Gtk.Align.CENTER
        Gtk.Window.__init__(self, title="Test")
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_border_width(10)
        self.set_resizable(False)
        self.connect("delete-event", Gtk.main_quit)

        Box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        Button = Gtk.Button("Change Label")
        Label = Gtk.Label()

        Test = "I'm a Label, Yay!"

        center(Box)
        center(Label)
        center(Button)

        Label.set_markup('<span><big>%s</big></span>' % Test)
        Label.set_ellipsize(Pango.EllipsizeMode.END)
        Label.set_justify(Gtk.Justification.LEFT)

        self.add(Box)

        Box.add(Label)
        Box.add(Button)

        #UNKNOWN/FORBIDDEN/DEPRECIATED/INCOMPREHENSIBLE MAGIC!
            #Uncomment only one or both, and watch it's magic!

        #self.set_resizable(True)
        #Box.set_resize_mode(Gtk.ResizeMode.QUEUE)

        def change_label(self):
            Label.set_markup('<span><big>%s</big></span>' % str(hashlib.sha384(str(random.random())).hexdigest()))

        Button.connect("clicked", change_label)

if __name__ == '__main__':
    MainWindow = Test()
    MainWindow.show_all()
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()

请注意 Window 不可调整大小。

如果您取消注释一个或两个 "Magic" 部分,您将看到 Window 如何改变它的行为!

但是

使用每一种方法都有两个缺点:

此外,在其他一些 Window 管理器和主题中,当您多次更改标签的字符串时,它会对 Window 的维度造成一些干扰。

你对此有什么建议吗?

我完全受够了这个。我已经尝试了几个星期,但没有结果 :c

也许有一种方法可以模拟 Window 可调整大小但不显示调整大小手柄和最大化按钮时的行为?

或者更新的方法是什么set_resize_mode(Gtk.ResizeMode.QUEUE)

PD:Label.set_max_width_chars() 不是我要搜索的内容

您可能想要了解 Gtk 3.12 中的帧时钟。这里有一个很好的article。 用于排队调整大小的新方法是 Gtk.Widget.queue_resize()

If some state changes that causes the size of your widget to change you call gtk_widget_queue_resize() which will request a layout phase and mark your widget as needing relayout.

我相信下面修改后的示例代码可以满足您的要求。诀窍在于用子框来包围 Gtk.LabelGtk.Button。然后将 max_width_chars 设置为 1,将 ellipsize 设置为 END,将 hexpand 设置为 True,将 halign 设置为 FILL在标签上。

import signal
import hashlib
import random
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango

class Test(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Test")
        self.set_size_request(250,-1)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_border_width(10)
        self.set_resizable(False)
        self.connect("delete-event", Gtk.main_quit)

        Box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        Sub_box_left = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        Sub_box_right = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        Button = Gtk.Button("Change Label")
        Label = Gtk.Label()

        Test = "I'm a Label, Yay!"

        Label.set_markup('<span><big>%s</big></span>' % Test)
        Label.set_max_width_chars(1)
        Label.set_ellipsize(Pango.EllipsizeMode.END)
        Label.set_hexpand(True)
        Label.props.halign = Gtk.Align.FILL
        Label.set_justify(Gtk.Justification.LEFT)

        self.add(Box)

        Sub_box_left.add(Label)
        Sub_box_right.add(Button)

        Box.add(Sub_box_left)
        Box.add(Sub_box_right)

        def change_label(self):
            Label.set_markup('<span><big>%s</big></span>'%str(hashlib.sha384(str(random.random())).hexdigest()))

        Button.connect("clicked", change_label)

if __name__ == '__main__':
    MainWindow = Test()
    MainWindow.show_all()
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()

好吧,经过一番思考,我找到了一种“hackish”的方法来实现我想要的。

我会尝试用文字来解释它,然后我会 post “最终”代码,但我相信它可以被优化,或者至少我是这样的希望:)

我所做的是获取两个代码(Jacques Gaudin 的原始版本和修改版本),分析它们并创建一个不太复杂的版本。

然后我意识到 Jacques Gaudin 的修改使得 Window set_size_request 依赖于开发人员,因为它需要宽度和高度。

作为“解决方法”,我决定执行以下操作:

  • 清理代码
  • 让Window不受限制地“出现”,这样它就可以计算出正确显示所需的确切宽度和高度,并立即隐藏window以避免用户按下“随机化按钮”太早了。
  • 一旦 Window 隐藏了自己,请求它的确切值(宽度和高度)
  • 收集这些值后,Window 仍然隐藏,重新声明 MainWindow 对象,但这次将其参数从 (None, None) 更改为先前收集的值: (Width, Height)
  • 接下来,Window 需要重新计算一些内部值,因为更改了它的参数
  • 最后,Window 完成重新计算值后,它会再次显示自己,但这次显示所需的宽度和高度,即使由于某种原因标签变大,Window 将保持相同的大小。

我知道这不是“最佳”答案,但至少它有效。

很遗憾,还有几个问题:

  • 我们怎样才能使标签“居中”?
  • 如果在慢速机器上使用此方法,是否有可能 window 隐藏时会很慢,如果用户提前按下“随机化”按钮会导致某种 bug/glitch ?
  • 动态文本翻译怎么样?甚至不需要“重新启动”Window 就可以实现它们吗? (嗯,这不是什么大问题,但还是好奇想一想...)
  • 有没有更好的方法来实现这个目标?(最重要的问题:c)

代码如下:

#!/usr/bin/python2

# -*- coding: utf-8 -*-

import gi
import signal
import hashlib
import random
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango

class TestWindow(Gtk.Window):
    
    def __init__(self, width, height):
        
        if width is None:
            width = -1
            
        if height is None:
            height = -1
            
        Gtk.Window.__init__(self, title="Test")
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_border_width(10)
        self.set_resizable(False)
        self.set_size_request(width, height)
        self.connect("delete-event", Gtk.main_quit)
        
        ##Declare Objects
        
        #Boxes
        Box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        
        #Buttons
        Button = Gtk.Button.new_with_mnemonic("Randomize Label")
        
        #Labels
        Label = Gtk.Label()
        
        #Variables & Misc
        Test = "I'm a Label, Yay!" #You can change me for a bigger label if you want
        
        ##Change Objects Properties
        
        #Alignments (Could break things...)
        #self.center(Box)
        #self.center(Label)
        #self.center(Button)
        
        #Labels
        Label.set_markup('<span><big>%s</big></span>' % Test)
        Label.set_ellipsize(Pango.EllipsizeMode.END)
        
        if width is not -1:
            Label.set_max_width_chars(1)
            
        Label.set_justify(Gtk.Justification.FILL)
        
        ##Packaging
        
        #Boxes
        self.add(Box)
        
        Box.pack_start(Label, True, True, 0)
        Box.add(Button)
        
        def change_label(self):
            Label.set_markup('<span><big>%s</big></span>' % str(hashlib.sha384(str(random.random())).hexdigest()))
            
        Button.connect("clicked", change_label)
            
    def center(self, object):
        object.props.valign = Gtk.Align.CENTER
        object.props.halign = Gtk.Align.CENTER
        
if __name__ == '__main__':
    MainWindow = TestWindow(None, None)
    MainWindow.show_all()
    MainWindow.hide()
    Width, Height = MainWindow.get_size()
    MainWindow = TestWindow(Width, Height)
    MainWindow.show_all()
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()

以下是部分截图:

这是按下按钮的“之前”...

这是“按下按钮后”...

经过数小时的研究和试验,我找到了完成此任务的另一种好方法。在我看来,这是最好的方法,除非它可能有一点限制,但它允许你用更少的代码做比第一种方法更多的事情。

这是我所做的:

  • 从 1° 方法中,我删除了 "hackish" 代码
  • 然后,我添加了一个"Mini-Box"对象,它是一个Gtk.ButtonBox(一种特殊的盒子...)并将其设置为"Homogeneous"
  • 之后,我从 "Box" 中删除了 "Button" 对象,并将 "Label" 和 "Button" 对象添加到 "Mini-Box"
  • 更不用说我还必须将 "Mini-Box" 添加到 "Box"...

完成!

示例代码如下:

#!/usr/bin/python2

# -*- coding: utf-8 -*-

import gi
import signal
import hashlib
import random
import time
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango

class TestWindow(Gtk.Window):

    def __init__(self):

        Gtk.Window.__init__(self, title="Test")
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_border_width(10)
        self.set_resizable(False)
        self.connect("delete-event", Gtk.main_quit)

        ##Declare Objects

        #Boxes
        Box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        Mini_Box = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL, spacing=10, homogeneous=True)

        #Buttons
        Button = Gtk.Button.new_with_mnemonic("_Randomize Label")

        #Labels
        Label = Gtk.Label()

        #Variables & Misc
        Test = "I'm a Label, Yay!" #Label's width should NOT be larger than the Button's size to be displayed entirely, though...

        ##Change Objects Properties

        #Alignments
        self.center(Box)

        #Labels
        Label.set_markup('<span><big>%s</big></span>' % Test)
        Label.set_ellipsize(Pango.EllipsizeMode.END)
        Label.set_justify(Gtk.Justification.LEFT)

        ##Packaging

        #Boxes
        self.add(Box)

        Box.add(Mini_Box)
        Mini_Box.add(Label)
        Mini_Box.add(Button)

        def change_label(self):
            Label.set_markup('<span><big>%s</big></span>' % str(hashlib.sha384(str(random.random())).hexdigest()).rstrip())

        Button.connect("clicked", change_label)

    def center(self, object):
        object.props.valign = Gtk.Align.CENTER
        object.props.halign = Gtk.Align.CENTER

if __name__ == '__main__':
    MainWindow = TestWindow()
    MainWindow.show_all()
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    Gtk.main()

不会post新截图,因为结果和上面一样...