Ткинтер |Пользовательский виджет: бесконечный (горизонтальный) календарь с прокруткой - PullRequest
0 голосов
/ 22 декабря 2018

КОНТЕКСТ

Я пытаюсь создать собственный календарь (виджет Tkinter), который имеет следующие атрибуты / функции:

  • Каждый столбец представляет 1 день
  • Каждая строка будет представлять человека
  • Она имеет бесконечную горизонтальную прокрутку -> такон может бесконечно идти в прошлое и настоящее
  • ячейки (прямоугольники) в календаре будут интерактивными, так что если я нажму левую кнопку мыши, я могу выбрать определенные ячейки для дальнейшей работы / функции

Это будет выглядеть примерно так:

sketch of how the widget should look like

(Примечание к изображению: красный столбец слева будет отдельным виджетом рамки. Я только что включил его в эскиз, чтобы показать назначение строк в календаре)


МОЙ ПЛАН

Чтобы иметь возможность взаимодействовать с клетками после построения календаря, я планируюch виджет объекта хранится в массиве с именем self.cells.

Также, поскольку я хочу, чтобы он бесконечно уходил в прошлое и будущее, при инициализации полоса прокрутки календаря будет посередине.


МОЙ ПРОГРЕСС (КОД)

import tkinter as tk
import datetime

CELL_SIZE = (100, 50)
FIRST_ROW_HEIGHT = 20

class Cell(tk.Canvas):
    def __init__(self, root,
        width = CELL_SIZE[0],
        height = CELL_SIZE[1],
        highlightthickness = 1,
        background = 'white',
        highlightbackground = 'black',
        highlightcolor = 'red',
        *args, **kwargs):

        tk.Canvas.__init__(self, root,
            width = width,
            height = height,
            background = background,
            highlightthickness = highlightthickness,
            highlightbackground = highlightbackground,
            highlightcolor = highlightcolor,
            *args, **kwargs)

class Calendar(tk.Frame):
    def __init__(self, root, rows=0, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)

        # create the canvas and frame
        self.calendar_canvas = tk.Canvas(self)
        self.calendar_frame = tk.Frame(self.calendar_canvas)
        self.calendar_canvas.create_window((4,4), window=self.calendar_frame, anchor="nw", tags="self.calendar_frame")
        self.calendar_canvas.pack(side="top", fill="both", expand=True)

        # building scrollbar
        self.scrollbar = tk.Scrollbar(self, orient='horizontal', command=self.calendar_canvas.xview)
        self.scrollbar.pack(side="bottom", fill="x")

        # hooking up scrollbar
        self.calendar_canvas.configure(xscrollcommand=self.scrollbar.set)
        self.calendar_frame.bind("<Configure>", self.onFrameConfigure)

        # variables
        self.rows = rows
        self.cells = []


    def onFrameConfigure(self, event):
        self.calendar_canvas.configure(scrollregion=self.calendar_canvas.bbox("all"))

    def set(self, day=0):
        today = datetime.date.today()

        for i in range(day):
            self.cells.append([])

            # create first row (indicating the date)
            cell = Cell(self.calendar_frame, height=FIRST_ROW_HEIGHT)
            cell.grid(row=0, column=i)

            # add the date label into the first row
            cell.create_text(
                CELL_SIZE[0]/2,
                FIRST_ROW_HEIGHT/2,
                text = (today + datetime.timedelta(days=i)).strftime('%d/%m/%y'))

            for c in range(self.rows):
                cell = Cell(self.calendar_frame)
                cell.grid(row=c+1, column=i)

                self.cells[i].append(cell)

Calendar - мой виджет пользовательского календаря в разработке.Мне удается подключить эту структуру, похожую на электронную таблицу, с помощью полосы прокрутки благодаря этому ответу (из @ Ethan Field ), который также послужил моей отправной точкой (базовый код).

В настоящее время виджет Calendar способен создавать n количество дней (начиная с сегодняшнего дня) с помощью функции Calendar.set().

Вы можете попробовать виджет, используя этот код:

root = tk.Tk()
calendar = Calendar(root, rows=3)
calendar.set(day=10)
calendar.pack(fill='both', expand=True)
root.mainloop()

ВОПРОС / ВОПРОС

Как реализовать эффект бесконечная прокрутка ?Я понятия не имею, как заставить его работать.


Разные заметки

  • Python 3, 64-битный
  • Windows 7, 64-битный


РЕДАКТИРОВАТЬ # 1 - создано addFuture() функция

# under class Calendar:
def addFuture(self, day=0):
    today = datetime.date.today()

    for i in range(day):
        index = i + self.lastColumn
        self.cells.append([])

        # create first row (indicating the date)
        cell = Cell(self.calendar_frame, height=FIRST_ROW_HEIGHT)
        cell.grid(row=0, column=index)

        # add the date label into the first row
        cell.create_text(
            CELL_SIZE[0]/2,
            FIRST_ROW_HEIGHT/2,
            text = (today + datetime.timedelta(days=index)).strftime('[%a] %d/%m/%y'))

        for c in range(self.rows):
            cell = Cell(self.calendar_frame)
            cell.grid(row=c+1, column=index)

            self.cells[i].append(cell)

    self.lastColumn = self.lastColumn + day

Эта addFuture() функция только слегка изменена set() функция.addFuture() можно вызывать несколько раз, и каждый раз он добавляет day количество дней в календарь.Просто нужно подключить полосу прокрутки вверх.Однако, как мне addPast()?


РЕДАКТИРОВАТЬ # 2 - бесконечная прокрутка в будущее работает!

Команды onFrameConfigure вызываются всякий раз, когдапользователь перетаскивает полосу прокрутки, поэтому я добавил оператор if self.scrollbar.get()[1] > 0.9:, чтобы проверить, приближается ли ось x полосы прокрутки к крайнему правому концу 1109 *.Если это так, он выполняет функцию добавления дополнительных дней, и полоса прокрутки каким-то образом автоматически перенастраивает шкалу (я понятия не имею , почему , но это работает).

def onFrameConfigure(self, event):
    self.calendar_canvas.configure(scrollregion=self.calendar_canvas.bbox("all"))
    if self.scrollbar.get()[1] > 0.9:
        self.addFuture(day=10)

Таким образом, мое окно имеет бесконечную прокрутку в будущее.Теперь у меня вопрос как заставить его бесконечно прокручиваться в прошлое (или слева)? .

Я могу обнаружить полосу прокрутки, когда она приближается к левой стороне, используя этот оператор:if self.scrollbar.get()[1] < 0.1:.Однако мне нужна какая-то команда self.addPast(), которая служит той же цели, что и команда self.addFuture(), но (как следует из названия) добавляет дни слева.

1 Ответ

0 голосов
/ 22 декабря 2018

Что вы хотите сделать, это убедиться, что на холсте всегда достаточно столбцов для прокрутки всего экрана вправо или влево.Первое, что нужно сделать, это начать с такого количества столбцов.Если вы хотите, чтобы каждый столбец составлял 100 пикселей, а сам холст - 400 пикселей, то вам нужно всего 1200 пикселей столбцов: 4 столбца слева, 4 видимых столбца и 4 столбца справа.

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

После того, как вы добавили новые столбцы справа или слева, вам нужно пересчитать scrollregion холста.Когда вы это сделаете, tkinter автоматически отрегулирует положение и размер большого пальца полосы прокрутки.

...