Почему моя полоса прокрутки Tkinter не прокручивает мой холст? - PullRequest
0 голосов
/ 05 августа 2020

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

class TimeTable(tk.Canvas):
"""Creates a time table using a tk.Canvas"""
def __init__(self, times, *args, **kwargs):
    """
    :param times: list[CubeUtils.Time]
    """

    # Initialize super class and define attributes
    super().__init__(*args, **kwargs)
    self.TIME_ATTRS = ["Time", "Scramble", "Date", "DNF"]
    self.ScrollbarY = None
    self.fullscreen = False
    self.times = times
    self.frame = self.nametowidget(self.winfo_parent())
    self.parent = self.frame.nametowidget(self.frame)
    self.config(height=len(self.times)*15)
    self.frame.config(height=len(self.times)*15)

    # Insert time attributes in entries
    for column, attr in enumerate(self.TIME_ATTRS):
        text = tk.Text(self, font=("Arial", 15, "bold"), width=50, height=1)
        text.insert("0.0", attr)
        text.config(state=tk.DISABLED)
        text.grid(row=0, column=column+1, sticky=tk.E)

    # Insert times
    for time_count, time in enumerate(self.times):
        time_info = [time_count+1, time.time, time.scramble, time.date, time.DNF]
        if time_info[0] > 49 and self.ScrollbarY is None:
            self.add_scrollbar()

        time_info_font = ("Arial", 15, "bold")
        for column, info in enumerate(time_info):
            if isinstance(info, int) and not isinstance(info, bool):
                text = tk.Text(self, font=time_info_font, width=2 if len(str(info)) <= 2 else len(str(info)), height=1, fg="#ff5000")

            else:
                text = tk.Text(self, font=time_info_font, width=50, height=1, fg="#ff5000")

            text.insert("0.0", str(info))
            text.grid(row=time_count + 1, column=column, sticky=tk.E)
            text.config(state=tk.DISABLED)

    # Bindings
    self.parent.bind("<F11>", lambda key: self.toggle_fullscreen())
    self.parent.bind("<Escape>", lambda key: self.exit_fullscreen())
    self.parent.bind_all("<MouseWheel>", self.on_mousewheel)

Прокрутка

def on_mousewheel(self, event):
    """Scrolls the canvas using the mouse wheel"""
    self.yview_scroll(int(-1 * (event.delta / 120)), "units")

def add_scrollbar(self):
    """Adds a scrollbar to the frame"""
    self.config(scrollregion=self.bbox("all"))
    self.ScrollbarY = tk.Scrollbar(self.frame)
    self.config(yscrollcommand=self.ScrollbarY.set)
    self.ScrollbarY.config(command=self.yview)
    self.ScrollbarY.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH)

Полный экран

def toggle_fullscreen(self):
    """Toggles fullscreen on and off"""
    self.fullscreen = not self.fullscreen
    self.parent.attributes("-fullscreen", self.fullscreen)

def exit_fullscreen(self):
    """Exists fullscreen"""
    self.fullscreen = False
    self.parent.attributes("-fullscreen", self.fullscreen)

Кстати, аргумент times должен быть списком с элементами типа Time, вот код для этого класса.

class Time:
"""Creates a time object that stores its time, scramble, date and whether or not it is a DNF"""
def __init__(self, time, scramble, date, DNF=False):
    """
    :param time: float
    :param scramble: str
    :param date: datetime.datetime
    :param DNF: bool
    """
    if not isinstance(date, datetime.datetime):
        raise TypeError("date parameter must be of type datetime.datetime")

    if not isinstance(time, float):
        raise TypeError("time parameter must be of type float")

    if not isinstance(scramble, str):
        raise TypeError("scramble parameter must be of type str")

    if not isinstance(DNF, bool):
        raise TypeError("DNF parameter must be of type bool")

    self.time = time
    self.scramble = scramble
    self.date = datetime.datetime.strftime(date, "%Y-%m-%d-%I:%M %p")
    self.DNF = DNF

Я пробовал читать веб-страницы на effbot.com и других сайтах о размещении полосы прокрутки на холсте, но ни один из них у меня не работает.

Edit: Благодаря acw1668 я закончил свой класс TimeTable, вот готовый код для этого

class TimeTable(tk.Frame):
    """Creates a time table using a tk.Canvas"""
    def __init__(self, parent, times, *args, **kwargs):
        """
        :param parent: tk.Tk()
        :param times: list[CubeUtils.Time]
        """

        # Initialize super class and define attributes
        super().__init__(*args, **kwargs)
        self.TIME_ATTRS = ["Time", "Scramble", "Date", "DNF"]
        self.fullscreen = False
        self.times = times
        self.canvas = tk.Canvas(self)
        self.frame = tk.Frame(self.canvas)
        self.parent = parent

        self.canvas.pack(fill=tk.BOTH, expand=True)
        self.canvas.create_window(2, 2, window=self.frame, anchor="nw")
        self.frame.bind("<Configure>", self.on_config)
        self.parent.bind("<MouseWheel>", self.on_mousewheel)
        self.parent.bind("<F11>", lambda event: self.toggle_fullscreen())
        self.parent.bind("<Escape>", lambda event: self.exit_fullscreen())
        self.populate()

    def populate(self):
        """Populates the frame with the times"""
        # Insert time attributes in text widgets
        for column, attr in enumerate(self.TIME_ATTRS):
            text = tk.Text(self.frame, font=("Arial", 15, "bold"), width=50, height=1)
            text.insert("0.0", attr)
            text.config(state=tk.DISABLED)
            column += 4
            text.grid(row=0, column=column)

        # Insert times in text widgets
        for time_count, time in enumerate(self.times):
            time_info = [time_count + 1, time.time, time.scramble, time.date, time.DNF]
            time_info_font = ("Arial", 15, "bold")
            for column, info in enumerate(time_info):
                if isinstance(info, int) and not isinstance(info, bool):
                    text = tk.Text(self.frame, font=time_info_font, width=2 if len(str(info)) <= 2 else len(str(info)),
                                   height=1, fg="#ff5000")

                else:
                    text = tk.Text(self.frame, font=time_info_font, width=50, height=1, fg="#ff5000")

                text.insert("0.0", str(info))
                row = time_count + 1
                column += 3

                text.grid(row=row, column=column, sticky=tk.E)
                text.config(state=tk.DISABLED)

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

    def on_mousewheel(self, event):
        """Scrolls the canvas using the mouse wheel"""
        self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def toggle_fullscreen(self):
        """Toggles fullscreen on and off"""
        self.fullscreen = not self.fullscreen
        self.parent.attributes("-fullscreen", self.fullscreen)

    def exit_fullscreen(self):
        """Exists fullscreen"""
        self.fullscreen = False
        self.parent.attributes("-fullscreen", self.fullscreen)
...