tcl - 映射/取消映射或提高/降低堆叠顺序以显示/隐藏选项卡式显示?
问题描述
我想构建一个类似于 ttk::notebook 小部件的选项卡式显示,这是我以前在 JavaScript 中做过的,现在想转移到 Tcl/Tk。我在 Tk Docs 网站上读到,笔记本选项卡是为少量小尺寸选项卡制作的,无论如何都需要对其进行自定义,以获取每个选项卡上的关闭按钮和类似功能。
在 JavaScript 中,每个选项卡的“框架”具有相同的几何形状,并且绝对位于父容器内的同一点;并且任何时候都只能看到一个标签框。单击选项卡按钮时,当前选项卡的可见性设置为隐藏,新选项卡设置为可见。
为了在 Tk 中做同样的事情,所有选项卡是否应该在同一行和列中“网格化”,并且在单击新选项卡按钮时更改堆叠顺序;或者,由于 Tk 保留了已移除框架的几何形状,是否应该一次只对一个选项卡进行网格化并在每次单击选项卡按钮时替换?还是有更好的方法?
每个选项卡都有一个可编辑的文本小部件,如果用户编辑文本、将焦点留在文本小部件中并单击新的选项卡按钮,我需要捕获任何更改。
谢谢你。
package require Tk
ttk::style theme use clam
ttk::style configure TScrollbar -arrowsize 20
wm geometry . "[winfo screenwidth .]x[winfo screenheight .]+0+0"
wm title . "Notebook Test"
ttk::label .main_l -text "Main Label"
grid .main_l -row 0 -column 0 -sticky ew
grid columnconfigure . 0 -weight 1
grid rowconfigure . 1 -weight 1
foreach n { 3 2 1 } {
ttk::frame .f$n -relief solid
tk::label .f$n.l -text "Tab $n"
tk::text .f$n.t -yscrollcommand ".f$n.v set" \
-background white -padx 10 -pady 10 -font { Georgia 12 } \
-wrap word -borderwidth 10 -relief flat
ttk::scrollbar .f$n.v -orient vertical -command ".f$n.t yview"
grid .f$n -row 1 -column 0 -sticky nsew
grid .f$n.l -in .f$n -row 0 -columnspan 2 -sticky ew
grid .f$n.t -in .f$n -row 1 -column 0 -sticky nsew
grid .f$n.v -in .f$n -row 1 -column 1 -sticky ns
grid rowconfigure .f$n 1 -weight 1
grid columnconfigure .f$n 0 -weight 1
set tab_foc($n) .f$n
}
focus .f1
set cur_tab 1
bind . <Alt-KeyPress-1> { navigate 1 }
bind . <Alt-KeyPress-2> { navigate 2 }
bind . <Alt-KeyPress-3> { navigate 3 }
proc navigate { n } {
global cur_tab tab_foc
set tab_foc($cur_tab) [focus]
set cur_tab $n
focus $tab_foc($n)
raise .f$n
}
我尝试了一个简单的示例,使用ttk::notebook
没有标签的样式并使用select
笔记本的方法来更改标签。更改选项卡时会有一点闪烁,使用上面的先前代码不存在。也许,notebook 使用grid remove
它的行为类似于display:block and display:none
JavaScript visibility:visible and visibility:hidden
,因为它display
会改变布局并可能导致闪烁,visibility
但不会改变布局。当然,我不确定。
package require Tk
ttk::style theme use clam
ttk::style configure TScrollbar -arrowsize 20
ttk::style layout Plain.TNotebook.Tab null
wm geometry . "[winfo screenwidth .]x[winfo screenheight .]+0+0"
wm title . "Notebook Test"
set nb [ttk::notebook .pnb -style Plain.TNotebook]
ttk::label .main_l -text "Main Label"
grid .main_l -row 0 -column 0 -sticky ew
grid columnconfigure . 0 -weight 1
grid rowconfigure . 1 -weight 1
grid $nb -row 1 -column 0 -sticky nsew
foreach n { 1 2 3 } {
set f [ ttk::frame $nb.f$n -relief solid ]
tk::label $f.l -text "Tab $n"
tk::text $f.t -yscrollcommand "$f.v set" \
-background white -padx 10 -pady 10 \
-font { Georgia 12 } -wrap word -borderwidth 10 -relief flat
ttk::scrollbar $f.v -orient vertical -command "$f.t yview"
$nb add $f -sticky nsew
grid rowconfigure $f 1 -weight 1
grid columnconfigure $f 0 -weight 1
grid $f.l -in $f -row 0 -columnspan 2 -sticky ew
grid $f.t -in $f -row 1 -column 0 -sticky nsew
grid $f.v -in $f -row 1 -column 1 -sticky ns
}
$nb select $nb.f1
bind . <Alt-KeyPress-1> { navigate 1 }
bind . <Alt-KeyPress-2> { navigate 2 }
bind . <Alt-KeyPress-3> { navigate 3 }
proc navigate { n } {
global nb
$nb select $nb.f$n
}
我也尝试过使用place
,但仍然体验到闪烁。也许,我编码错了。
package require Tk
ttk::style theme use clam
ttk::style configure TScrollbar -arrowsize 20
wm geometry . "[winfo screenwidth .]x[winfo screenheight .]+0+0"
wm title . "Notebook Test"
ttk::label .main_l -text "Main Label"
place .main_l -relx 0.0 -rely 0.0 -relwidth 1.0 -height 30
foreach n { 3 2 1 } {
set f [ ttk::frame .f$n -relief solid ]
tk::label $f.l -text "Tab $n"
tk::text $f.t -yscrollcommand "$f.v set" \
-background white -padx 10 -pady 10 \
-font { Georgia 12 } -wrap word -borderwidth 10 -relief flat
ttk::scrollbar $f.v -orient vertical -command "$f.t yview"
place $f -relx 0.0 -y 31 -relwidth 1.0 -relheight 1.0 -height -30
place $f.l -in $f -relx 0.0 -rely 0.0 -relwidth 1.0 -height 30
place $f.t -in $f -relx 0.0 -rely 0.0 -y 30 -relwidth 1.0 -width -23 -relheight 1.0 -height -30
place $f.v -in $f -relx 1.0 -x -22 -rely 0.0 -y 31 -width 22 -relheight 1.0 -height -30
if { $n > 1 } { place forget $f }
}
set curTab 1
bind . <Alt-KeyPress-1> { navigate 1 }
bind . <Alt-KeyPress-2> { navigate 2 }
bind . <Alt-KeyPress-3> { navigate 3 }
proc navigate { n } {
global curTab
place .f$n -relx 0.0 -y 31 -relwidth 1.0 -relheight 1.0 -height -30
raise .f$n
place forget .f$curTab
set curTab $n
}
单独使用grid
也有闪烁,但是在映射之前使用lower
和在删除当前映射的选项卡之前执行update idletasks
,似乎已经消除或显着减少了闪烁。也就是说,尝试将选项卡映射到当前选项卡后面,使其类似于隐藏,更新 idletasks 以调整其大小,然后取消映射当前选项卡。对我来说奇怪的是,如果单击一个条目元素,然后导航到不同的选项卡并在执行其他任何操作之前键入一些文本,则文本会出现在被 删除的选项卡中grid remove
。为什么?它不再处于焦点循环中,但在移除后仍保留键盘焦点。
grid .main_l -row 0 -column 0 -sticky ew
grid columnconfigure . 0 -weight 1
grid rowconfigure . 1 -weight 1
foreach n { 3 2 1 } {
set f [ ttk::frame .f$n -relief solid ]
tk::label $f.l -text "Tab $n"
ttk::entry .f$n.e1
ttk::entry .f$n.e2
tk::text $f.t -yscrollcommand "$f.v set" \
-background white -padx 10 -pady 10 -font { Georgia 12 } -wrap word -borderwidth 10 -relief flat
ttk::scrollbar $f.v -orient vertical -command "$f.t yview"
grid .f$n -row 1 -column 0 -sticky nsew
grid rowconfigure .f$n 1 -weight 1
grid columnconfigure .f$n 0 -weight 1
grid .f$n.l -in .f$n -row 0 -columnspan 2 -sticky ew
grid .f$n.t -in .f$n -row 1 -column 0 -sticky nsew
grid .f$n.v -in .f$n -row 1 -column 1 -sticky ns
grid .f$n.e1 -in .f$n -row 0 -column 2
grid .f$n.e2 -in .f$n -row 1 -column 2
if { $n > 1 } { grid remove $f }
}
set curTab 1
bind . <Alt-KeyPress-1> { if { $curTab != 1 } { navigate 1 } }
bind . <Alt-KeyPress-2> { if { $curTab != 2 } { navigate 2 } }
bind . <Alt-KeyPress-3> { if { $curTab != 3 } { navigate 3 } }
proc navigate { n } {
global curTab
lower .f$n
grid .f$n
update idletasks
grid remove .f$curTab
set curTab $n
}
解决方案
经过一番研究,我发现有一种方法可以做你想做的事情ttk::notebook
(这很好;它可以处理大小计算等所有棘手的负载),这在ttk::notebook wiki 页面上进行了描述:
# Need this style
ttk::style layout Plain.TNotebook.Tab null
# Make the notebook and pages
ttk::notebook .foo -style Plain.TNotebook
.foo add [button .foo.bar -text bar]
.foo add [button .foo.baz -text baz]
# Select a page; you'll need to provide a mechanism for users to switch
.foo select .foo.bar
边界还有一些额外的复杂性,您可能想做也可能不想做任何事情。(风格编码很复杂,唉。)
否则,grid remove
它是一个有用的工具,因为它会停止管理小部件(导致它变得未映射且不可聚焦),而无需清除您希望如何管理它的设置;当您将小部件放回原处时,它将使用以前的内容。但是,您仍然会遇到内容小部件大小不同的问题,因此每次更改页面时都会冒调整大小的风险。
由于您在这样做时已经开始做很多工作,因此您可能可以考虑使用place
。主要技巧是绑定<Configure>
每个页面,以便您可以找出它们的大小(如果/何时发生变化)。
raise
只是用and改变堆叠顺序lower
是行不通的。关键问题是这不会正确影响键盘焦点循环;用户将能够Tab进入他们看不到的小部件,这非常令人困惑!
在回答您在评论中的问题时,默认情况下,选择在 Tk 应用程序中是全局的(或在 X11 上的所有应用程序中是全局的;这就是PRIMARY
选择的工作方式)。您可以通过将小部件配置为不导出选择来为小部件提供独立选择。
推荐阅读
- php - 我的 php 表单没有向 PhpMyAdmin 添加消息
- javascript - 如何在数组中添加换行符并使其右对齐
- sql-server - 在同一个表中比较 SQL Server 中的 2 个句点
- python - 在 Windows 上使用 __init__.py 导入
- javascript - 类选择器无法设置 img 标签的样式,而 ID 选择器可以设置相同图像的样式?
- ignite - 使用 The Apache Ignite 时后端存储是否支持 HDFS?
- reactjs - 在反应js中将道具从父母传递给孩子
- kubernetes - 如何从 k8s 中的不同 pod 连接到容器?
- reactjs - 如何在使用 create-react-app 构建的应用程序中导入库的本地副本
- reactjs - 如何反转reactstrap中的列?