可调整大小的 Tk 窗口做得很好

发布于 2024-11-13 08:00:51 字数 1065 浏览 2 评论 0 原文

我组装 Tk 窗口的方式有问题(在 Win XP 下使用 R tcltk 和 tcltk2)

library(tcltk)
library(tcltk2)

expandTk <- function() {
  root  <- tktoplevel()
  # textbox with scroll bars
  textbox <- tk2frame(root)
  scr <- tkscrollbar(textbox, repeatinterval=5, command=function(...) tkyview(txt,...))
  txt <- tktext(textbox, bg="white", font="courier", wrap="word", yscrollcommand=function(...)tkset(scr,...))
  tkpack(txt, side="left", fill="both", expand=TRUE)
  tkpack(scr, side="right", fill="y")
  tkmark.set(txt,"insert","0.0")
  tkpack(textbox, fill="both", expand=TRUE)
  # status bar and size grip
  statusText <- tclVar("")
  f <- tk2frame(root, relief="sunken")
  l <- tk2label(f, textvariable=statusText)
  tkpack(l, side="left", pady=2, padx=5, expand=0, fill="x")
  tkpack(f, side="left", expand=1, fill="x", anchor="s")
  sg <- ttksizegrip(root)
  tkpack(sg, side="left", expand=0, anchor="se")
}

窗口看起来不错,但是一旦我调整它的大小(即使其变小),滚动条和状态栏就会消失。我很确定这是一个用户错误,我见过其他 Tk 应用程序可以正确调整大小,但我不知道应该使用哪个选项...

任何提示表示赞赏, 卡斯滕

There is something wrong with the way I assemble my Tk windows (with R tcltk and tcltk2, under Win XP)

library(tcltk)
library(tcltk2)

expandTk <- function() {
  root  <- tktoplevel()
  # textbox with scroll bars
  textbox <- tk2frame(root)
  scr <- tkscrollbar(textbox, repeatinterval=5, command=function(...) tkyview(txt,...))
  txt <- tktext(textbox, bg="white", font="courier", wrap="word", yscrollcommand=function(...)tkset(scr,...))
  tkpack(txt, side="left", fill="both", expand=TRUE)
  tkpack(scr, side="right", fill="y")
  tkmark.set(txt,"insert","0.0")
  tkpack(textbox, fill="both", expand=TRUE)
  # status bar and size grip
  statusText <- tclVar("")
  f <- tk2frame(root, relief="sunken")
  l <- tk2label(f, textvariable=statusText)
  tkpack(l, side="left", pady=2, padx=5, expand=0, fill="x")
  tkpack(f, side="left", expand=1, fill="x", anchor="s")
  sg <- ttksizegrip(root)
  tkpack(sg, side="left", expand=0, anchor="se")
}

The window looks fine, but as soon as I resize it (ie make it smaller), the scrollbar and the statusbar disappears. I am quite sure that this is a user error, I have seen other Tk apps which resize properly, but I can not figure out which option I should use...

Any hint appreciated,
Karsten

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

同展鸳鸯锦 2024-11-20 08:00:51

这是 Tk pack 几何管理器的标准行为。以下是 pack 手册页的相关部分:

如果空腔变得太小而无法满足从属设备的需求,那么
奴隶将被给予空腔中剩余的任何空间。如果腔体收缩
到零大小,那么装箱单上的所有剩余从站都将被取消映射
屏幕,直到主窗口变得足够大以再次容纳它们。

因此,如果将整个窗口缩小到小于文本小部件请求的空间,则不会为其他小部件留下任何空间,并且它们将被取消映射。

最好的解决方案是使用grid几何管理器,而不是pack。一般来说,我发现 gridpack 更容易使用且功能强大,尽管您的情况可能会有所不同。特别是,它消除了对许多多余框架小部件的需要,这可以大大简化您的代码。

我认为你可以使用这样的东西:

expandTk <- function() {
  root  <- tktoplevel()
  # textbox with scroll bars
  textbox <- tk2frame(root)
  txt <- tktext(textbox, bg="white", font="courier", wrap="word", yscrollcommand=function(...)tkset(scr,...))
  scr <- tkscrollbar(textbox, repeatinterval=5, command=function(...) tkyview(txt,...))
  tkmark.set(txt,"insert","0.0")

  # Set up the geometry for the stuff inside the "textbox" frame.

  # The text and scrollbar widgets live on the same row.
  tkgrid(txt, scr)

  # The text widget should stick to all four sides of its parcel.
  tkgrid.configure(txt, sticky="nsew")

  # The scrollbar should stick to the top and bottom of its parcel, it need not stick to the
  # left and right.
  tkgrid.configure(scr, sticky="ns")

  # When the window is resized, we want surplus space to be allocated to the text widget,
  # which is in the top left corner of this frame.
  tkgrid.columnconfigure(textbox,0,weight=1)
  tkgrid.rowconfigure(textbox,0,weight=1)

  # status bar and size grip
  statusText <- tclVar("")
  l <- tk2label(root, textvariable=statusText,relief="sunken")
  sg <- ttksizegrip(root)

  # Set up the geometry for the stuff inside the "root" window.

  # First row is just the textbox frame...
  tkgrid(textbox)

  # Second row is the status label and the resize gadget
  tkgrid(l, sg)

  # The textbox widget should span 2 colums, and stick to all four sides of its parcel.
  tkgrid.configure(textbox,columnspan=2,sticky="nsew")

  # The status label should stick to all four sides of its parcel too
  tkgrid.configure(l,sticky="nsew")

  # The resize gadget should only stick to the bottom right of its parcel
  tkgrid.configure(sg,sticky="se")

  # When the window is resized, we want surplus space to go to the textbox frame (and from there
  # to the text widget itself, which it will do thanks to the grid weights we set up above).  The
  # textbox frame is in the top left corner of its parent window.
  tkgrid.columnconfigure(root,0,weight=1)
  tkgrid.rowconfigure(root,0,weight=1)
}

有一些关于使用 R 此处

That's standard behavior for the Tk pack geometry manager. Here's a relevant section of the pack man page:

If the cavity should become too small to meet the needs of a slave then the
slave will be given whatever space is left in the cavity. If the cavity shrinks
to zero size, then all remaining slaves on the packing list will be unmapped from
the screen until the master window becomes large enough to hold them again.

So if you shrink the overall window to be smaller than the space requested for the text widget, you leave no space for the other widgets, and they get unmapped.

The best solution is to use the grid geometry manager, instead of pack. Generally speaking, I find grid to be much easier to use and capable than pack anyway, although your mileage may vary. In particular, it eliminates the need for many superfluous frame widgets, which can simplify your code a lot.

I think you can use something like this:

expandTk <- function() {
  root  <- tktoplevel()
  # textbox with scroll bars
  textbox <- tk2frame(root)
  txt <- tktext(textbox, bg="white", font="courier", wrap="word", yscrollcommand=function(...)tkset(scr,...))
  scr <- tkscrollbar(textbox, repeatinterval=5, command=function(...) tkyview(txt,...))
  tkmark.set(txt,"insert","0.0")

  # Set up the geometry for the stuff inside the "textbox" frame.

  # The text and scrollbar widgets live on the same row.
  tkgrid(txt, scr)

  # The text widget should stick to all four sides of its parcel.
  tkgrid.configure(txt, sticky="nsew")

  # The scrollbar should stick to the top and bottom of its parcel, it need not stick to the
  # left and right.
  tkgrid.configure(scr, sticky="ns")

  # When the window is resized, we want surplus space to be allocated to the text widget,
  # which is in the top left corner of this frame.
  tkgrid.columnconfigure(textbox,0,weight=1)
  tkgrid.rowconfigure(textbox,0,weight=1)

  # status bar and size grip
  statusText <- tclVar("")
  l <- tk2label(root, textvariable=statusText,relief="sunken")
  sg <- ttksizegrip(root)

  # Set up the geometry for the stuff inside the "root" window.

  # First row is just the textbox frame...
  tkgrid(textbox)

  # Second row is the status label and the resize gadget
  tkgrid(l, sg)

  # The textbox widget should span 2 colums, and stick to all four sides of its parcel.
  tkgrid.configure(textbox,columnspan=2,sticky="nsew")

  # The status label should stick to all four sides of its parcel too
  tkgrid.configure(l,sticky="nsew")

  # The resize gadget should only stick to the bottom right of its parcel
  tkgrid.configure(sg,sticky="se")

  # When the window is resized, we want surplus space to go to the textbox frame (and from there
  # to the text widget itself, which it will do thanks to the grid weights we set up above).  The
  # textbox frame is in the top left corner of its parent window.
  tkgrid.columnconfigure(root,0,weight=1)
  tkgrid.rowconfigure(root,0,weight=1)
}

There's some more information about using the grid geometry manager from R here.

月亮是我掰弯的 2024-11-20 08:00:51

如果您坚持打包小部件,则应该注意,如果没有足够的空间为所有小部件提供它们所要求的空间,则空间将优先分配给第一个打包的小部件(在特定容器)。首先放置状态栏,然后是滚动条,最后才是主小部件。 (您可能需要更改将特定小部件打包到哪一侧,以使其全部正常工作。)此外,如果它变得太复杂,请记住您可以将其打包在框架内;这为您提供了很多的灵活性。

但这就是使用网格几何管理器才有意义的一点。当您想要应用程序外观的最后 10% 时,它可以为您提供更精细的控制,并且需要更少的小部件嵌套来实现它。

If you're insistent on packing the widgets, you should be aware that if there isn't enough space to give all widgets the room they asked for, space is given preferentially to the first widgets packed (within a particular container). Put the statusbar in first, then the scrollbars, and only then the main widget. (You may need to alter which side you're packing particular widgets on to make it all work right.) Also, if it is getting too complicated, remember that you can pack inside frames packed inside frames; that gives you lots of flexibility.

But that's the point when using the grid geometry manager just makes sense. It gives you a lot more fine control when you're going for that last 10% of the look of your app, and needs less nesting of widgets to achieve it.

梦在夏天 2024-11-20 08:00:51

正如 Eric 指出的那样,网格绝对是最好的,但如果您确实想使用 pack,那么调整扩展 txt 小部件的大小(如下所示)将得到您想要的东西。有一些尺寸启发法可以改进。

将其添加到代码末尾:

widthOfChar <- ceiling(as.numeric(tclvalue(tcl("font","measure","TkTextFont","0123456789")))/10) + 2
tkbind(root, "<Configure>", function(W) {
  w.width <- as.integer(tkwinfo("width",W))
  txt.width <- w.width - 15L
  tkconfigure(txt, width=floor(txt.width/widthOfChar))
})

Definitely grid is best, as Eric points out, but if you really want to use pack then resizing the expanding txt widget, like below, will get you what you are looking for. There are some size heuristics that could be improved.

Add this to the end of your code:

widthOfChar <- ceiling(as.numeric(tclvalue(tcl("font","measure","TkTextFont","0123456789")))/10) + 2
tkbind(root, "<Configure>", function(W) {
  w.width <- as.integer(tkwinfo("width",W))
  txt.width <- w.width - 15L
  tkconfigure(txt, width=floor(txt.width/widthOfChar))
})
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文