我如何在 tkInter 中模拟滚动条 Canvas
How do I simulate a Scrollbar in tkInter Canvas
我正在 Python 3.7 tkInter 中专门创建一个游戏启动器,我想制作自己的样式 Scrollbar
(在 Windows 10(版本 1903))。
我试过添加一个隐藏的 Scrollbar
,隐藏有效,但我无法模拟它:
def scroll(self, i, reqHeight, vbarValue):
print("vbarValue", vbarValue)
value = -i / 1.4
a1 = int(self.canvass.coords(self.scroll2)[1]) == 5
a2 = value > 0
a = not(a1 ^ a2)
b1 = ((self.canvass.coords(self.scroll2)[3] > self.cHeight))
b2 = value < 0
b = not(b1 ^ b2)
print(value, value < 0)
print(a1, 5)
print("====")
print(a1, a2)
print(a)
print("----")
print(b1, b2)
print(b)
print("====\n\n")
print("OK")
x1, y1, x2, y2 = self.canvass.coords(self.scroll2)
_y1, _y2 = vbarValue
print("1:",y1, y2)
print("2:",_y1, _y2)
print("3:",(_y2 - _y1) / 2 - y2)
print("4:",(_y1 + (_y2 - _y1) / 120) * self.cHeight)
print("5:",(_y1 + (_y2 - _y1) / 120) * self.cHeight - (y2 / y1))
print("6:",((_y2 - _y1) / 120) * self.cHeight - y2* -i)
print("7:",(_y1 + (_y2 - _y1) / 120))
value = (_y1 + (_y2 - _y1) / 120) * self.cHeight / (y1 / y2)
print("8:",(y2 / y1))
# value = value - (y1 / y2)
print("Dynamic Canvas Region Height:")
print("DCRH:", self.cHeight)
print("Value: %s", value)
self.canvass.move(self.scroll2, 0, -y2)
self.canvass.move(self.scroll2, 0, value)
print("coords: %s" % self.canvass.coords(self.scroll2))
print("reqHeight: %s" % reqHeight)
事件:
def _bound_to_mousewheel(self, event): # <Enter> Event
self.canv.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event): # <Leave> Event
self.canv.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event): # <Configure> Event
self.canv.yview_scroll(int(-1 * (event.delta / 120)), "units")
self.scrollCommand(int(-1 * (event.delta / 120)), self.scrollwindow.winfo_reqheight(), self.vbar.get())
def _configure_window(self, event):
# update the scrollbars to match the size of the inner frame
size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight()+1)
self.canv.config(scrollregion='0 0 %s %s' % size)
# if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width():
# # update the canvas's width to fit the inner frame
# # self.canv.config(width=self.scrollwindow.winfo_reqwidth())
# if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height():
# # update the canvas's width to fit the inner frame
# # self.canv.config(height=self.scrollwindow.winfo_reqheight())
顺便说一句,self.scrollCommand(...)
和第一个代码上的滚动一样。
我希望为 canvas.move method
.
获得一些 x 和 y 输出
How do i simulate a Scrollbar in Tkinter Canvas
滚动条有一个定义明确的界面。要模拟滚动条,您需要做的就是实现此接口。这最容易通过创建具有以下属性的 class 来完成:
- 您需要定义
set
方法,每当被滚动的小部件想要更新滚动条时调用该方法
- 您需要添加鼠标绑定以调用由滚动条控制的小部件的
yview
方法(或者 xview
如果创建水平小部件)。
如果你做了这两件事,你的滚动条就可以像内置滚动条一样使用了。
对于这个答案的其余部分,我假设您想要模拟一个垂直滚动条。模拟水平滚动条的工作方式相同,但您处理的不是 'top' 和 'bottom',而是 'left' 和 right'.
定义 set 方法
set 方法将用两个分数调用。 The canonical documentation 是这样描述的:
This command is invoked by the scrollbar's associated widget to tell the scrollbar about the current view in the widget. The command takes two arguments, each of which is a real fraction between 0 and 1. The fractions describe the range of the document that is visible in the associated widget. For example, if first is 0.2 and last is 0.4, it means that the first part of the document visible in the window is 20% of the way through the document, and the last visible part is 40% of the way through.
定义绑定
等式的另一半是当用户与滚动条交互以滚动另一个小部件时。发生这种情况的方式是滚动条应该调用要控制的小部件的yview
命令(例如:canvas,文本,列表框等)。
您必须传递给命令的第一个参数是字符串“moveto”或“scroll”。
如果是“moveto”,第二个参数是一个小数,表示从顶部滚出的数量。这通常在单击滚动条时调用,以立即将滚动条移动到新位置
如果是“scroll”,第二个参数是一个表示数量的整数,第三个参数是字符串“units”或“pages”。 “单位”的定义是指 yscrollincrement
选项的值。 “页面”代表 window 高度的 9/10。这通常在将鼠标拖到滚动条上时调用。
选项在每个可滚动小部件的手册页中都有详细说明。
例子
下面是一个使用文本小部件的示例,这样您就可以看到当您键入时,滚动条会适当地增长和收缩。如果您单击滚动条中的任意位置,它将滚动到文档中的那个位置。
为使示例简短,此代码不处理滚动条的拖动,并且硬编码了许多可能应该可配置的值。关键是要表明模拟滚动条所需要做的就是创建一个 class,它有一个 set
方法并调用 yview
或 xview
方法已连接的小部件。
首先是滚动条class
import tkinter as tk
class CustomScrollbar(tk.Canvas):
def __init__(self, parent, **kwargs):
self.command = kwargs.pop("command", None)
tk.Canvas.__init__(self, parent, **kwargs)
# coordinates are irrelevant; they will be recomputed
# in the 'set' method
self.create_rectangle(0,0,1,1, fill="red", tags=("thumb",))
self.bind("<ButtonPress-1>", self.on_click)
def set(self, first, last):
first = float(first)
last = float(last)
height = self.winfo_height()
x0 = 2
x1 = self.winfo_width()-2
y0 = max(int(height * first), 0)
y1 = min(int(height * last), height)
self.coords("thumb", x0, y0, x1, y1)
def on_click(self, event):
y = event.y / self.winfo_height()
self.command("moveto", y)
在程序中使用class
您可以像使用本机滚动条一样使用此 class:实例化它,并将命令设置为可滚动小部件的 yview
命令。
此示例使用文本小部件,因此您可以在键入时看到滚动条更新,但完全相同的代码也适用于 Canvas 或任何其他可滚动的 window.
root = tk.Tk()
text = tk.Text(root)
sb = CustomScrollbar(root, width=20, command=text.yview)
text.configure(yscrollcommand=sb.set)
sb.pack(side="right", fill="y")
text.pack(side="left", fill="both", expand=True)
with open(__file__, "r") as f:
text.insert("end", f.read())
root.mainloop()
我正在 Python 3.7 tkInter 中专门创建一个游戏启动器,我想制作自己的样式 Scrollbar
(在 Windows 10(版本 1903))。
我试过添加一个隐藏的 Scrollbar
,隐藏有效,但我无法模拟它:
def scroll(self, i, reqHeight, vbarValue):
print("vbarValue", vbarValue)
value = -i / 1.4
a1 = int(self.canvass.coords(self.scroll2)[1]) == 5
a2 = value > 0
a = not(a1 ^ a2)
b1 = ((self.canvass.coords(self.scroll2)[3] > self.cHeight))
b2 = value < 0
b = not(b1 ^ b2)
print(value, value < 0)
print(a1, 5)
print("====")
print(a1, a2)
print(a)
print("----")
print(b1, b2)
print(b)
print("====\n\n")
print("OK")
x1, y1, x2, y2 = self.canvass.coords(self.scroll2)
_y1, _y2 = vbarValue
print("1:",y1, y2)
print("2:",_y1, _y2)
print("3:",(_y2 - _y1) / 2 - y2)
print("4:",(_y1 + (_y2 - _y1) / 120) * self.cHeight)
print("5:",(_y1 + (_y2 - _y1) / 120) * self.cHeight - (y2 / y1))
print("6:",((_y2 - _y1) / 120) * self.cHeight - y2* -i)
print("7:",(_y1 + (_y2 - _y1) / 120))
value = (_y1 + (_y2 - _y1) / 120) * self.cHeight / (y1 / y2)
print("8:",(y2 / y1))
# value = value - (y1 / y2)
print("Dynamic Canvas Region Height:")
print("DCRH:", self.cHeight)
print("Value: %s", value)
self.canvass.move(self.scroll2, 0, -y2)
self.canvass.move(self.scroll2, 0, value)
print("coords: %s" % self.canvass.coords(self.scroll2))
print("reqHeight: %s" % reqHeight)
事件:
def _bound_to_mousewheel(self, event): # <Enter> Event
self.canv.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event): # <Leave> Event
self.canv.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event): # <Configure> Event
self.canv.yview_scroll(int(-1 * (event.delta / 120)), "units")
self.scrollCommand(int(-1 * (event.delta / 120)), self.scrollwindow.winfo_reqheight(), self.vbar.get())
def _configure_window(self, event):
# update the scrollbars to match the size of the inner frame
size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight()+1)
self.canv.config(scrollregion='0 0 %s %s' % size)
# if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width():
# # update the canvas's width to fit the inner frame
# # self.canv.config(width=self.scrollwindow.winfo_reqwidth())
# if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height():
# # update the canvas's width to fit the inner frame
# # self.canv.config(height=self.scrollwindow.winfo_reqheight())
顺便说一句,self.scrollCommand(...)
和第一个代码上的滚动一样。
我希望为 canvas.move method
.
How do i simulate a Scrollbar in Tkinter Canvas
滚动条有一个定义明确的界面。要模拟滚动条,您需要做的就是实现此接口。这最容易通过创建具有以下属性的 class 来完成:
- 您需要定义
set
方法,每当被滚动的小部件想要更新滚动条时调用该方法 - 您需要添加鼠标绑定以调用由滚动条控制的小部件的
yview
方法(或者xview
如果创建水平小部件)。
如果你做了这两件事,你的滚动条就可以像内置滚动条一样使用了。
对于这个答案的其余部分,我假设您想要模拟一个垂直滚动条。模拟水平滚动条的工作方式相同,但您处理的不是 'top' 和 'bottom',而是 'left' 和 right'.
定义 set 方法
set 方法将用两个分数调用。 The canonical documentation 是这样描述的:
This command is invoked by the scrollbar's associated widget to tell the scrollbar about the current view in the widget. The command takes two arguments, each of which is a real fraction between 0 and 1. The fractions describe the range of the document that is visible in the associated widget. For example, if first is 0.2 and last is 0.4, it means that the first part of the document visible in the window is 20% of the way through the document, and the last visible part is 40% of the way through.
定义绑定
等式的另一半是当用户与滚动条交互以滚动另一个小部件时。发生这种情况的方式是滚动条应该调用要控制的小部件的yview
命令(例如:canvas,文本,列表框等)。
您必须传递给命令的第一个参数是字符串“moveto”或“scroll”。
如果是“moveto”,第二个参数是一个小数,表示从顶部滚出的数量。这通常在单击滚动条时调用,以立即将滚动条移动到新位置
如果是“scroll”,第二个参数是一个表示数量的整数,第三个参数是字符串“units”或“pages”。 “单位”的定义是指
yscrollincrement
选项的值。 “页面”代表 window 高度的 9/10。这通常在将鼠标拖到滚动条上时调用。
选项在每个可滚动小部件的手册页中都有详细说明。
例子
下面是一个使用文本小部件的示例,这样您就可以看到当您键入时,滚动条会适当地增长和收缩。如果您单击滚动条中的任意位置,它将滚动到文档中的那个位置。
为使示例简短,此代码不处理滚动条的拖动,并且硬编码了许多可能应该可配置的值。关键是要表明模拟滚动条所需要做的就是创建一个 class,它有一个 set
方法并调用 yview
或 xview
方法已连接的小部件。
首先是滚动条class
import tkinter as tk
class CustomScrollbar(tk.Canvas):
def __init__(self, parent, **kwargs):
self.command = kwargs.pop("command", None)
tk.Canvas.__init__(self, parent, **kwargs)
# coordinates are irrelevant; they will be recomputed
# in the 'set' method
self.create_rectangle(0,0,1,1, fill="red", tags=("thumb",))
self.bind("<ButtonPress-1>", self.on_click)
def set(self, first, last):
first = float(first)
last = float(last)
height = self.winfo_height()
x0 = 2
x1 = self.winfo_width()-2
y0 = max(int(height * first), 0)
y1 = min(int(height * last), height)
self.coords("thumb", x0, y0, x1, y1)
def on_click(self, event):
y = event.y / self.winfo_height()
self.command("moveto", y)
在程序中使用class
您可以像使用本机滚动条一样使用此 class:实例化它,并将命令设置为可滚动小部件的 yview
命令。
此示例使用文本小部件,因此您可以在键入时看到滚动条更新,但完全相同的代码也适用于 Canvas 或任何其他可滚动的 window.
root = tk.Tk()
text = tk.Text(root)
sb = CustomScrollbar(root, width=20, command=text.yview)
text.configure(yscrollcommand=sb.set)
sb.pack(side="right", fill="y")
text.pack(side="left", fill="both", expand=True)
with open(__file__, "r") as f:
text.insert("end", f.read())
root.mainloop()