1

我正在尝试pack(或place)一个小部件,它是另一个顶层内的根顶层的子级,它本身.就是一个子级.。那是,

% toplevel .tl
.tl
% frame .f
.f
% pack .f -in .tl
can't pack .f inside .tl

但是,我发现这段代码几乎可以工作:

% frame .tl
.tl
% frame .f
.f
% pack .f -in .tl
% wm manage .tl

我说差不多,因为.f是不可见的。这有点奇怪,因为如果我在里面放一个按钮.f,比如

button .f.b -text FooBar
pack .f.b

我看到几何管理器保留的空白空间,但看不到任何小部件。

我确定我做错了什么,但我不知道是什么以及为什么,并且pack,gridplace手册页没有帮助。


编辑:关于我在做什么的一些细节

我正在尝试构建一个 snit 小部件,它可以自动执行一些顶级创建内容。我通常做的一件事是在ttk::frame我创建的每个顶层中放置一个,并使用pack ... -fill both -expand true命令对其进行管理。

我的 snidget 应该总是这样做,但我想从用户的角度隐藏它,以便对实现的任何更改都不会破坏现有代码。

简单的方法是这样

snit::widget Toplevel {
    hulltype toplevel
    component f

    constructor {args} {
        set f [ttk::frame $self.f -padding 2]
        pack $f -fill both -expand 1

        $self configurelist $args
    }
}

但用户必须了解该f组件,并创建其他小部件作为它的子级。

所以,我尝试了另一种解决方案:我使用一个ttk::frame小部件作为船体类型,然后构建船体的同级顶层,并尝试将船体放入顶层。

我尝试的代码类似于以下内容:

snit::widget Toplevel {
    hulltype ttk::frame
    component tl

    constructor {args} {
        set segments [split $self .]
        set wname [join [lreplace $segments end end _[lindex $segments end]] .]

        set tl [frame $wname -width 100 -height 100]
        pack $self -in $tl -fill both -expand 1
        wm manage $tl

        $self configurelist $args
    }
}

如果它按预期工作,用户可以编写如下内容:

% Toplevel .t
.t
% button .t.b -text Foobar
.t.b
% pack .t.b

.t并会使用 snidget在顶层构建中获得一个按钮。

4

2 回答 2

1

你想要做的事情是不可能的,马可。所有小部件都必须是其顶级容器的子级。

于 2013-08-07T15:54:16.923 回答
1

除了顶层之外的小部件被安排在一个严格的包含层次结构中;小部件.foo包含小部件.foo.bar,而小部件又包含.foo.bar.grill等。顶层小部件实际上都是根窗口的子窗口。

您可以做两件事来改变这一点。

  1. 您可以使用wm manage(需要 8.5 或更高版本)将标准框架小部件转换为顶层,并wm forget反转它(您还必须重新pack/重新grid)。(我认为 OSX/Aqua 不支持此功能。)

    frame .foo
    # Define its contents...
    wm manage .foo
    
    # Later...
    wm forget .foo
    pack .foo
    

    这是一对有用的操作,用于制作像工具栏这样的撕掉窗口。Tk 小部件演示中甚至还有一个演示。

  2. 您可以在创建时将框架(或顶层)转换为容器小部件(在创建选项中将-container选项设置为 true;以后无法完成)。然后,您可以获取窗口小部件的 ID(使用)并在创建时通过选项winfo id告诉顶层使用该小部件 ID 作为其父级。-use

    frame .foo -container 1
    set id [winfo id .foo]
    toplevel .bar -use $id
    

    请注意,在这种情况下,在 Unix/X11 上,这些 ID 可以传递给其他进程并使用,而不必实际引用 Tk 创建的窗口。(一些应用程序也可以做相反的事情,将自己嵌入到由 Tk 定义的 ID 给定的窗口中。)在 Windows 和 OSX/Aqua 上,ID 只保证在单个进程中工作。

我不知道您要执行的操作是否可以通过这两种可能的操作中的任何一种来完成;你不太清楚你正在尝试做什么的更高层次的观点。它们混合得不是特别好,因为它们-container-use仅创建时间的选项,并且随后是只读的,并且您无法更改名称层次结构(在创建后完全固定)。真正复杂的东西可能需要您退后一步并正式定义一个模型,您可以查看多个小部件布局。

于 2013-08-10T11:37:27.547 回答