|
【 STM32MP135F-DK测评】+(6)为制作图形界面通读python-gtk-3手册 之二
[复制链接]
本帖最后由 damiaa 于 2025-3-5 22:11 编辑
【 STM32MP135F-DK测评】+(6)为制作图形界面通读python-gtk-3手册 之二
继续上面读第6章 Layout容器 关于布局
6. 布局容器
虽然许多 GUI 工具包要求您使用绝对定位将小部件精确地放置在窗口中,但 GTK+ 使用不同的方法。您可以按行、列和/或表格排列窗口小部件,而不是指定窗口中每个小部件的位置和大小。窗口的大小可以根据窗口包含的小部件的大小自动确定。而 Widget 的大小又取决于它们包含的文本量、您指定的最小和最大大小,和/或您如何请求在 Widget 集之间共享可用空间。您可以通过为每个小组件指定填充距离和居中值来完善布局。然后,当用户作窗口时,GTK+ 会使用所有这些信息来合理而平滑地调整所有内容的大小和位置。
GTK+ 使用容器分层排列小部件。它们对最终用户不可见,并入到窗口中,o
6.1. 盒子
盒子是我们可以将小部件装入其中的无形容器。将 widget 打包到水平框中时,对象将从左到右或从右到左水平插入,具体取决于使用的是 Gtk.Box.pack_start() 还是 Gtk.Box.pack_end()。在垂直框中,小部件从上到下打包,反之亦然。您可以在其他框内部或旁边使用任意框组合来创建所需的效果。
6.1.1. 示例
让我们看一下带有两个按钮的扩展示例的略微修改版本。
先用
self.box = Gtk.Box(spacing=6)
self.add(self.box)
创创建一个水平方向的框容器,其中 6 个像素放置在子对象之间。此框将成为顶级窗。
紧接着使用下面几句加入两个button到box容器中,当然里面也包括了连接响应函数。
6.2. 网格
Gtk.Grid 是一个容器,它将其子小部件排列在行和列中,但你不需要在构造函数中指定维度。使用 Gtk.Grid.attach() 添加子项。它们可以跨多行或多列。Gtk.Grid.attach() 方法有五个参数:
child 参数是要添加的 Gtk.Widget。
left 是将 Child 的左侧附加到的列号。
top 表示要将 Child 的 top 侧附加到的行号。
width 和 height 分别表示子项将跨越的列数和子项将跨越的行数。
也可以使用 Gtk.Grid.attach_next_to() 在现有子项旁边添加一个子项,它也需要五个参数:
child 是要添加的 Gtk.Widget,如上所述。
sibling 是 self (一个 Gtk.Grid 实例) 或 None 的现有子小部件。子小部件将放置在 sibling 旁边,或者如果 sibling 为 None,则放置在网格的开头或结尾。
side 是一个 Gtk.PositionType,表示子项位于该子项旁边的兄弟姐妹的一侧。
width 和 height 分别表示子 widget 将跨越的列数和行数。
最后,Gtk.Grid可以像Gtk.Box一样使用,只需使用Gtk.Grid.add(),它将按照“orientation”属性(默认为Gtk.Orientation.HORIZONTAL)确定的方向将子项彼此相邻放置。
6.2.1. Example
下面的代码运行后会这样:
6.3. ListBox
Gtk.ListBox 是一个包含 Gtk.ListBoxRow 子项的垂直容器。这些行可以动态排序和筛选,并且可以根据行内容动态添加标题。它还允许键盘和鼠标导航和选择,就像典型的列表一样。
使用 Gtk.ListBox 通常是 Gtk.TreeView 的替代方案,特别是当列表内容的布局比 Gtk.CellRenderer 允许的布局更复杂时,或者当内容是交互式的(例如,里面有一个按钮)时。
虽然 Gtk.ListBox 必须只有 Gtk.ListBoxRow 子项,但你可以通过 Gtk.Container.add() 向它添加任何类型的小部件,并且 Gtk.ListBoxRow 小部件将自动插入到列表和小部件之间。
6.3.1. Example
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ListBoxRowWithData(Gtk.ListBoxRow):
def __init__(self, data):
super().__init__()
self.data = data
self.add(Gtk.Label(label=data))
class ListBoxWindow(Gtk.Window):
def __init__(self):
super().__init__(title="ListBox Demo")
self.set_border_width(10)
box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(box_outer)
listbox = Gtk.ListBox()
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
box_outer.pack_start(listbox, True, True, 0)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label1 = Gtk.Label(label="Automatic Date & Time", xalign=0)
label2 = Gtk.Label(label="Requires internet access", xalign=0)
vbox.pack_start(label1, True, True, 0)
vbox.pack_start(label2, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
hbox.pack_start(switch, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label(label="Enable Automatic Update", xalign=0)
check = Gtk.CheckButton()
hbox.pack_start(label, True, True, 0)
hbox.pack_start(check, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label(label="Date Format", xalign=0)
combo = Gtk.ComboBoxText()
combo.insert(0, "0", "24-hour")
combo.insert(1, "1", "AM/PM")
hbox.pack_start(label, True, True, 0)
hbox.pack_start(combo, False, True, 0)
listbox.add(row)
listbox_2 = Gtk.ListBox()
items = "This is a sorted ListBox Fail".split()
for item in items:
listbox_2.add(ListBoxRowWithData(item))
def sort_func(row_1, row_2, data, notify_destroy):
return row_1.data.lower() > row_2.data.lower()
def filter_func(row, data, notify_destroy):
return False if row.data == "Fail" else True
listbox_2.set_sort_func(sort_func, None, False)
listbox_2.set_filter_func(filter_func, None, False)
def on_row_activated(listbox_widget, row):
print(row.data)
listbox_2.connect("row-activated", on_row_activated)
box_outer.pack_start(listbox_2, True, True, 0)
listbox_2.show_all()
win = ListBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.4. Stack 和 StackSwitcher
Gtk.Stack 是一个一次只显示其一个子项的容器。与 Gtk.Notebook 相比,Gtk.Stack 没有为用户提供更改可见子项的方法。相反,Gtk.StackSwitcher 小部件可以与 Gtk.Stack 一起使用来提供此功能。
页面之间的过渡效果可以动画化为幻灯片或淡化效果。这可以通过 Gtk.Stack.set_transition_type() 进行控制。这些动画遵循 “gtk-enable-animations” 设置。
过渡速度可通过 Gtk.Stack.set_transition_duration() 进行调整
Gtk.StackSwitcher 小部件充当 Gtk.Stack 的控制器;它显示一行按钮,用于在关联的 Stack Widget 的各个页面之间切换。
按钮的所有内容都来自 Gtk.Stack 的子属性。
可以将多个 Gtk.StackSwitcher 小部件与同一个 Gtk.Stack 小部件相关联。
6.4.1. 示例
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class StackWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
self.set_border_width(10)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
stack = Gtk.Stack()
stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
stack.set_transition_duration(1000)
checkbutton = Gtk.CheckButton(label="Click me!")
stack.add_titled(checkbutton, "check", "Check Button")
label = Gtk.Label()
label.set_markup("<big>A fancy label</big>")
stack.add_titled(label, "label", "A label")
stack_switcher = Gtk.StackSwitcher()
stack_switcher.set_stack(stack)
vbox.pack_start(stack_switcher, True, True, 0)
vbox.pack_start(stack, True, True, 0)
win = StackWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.5. HeaderBar
Gtk.HeaderBar 类似于水平的 Gtk.Box,它允许将子项放在开头或结尾。此外,它还允许显示标题。标题将相对于框的宽度居中,即使两侧的子对象占用的空间量不同。
由于 GTK+ 现在支持客户端装饰,因此可以使用 Gtk.HeaderBar 代替标题栏(由窗口管理器呈现)。
Gtk.HeaderBar 通常位于窗口的顶部,并且应该包含影响下面内容的常用控件。它们还提供对窗口控件的访问,包括关闭窗口按钮和窗口菜单。
6.5.1. 示例
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio
class HeaderBarWindow(Gtk.Window):
def __init__(self):
super().__init__(title="HeaderBar Demo")
self.set_border_width(10)
self.set_default_size(400, 200)
hb = Gtk.HeaderBar()
hb.set_show_close_button(True)
hb.props.title = "HeaderBar example"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="mail-send-receive-symbolic")
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
button.add(image)
hb.pack_end(button)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
Gtk.StyleContext.add_class(box.get_style_context(), "linked")
button = Gtk.Button()
button.add(
Gtk.Arrow(arrow_type=Gtk.ArrowType.LEFT, shadow_type=Gtk.ShadowType.NONE)
)
box.add(button)
button = Gtk.Button.new_from_icon_name("pan-end-symbolic", Gtk.IconSize.MENU)
box.add(button)
hb.pack_start(box)
self.add(Gtk.TextView())
win = HeaderBarWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.6. FlowBox
注意
这个例子至少需要 GTK+ 3.12。
Gtk.FlowBox 是一个容器,它根据子部件的方向按顺序定位子部件。
例如,在水平方向下,小部件将从左到右排列,必要时在上一行下开始新行。在这种情况下,减小宽度将需要更多的行,因此将需要更大的高度。
同样,在垂直方向下,小部件将从上到下排列,必要时从右侧开始一个新的列。减小高度将需要更多的列,因此将需要更大的宽度。
Gtk.FlowBox 的子级可以动态排序和过滤。
虽然 Gtk.FlowBox 必须只有 Gtk.FlowBoxChild 子项,但你可以通过 Gtk.Container.add() 向它添加任何类型的小部件,并且 Gtk.FlowBoxChild 小部件将自动插入到盒子和小部件之间。
6.6.1. 示例
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
class FlowBoxWindow(Gtk.Window):
def __init__(self):
super().__init__(title="FlowBox Demo")
self.set_border_width(10)
self.set_default_size(300, 250)
header = Gtk.HeaderBar(title="Flow Box")
header.set_subtitle("Sample FlowBox app")
header.props.show_close_button = True
self.set_titlebar(header)
scrolled = Gtk.ScrolledWindow()
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
flowbox = Gtk.FlowBox()
flowbox.set_valign(Gtk.Align.START)
flowbox.set_max_children_per_line(30)
flowbox.set_selection_mode(Gtk.SelectionMode.NONE)
self.create_flowbox(flowbox)
scrolled.add(flowbox)
self.add(scrolled)
self.show_all()
def on_draw(self, widget, cr, data):
context = widget.get_style_context()
width = widget.get_allocated_width()
height = widget.get_allocated_height()
Gtk.render_background(context, cr, 0, 0, width, height)
r, g, b, a = data["color"]
cr.set_source_rgba(r, g, b, a)
cr.rectangle(0, 0, width, height)
cr.fill()
def color_swatch_new(self, str_color):
rgba = Gdk.RGBA()
rgba.parse(str_color)
button = Gtk.Button()
area = Gtk.DrawingArea()
area.set_size_request(24, 24)
area.connect("draw", self.on_draw, {"color": rgba})
button.add(area)
return button
def create_flowbox(self, flowbox):
colors = [
"AliceBlue",
"AntiqueWhite",
"AntiqueWhite1",
"AntiqueWhite2",
"AntiqueWhite3",
"AntiqueWhite4",
"aqua",
"aquamarine",
"aquamarine1",
"aquamarine2",
"aquamarine3",
"aquamarine4",
"azure",
"azure1",
"azure2",
"azure3",
"azure4",
"beige",
"bisque",
"bisque1",
"bisque2",
"bisque3",
"bisque4",
"black",
"BlanchedAlmond",
"blue",
"blue1",
"blue2",
"blue3",
"blue4",
"BlueViolet",
"brown",
"brown1",
"brown2",
"brown3",
"brown4",
"burlywood",
"burlywood1",
"burlywood2",
"burlywood3",
"burlywood4",
"CadetBlue",
"CadetBlue1",
"CadetBlue2",
"CadetBlue3",
"CadetBlue4",
"chartreuse",
"chartreuse1",
"chartreuse2",
"chartreuse3",
"chartreuse4",
"chocolate",
"chocolate1",
"chocolate2",
"chocolate3",
"chocolate4",
"coral",
"coral1",
"coral2",
"coral3",
"coral4",
]
for color in colors:
button = self.color_swatch_new(color)
flowbox.add(button)
win = FlowBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.7. notebook笔记本
Gtk.Notebook 小部件是一个 Gtk.Container,它的子组件是可以在沿一个边缘使用标签标签之间切换的页面。
GtkNotebook 有许多配置选项。除其他外,你可以选择选项卡出现在哪个边缘(参见 Gtk.Notebook.set_tab_pos()),如果选项卡太多而无法容纳笔记本,是否应该放大或添加滚动箭头(参见 Gtk.Notebook.set_scrollable()),以及是否会有一个弹出菜单允许用户切换页面(参见 Gtk.Notebook.popup_enable()、Gtk.Notebook.popup_disable())。
6.7.1. 示例
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Simple Notebook Example")
self.set_border_width(3)
self.notebook = Gtk.Notebook()
self.add(self.notebook)
self.page1 = Gtk.Box()
self.page1.set_border_width(10)
self.page1.add(Gtk.Label(label="Default Page!"))
self.notebook.append_page(self.page1, Gtk.Label(label="Plain Title"))
self.page2 = Gtk.Box()
self.page2.set_border_width(10)
self.page2.add(Gtk.Label(label="A page with an image for a Title."))
self.notebook.append_page(
self.page2, Gtk.Image.new_from_icon_name("help-about", Gtk.IconSize.MENU)
)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
先写到这里,谢谢
|
|