I am trying to output the contents of a database to a Tkinter widget. The database has enough rows and columns to where I need to have both horizontal and vertical scrollbars enabled, but I am having a hard time getting horizontal and vertical scrolling to work simultaneously. I am agnostic about which Tkinter widget is used but here is my current implementation:

我正在尝试将数据库的内容输出到Tkinter小部件。数据库中有足够多的行和列,我需要同时启用水平和垂直滚动条,但是我很难同时启用水平和垂直滚动。我不知道使用哪个Tkinter小部件,但以下是我当前的实现:

# Create root
self.root = Tk()
self.root.geometry('1000x500+0+0')

# Create canvas
self.canvas = Canvas(self.root)
self.canvas.pack(side=TOP, fill=BOTH, expand=TRUE)

# Create scrollbars
self.xscrollbar = Scrollbar(self.root, orient=HORIZONTAL, command=self.canvas.xview)
self.xscrollbar.pack(side=BOTTOM, fill=X)
self.yscrollbar = Scrollbar(self.root, orient=VERTICAL, command=self.canvas.yview)
self.yscrollbar.pack(side=RIGHT, fill=Y)

# Attach canvas to scrollbars
self.canvas.configure(xscrollcommand=self.xscrollbar.set)
self.canvas.configure(yscrollcommand=self.yscrollbar.set)

# Create frame inside canvas
self.frame = Frame(self.canvas)
self.canvas.create_window((0,0), window=self.frame, anchor=NW)
self.frame.bind('<Configure>', self.set_scrollregion)

# Write db contents to canvas
self.print_dbcontents()

# Invoke main loop
self.root.mainloop()

def set_scrollregion(self, event):
    self.canvas.configure(scrollregion=self.canvas.bbox('all'))

In this implementation, I can only get scrolling to work in one direction, depending on how I pack the canvas:

在这个实现中,我只能在一个方向上滚动工作,这取决于我如何打包画布:

self.canvas.pack(side=TOP, fill=BOTH, expand=TRUE) # scrolling works in x but not y
self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) # scrolling works in y but not x

I just need to get horizontal and vertical scrolling to work simultaneously, or find an alternate solution.

我只需要让水平和垂直滚动同时工作,或者找到一个替代的解决方案。

1 个解决方案

#1


8

I don't see any code that would prevent the scrollbars from working. I do see a problem that prevents one of the scrollbars from showing up where you expect it (assuming you expect them to appear in the traditional place). Is that what you mean whey you say you want them to "work simultaneously"?

我没有看到任何代码可以阻止滚动条工作。我确实看到了一个问题,它阻止一个滚动条出现在您期望的位置(假设您希望它们出现在传统位置)。这就是你说你想让他们“同时工作”的意思吗?

Your layout is done with the following code and in the following order:

您的布局是用以下代码完成的,顺序如下:

self.canvas.pack(side=TOP, fill=BOTH, expand=TRUE)
self.xscrollbar.pack(side=BOTTOM, fill=X)
self.yscrollbar.pack(side=RIGHT, fill=Y)

That first line causes the canvas to fill the whole top of the widget, all the way from the left to all the way to the right. When you later place the yscrollbar on the right, this means it goes to the right of the space left over after the canvas fills up the top. Since the canvas fills the top, there is no left over space to the right, only below. Thus, your scrollbar will appear as a tiny widget about the height of the horizontal scrollbar below the canvas.

第一行使画布填充了小部件的整个顶部,从左到右。当您稍后将yscrollbar放在右边时,这意味着它会在画布填满顶部之后,转到左边的右边。因为画布填充了顶部,所以右边没有剩余空间,只有下面。因此,滚动条将作为一个小部件出现,大小与画布下方水平滚动条的高度有关。

A quick fix is to pack the vertical scrollbar first, then the horizontal, and then the canvas. Your "major" widget should always be one of the last things you pack/grid. One, you do that for the obvious reason that you need to in this case to get the desired effect, but also because it makes your resize behavior right. I'm getting off topic to explain why in this answer, so read this answer on stackoverflow for more information.

一个快速的解决方案是先打包垂直滚动条,然后打包水平滚动条,然后打包画布。您的“主要”小部件应该始终是您打包/网格的最后一部分。首先,你这么做的原因很明显,你需要在这种情况下得到想要的效果,但也因为它使你的调整行为正确。我要离开主题来解释为什么在这个答案中,所以阅读这个关于stackoverflow的答案来获得更多信息。

Second, when working with scrollbars it's best to use grid if you want a professional appearance. If you use pack, the scrollbars will not align property in the corner in which they meet. You want them to look like this, with a small blank space in the lower-right corner:

第二,当使用滚动条时,如果您想要专业的外观,最好使用网格。如果您使用pack,滚动条将不会对它们相遇的角落中的属性进行对齐。你想让它们看起来像这样,在右下角有一个小的空白区域:

  ||
==

However, if you use pack they'll look like one of these:

但是,如果你使用包装的话,它们会是这样的:

   ||    -or-      ||
 ====            ==||

Finally, I encourage you to not import *, it could cause problems down the road. Instead, get in the habit of doing import Tkinter as tk and then prefixing all of the tk commands with "tk." (eg: tk.Canvas, etc). You'll see why this matters the first time you try to mix ttk and tkinter widgets in the same UI, but you could have problems elsewhere if you also "import *" from other packages as well. Plus, this way it's obvious when you're using tk features and when you're using features from other packages.

最后,我鼓励您不要进口*,它可能会在未来引起问题。相反,养成将Tkinter作为tk进行导入的习惯,然后用“tk”前缀所有tk命令。(如:tk。帆布等)。您将会看到为什么第一次尝试在同一个UI中混合ttk和tkinter小部件时很重要,但是如果您也从其他包“导入*”,那么您在其他地方可能会遇到问题。另外,当您使用tk特性时,以及使用其他包的特性时,这是很明显的。

更多相关文章

  1. 如何在qt上访问父窗口小部件?
  2. Canvas(画布)类的使用
  3. Android自定义万能Canvas画布

随机推荐

  1. 如何获得嵌入式Jetty Web服务器来转储其J
  2. java网上在线支付实战视频
  3. 在本地运行数据流导致JVM崩溃(OOM)
  4. 如何判断用户的java代码是否已成功编译?
  5. Byte Buddy - java.lang.NoSuchMethodE
  6. Eclipse打开出错:Java wa started but ret
  7. Java String类具体解释
  8. javascript获得客户端IP的又一方法
  9. 根据用户的动态字段对链接列表进行排序
  10. (翻译)Java使用POI中的SXSSF处理大数据量