Gtk4中如何旋转控件?Gtk3迁移至Gtk4的Label旋转方案问询
在Gtk4中实现旋转Label(替代Gtk3的set_angle)
Gtk4移除了GtkLabel的set_angle方法,直接用CSS transform会导致布局尺寸不匹配(仅视觉旋转,不影响控件布局占位)。正确的做法是自定义一个包裹GtkLabel的Widget,通过重写measure和size_allocate方法来处理尺寸交换和旋转变换,确保布局和视觉一致。
可运行实现示例(Python/PyGObject)
import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, Gsk, Gdk class RotatedLabel(Gtk.Widget): def __init__(self, label_text, angle=90): super().__init__() self.label = Gtk.Label(label=label_text) self.label.set_parent(self) self.angle = angle # 旋转角度(单位:度) def do_measure(self, orientation, for_size): # 旋转后,控件的宽度对应原Label的高度,高度对应原Label的宽度 if orientation == Gtk.Orientation.HORIZONTAL: child_min_h, child_nat_h = self.label.measure(Gtk.Orientation.VERTICAL, for_size) return child_min_h, child_nat_h, -1, -1 else: child_min_w, child_nat_w = self.label.measure(Gtk.Orientation.HORIZONTAL, for_size) return child_min_w, child_nat_w, -1, -1 def do_size_allocate(self, width, height, baseline): # 给Label分配交换后的宽高(旋转后原高度变宽度,原宽度变高度) child_width = height child_height = width # 让Label在分配的区域内居中 x = (width - child_height) // 2 y = (height - child_width) // 2 # 创建旋转变换:围绕Label中心旋转 transform = Gsk.Transform.new() # 平移到Label中心位置 transform = transform.translate((x + child_width/2, y + child_height/2)) # 转换角度为弧度并旋转 transform = transform.rotate(self.angle * 3.14159265 / 180) # 平移回原点,确保旋转中心正确 transform = transform.translate((-child_width/2, -child_height/2)) self.label.set_transform(transform) self.label.size_allocate(child_width, child_height, baseline) # 测试窗口 class TestWindow(Gtk.ApplicationWindow): def __init__(self, app): super().__init__(application=app, title="Rotated Label Demo") self.set_default_size(400, 300) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20) box.set_margin_top(50) box.set_margin_start(50) self.set_child(box) # 普通标签 normal_label = Gtk.Label(label="Normal Label") box.append(normal_label) # 顺时针旋转90度的标签 rotated_label = RotatedLabel("Rotated 90°", angle=90) box.append(rotated_label) # 逆时针旋转90度的标签 rotated_label2 = RotatedLabel("Rotated -90°", angle=-90) box.append(rotated_label2) class MyApp(Gtk.Application): def __init__(self): super().__init__(application_id="com.example.RotatedLabelDemo") def do_activate(self): win = TestWindow(self) win.present() if __name__ == "__main__": app = MyApp() app.run()
关键实现说明
重写
do_measure方法- 旋转后控件的布局尺寸会交换:原Label的高度变为旋转后控件的宽度,原Label的宽度变为旋转后控件的高度。通过交换子控件的测量结果,让布局系统正确计算控件的占位空间。
重写
do_size_allocate方法- 给内部Label分配交换后的宽高,确保文本有足够的绘制空间。
- 通过
Gsk.Transform实现围绕中心旋转:先将坐标平移到Label中心,旋转后再平移回原点,避免旋转后文本偏移或超出控件边界。
为什么CSS transform不适用?
CSS的transform仅在绘制阶段生效,不会改变布局系统计算的控件尺寸,导致旋转后的文本超出控件占位范围,出现重叠或截断问题。而自定义Widget的方式让布局系统感知到旋转后的尺寸,确保整体布局协调。
内容的提问来源于stack exchange,提问作者Thayne
相关产品推荐
相关产品推荐

