Как я могу сделать мою полосу прокрутки python с возможностью прокрутки и автоматического изменения размера холста, используя сетку вместо пакета

#python #tkinter #grid #scrollbar

#python #tkinter #сетка #полоса прокрутки

Вопрос:

Я пытаюсь сделать виджеты в моем холсте с возможностью прокрутки, а холст / виджеты автоматически изменять размер.

В моем коде у меня есть «canvas.create_window ((0, 0), window = new_frame, anchor =’nw’)» прокомментировано. Запуск таким образом автоматически изменит размер виджетов, но полоса прокрутки не будет работать.

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

Я не могу найти решение, в котором используется .grid() . Решение будет оценено.

 import tkinter as tk
from tkinter import *
from tkinter import ttk


def on_mousewheel(event):
    canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

def on_configure(event):
    # update scrollregion after starting 'mainloop'
    # when all widgets are in canvas
    canvas.configure(scrollregion=canvas.bbox('all'))

# Create new window
new_win = tk.Tk()
new_win.focus_force()

# Create a canvas with a scrollbar
canvas = tk.Canvas(new_win)
canvas.grid(row=0, column=0, sticky=tk.N   tk.S   tk.E   tk.W)

scrollbar = ttk.Scrollbar(new_win, command=canvas.yview)
scrollbar.grid(sticky=(N, S), row=0, column=1)
canvas.config(yscrollcommand=scrollbar.set)

# --- put frame in canvas ---
new_frame = tk.Frame(canvas)
new_frame.grid(row=0, column=0, sticky=tk.N   tk.S   tk.E   tk.W)

# canvas.create_window((0, 0), window=new_frame, anchor='nw')

# update scrollregion after starting 'mainloop'
# when all widgets are in canvas
canvas.bind('<Configure>', on_configure)
new_win.bind('<MouseWheel>', on_mousewheel)

# Add Widgets
label = tk.Label(new_frame, text="test")
label2 = tk.Label(new_frame, text="test")
label.grid(column=0, row=0, sticky=tk.N   tk.S   tk.E   tk.W)
label2.grid(column=0, row=1, sticky=tk.N   tk.S   tk.E   tk.W)


txt_box = tk.Text(new_frame)
txt_box2 = tk.Text(new_frame)
txt_box.grid(column=1, row=0, sticky=tk.N   tk.S   tk.E   tk.W)
txt_box2.grid(column=1, row=1, sticky=tk.N   tk.S   tk.E   tk.W)

# configure
new_win.grid_columnconfigure(0, weight=1)
new_win.grid_rowconfigure(0, weight=1)

new_frame.grid_columnconfigure(1, weight=1)
new_frame.grid_rowconfigure(0, weight=1)

canvas.grid_columnconfigure(0, weight=1)
canvas.grid_rowconfigure(0, weight=1)

new_win.mainloop()
 

Комментарии:

1. Я рекомендую попытаться уменьшить размер кода. Например, вы могли бы использовать цикл для замены 19 вызовов на grid_rowconfigure две строки кода. Аналогично для создания виджетов и вызова grid . Вы можете легко обрезать свой пример на 75 строк или более.

2. Привет, мозг, спасибо за ввод. Это уменьшит объем кода и сделает его более чистым. Однако это не меняет функциональность.

3. Вероятно, вы правы, это вряд ли поможет функциональности, но поможет нам лучше понять ваш вопрос. Когда я смотрю на вопрос и вижу несколько сотен строк, моя первоначальная мысль заключается в том, что я должен просмотреть каждую строку, чтобы увидеть, есть ли проблема. Когда есть сотни строк, это также сигнализирует о том, что автор не нашел времени, чтобы попытаться сузить проблему. Ваша цель при написании вопроса всегда должна заключаться в том, чтобы людям было как можно проще понять и воспроизвести проблему.

4. Хорошо, я удалил много кода и оставил ту же функциональность всего с несколькими виджетами.

5. Теперь вы сделали так, что полосы прокрутки никогда не будут работать, потому что слишком мало виджетов, требующих прокрутки.

Ответ №1:

Во-первых, единственный способ прокрутить что-либо на холсте — это поместить объект на холст с помощью одной из create_* функций. Если вы добавляете рамку к холсту grid , ее нельзя прокручивать. Поэтому вам нужно удалить строку grid , которая вызывает new_frame , и раскомментировать вызывающую строку create_window .

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

Поскольку у вас уже есть привязка к <Configure> холсту, все, что вам нужно сделать, это настроить размер внутренней рамки на основе width параметра, переданного в объект события. Для этого вам нужно либо сохранить идентификатор созданного окна, либо присвоить созданному окну тег.

Давайте начнем с присвоения окну тега, который вы можете сделать при создании окна:

 canvas.create_window((0, 0), window=new_frame, anchor='nw', tags=('internal_frame',))
 

Затем сбросьте ширину этого фрейма, чтобы он соответствовал ширине вашего холста:

 def on_configure(event):
    canvas.itemconfigure('internal_frame', width=event.width-10)
    ...
 

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