如何在 tkinter 上制作响应式画布?
Posted
技术标签:
【中文标题】如何在 tkinter 上制作响应式画布?【英文标题】:How to make a responsive canva on tkinter? 【发布时间】:2020-07-13 12:54:21 【问题描述】:(第一次编辑是在更改标题之前进行的,请阅读到最后!)
在 Windows 10 上调整 Tkinter 的屏幕时遇到问题。
我正在做这样的事情:
width_screen = root.winfo_screenwidth()
height_screen = root.winfo_screenheight()
root.geometry(f'width_screenxheight_screen')
但问题是这个配置隐藏了我的任务栏...我搜索了一种方法来设置屏幕,就像我的浏览器一样,例如,最大化窗口和任务栏。
非常感谢您的帮助。
编辑 1:它不适用于此代码...
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -------------------------------- Importation ------------------------------- #
import os
import subprocess
import tkinter as tk
# ------------------------------ Initialisation ------------------------------ #
root = tk.Tk() #initialise l'application
root.title("Bruits ambiants pour l'écoute du patient")
width_screen = root.winfo_screenwidth()
height_screen = root.winfo_screenheight()
root.state('zoomed')
wav_files = ["a.wav","b.wav","c.wav","d.wav","e.wav","f.wav","g.wav","h.wav","i.wav","j.wav","k.wav","l.wav","m.wav","n.wav","o.wav","p.wav","q.wav","r.wav","s.wav","t.wav","u.wav","v.wav","w.wav","x.wav","y.wav","z.wav","aa.wav","bb.wav","cc.wav","dd.wav","ee.wav","ff.wav","gg.wav","hh.wav","ii.wav","jj.wav"]
# ---------------------------------------------------------------------------- #
# Vertical scrolled frame #
# ---------------------------------------------------------------------------- #
class VerticalScrolledFrame(tk.Frame):
def __init__(self, parent, *args, **kw):
tk.Frame.__init__(self, parent, *args, **kw)
# Create a frame for the canvas with non-zero row&column weights
self.frame_canvas = tk.Frame(self,bg="gray50")
self.frame_canvas.grid(row=2, column=0, sticky='nw')
self.frame_canvas.grid_rowconfigure(0, weight=1)
self.frame_canvas.grid_columnconfigure(0, weight=1)
self.parent=parent
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = tk.Scrollbar(self.frame_canvas, orient=tk.VERTICAL)
vscrollbar.grid(row=0, column=1, sticky='ns')
self.canvas = tk.Canvas(self.frame_canvas, bd=0, highlightthickness=0,
yscrollcommand=vscrollbar.set, width=self.parent.winfo_screenwidth(),
height=self.parent.winfo_screenheight()-100)
self.canvas.grid(row=0, column=0, sticky="news")
vscrollbar.config(command=self.canvas.yview)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = tk.Frame(self.canvas,bg="gray50")
interior_id = self.canvas.create_window(0, 0, window=interior,
anchor=tk.NW)
self.interior.update_idletasks()
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
self.canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != self.canvas.winfo_width():
# update the canvas's width to fit the inner frame
self.canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def _configure_canvas(event):
if interior.winfo_reqwidth() != self.canvas.winfo_width():
# update the inner frame's width to fill the canvas
self.canvas.itemconfigure(interior_id, width=self.canvas.winfo_width())
self.canvas.bind('<Configure>', _configure_canvas)
def _on_mousewheel(self, event):
if len(wav_files) > 25:
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
# ---------------------------------------------------------------------------- #
# Sound Buttons #
# ---------------------------------------------------------------------------- #
class Make_sound:
def __init__(self, name, parent, i):
self.varbutton = tk.StringVar()
self.name = name
self.parent = parent
self.num = i
self.soundbuttoncreator()
def soundbuttoncreator(self):
self.rows = self.num//4
self.columns = self.num%4
self.frame = tk.Frame(self.parent,bg="gray50", bd=3, relief="flat") # create a frame to hold the widgets
# use self.frame as parent instead of self.parent
self.button = tk.Checkbutton(self.frame, text=self.name.capitalize(), indicatoron=False, selectcolor="DeepSkyBlue3", background="slate gray", activebackground="LightSteelBlue3",variable=self.varbutton, command=self.launchsound, height=6, width=20)
self.button.pack()
self.button.bind("<Enter>", self.on_enter)
self.button.bind("<Leave>", self.on_leave)
self.frame.grid(row=self.rows, column=self.columns)
def on_enter(self, e):
self.button['background'] = 'LightSteelBlue3'
def on_leave(self, e):
self.button['background'] = 'slate gray'
def launchsound(self):
pass
def sounds_buttons(parent):
for i in range(len(wav_files)):
new_name = wav_files[i][:-4]
globals()["wav_files"][i] = Make_sound(new_name,parent,i)
def end_all():
for i in range(len(wav_files)):
globals()["wav_files"][i].varbutton.set("0")
try:
globals()["wav_files"][i].chan.stop()
except AttributeError:
pass
# ---------------------------------------------------------------------------- #
# Creation #
# ---------------------------------------------------------------------------- #
# ---------------------------------- Button ---------------------------------- #
frame_test = tk.Frame(root)
frame_test.grid(row=10,column=0, columnspan=5, sticky="s",padx=5,pady=10)
Button_open = tk.Button(frame_test, text="Open", background="slate gray", activebackground="LightSteelBlue3")
Button_open.pack(fill="x")
Button_end = tk.Button(frame_test, text="End", background="slate gray", activebackground="LightSteelBlue3")
Button_end.pack(fill="x")
# ---------------------------------------------------------------------------- #
# LEFT BUTTONS #
# ---------------------------------------------------------------------------- #
frame_buttons = tk.Frame(root,bd=5,bg="gray50")
frame_buttons.grid(row=1,column=0,rowspan=8,padx=5,pady=10,sticky="nw")
scframe = VerticalScrolledFrame(frame_buttons)
scframe.grid(row=1,column=0,rowspan=20,columnspan=3)
sounds_buttons(scframe.interior)
# ----------------------------------- test ----------------------------------- #
panel = tk.Button(root, text="test", background="slate gray", activebackground="LightSteelBlue3")
panel.grid(row=0,column=0,sticky="nw")
# ---------------------------------------------------------------------------- #
# ROOT #
# ---------------------------------------------------------------------------- #
root.mainloop()
(为了您的可读性,一些编辑被禁止)
最后编辑:
我发现问题来自我班的一部分:
self.canvas = tk.Canvas(self.frame_canvas, bd=0, highlightthickness=0,
yscrollcommand=vscrollbar.set, width=self.parent.winfo_screenwidth(),
height=self.parent.winfo_screenheight()-100)
事实上,height=self.parent.winfo_screenheight()-100
部分工作不正常。如果我输入height=self.parent.winfo_screenheight()-1000
,这是我的输出:
很有希望,因为我现在看到了框架。现在,我知道我只希望画布具有响应性,而不是设置高度和宽度,尽管我可以在许多计算机上使用它!
您能解释一下实现这一目标的方法吗?例如,总是有 4 列按钮,但它们的尺寸可以改变,并且将按钮列表设置为总是占据屏幕的其余部分(我们可以说它可能占据屏幕宽度的一半,并且上方和下方的按钮必须随着按钮列表的增长而增长?)。
【问题讨论】:
root.state('zoomed')
.
嗯...我编辑了我的帖子,因为它在我的配置中不起作用...
在我的电脑上运行良好。
哦...我编辑给你看我的输出。
在这种情况下点击两次“最大化”按钮会有什么不同吗?
【参考方案1】:
试试下面的代码:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -------------------------------- Importation ------------------------------- #
import os
import subprocess
import tkinter as tk
# ------------------------------ Initialisation ------------------------------ #
root = tk.Tk() # initialise l'application
root.title("Bruits ambiants pour l'écoute du patient")
width_screen = root.winfo_screenwidth()
height_screen = root.winfo_screenheight()
root.state('zoomed')
wav_files = ["a.wav", "b.wav", "c.wav", "d.wav", "e.wav", "f.wav", "g.wav", "h.wav", "i.wav", "j.wav", "k.wav", "l.wav",
"m.wav", "n.wav", "o.wav", "p.wav", "q.wav", "r.wav", "s.wav", "t.wav", "u.wav", "v.wav", "w.wav", "x.wav",
"y.wav", "z.wav", "aa.wav", "bb.wav", "cc.wav", "dd.wav", "ee.wav", "ff.wav", "gg.wav", "hh.wav", "ii.wav",
"jj.wav"]
# ---------------------------------------------------------------------------- #
# Vertical scrolled frame #
# ---------------------------------------------------------------------------- #
class VerticalScrolledFrame(tk.Frame):
def __init__(self, parent, *args, **kw):
tk.Frame.__init__(self, parent, *args, **kw)
# Create a frame for the canvas with non-zero row&column weights
self.parent = parent
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
vscrollbar.pack(fill="y", side="right",expand=True)
self.canvas = tk.Canvas(self, bd=0, highlightthickness=1,
yscrollcommand=vscrollbar.set)
self.canvas.pack(fill="both", expand=True)
vscrollbar.config(command=self.canvas.yview)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = tk.Frame(self.canvas, bg="gray50")
interior_id = self.canvas.create_window(0, 0, window=interior,
anchor=tk.NW)
self.interior.update_idletasks()
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
self.canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != self.canvas.winfo_width():
# update the canvas's width to fit the inner frame
self.canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def _configure_canvas(event):
if interior.winfo_reqwidth() != self.canvas.winfo_width():
# update the inner frame's width to fill the canvas
self.canvas.itemconfigure(interior_id, width=self.canvas.winfo_width())
self.canvas.bind('<Configure>', _configure_canvas)
def _on_mousewheel(self, event):
if len(wav_files) > 25:
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
# ---------------------------------------------------------------------------- #
# Sound Buttons #
# ---------------------------------------------------------------------------- #
class Make_sound:
def __init__(self, name, parent, i):
self.varbutton = tk.StringVar()
self.name = name
self.parent = parent
self.num = i
self.soundbuttoncreator()
def soundbuttoncreator(self):
self.rows = self.num // 4
self.columns = self.num % 4
self.frame = tk.Frame(self.parent, bg="gray50", bd=3, relief="flat") # create a frame to hold the widgets
# use self.frame as parent instead of self.parent
self.button = tk.Checkbutton(self.frame, text=self.name.capitalize(), indicatoron=False,
selectcolor="DeepSkyBlue3", background="slate gray",
activebackground="LightSteelBlue3", variable=self.varbutton,
command=self.launchsound, height=6, width=20)
self.button.pack()
self.button.bind("<Enter>", self.on_enter)
self.button.bind("<Leave>", self.on_leave)
self.frame.grid(row=self.rows, column=self.columns)
def on_enter(self, e):
self.button['background'] = 'LightSteelBlue3'
def on_leave(self, e):
self.button['background'] = 'slate gray'
def launchsound(self):
pass
def sounds_buttons(parent):
for i in range(len(wav_files)):
new_name = wav_files[i][:-4]
globals()["wav_files"][i] = Make_sound(new_name, parent, i)
def end_all():
for i in range(len(wav_files)):
globals()["wav_files"][i].varbutton.set("0")
try:
globals()["wav_files"][i].chan.stop()
except AttributeError:
pass
# ---------------------------------------------------------------------------- #
# Creation #
# ---------------------------------------------------------------------------- #
# ---------------------------------- Button ---------------------------------- #
frame_test = tk.Frame(root)
frame_test.grid(row=10, column=0, columnspan=5, sticky="ns")
Button_open = tk.Button(frame_test, text="Open", background="slate gray", activebackground="LightSteelBlue3")
Button_open.grid(row=0, column=0, sticky="ns")
Button_end = tk.Button(frame_test, text="End", background="slate gray", activebackground="LightSteelBlue3")
Button_end.grid(row=1, column=0, sticky="ns")
# ---------------------------------------------------------------------------- #
# LEFT BUTTONS #
# ---------------------------------------------------------------------------- #
frame_buttons = tk.Frame(root, bd=5, bg="gray50")
frame_buttons.grid(row=1, column=0, rowspan=8, padx=5, pady=10, sticky="nwes")
scframe = VerticalScrolledFrame(frame_buttons)
scframe.pack(fill="both", expand=True)
sounds_buttons(scframe.interior)
# ----------------------------------- test ----------------------------------- #
panel = tk.Button(root, text="test", background="slate gray", activebackground="LightSteelBlue3")
panel.grid(row=0, column=0, sticky="nw")
# ---------------------------------------------------------------------------- #
# ROOT #
# ---------------------------------------------------------------------------- #
for i in range(1, 11):
root.grid_rowconfigure(i, weight=1)
for i in range(frame_test.grid_size()[1]+1):
frame_test.grid_rowconfigure(i, weight=1)
root.mainloop()
代码太多,有点难以理解你的布局。
我从你的代码中改变了很多,你的frame_buttons
没有使用sticky="nwes"
。所以它无法填充框架。
而在画布中,你还需要使用pack
manager(如果你没有使用sticky="nwes"
并设置了rowconfigure
,我仍然建议你使用pack
)。
为了响应式,你需要设置gird_rowconfigure
查看代码了解更多详情。
输出:
如果画布上只有一个按钮,则滚动条被禁用:
【讨论】:
哇,谢谢!我们能想象按钮随着窗口的增长而增长吗?比如,如果我在frame_buttons.grid()
中有columnspan=3
,并且如果我删除了self.button 按钮的高度和宽度。当我像你一样在 range(0.5) 中循环一个 grid_columnconfigure 之后这样做时,我的按钮和灰色部分的宽度很小,并且滚动条不在右侧。谢谢你,伙计!
@TristanN 检查一下。
是的,我知道它可以在按钮列表(wav_files)之外的按钮上工作。但是由于我们在框架内有滚动按钮列表,我不知道如何为里面的按钮实现这一点(让它们在画布内增长)......另外,当我们没有足够的按钮需要滚动时,我们仍然可以滚动,这很奇怪,而且我找不到在不需要滚动条时停用(例如state='disabled'
)滚动条的方法...
那么有没有办法实现呢?
@TristanN 我真的无法重现,如果canvas
(wav_files) 中只有一个按钮?滚动条被禁用...以上是关于如何在 tkinter 上制作响应式画布?的主要内容,如果未能解决你的问题,请参考以下文章