#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)
...
Примечание: чтобы помочь визуализировать, что происходит во время отладки, это помогает придать отличительные цвета фона холсту, внутренней рамке и окну. Это также помогает добавить отступы или границы, чтобы вы могли видеть, где заканчивается один виджет и начинается другой.