У меня есть приложение, которое делит главное окно на две части:
Слева: холст, на котором будет отображаться карта
Справа: фрейм, в котором несколько других фреймов будут разделять пространство, и один из них будет отображаться с помощью tkraise()
На предыдущем снимке экрана в правой части окна виден фрейм данных с информацией о транспортном средстве и вертикальной полосой прокрутки для размещения всех возможных транспортных средств и людей, имеющих те же координаты, что и выбранное транспортное средство.
Если я нажму на имя человека, правый фрейм изменится (с помощью tkraise()) и мы можем видеть это:
Я могу циклически просматривать список транспортных средств и людей, нажимая «Следующий» или «Предыдущий», а также могу видеть информацию о человеке и транспортном средстве, нажимая на цветные метки.
Как видно из примера кода, который я вставляю ниже, это работает, потому что я Я объединяю все правые кадры в начале программы. Пример сокращен до минимума рабочей программы, но на самом деле у меня есть несколько разных кадров, которые нужно отобразить с правой стороны, и если я в начале размечу их все по сетке, то смогу увидеть, как отрисовывается каждый из них, пока последний, который нужно отрисовать, не останется сверху. Такое поведение мигания всех виджетов до тех пор, пока не будет показан последний кадр, не очень привлекательно.
Поэтому я подумал, что мне следует использовать Grid() только один из кадров в начале, а остальные будут объединены в сетку (и подняты) при первом посещении. Но моя проблема в том, что, если я не использую сетку() в начале, список элементов, разделяющих координаты, не отображается должным образом:
Но в прокручиваемом фрейме можно увидеть что-то маленькое.
Единственная разница в том, что я использую сетку для кадров. позже, а не в начале.
Вот код:
import tkinter as tk
from tkinter import ttk
class App:
def __init__(self):
self.root = tk.Tk()
self.root.minsize(width=800, height=400)
self.root.maxsize(width=800, height=400)
self.style = ttk.Style(self.root)
self.style.configure('Left.TFrame', background='#DBD9D9')
self.style.configure('Right.TFrame', background='#EDE8E8')
# Active data info frame (right side)
self.active_data_frame = None
self.current_person = 0
self.current_vehicle = 0
# Frames
self.root.rowconfigure(0, weight=1)
self.root.columnconfigure(0, weight=0, minsize=400)
self.root.columnconfigure(1, weight=1)
self.left = ttk.Frame(self.root, style='Left.TFrame')
self.left.grid(row=0, column=0, sticky='nswe')
self.left.rowconfigure(0, weight=1)
self.left.columnconfigure(0, weight=1)
self.right = ttk.Frame(self.root, style='Right.TFrame')
self.right.grid(row=0, column=1, sticky='nswe')
self.right.rowconfigure(0, weight=1)
self.right.columnconfigure(0, weight=1)
# People and vehicles have different ids
self.people = [
{'id': 1001, 'birth': '01/02/1980', 'name': 'Helen', 'surname': 'Doe', 'weight': 66, 'height': 171, 'profession': 'Doctor', 'Coordinates': (100, 100)},
{'id': 1002, 'birth': '01/03/1981', 'name': 'Alicia', 'surname': 'Smith', 'weight': 55, 'height': 150, 'profession': 'Teacher', 'Coordinates': (200, 200)},
{'id': 1003, 'birth': '01/06/1982', 'name': 'Laura', 'surname': 'Morgan', 'weight': 68, 'height': 175, 'profession': 'Attorney', 'Coordinates': (140, 170)},
{'id': 1004, 'birth': '01/09/1983', 'name': 'Susan', 'surname': 'S. M.', 'weight': 76, 'height': 166, 'profession': 'Engineer', 'Coordinates': (205, 120)},
{'id': 1005, 'birth': '01/12/1984', 'name': 'John', 'surname': 'Doe2', 'weight': 63, 'height': 171, 'profession': 'Footballer', 'Coordinates': (205, 120)},
{'id': 1006, 'birth': '01/05/1985', 'name': 'Doug', 'surname': 'Williams', 'weight': 66, 'height': 160, 'profession': 'Fisherman', 'Coordinates': (200, 200)},
{'id': 1007, 'birth': '01/08/1986', 'name': 'Frank', 'surname': 'Frankenstein', 'weight': 70, 'height': 188, 'profession': 'Fireman', 'Coordinates': (205, 120)}
]
self.vehicles = [
{'id': 8001, 'plates': 'ABC123', 'make': 'Ford', 'model': 'Mondeo', 'color': 'red', 'Coordinates': (200, 200)},
{'id': 8002, 'plates': 'JBN134', 'make': 'Renault', 'model': 'Clio', 'color': 'blue', 'Coordinates': (100, 100)},
{'id': 8003, 'plates': 'JBN251', 'make': 'Fiat', 'model': 'Marea', 'color': 'red', 'Coordinates': (205, 120)},
{'id': 8004, 'plates': 'JSN368', 'make': 'Cadillac', 'model': 'Seville', 'color': 'orange', 'Coordinates': (140, 170)},
{'id': 8005, 'plates': 'JSN485', 'make': 'Tesla', 'model': 'S', 'color': 'black', 'Coordinates': (100, 100)},
{'id': 8006, 'plates': 'JSC602', 'make': 'Ford', 'model': 'Mustang', 'color': 'red', 'Coordinates': (200, 200)},
{'id': 8007, 'plates': 'JSC719', 'make': 'BMW', 'model': '320i', 'color': 'yellow', 'Coordinates': (205, 120)}
]
self.objects_at_xy = {}
for item in self.people:
coords = item['Coordinates']
if coords in self.objects_at_xy:
self.objects_at_xy[coords].append(('p', item['id'], item['name'], item['surname']))
else:
self.objects_at_xy[coords] = [('p', item['id'], item['name'], item['surname'])]
for item in self.vehicles:
coords = item['Coordinates']
if coords in self.objects_at_xy:
self.objects_at_xy[coords].append(('v', item['id'], item['plates'], item['make'], item['model']))
else:
self.objects_at_xy[coords] = [('v', item['id'], item['plates'], item['make'], item['model'])]
# Initialize different viewers
self.peopleviewer = PeopleViewer(self)
self.vehicleviewer = VehicleViewer(self)
class PeopleViewer:
"""Class for displaying and handling people data."""
def __init__(self, app):
self.app = app
self.frame = ttk.Frame(self.app.right)
# Only grid when calling update()
self.frame.grid(row=0, column=0, sticky='nswe')
self.frame.rowconfigure((0,1,2,3,4), weight=0, uniform='frame_r')
self.frame.rowconfigure(5, weight=1)
self.frame.columnconfigure((0,1,2,3), weight=0, uniform='frame_c')
self.button_next = ttk.Button(self.frame, text='Next person', command=self.next_element)
self.button_prev = ttk.Button(self.frame, text='Previous person', command=self.prev_element)
self.button_next.grid(row=0, column=0, columnspan=2, sticky='NSWE')
self.button_prev.grid(row=0, column=2, columnspan=2, sticky='NSWE')
self.label_id = ttk.Label(self.frame, text="ID", relief=tk.GROOVE)
self.label_id_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_id.grid(row=1, column=0, sticky='NSWE')
self.label_id_val.grid(row=1, column=1, sticky='NSWE')
self.label_birth_date = ttk.Label(self.frame, text="Birth date", relief=tk.GROOVE)
self.label_birth_date_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_birth_date.grid(row=1, column=2, sticky='NSWE')
self.label_birth_date_val.grid(row=1, column=3, sticky='NSWE')
self.label_name = ttk.Label(self.frame, text="Name", relief=tk.GROOVE)
self.label_name_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_name.grid(row=2, column=0, sticky='NSWE')
self.label_name_val.grid(row=2, column=1, sticky='NSWE')
self.label_surname = ttk.Label(self.frame, text="Surname", relief=tk.GROOVE)
self.label_surname_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_surname.grid(row=2, column=2, sticky='NSWE')
self.label_surname_val.grid(row=2, column=3, sticky='NSWE')
self.label_weight = ttk.Label(self.frame, text="Weight", relief=tk.GROOVE)
self.label_weight_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_weight.grid(row=3, column=0, sticky='NSWE')
self.label_weight_val.grid(row=3, column=1, sticky='NSWE')
self.label_height = ttk.Label(self.frame, text="Height", relief=tk.GROOVE)
self.label_height_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_height.grid(row=3, column=2, sticky='NSWE')
self.label_height_val.grid(row=3, column=3, sticky='NSWE')
self.label_profession = ttk.Label(self.frame, text="Profession", relief=tk.GROOVE)
self.label_profession_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_profession.grid(row=4, column=0, sticky='NSWE')
self.label_profession_val.grid(row=4, column=1, sticky='NSWE')
self.label_coordinates = ttk.Label(self.frame, text="Coordinates", relief=tk.GROOVE)
self.label_coordinates_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_coordinates.grid(row=4, column=2, sticky='NSWE')
self.label_coordinates_val.grid(row=4, column=3, sticky='NSWE')
self.frame_elements = ttk.Frame(self.frame)
self.frame_elements.grid(row=5, column=0, columnspan=4, sticky='NSWE', pady=(3, 3))
# Vertical scroll implemented as in
# https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter/3092341#3092341
self.canvas_in_frame_elements = tk.Canvas(self.frame_elements, borderwidth=0)
self.frame_inside_canvas = ttk.Frame(self.canvas_in_frame_elements)
self.frame_inside_canvas.columnconfigure((0, 2), weight=0, minsize=20)
self.frame_inside_canvas.columnconfigure((1, 3), weight=1, uniform='elements')
self.vsb = ttk.Scrollbar(self.frame_elements, orient="vertical", command=self.canvas_in_frame_elements.yview)
self.canvas_in_frame_elements.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas_in_frame_elements.pack(side="left", fill="both", expand=True)
self.canvas_in_frame_elements.update()
w = self.canvas_in_frame_elements.winfo_width()
self.canvas_in_frame_elements.create_window((0, 0), window=self.frame_inside_canvas, anchor="nw", width=w)
self.frame_inside_canvas.bind("", self.onFrameConfigure)
def onFrameConfigure(self, event) -> None:
"""Reset the scroll region to encompass the inner frame."""
self.canvas_in_frame_elements.configure(scrollregion=self.canvas_in_frame_elements.bbox("all"))
def next_element(self) -> None:
"""Iterates forward in the list of elements."""
self.app.current_person += 1
if self.app.current_person == len(self.app.people):
self.app.current_person = 0
person = self.app.people[self.app.current_person]
self.update(person)
def prev_element(self) -> None:
"""Iterates backward in the list of elements."""
self.app.current_person -= 1
if self.app.current_person < 0:
self.app.current_person = len(self.app.people) - 1
person = self.app.people[self.app.current_person]
self.update(person)
def update(self, person) -> None:
"""Updates the frame with a person's info."""
if not self.frame.winfo_ismapped():
self.frame.grid(row=0, column=0, sticky='nswe')
print('PeopleViewer gridded')
if self.app.active_data_frame != self:
self.frame.tkraise()
self.app.active_data_frame = self
print('PeopleViewer raised')
# Update labels' content
self.label_id_val['text'] = person['id']
self.label_birth_date_val['text'] = person['birth']
self.label_name_val['text'] = person['name']
self.label_surname_val['text'] = person['surname']
self.label_weight_val['text'] = person['weight']
self.label_height_val['text'] = person['height']
self.label_profession_val['text'] = person['profession']
x, y = person['Coordinates']
self.label_coordinates_val['text'] = f'{x},{y}'
# Destroy previous labels (if any) from the scrollable frame
for element in self.frame_inside_canvas.winfo_children():
element.destroy()
self.person_labels = {}
current_row = 0
column = 0
# Find objects at this coordinates
for obj in self.app.objects_at_xy[person['Coordinates']]:
if obj[0] == 'p':
background = '#7cf576'
text = f'{obj[2]} {obj[3]}'
elif obj[0] == 'v':
background = '#d3e35b'
text = f'{obj[2]} - {obj[3]} {obj[4]}'
label_id = ttk.Label(self.frame_inside_canvas, text=str(obj[1]), borderwidth=1, relief="ridge", anchor=tk.CENTER, background=background)
label_info = ttk.Label(self.frame_inside_canvas, text=text, borderwidth=1, relief="ridge", anchor=tk.W, background=background)
if column == 1:
id1 = label_id.grid(row=current_row, column=2, sticky='NSWE')
id2 = label_info.grid(row=current_row, column=3, sticky='NSWE')
else:
id1 = label_id.grid(row=current_row, column=0, sticky='NSWE')
id2 = label_info.grid(row=current_row, column=1, sticky='NSWE')
label_info.bind('', self.label_enter)
label_info.bind('', self.label_leave)
label_info.bind('', self.label_click)
self.person_labels[label_info] = label_id
column+= 1
if column== 2:
current_row += 1
column= 0
def label_enter(self, event):
self.current_cursor = event.widget['cursor']
event.widget['cursor'] = 'hand2'
def label_leave(self, event):
event.widget['cursor'] = self.current_cursor
def label_click(self, event):
element_id = int(self.person_labels[event.widget]['text'])
# Show data about the clicked person
found = False
for person in self.app.people:
if person['id'] == element_id:
found = True
break
if not found:
for vehicle in self.app.vehicles:
if vehicle['id'] == element_id:
break
# TO DO: "current" must change accordingly
if element_id > 8000:
self.app.vehicleviewer.update(vehicle)
else:
self.update(person)
class VehicleViewer:
"""Class for displaying and handling vehicle data."""
def __init__(self, app):
self.app = app
self.frame = ttk.Frame(self.app.right)
# Only grid when calling update()
self.frame.grid(row=0, column=0, sticky='nswe')
self.frame.rowconfigure((0,1,2,3), weight=0, uniform='frame_r')
self.frame.rowconfigure(4, weight=1)
self.frame.columnconfigure((0,1,2,3), weight=0, uniform='frame_c')
self.button_next = ttk.Button(self.frame, text='Next vehicle', command=self.next_element)
self.button_prev = ttk.Button(self.frame, text='Previous vehicle', command=self.prev_element)
self.button_next.grid(row=0, column=0, columnspan=2, sticky='NSWE')
self.button_prev.grid(row=0, column=2, columnspan=2, sticky='NSWE')
self.label_id = ttk.Label(self.frame, text="ID", relief=tk.GROOVE)
self.label_id_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_id.grid(row=1, column=0, sticky='NSWE')
self.label_id_val.grid(row=1, column=1, sticky='NSWE')
self.label_plates = ttk.Label(self.frame, text="Plates", relief=tk.GROOVE)
self.label_plates_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_plates.grid(row=1, column=2, sticky='NSWE')
self.label_plates_val.grid(row=1, column=3, sticky='NSWE')
self.label_make = ttk.Label(self.frame, text="Make", relief=tk.GROOVE)
self.label_make_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_make.grid(row=2, column=0, sticky='NSWE')
self.label_make_val.grid(row=2, column=1, sticky='NSWE')
self.label_model = ttk.Label(self.frame, text="Model", relief=tk.GROOVE)
self.label_model_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_model.grid(row=2, column=2, sticky='NSWE')
self.label_model_val.grid(row=2, column=3, sticky='NSWE')
self.label_color = ttk.Label(self.frame, text="Color", relief=tk.GROOVE)
self.label_color_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_color.grid(row=3, column=0, sticky='NSWE')
self.label_color_val.grid(row=3, column=1, sticky='NSWE')
self.label_coordinates = ttk.Label(self.frame, text="Coordinates", relief=tk.GROOVE)
self.label_coordinates_val = ttk.Label(self.frame, relief=tk.GROOVE)
self.label_coordinates.grid(row=3, column=2, sticky='NSWE')
self.label_coordinates_val.grid(row=3, column=3, sticky='NSWE')
self.frame_elements = ttk.Frame(self.frame)
self.frame_elements.grid(row=4, column=0, columnspan=4, sticky='NSWE', pady=(3, 3))
# Vertical scroll implemented as in
# https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter/3092341#3092341
self.canvas_in_frame_elements = tk.Canvas(self.frame_elements, borderwidth=0)
self.frame_inside_canvas = ttk.Frame(self.canvas_in_frame_elements)
self.frame_inside_canvas.columnconfigure((0, 2), weight=0, minsize=20)
self.frame_inside_canvas.columnconfigure((1, 3), weight=1, uniform='elements')
self.vsb = ttk.Scrollbar(self.frame_elements, orient="vertical", command=self.canvas_in_frame_elements.yview)
self.canvas_in_frame_elements.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas_in_frame_elements.pack(side="left", fill="both", expand=True)
self.canvas_in_frame_elements.update()
w = self.canvas_in_frame_elements.winfo_width()
self.canvas_in_frame_elements.create_window((0, 0), window=self.frame_inside_canvas, anchor="nw", width=w)
self.frame_inside_canvas.bind("", self.onFrameConfigure)
# Start with the first vehicle
vehicle = self.app.vehicles[self.app.current_vehicle]
self.update(vehicle)
def onFrameConfigure(self, event) -> None:
"""Reset the scroll region to encompass the inner frame."""
self.canvas_in_frame_elements.configure(scrollregion=self.canvas_in_frame_elements.bbox("all"))
def next_element(self) -> None:
"""Iterates forward in the list of elements."""
self.app.current_vehicle += 1
if self.app.current_vehicle == len(self.app.vehicles):
self.app.current_vehicle = 0
vehicle = self.app.vehicles[self.app.current_vehicle]
self.update(vehicle)
def prev_element(self) -> None:
"""Iterates backward in the list of elements."""
self.app.current_vehicle -= 1
if self.app.current_vehicle < 0:
self.app.current_vehicle = len(self.app.vehicles) - 1
vehicle = self.app.vehicles[self.app.current_vehicle]
self.update(vehicle)
def update(self, vehicle) -> None:
"""Updates the frame with a vehicle's info."""
if not self.frame.winfo_ismapped():
self.frame.grid(row=0, column=0, sticky='nswe')
print('VehicleViewer gridded')
if self.app.active_data_frame != self:
self.frame.tkraise()
self.app.active_data_frame = self
print('VehicleViewer raised')
# Update labels's info
self.label_id_val['text'] = vehicle['id']
self.label_plates_val['text'] = vehicle['plates']
self.label_make_val['text'] = vehicle['make']
self.label_model_val['text'] = vehicle['model']
self.label_color_val['text'] = vehicle['color']
x, y = vehicle['Coordinates']
self.label_coordinates_val['text'] = f'{x},{y}'
# Destroy previous labels (if any) from the scrollable frame
for element in self.frame_inside_canvas.winfo_children():
element.destroy()
self.vehicle_labels = {}
current_row = 0
column = 0
# Find objects at this coordinates
for obj in self.app.objects_at_xy[vehicle['Coordinates']]:
if obj[0] == 'p':
background = '#7cf576'
text = f'{obj[2]} {obj[3]}'
elif obj[0] == 'v':
background = '#d3e35b'
text = f'{obj[2]} - {obj[3]} {obj[4]}'
label_id = ttk.Label(self.frame_inside_canvas, text=str(obj[1]), borderwidth=1, relief="ridge", anchor=tk.CENTER, background=background)
label_info = ttk.Label(self.frame_inside_canvas, text=text, borderwidth=1, relief="ridge", anchor=tk.W, background=background)
if column == 1:
id1 = label_id.grid(row=current_row, column=2, sticky='NSWE')
id2 = label_info.grid(row=current_row, column=3, sticky='NSWE')
else:
id1 = label_id.grid(row=current_row, column=0, sticky='NSWE')
id2 = label_info.grid(row=current_row, column=1, sticky='NSWE')
label_info.bind('', self.label_enter)
label_info.bind('', self.label_leave)
label_info.bind('', self.label_click)
self.vehicle_labels[label_info] = label_id
column+= 1
if column== 2:
current_row += 1
column= 0
self.frame.update_idletasks()
print('self.frame_inside_canvas.winfo_children')
for widget in self.frame_inside_canvas.winfo_children():
print(widget, widget.winfo_ismapped())
def label_enter(self, event):
self.current_cursor = event.widget['cursor']
event.widget['cursor'] = 'hand2'
def label_leave(self, event):
event.widget['cursor'] = self.current_cursor
def label_click(self, event):
element_id = int(self.vehicle_labels[event.widget]['text'])
print('Clicked', element_id)
# Show data about the clicked item
found = False
for vehicle in self.app.vehicles:
if vehicle['id'] == element_id:
found = True
break
if not found:
for person in self.app.people:
if person['id'] == element_id:
break
# TO DO: "current" must change accordingly
if element_id > 8000:
self.update(vehicle)
else:
self.app.peopleviewer.update(person)
if __name__ == "__main__":
app = App()
app.root.mainloop()
В моей реальной программе список людей и транспортных средств (и домашних животных, и городов и т. д.) не фиксированный, а динамический, поэтому мне нужна вертикальная прокрутка, потому что многие объекты могут иметь одни и те же координаты. Это может быть список вместо холста (и фрейм внутри холста), но я хочу использовать внутри него этот макет из 4 столбцов, а также значки в метках, поэтому я выбрал холст, как описано здесь.
Обратите внимание на
в строках 85 и 282.
Если я прокомментирую одну или обе строки, я получу странное поведение, которое показано на рисунке, несмотря на то, что в строках 187 и 378 при первом посещении кадр имеет сетку. Я проверяю, привязан ли кадр к сетке, используя .winfo_ismapped() . И, если кадр не активен, я поднимаю его.
Если я вставлю это в конец VehicleViewer.update():
self.frame.update_idletasks()
print('self.frame_inside_canvas.winfo_children')
for widget in self.frame_inside_canvas.winfo_children():
print(widget, widget.winfo_ismapped())
Я вижу это, когда использую метод Grid() для кадра в начале:
и я не знаю, почему.
Все метки и кнопки отображаются правильно, если рамки позже будут объединены в сетку, но не содержимое области прокрутки.
Я использую Python 3.13.7 в Windows 11.>
На предыдущем снимке экрана в правой части окна виден фрейм данных с информацией о транспортном средстве и вертикальной полосой прокрутки для размещения всех возможных транспортных средств и людей, имеющих те же координаты, что и выбранное транспортное средство. Если я нажму на имя человека, правый фрейм изменится (с помощью tkraise()) и мы можем видеть это: [img]https://i.sstatic.net/M6o4BMup.png[/img]
Я могу циклически просматривать список транспортных средств и людей, нажимая «Следующий» или «Предыдущий», а также могу видеть информацию о человеке и транспортном средстве, нажимая на цветные метки. Как видно из примера кода, который я вставляю ниже, это работает, потому что я Я объединяю все правые кадры в начале программы. Пример сокращен до минимума рабочей программы, но на самом деле у меня есть несколько разных кадров, которые нужно отобразить с правой стороны, и если я в начале размечу их все по сетке, то смогу увидеть, как отрисовывается каждый из них, пока последний, который нужно отрисовать, не останется сверху. Такое поведение мигания всех виджетов до тех пор, пока не будет показан последний кадр, не очень привлекательно. Поэтому я подумал, что мне следует использовать Grid() только один из кадров в начале, а остальные будут объединены в сетку (и подняты) при первом посещении. Но моя проблема в том, что, если я не использую сетку() в начале, список элементов, разделяющих координаты, не отображается должным образом: [img]https://i.sstatic.net/itDy0tXj.png[/img]
Но в прокручиваемом фрейме можно увидеть что-то маленькое. Единственная разница в том, что я использую сетку для кадров. позже, а не в начале. Вот код: [code]import tkinter as tk from tkinter import ttk
class App: def __init__(self): self.root = tk.Tk()
column+= 1 if column== 2: current_row += 1 column= 0
self.frame.update_idletasks() print('self.frame_inside_canvas.winfo_children') for widget in self.frame_inside_canvas.winfo_children(): print(widget, widget.winfo_ismapped())
# Show data about the clicked item found = False for vehicle in self.app.vehicles: if vehicle['id'] == element_id: found = True break
if not found: for person in self.app.people: if person['id'] == element_id: break
# TO DO: "current" must change accordingly if element_id > 8000: self.update(vehicle) else: self.app.peopleviewer.update(person)
if __name__ == "__main__": app = App() app.root.mainloop() [/code] В моей реальной программе список людей и транспортных средств (и домашних животных, и городов и т. д.) не фиксированный, а динамический, поэтому мне нужна вертикальная прокрутка, потому что многие объекты могут иметь одни и те же координаты. Это может быть список вместо холста (и фрейм внутри холста), но я хочу использовать внутри него этот макет из 4 столбцов, а также значки в метках, поэтому я выбрал холст, как описано здесь. Обратите внимание на [code]self.frame.grid(row=0, column=0, sticky='nswe') [/code] в строках 85 и 282. Если я прокомментирую одну или обе строки, я получу странное поведение, которое показано на рисунке, несмотря на то, что в строках 187 и 378 при первом посещении кадр имеет сетку. Я проверяю, привязан ли кадр к сетке, используя .winfo_ismapped() . И, если кадр не активен, я поднимаю его. Если я вставлю это в конец VehicleViewer.update(): [code]self.frame.update_idletasks() print('self.frame_inside_canvas.winfo_children') for widget in self.frame_inside_canvas.winfo_children(): print(widget, widget.winfo_ismapped()) [/code] Я вижу это, когда использую метод Grid() для кадра в начале: [code].!frame2.!frame2.!frame.!canvas.!frame.!label 1 .!frame2.!frame2.!frame.!canvas.!frame.!label2 1 .!frame2.!frame2.!frame.!canvas.!frame.!label3 1 .!frame2.!frame2.!frame.!canvas.!frame.!label4 1 .!frame2.!frame2.!frame.!canvas.!frame.!label5 1 .!frame2.!frame2.!frame.!canvas.!frame.!label6 1 .!frame2.!frame2.!frame.!canvas.!frame.!label7 1 .!frame2.!frame2.!frame.!canvas.!frame.!label8 1 [/code] но это когда я использую метод Grid() позже (то есть, когда я комментирую строку 282) и посещаю фрейм: [code].!frame2.!frame2.!frame.!canvas.!frame.!label 1 .!frame2.!frame2.!frame.!canvas.!frame.!label2 0 .!frame2.!frame2.!frame.!canvas.!frame.!label3 1 .!frame2.!frame2.!frame.!canvas.!frame.!label4 0 .!frame2.!frame2.!frame.!canvas.!frame.!label5 1 .!frame2.!frame2.!frame.!canvas.!frame.!label6 0 .!frame2.!frame2.!frame.!canvas.!frame.!label7 1 .!frame2.!frame2.!frame.!canvas.!frame.!label8 0 [/code] Нели означают, что не все метки здесь расположены правильно: [code] label_id = ttk.Label(self.frame_inside_canvas, text=str(obj[1]), borderwidth=1, relief="ridge", anchor=tk.CENTER, background=background) label_info = ttk.Label(self.frame_inside_canvas, text=text, borderwidth=1, relief="ridge", anchor=tk.W, background=background)
if column == 1: id1 = label_id.grid(row=current_row, column=2, sticky='NSWE') id2 = label_info.grid(row=current_row, column=3, sticky='NSWE') else: id1 = label_id.grid(row=current_row, column=0, sticky='NSWE') id2 = label_info.grid(row=current_row, column=1, sticky='NSWE') [/code] и я не знаю, почему. Все метки и кнопки отображаются правильно, если рамки позже будут объединены в сетку, но не содержимое области прокрутки. Я использую Python 3.13.7 в Windows 11.>