Визуальные артефакты при изменении размера PanedWindow в tkinter - PullRequest
1 голос
/ 13 февраля 2020

Я работаю над приложением в tkinter. Невозможно опубликовать код, потому что он слишком сложный и артефакты не будут видны в упрощенной версии.

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

У вас есть опыт с этим? Несколько советов, что может вызвать такое поведение?
видео YouTube с изменением размера

resizing

РЕДАКТИРОВАТЬ:

Я создал минимальную версию, которая воспроизводит поведение. Класс ScrollFrame делает артефакты более заметными.

import tkinter as tk
import random


class ScrollFrame(tk.Frame):
    def __init__(self, parent, **kwargs):
        super().__init__(parent, **kwargs)

        self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
        self.canvas.bind("<Enter>", self._bind_mouse)
        self.canvas.bind("<Leave>", self._unbind_mouse)
        self.viewPort = tk.Frame(self.canvas)
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas_window = self.canvas.create_window((4, 4), window=self.viewPort,
                                                       anchor="nw",
                                                       tags="self.viewPort",
                                                       )

        self.viewPort.bind("<Configure>", self.onFrameConfigure)
        self.canvas.bind("<Configure>", self.onCanvasConfigure)

        self.onFrameConfigure(None)

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox(
            "all"))

    def onCanvasConfigure(self, event):
        '''Reset the canvas window to encompass inner frame when required'''
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_window,
                               width=canvas_width)

    def _bind_mouse(self, event=None):
        self.canvas.bind_all("<4>", self._on_mousewheel)
        self.canvas.bind_all("<5>", self._on_mousewheel)
        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)

    def _unbind_mouse(self, event=None):
        self.canvas.unbind_all("<4>")
        self.canvas.unbind_all("<5>")
        self.canvas.unbind_all("<MouseWheel>")

    def _on_mousewheel(self, event):
        """Linux uses event.num; Windows / Mac uses event.delta"""
        if self.vsb.get() != (0, 1):
            if event.num == 4 or event.delta > 0:
                self.canvas.yview_scroll(-1, "units")
            elif event.num == 5 or event.delta < 0:
                self.canvas.yview_scroll(1, "units")


class OptionAttribute:
    def __init__(self, target_widget, name, options, unit):
        self.name = tk.Label(target_widget, text=name)
        self.input = tk.Button(target_widget, text=options[0], anchor='w',
                               command=lambda: self.show_options(self.input), relief='flat', bg='white', bd=0)
        self.menu = tk.Menu(target_widget, tearoff=0)
        for o in options:
            self.menu.add_command(label=o, command=lambda selected=o: self.input.configure(text=selected))
        self.unit = tk.Label(target_widget, text=unit)

    def show_options(self, widget):
        self.input.focus_set()
        self.menu.post(widget.winfo_rootx(), widget.winfo_rooty())


if __name__ == '__main__':
    root = tk.Tk()
    root.minsize(width=640, height=480)
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)

    pw = tk.PanedWindow(root, orient='horizontal', sashrelief='ridge', sashwidth=8)
    f1 = tk.Frame(pw)
    pw.add(f1, stretch='always', minsize=200, width=400)

    f2 = tk.Frame(pw)
    f2.grid_columnconfigure(0, weight=1)
    f2.grid_rowconfigure(0, weight=1)

    f2_scroll = ScrollFrame(f2)
    f2_scorr_inner = f2_scroll.viewPort
    f2_scorr_inner.grid_columnconfigure(1, weight=80)
    f2_scorr_inner.grid_columnconfigure(2, weight=20)
    f2_scroll.grid(sticky='nsew')

    option_attrs = [OptionAttribute(f2_scorr_inner,
                                    str(random.randint(0, 100000)),
                                    [str(random.randint(0, 100000)) for __ in range(10)],
                                    random.choice(['mm', 'nm', 'kg', 'h', 'km', ])
                                    ) for _ in range(100)]
    r = 0
    for oa in option_attrs:
        oa.name.grid(column=0, row=r, sticky='w', padx=(0, 10))
        oa.input.grid(column=1, row=r, sticky='w')
        oa.unit.grid(column=2, row=r, sticky='w')
        r += 1
        tk.Frame(f2_scorr_inner, height=1, bg="gray80").grid(column=0, row=r, sticky="ew", columnspan=3)
        r += 1

    pw.add(f2, stretch='always', minsize=200, width=400)
    pw.grid(sticky='nsew')

    root.mainloop()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...