Tcl Can';t在同级顶级中打包小部件

Tcl Can';t在同级顶级中打包小部件,tcl,tk,Tcl,Tk,我正在尝试打包(或放置)一个小部件,它是根顶级的子部件,位于另一个顶级内部,它本身就是的子部件。就是 % toplevel .tl .tl % frame .f .f % pack .f -in .tl can't pack .f inside .tl 但是,我发现这段代码几乎可以工作: 我说差不多,因为.f不可见。这有点奇怪,因为如果我在.f内放置一个按钮,例如 button .f.b -text FooBar pack .f.b 我看到几何体管理器保留的空白空间,但没有可见的小部件 我肯

我正在尝试
打包
(或
放置
)一个小部件,它是根顶级
的子部件,位于另一个顶级
内部,它本身就是
的子部件。就是

% toplevel .tl
.tl
% frame .f
.f
% pack .f -in .tl
can't pack .f inside .tl
但是,我发现这段代码几乎可以工作:

我说差不多,因为
.f
不可见。这有点奇怪,因为如果我在
.f
内放置一个按钮,例如

button .f.b -text FooBar
pack .f.b
我看到几何体管理器保留的空白空间,但没有可见的小部件

我肯定我做错了什么,但我不知道是什么和为什么,而且
网格
地方
手册页也没有帮助


编辑:关于我正在做的事情的一些细节

我正在尝试构建一个snit小部件,它可以自动化一些顶级的创建内容。我通常做的一件事是在我创建的每个顶层中放置一个
ttk::frame
,并使用
pack来管理它-同时填充-展开真值
命令

我的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构建一个按钮。

你想做的是不可能的,Marco。所有小部件都必须是其顶层容器的子部件。

除了顶层以外的小部件都按照严格的包含层次结构排列;小部件
.foo
包含小部件
.foo.bar
,而小部件又包含
.foo.bar.grill
等。顶级小部件实际上都是根窗口的子窗口

要改变这一点,你可以做两件事

  • 您可以使用
    wm manage
    (需要8.5或更高版本)将标准框架小部件转换为顶级,并使用
    wm forget
    来扭转这种情况(您还必须重新打包
    /re-
    网格
    它)。(我认为OSX/Aqua不支持这一点。)

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

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

    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
    是创建时唯一的选项,并且随后是只读的,并且您不能更改名称层次结构(创建后完全固定)。真正复杂的东西可能需要你退一步,正式定义一个模型,你有多个小部件布局作为视图。

    你确定吗?我知道我可以使用
    -use
    -container
    选项和
    winfoid
    命令在框架内重新租用顶层;此外,使用
    /
    放置
    几何体管理器的
    -in
    选项,我可以将小部件放在同级中,而不涉及父子关系。例如
    %frame.f1
    %frame.f2;#这是.f1
    %pack.f1
    %pack.f2-in.f1
    的兄弟。是的,我很确定。任何本身不是顶级小部件的小部件都只能在其顶级父部件的上下文中实例化。只有当它们都具有相同的顶级窗口时,才能
    pack.f2-in.f1
    。请尝试使用
    %toplevel.tl%pack[frame.tl.f]
    。在我的情况下,框架不是顶级的子级,而是同级。你所建议的是通常的情况,当然,效果很好。如果你在你的情况下尝试在
    pack.f-in.tl
    之后添加
    raise.f
    ,几乎奏效了?我添加了一个较长的解释,说明我想要得到的东西。我怀疑你可能能够通过使框架成为顶级的孩子来实现你的目标,以及重命名小部件命令。不过,不确定这将如何与snit交互。如何在UI的帧之间切换?
    frame .foo
    # Define its contents...
    wm manage .foo
    
    # Later...
    wm forget .foo
    pack .foo
    
    frame .foo -container 1
    set id [winfo id .foo]
    toplevel .bar -use $id