如何在 tkInter Canvas 中模拟滚动条 [英] How do I simulate a Scrollbar in tkInter Canvas

查看:76
本文介绍了如何在 tkInter Canvas 中模拟滚动条的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我专门在 Python 3.7 tkInter 中创建了一个游戏启动器,我想制作自己的样式 Scrollbar(在 Windows 10(版本 1903)中).

I'm creating a game launcher specially in Python 3.7 tkInter, and I want to make my own styled Scrollbar (in Windows 10 (version 1903)).

我尝试添加一个隐藏的 Scrollbar,并且隐藏有效,但我无法模拟它:

I've tried adding a hidden Scrollbar, and hiding works but i can't simulate it:

    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(...) 与第一个代码上的滚动相同.

By the way, self.scrollCommand(...) is the same as scroll on the first code.

我希望为 canvas.move 方法 获得一些 xy 输出.

I expect to get some x and y output for the canvas.move method.

推荐答案

我如何在 Tkinter Canvas 中模拟滚动条

How do i simulate a Scrollbar in Tkinter Canvas

滚动条有一个定义明确的界面.要模拟滚动条,您需要做的就是实现这个接口.通过创建具有以下属性的类最容易做到这一点:

The scrollbar has a well defined interface. To simulate a scrollbar all you need to do is implement this interface. This is most easily done by creating a class that has the following attributes:

  • 您需要定义 set 方法,每当正在滚动的小部件想要更新滚动条时都会调用该方法
  • 您需要添加鼠标绑定来调用由滚动条控制的小部件的 yview 方法(如果创建水平小部件,则为 xview).
  • you need to define the set method, which is called whenever the widget being scrolled wants to update the scrollbar
  • you need to add mouse bindings to call the yview method of the widget being controlled by the scrollbar (or xview if creating a horizontal widget).

如果你做这两件事,你的滚动条就可以像内置滚动条一样使用了.

If you do those two things, your scrollbar can be used exactly like a built-in scrollbar.

对于这个答案的其余部分,我将假设您要模拟垂直滚动条.模拟水平滚动条的工作原理相同,但您处理的是左"和右",而不是顶部"和底部".

For the rest of this answer, I'm going to assume you want to simulate a vertical scrollbar. Simulating a horizontal scrollbar works identically, but instead of 'top' and 'bottom', you are dealing with 'left' and right'.

set 方法将使用两个分数调用.规范文档是这样描述的:

The set method will be called with two fractions. The canonical documentation describes it like this:

此命令由滚动条的关联小部件调用,以告诉滚动条小部件中的当前视图.该命令有两个参数,每个参数都是一个介于 0 和 1 之间的实数.这些分数描述了在相关小部件中可见的文档范围.例如,如果 first 是 0.2,last 是 0.4,则表示在窗口中可见的文档的第一部分是文档的 20%,最后可见的部分是文档的 40%.

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命令(例如:画布、文本、列表框等).

Defining the bindings

The other half of the equation is when the user interacts with the scrollbar to scroll another widget. The way this happens is that the scrollbar should call the yview command of the widget to be controlled (eg: canvas, text, listbox, etc).

必须传递给命令的第一个参数是字符串moveto"或moveto".或滚动".

The first argument you must pass to the command is either the string "moveto" or "scroll".

  • 如果是moveto",则第二个参数是一个分数,表示从顶部滚动的数量.这通常在单击滚动条时调用,以立即将滚动条移动到新位置

  • If "moveto", the second argument is a fraction which represents the amount that has been scrolled off of the top. This is typically called when clicking on the scrollbar, to immediately move the scrollbar to a new position

如果是scroll",则第二个参数是表示数量的整数,第三个参数是字符串units"或units".或页面".单位"的定义指的是 yscrollincrement 选项的值.页面"代表窗口高度的 9/10.这通常在将鼠标拖到滚动条上时调用.

if "scroll", the second argument is an integer representing an amount, and the third argument is either the string "units" or "pages". The definition of "units" refers to the value of the yscrollincrement option. "pages" represents 9/10ths of the window height. This is typically called when dragging the mouse over the scrollbar.

选项在每个可滚动小部件的手册页中都有详细说明.

The options are spelled out in the man pages for each scrollable widget.

以下是使用文本小部件的示例,以便您可以看到在键入时,滚动条正确地增长和缩小.如果您单击滚动条中的任意位置,它将滚动到文档中的该点.

The following is an example of a uses a text widget, so that you can see that when you type, the scrollbar properly grows and shrinks. If you click anywhere in the scrollbar, it will scroll to that point in the documentation.

为了使示例简短,此代码不处理拖动滚动条,并且硬编码了许多可能应该可配置的值.关键是要表明模拟滚动条所需要做的就是创建一个具有 set 方法并调用 yviewxview 连接小部件的方法.

To keep the example short, this code doesn't handle dragging the scrollbar, and it hard-codes a lot of values that probably ought to be configurable. The point is to show that all you need to do to simulate a scrollbar is create a class that has a set method and which calls the yview or xview method of the connected widget.

一、滚动条类

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)

在程序中使用类

您可以像使用原生滚动条一样使用此类:实例化它,并将命令设置为可滚动小部件的 yview 命令.

You would use this class exactly like you would a native scrollbar: instantiate it, and set the command to be the yview command of a scrollable widget.

此示例使用文本小部件,因此您可以在键入时看到滚动条更新,但完全相同的代码适用于 Canvas 或任何其他可滚动窗口.

This example uses a text widget so you can see the scrollbar updating as you type, but the exact same code would work with a Canvas, or any other scrollable 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()

这篇关于如何在 tkInter Canvas 中模拟滚动条的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆