Я новичок в Python и tkinter, я хочу создать панель мониторинга с помощью tkinter. Я написал приведенный ниже код, чтобы добавить графики в tkinter, используя Matplotlib. Так как у меня 4 графика и я не могу уместить все, поэтому добавил горизонтальную полосу прокрутки, но почему-то она не работает. Пожалуйста, найдите приведенный ниже код.
import tkinter as tk
from tkinter import ttk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
def calculate_gap(sum_of_demand, allocated, capacity):
if sum_of_demand - allocated < 0:
sum_of_not_demanded = abs(sum_of_demand - allocated)
elif capacity - sum_of_demand > 0:
sum_of_not_demanded = capacity - sum_of_demand
else:
sum_of_not_demanded = 0
if capacity - allocated > 0:
spare_capacity = capacity - allocated
else:
spare_capacity = 0
if sum_of_demand - capacity > 0:
skill_gap = sum_of_demand - capacity
else:
skill_gap = 0
return sum_of_not_demanded, spare_capacity, skill_gap
def h_scroll(*args):
print("In scroll")
graph1_canvas.get_tk_widget().xview(*args)
graph2_canvas.get_tk_widget().xview(*args)
graph3_canvas.get_tk_widget().xview(*args)
graph4_canvas.get_tk_widget().xview(*args)
def test_gap():
sum_of_demand = 256
allocated = 73
capacity = 66
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
below = np.array([sum_of_demand, allocated, capacity])
above = np.array([sum_of_not_demanded, spare_capacity, skill_gap])
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph4_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph4_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph4_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph4_canvas.get_tk_widget().config(scrollregion=graph4_canvas.get_tk_widget().bbox("all"))
graph4_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set,
scrollregion=graph4_canvas.get_tk_widget().bbox("all"))
# test_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
# test_canvas.get_tk_widget().bind("<<Key>>", pop_up)
def graph_three():
sum_of_demand = 256
allocated = 73
capacity = 66
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
if sum_of_demand - capacity > 0:
skill_gap = sum_of_demand - capacity
else:
skill_gap = 0
width = 0.1
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph3_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph3_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph3_canvas.get_tk_widget().config(scrollregion=graph3_canvas.get_tk_widget().bbox("all"))
graph3_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set,
scrollregion=graph3_canvas.get_tk_widget().bbox("all"))
# mobile_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
def graph_two():
sum_of_demand = 830
allocated = 313
capacity = 339
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph2_ax.bar(title, width, label=boolean, bottom=bottom)
bottom += weight_count
graph2_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph2_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph2_canvas.get_tk_widget().config(scrollregion=graph2_canvas.get_tk_widget().bbox("all"))
graph2_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set,
scrollregion=graph2_canvas.get_tk_widget().bbox("all"))
# be_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
def graph_one():
sum_of_demand = 1631
allocated = 778
capacity = 795
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph1_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph1_canvas.draw()
graph1_canvas.get_tk_widget().config(scrollregion=graph1_canvas.get_tk_widget().bbox("all"))
graph1_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set,
scrollregion=graph1_canvas.get_tk_widget().bbox("all"))
# horizontal_scrollbar.config(command=h_scroll())
root = tk.Tk()
# Main Frame
frame = ttk.Frame(root)
frame.pack()
# Data Frame
graph_frame = ttk.Labelframe(frame, text = "Skill Gap")
graph_frame.grid(side = tk.RIGHT, expand = True, fill = tk.BOTH)
horizontal_scrollbar = ttk.Scrollbar(graph_frame, orient=tk.HORIZONTAL, command=h_scroll)
horizontal_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
# Canvas
graph1_fig, graph1_ax = plt.subplots(dpi=100)
graph1_canvas = FigureCanvasTkAgg(graph1_fig, graph_frame)
horizontal_scrollbar.config(command=graph1_canvas.get_tk_widget().xview)
graph1_canvas.get_tk_widget().config(yscrollcommand=horizontal_scrollbar.set)
# Canvas
graph2_fig, graph2_ax = plt.subplots(dpi=100)
graph2_canvas = FigureCanvasTkAgg(graph2_fig, graph_frame)
# Canvas
graph3_fig, graph_ax = plt.subplots(dpi=100)
graph3_canvas = FigureCanvasTkAgg(graph3_fig, graph_frame)
# Canvas
graph4_fig, graph4_ax = plt.subplots(dpi=100)
graph4_canvas = FigureCanvasTkAgg(graph4_fig, graph_frame)
graph_one()
graph_two()
graph_three()
test_gap()
horizontal_scrollbar.config(command=h_scroll)
tk.mainloop()
Я ожидаю, что горизонтальная полоса прокрутки будет работать. И возможность прокручивать все графики.
можно ли обойтись без Canvas?
ты не можешь. В tkitner Scrollbar
работает только с Canvas
, Listbox
, Text
, но не с Farme
. Итак, вам нужно поместить рамку на холст и прокрутить холст. У меня уже есть рабочий пример с (коротким) кодом из предыдущего вопроса.
Tkitner
можно прокручивать только Canvas
, Listbox
и Text
, но не Frame
Если вы хотите прокручивать все элементы, вам нужно объединить их в один tkinter.Frame
и поставить этот фрейм tkinter.Canvas
и использовать tkinter.Scrollbar
для прокрутки этого кадра на холсте.
Я взял один из своих кодов из ответа на ваш предыдущий вопрос.
Python — невозможно отображать более 4-5 гистограмм с помощью matplotlib — 1 ответ
и я добавил прокручиваемые кавны
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
# --- functions ---
def resize(event):
dashboard_canvas.configure(scrollregion=dashboard_canvas.bbox('all'))
# --- main ---
x = [1, 2, 3, 4]
y = [1, 2, 3, 4]
AS = [10 / 2 ** 0]
# ---
root = tk.Tk()
root.geometry("1000x1000")
root.title("eggs")
# ---
# canvas
dashboard_canvas = tk.Canvas(root)#, bg='#00c000') # background color only to test its size
dashboard_inner_frame = tk.Frame(dashboard_canvas)
inner_frame_id = dashboard_canvas.create_window((0,0), window=dashboard_inner_frame, anchor='nw')
dashboard_canvas.pack(fill='both', expand=True)
# scrollbar
dasboard_scrollbar_x = tk.Scrollbar(root, orient='horizontal')
dasboard_scrollbar_x.pack(fill='x')
# join widgets
dashboard_canvas.configure(xscrollcommand=dasboard_scrollbar_x.set)
dasboard_scrollbar_x['command'] = dashboard_canvas.xview
# resize scrollregion on canvas when plots will have size (and it will be after starting program and drawing plots)
dashboard_inner_frame.bind('<Configure>', resize)
#---
# put on dashboard_inner_frame
frame_top = tk.Frame(dashboard_inner_frame, width=2000)
frame_top.pack(fill='both', expand=True)
plots = []
for index in range(10):
fig = Figure(dpi=100)
ax = fig.add_subplot(111)
ax.plot(x, y)
fig.suptitle(f"Plot {index+1}")
canvas = FigureCanvasTkAgg(fig, master=frame_top)
canvas.draw()
canvas.get_tk_widget().pack(side = "left", fill='both', expand=True)
#canvas.get_tk_widget()['width'] = 1
plots.append({'fig': fig, 'canvas': canvas})
root.mainloop()
Версия с кодом из текущего вопроса
import tkinter as tk
from tkinter import ttk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
# --- functions ---
def resize(event):
dashboard_canvas.configure(scrollregion=dashboard_canvas.bbox('all'))
def calculate_gap(sum_of_demand, allocated, capacity):
if sum_of_demand - allocated < 0:
sum_of_not_demanded = abs(sum_of_demand - allocated)
elif capacity - sum_of_demand > 0:
sum_of_not_demanded = capacity - sum_of_demand
else:
sum_of_not_demanded = 0
if capacity - allocated > 0:
spare_capacity = capacity - allocated
else:
spare_capacity = 0
if sum_of_demand - capacity > 0:
skill_gap = sum_of_demand - capacity
else:
skill_gap = 0
return sum_of_not_demanded, spare_capacity, skill_gap
def h_scroll(*args):
print("In scroll")
graph1_canvas.get_tk_widget().xview(*args)
graph2_canvas.get_tk_widget().xview(*args)
graph3_canvas.get_tk_widget().xview(*args)
graph4_canvas.get_tk_widget().xview(*args)
def test_gap():
sum_of_demand = 256
allocated = 73
capacity = 66
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
below = np.array([sum_of_demand, allocated, capacity])
above = np.array([sum_of_not_demanded, spare_capacity, skill_gap])
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph4_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph4_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph4_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph4_canvas.get_tk_widget().config(scrollregion=graph4_canvas.get_tk_widget().bbox("all"))
# test_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
# test_canvas.get_tk_widget().bind("<<Key>>", pop_up)
def graph_three():
sum_of_demand = 256
allocated = 73
capacity = 66
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
if sum_of_demand - capacity > 0:
skill_gap = sum_of_demand - capacity
else:
skill_gap = 0
width = 0.1
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph3_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph3_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph3_canvas.get_tk_widget().config(scrollregion=graph3_canvas.get_tk_widget().bbox("all"))
# mobile_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
def graph_two():
sum_of_demand = 830
allocated = 313
capacity = 339
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph2_ax.bar(title, width, label=boolean, bottom=bottom)
bottom += weight_count
graph2_canvas.draw()
# canvas1.get_tk_widget().pack(side = "left",fill = "both",expand=True)
graph2_canvas.get_tk_widget().pack(fill = "both", expand=True, side = "left")
graph2_canvas.get_tk_widget().config(scrollregion=graph2_canvas.get_tk_widget().bbox("all"))
# be_canvas.get_tk_widget().config(xscrollcommand=horizontal_scrollbar.set)
def graph_one():
sum_of_demand = 1631
allocated = 778
capacity = 795
sum_of_not_demanded, spare_capacity, skill_gap = calculate_gap(sum_of_demand, allocated, capacity)
width = 0.35
weight_counts = {
"Below": np.array([sum_of_demand, allocated, capacity]),
"Above": np.array([sum_of_not_demanded, spare_capacity, skill_gap])
}
title = ['Demand', 'Allocated', 'Capacity']
bottom = np.zeros(3)
for boolean, weight_count in weight_counts.items():
p = graph1_ax.bar(title, weight_count, width, label=boolean, bottom=bottom)
bottom += weight_count
graph1_canvas.draw()
graph1_canvas.get_tk_widget().config(scrollregion=graph1_canvas.get_tk_widget().bbox("all"))
# horizontal_scrollbar.config(command=h_scroll())
root = tk.Tk()
# Main Frame
frame = ttk.Frame(root)
frame.pack(expand=True, fill='both')
# Data Frame
graph_frame = ttk.Labelframe(frame, text = "Skill Gap")
graph_frame.pack(expand=True, fill='both')
# ---
# canvas
dashboard_canvas = tk.Canvas(graph_frame)#, bg='#00c000') # background color only to test its size
dashboard_inner_frame = tk.Frame(dashboard_canvas)
inner_frame_id = dashboard_canvas.create_window((0,0), window=dashboard_inner_frame, anchor='nw')
dashboard_canvas.pack(fill='both', expand=True)
# scrollbar
dasboard_scrollbar_x = tk.Scrollbar(graph_frame, orient='horizontal')
dasboard_scrollbar_x.pack(fill='x')
# join widgets
dashboard_canvas.configure(xscrollcommand=dasboard_scrollbar_x.set)
dasboard_scrollbar_x['command'] = dashboard_canvas.xview
# resize scrollregion on canvas when plots will have size (and it will be after starting program and drawing plots)
dashboard_inner_frame.bind('<Configure>', resize)
#-----
# Canvas
graph1_fig, graph1_ax = plt.subplots(dpi=100)
graph1_canvas = FigureCanvasTkAgg(graph1_fig, dashboard_inner_frame)
# Canvas
graph2_fig, graph2_ax = plt.subplots(dpi=100)
graph2_canvas = FigureCanvasTkAgg(graph2_fig, dashboard_inner_frame)
# Canvas
graph3_fig, graph_ax = plt.subplots(dpi=100)
graph3_canvas = FigureCanvasTkAgg(graph3_fig, dashboard_inner_frame)
# Canvas
graph4_fig, graph4_ax = plt.subplots(dpi=100)
graph4_canvas = FigureCanvasTkAgg(graph4_fig, dashboard_inner_frame)
graph_one()
graph_two()
graph_three()
test_gap()
tk.mainloop()
Я убираю вашу полосу прокрутки и помещаю все файлы PictureCanvasTkAgg в один и тот же deskboard_inner_frame
, а deskboard_canvas
и deskboard_scrollbar
в ваш label_frame
.
Чтобы сделать его более контролируемым, вы можете сохранить как desckboard_cavnas
, так иdeskboard_scrollbarin one frame (e.g.
deskboardor
deskboard_outer_frame) and then you have to put only one element in
label_frame`
Код длинный, и его сложно объяснить, поэтому, возможно, используйте такой инструмент, как Meld, чтобы увидеть различия между вашей и моей версией.
Я попробовал это, добавив два кадра (Frame1 и Frame2), но поле холста стало очень маленьким. Pack(side=tk.TOP,expand=True)frame2.pack(side=tk.BOTTOM,expand=True) # холст Dashboard_canvas = tk.Canvas(frame1)#, bg='#00c000') # цвет фона только для проверьте его размер Dashboard_inner_frame = tk.Frame(dashboard_canvas) Internal_frame_id = Dashboard_canvas.create_window((0,0), window=dashboard_inner_frame,nchor='nw') Dashboard_canvas.pack(fill='both',expand=True) Не могли бы вы, пожалуйста? Помоги мне
В моем случае мне нужно держать холст внутри фрейма (а не в корне)
сначала поместите все в один кадр, а затем поместите этот кадр на холст. Лучше поставьте код под вопрос — он будет более читабельным. И у вас будет больше места для описания проблемы и отображения сообщений об ошибках.
Спасибо Фурас за поддержку. Я сохранил код в новом протекторе. Пожалуйста, посмотрите. Я тоже пытался сохранить фрейм верхнего уровня, но он тоже не работает должным образом. stackoverflow.com/questions/78658845/…
тем временем я сделал пример с вашим кодом и поместил его в текущий ответ.
Спасибо Фурас, все получилось. Спасибо за поддержку.
если вы хотите переместить все элементы, вам следует поместить их все в один
tkinter.Frame
, поместить этот фрейм вtkinter.Canvas
и прокрутить этот фрейм внутри Canvas - но вы пытаетесь прокручивать контент вFigureCanvasTkAgg
. Но у него может быть сложная система, позволяющая держать сюжет в центре. Может иметь собственную функцию для прокрутки данных на графике - Python - Прокрутка графиков - GeeksforGeeks