Можно ли заставить полосы прокрутки Tkinter двигаться независимо друг от друга в разных окнах Toplevel? - PullRequest
1 голос
/ 26 апреля 2019

Представьте себе, что есть два окна Tkinter.Toplevel (), называемые Window_1 и Window_2, которые можно открыть, нажав одну и ту же кнопку (например, Button_0).

Кнопка_0 нажата, и Window_1 всплывает. В Window_1 я могу прокручивать вверх и вниз с помощью коврика для мыши (MAC OS). После этого я оставил Window_1 открытым.

Кнопка_0 снова нажата, и Window_2 всплывает, а Window_1 остается открытым. В Window_2 я снова могу прокручивать вверх и вниз.

Теперь я возвращаюсь к Window_1 и пытаюсь прокрутить с помощью коврика для мыши, содержимое в Window_1 НЕ ПЕРЕМЕЩАТЬ, но содержимое в Window_2 ПЕРЕМЕСТИТЬ.

Затем я закрываю Window_2 и пытаюсь прокрутить Window_1, на этот раз я получаю сообщения об ошибках с запросом холста в Window_2.

Я сделал функцию связывания,

def on_vertical(canvas,event):
     canvas.yview_scroll(-3 * event.delta, 'units')

на холст внутри каждого окна. Насколько я знаю об ошибке, похоже, что эту функцию нельзя было использовать дважды одновременно (оба окна открыты).

Мне бы хотелось, чтобы когда обе Windows оставались открытыми. Находясь в каждом окне, я могу прокручивать вверх-вниз, пока другое не перемещается. Можно ли это закодировать?

Это пример кода (обратите внимание, что имя окна не является исправленной меткой.)

from tkinter import *


######################## FUNCTIONS (DEF) ########################
def on_vertical(canvas,event):
    canvas.yview_scroll(-3 * event.delta, 'units')

######################## FUNCTIONS (CLASS) ########################
class Window(Frame):

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.master = master
        self.init_window()

    #INITIAL WINDOW
    def init_window(self):

        self.master.title("Main Window")
        self.pack(fill=BOTH, expand=1)

        Button(self, text="Button_0",command = self.load_and_print).place(x = 7, y = 95)

        # creating a button instance
        Button(self, text="EXIT PROGRAM", command=self.client_exit).place(x=500, y=250)


    #OPEN A NEW WINDOW CONTAINING STOCK LISTS
    def load_and_print(self):

        new_window = Toplevel(self)
        new_window.title("Window")

        canvas = Canvas(new_window, width = 800, height = 500, scrollregion = (0, 0, 0, 2500))
        frame = Frame(canvas)

        vbar = Scrollbar(new_window, orient = VERTICAL, command = canvas.yview)
        vbar.pack(side = RIGHT,fill = Y)

        canvas.create_window(0,0, window = frame, anchor = NW)
        canvas.config(yscrollcommand = vbar.set)
        canvas.pack(side = TOP,expand = True,fill = BOTH)
        canvas.bind_all('<MouseWheel>', lambda event, canvas=canvas: on_vertical(canvas,event))

    #MAKE PROGRAM EXIT
    def client_exit(self):
        exit()

######################## MAIN PROGRAMME ########################
#call window
root = Tk()

#size of the window
root.geometry("700x300")

app = Window(root)
root.mainloop()
root.update()

1 Ответ

1 голос
/ 27 апреля 2019

Проблема в том, что вы используете bind_all вместо bind для события mousewheel.

Поскольку вы используете bind_all, каждый раз, когда вы создаете новое окно, оно заменяет старую привязку.с новой привязкой.Независимо от того, какое окно получает событие, ваша функция всегда будет работать только для последнего создаваемого окна.И, конечно же, когда это окно будет уничтожено, привязка мыши выдаст ошибку, так как холст больше не существует.

Использование bind

Одно решение простое: вместо bind используйтеbind_all.

canvas.bind_all('<MouseWheel>', lambda event, canvas=canvas: on_vertical(canvas,event))

Использование bind_all

Если вы хотите воспользоваться преимуществами bind_all, а именно, чтобы прокрутка работала, даже если указатель мыши находится над другим виджетом, вам нужно изменить on_vertical чтобы выяснить, какой холст прокручивать во время его выполнения, вместо того, чтобы передать холст.

Вы можете сделать это с небольшим самоанализом.Например, объект event знает, какой виджет получил событие.Из этого вы можете выяснить, в каком окне находится мышь, и из этого вы можете выяснить, какой холст прокручивать.

Например, переместите привязку вверх до __init__ и измените ее следующим образом:

self.bind_all('<MouseWheel>', on_vertical)

Затем измените on_vertical, чтобы выяснить, какой холст прокручивать.В следующем примере я предполагаю, что каждый верхний уровень имеет ровно один холст и что вы всегда хотите прокрутить этот холст (то есть: вы теряете возможность прокручивать текстовые виджеты и списки)

Если это не так, вы можете добавитьКакую бы логику вы хотели выяснить, какой виджет прокручивать.

def on_vertical(event):
    top = event.widget.winfo_toplevel()
    for child in top.winfo_children():
        if child.winfo_class() == "Canvas":
            child.yview_scroll(-3 * event.delta, 'units')
            break
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...