[英]Autohide Tkinter canvas scrollbar with pack geometry
當不需要時,我需要有關自動隱藏 tkinter 滾動條的幫助。 我從 effbot.org 找到了這段代碼,它自動隱藏滾動條,但僅限於網格幾何。 在我的情況下,我沒有使用網格幾何。 這是我的代碼。
import Tkinter as tk
from Tkinter import *
import tkFont
class AutoScrollbar(Scrollbar):
# a scrollbar that hides itself if it's not needed. only
# works if you use the grid geometry manager.
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
# grid_remove is currently missing from Tkinter!
self.tk.call("grid", "remove", self)
else:
self.grid()
Scrollbar.set(self, lo, hi)
def pack(self, **kw):
raise TclError, "cannot use pack with this widget"
def place(self, **kw):
raise TclError, "cannot use place with this widget"
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
w = 1200
h = 650
x = self.winfo_screenwidth()/2 - w/2
y = self.winfo_screenheight()/2 - h/2
self.geometry("%ix%i+%i+%i" % (w, h, x, y))
self.mainTopFrame = Frame(self, height=75)
self.mainTopFrame.pack(side=TOP, fill=X)
self.canvas = Canvas(self, borderwidth=0, bg='#ffffff')
self.mainBottomFrame = Frame(self.canvas, bg='#000000')
self.yscroll = Scrollbar(self.canvas, orient=VERTICAL, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.yscroll.set)
self.canvas.pack(side=TOP, fill=BOTH, expand=1)
self.yscroll.pack(side=RIGHT, fill=Y)
self.canvas.create_window((4,4), window=self.mainBottomFrame, anchor=NW)
self.mainBottomFrame.bind("<Configure>", self.onFrameConfigure)
self.menuFrame = Frame(self.mainTopFrame, bg='#545454')
self.menuFrame.pack(side=TOP, fill=BOTH, expand=True)
self.container = Frame(self.mainBottomFrame)
self.container.pack(side=TOP, fill=BOTH, expand=True)
self.frames = {}
for F in (MonitorPage, PlanPage, DataLogPage, HelpPage):
self.frame = F(self.container, self)
self.frames[F] = self.frame
self.frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MonitorPage)
def show_frame(self, cont):
self.frame = self.frames[cont]
self.frame.tkraise()
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
class AutoScrollbar(Scrollbar):
# a scrollbar that hides itself if it's not needed. only
# works if you use the grid geometry manager.
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
# grid_remove is currently missing from Tkinter!
self.tk.call("grid", "remove", self)
else:
self.grid()
Scrollbar.set(self, lo, hi)
def pack(self, **kw):
raise TclError, "cannot use pack with this widget"
def place(self, **kw):
raise TclError, "cannot use place with this widget"
class MonitorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.labelFont = tkFont.Font(family="Fixedsys", size=15, weight=tkFont.BOLD)
self.leftFrame0 = Frame(self, bg='#888888')
self.leftFrame0.pack(side=LEFT, fill=BOTH)
self.rightFrame0 = Frame(self, bg='#888888')
self.rightFrame0.pack(side=RIGHT, fill=BOTH)
self.upLftFrame0 = Frame(self.leftFrame0)
self.upLftFrame0.pack(side=TOP, fill=BOTH, padx=10, pady=10)
self.dnLftFrame0 = Frame(self.leftFrame0)
self.dnLftFrame0.pack(side=BOTTOM, fill=BOTH, padx=10, pady=10)
self.upLftLblFrame0 = tk.LabelFrame(self.upLftFrame0)
self.upLftLblFrame0.pack(side=TOP, fill=BOTH, padx=5, pady=5)
self.dnLftLblFrame0 = tk.LabelFrame(self.dnLftFrame0)
self.dnLftLblFrame0.pack(side=BOTTOM, fill=BOTH, padx=5, pady=5)
self.rtLblFrame0 = tk.LabelFrame(self.rightFrame0)
self.rtLblFrame0.pack(side=TOP, fill=BOTH, padx=10, pady=10)
self.label0 = Label(self.rtLblFrame0, height=40, width=70)
self.label0.pack()
self.label1 = Label(self.upLftLblFrame0, height=25, width=115)
self.label1.pack()
self.label2 = Label(self.dnLftLblFrame0, height=10, width=115)
self.label2.pack()
class PlanPage(tk.Frame, MainWindow):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
class DataLogPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
class HelpPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
if __name__ == '__main__':
rungui = MainWindow()
rungui.mainloop()
因此,即使在使用包幾何圖形時,我也想自動隱藏滾動條。我希望我的問題很清楚。 我對 python 和 tkinter 很陌生。
我改編了 effbot.org 的例子來打包方法:
from Tkinter import *
class AutoScrollbar(Scrollbar):
# a scrollbar that hides itself if it's not needed. only
# works if you use the grid geometry manager.
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
# grid_remove is currently missing from Tkinter!
self.pack_forget()
else:
if self.cget("orient") == HORIZONTAL:
self.pack(fill=X)
else:
self.pack(fill=Y)
Scrollbar.set(self, lo, hi)
def grid(self, **kw):
raise TclError, "cannot use grid with this widget"
def place(self, **kw):
raise TclError, "cannot use place with this widget"
# create scrolled canvas
root = Tk()
hscrollbar = AutoScrollbar(root, orient=HORIZONTAL)
canvas = Canvas(root,
xscrollcommand=hscrollbar.set)
canvas.pack(side=TOP, fill=BOTH, expand=True)
hscrollbar.pack()
hscrollbar.config(command=canvas.xview)
# make the canvas expandable
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
# create canvas contents
frame = Frame(canvas)
frame.rowconfigure(1, weight=1)
frame.columnconfigure(1, weight=1)
rows = 5
for i in range(1,rows):
for j in range(1,10):
button = Button(frame, padx=7, pady=7, text="[%d,%d]" % (i,j))
button.grid(row=i, column=j, sticky='news')
canvas.create_window(0, 0, anchor=NW, window=frame)
frame.update_idletasks()
canvas.config(scrollregion=canvas.bbox("all"))
root.mainloop()
我從 j_4321 改編了這個:
from functools import partial
import tkinter as tk
class AutoScrollbar(tk.Scrollbar):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.geometry_manager_add = lambda: None
self.geometry_manager_forget = lambda: None
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
self.geometry_manager_forget()
else:
self.geometry_manager_add()
super().set(lo, hi)
def grid(self, **kwargs):
self.geometry_manager_add = partial(super().grid, **kwargs)
self.geometry_manager_forget = super().grid_forget
def pack(self, **kwargs):
self.geometry_manager_add = partial(super().pack, **kwargs)
self.geometry_manager_forget = super().pack_forget
def place(self, **kwargs):
self.geometry_manager_add = partial(super().place, **kwargs)
self.geometry_manager_forget = super().place_forget
現在它適用於所有幾何管理器。 它會記住傳入的kwargs
,並在顯示滾動條時始終通過它們。
TheLizzard 的回答很好,但是當用戶調整大小到滾動條開始在可見和不可見之間擺動的區域時,它會受到鎖定。 這可以通過引入一個簡單的時間延遲來解決(我還添加了一點,以便用戶可以檢查滾動條的可見性,因為我沒有從 Scrollbar.info_ismapped() 獲得好的結果):
class AutoScrollbar(Scrollbar):
"""A subclass of `tkinter.Scrollbar` that automatically hides and shows itself as needed. If you need to
find out if an instance of this class is currently visible, check it's :py:attr:`visible` attribute.
"""
def __init__(self, master, **kwargs):
""
super().__init__(master, **kwargs)
self.geometry_manager_add = lambda: None # replaced by grid(), pack() or place()
self.geometry_manager_forget = lambda: None
self.visible:bool = False # needed because super().winfo_ismapped() doesn't work as expected...
"True iff the scrollbar is visible. Users should treat this as a read-only variable; it is only set by this class."
self._delayTime = time.time()
@override
def set(self, lo, hi):
if self._delay(): # do these checks only after a threshold time limit to prevent runaway oscilations in scrollbar visibility.
if float(lo) <= 0.0 and float(hi) >= 1.0:
if self.visible: # avoid calling the geometry manager too often
self.geometry_manager_forget()
self.visible = False
else:
if not self.visible: # avoid calling the geometry manager too often
self.geometry_manager_add()
self.visible = True
super().set(lo, hi)
def _delay(self) -> bool:
"""This method prevents locking up due to bouncing between showing and hiding the scroll
bars. It should be called as part of the conditional to change the state of the scroll bars.
It works by introducing a one second delay between state changes giving the user time to drag
by the 'purgatory' in-between state, and at least preventing runaway oscilations from
locking up the GUI"""
now = time.time()
if now - self._delayTime > 1.0:
self._delayTime = now
return True
else:
return False
@override
def grid(self, **kwargs):
self.geometry_manager_add = partial(super().grid, **kwargs)
self.geometry_manager_forget = super().grid_forget
@override
def pack(self, **kwargs):
self.geometry_manager_add = partial(super().pack, **kwargs)
self.geometry_manager_forget = super().pack_forget
@override
def place(self, **kwargs):
self.geometry_manager_add = partial(super().place, **kwargs)
self.geometry_manager_forget = super().place_forget
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.