我創建了這個測驗代碼來模擬一個帶有可調整大小的左面板的 Tk 視窗。這個怎么運作:
- 當滑鼠指標移到 ttk.Separator 上時,滑鼠指標所在的位置會出現一個可調整大小的箭頭指示器。
- 按下滑鼠左鍵并移動滑鼠指標,左面板的寬度將根據滑鼠指標的 x 位置調整大小。
- 可調整大小的箭頭指示器也應與滑鼠指標同步移動。
我能夠執行第 1 步和第 2 步。但是,對于第 3 步,我遇到了問題。步驟 1 中的可調整大小的箭頭指示器沒有消失,而步驟 3 中的可調整大小的箭頭指示器位置偶爾會跟隨滑鼠指標:這兩個步驟之間似乎存在競爭。
我該如何解決這個問題?
測驗代碼:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.ttk as ttk
class App(ttk.Frame):
def __init__(self, master):
self.master = master
self.master.title('App')
self.master.geometry('1500x140')
self.mouse_pointer_x = tk.IntVar()
self.mouse_pointer_y = tk.IntVar()
super().__init__(master, style='App.TFrame', borderwidth=20)
self._set_style()
self._create_widgets()
self.bind('<Motion>', self._store_mouse_pointer_coordinate)
def _set_style(self):
self.style = ttk.Style()
self.style.configure('App.TFrame', background='pink')
self.style.configure('lframe.TFrame', background='green')
self.style.configure('rframe.TFrame', background='orange')
self.style.configure('TSeparator', background='red')
def _create_widgets(self):
self.lframe = ttk.Frame(self, style='lframe.TFrame', borderwidth=20)
self.rframe = ttk.Frame(self, style='rframe.TFrame', borderwidth=20)
self.divider = ttk.Separator(self, orient=tk.VERTICAL)
self.lframe.grid(row=0, column=0, sticky='nsew')
self.divider.grid(row=0, column=1, sticky='nsew', padx=20)
self.rframe.grid(row=0, column=2, sticky='nsew')
harrow = './resize-arrow-24.png'
self.icon_harrow = tk.PhotoImage(file=harrow)
self.harrow = ttk.Label(self, image=self.icon_harrow)
self.harrow.place(x=0, y=0)
self.harrow.place_forget()
self.ltv = self._create_treeview(self.lframe)
self.rtv = self._create_treeview(self.rframe)
self.ltv.grid(row=0, column=0, sticky='nsew')
self.rtv.grid(row=0, column=0, sticky='nsew')
self.divider.bind('<Enter>', self._show_divider)
self.divider.bind('<Leave>', self._hide_divider)
self.divider.bind("<B1-Motion>", self._button1_press_move)
def _create_treeview(self, parent):
# Create Treeview
SearchCols = ('#01', '#02', '#03', '#04', '#05', '#06')
tv = ttk.Treeview(parent, columns=SearchCols, height=2,
displaycolumn=['#05', '#06', '#01',
'#02', '#03', '#04'],
style='search.Treeview',
selectmode='extended', takefocus=True)
# Setup column & it's headings
tv.column('#0', stretch=0, minwidth=100, width=100, anchor='w')
tv.column('#01', stretch=0, anchor='n', width=70)
tv.column('#02', stretch=0, anchor='n', width=80)
tv.column('#03', stretch=0, anchor='n', width=75)
tv.column('#04', stretch=0, anchor='w')
tv.column('#05', stretch=0, anchor='e', width=80)
tv.column('#06', stretch=0, anchor='n', width=70)
tv.heading('#0', text=' Directory ', anchor='w')
tv.heading('#01', text='#01', anchor='center')
tv.heading('#02', text='#02', anchor='center')
tv.heading('#03', text='#03', anchor='center')
tv.heading('#04', text='#04', anchor='w')
tv.heading('#05', text='#05', anchor='center')
tv.heading('#06', text='#06', anchor='center')
# #0, #01, #02 denotes the 0, 1st, 2nd columns
return tv
# Event Handlers
def _store_mouse_pointer_coordinate(self, event):
self.mouse_pointer_x.set(event.x)
self.mouse_pointer_y.set(event.y)
print(self.mouse_pointer_x.get(), self.mouse_pointer_y.get())
def _show_divider(self, event):
x = self.mouse_pointer_x.get()
y = self.mouse_pointer_y.get()
self.harrow.place_configure(x=x-31, y=y-36)
self.harrow.lower(belowThis=self.divider)
def _hide_divider(self, event):
self.harrow.place_forget()
def _button1_press_move(self, event):
# Configure self.lframe
new_width = self.lframe.winfo_pointerx() - self.lframe['borderwidth']*2
self.lframe['width'] = new_width
print(f'self.lframe["width"]={self.lframe["width"]}')
self.lframe.grid_propagate(0)
# Configure self.harrow
new_height = event.y
self.harrow.place_forget()
self.harrow.place_configure(x=new_width 9, y=new_height-4)
self.harrow.lower(belowThis=self.divider)
self.update_idletasks()
if __name__ == '__main__':
root = tk.Tk()
root.resizable(width=False, height=False)
root.title('App')
root.geometry('1300x400 0 24')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
app = App(root)
app.grid(row=0, column=0, sticky='nsew')
root.mainloop()
調整箭頭 24.png:
uj5u.com熱心網友回復:
為了解決我的可調整大小的箭頭指示器問題,我必須引入事件處理程式來取消系結和重新系結事件<Enter>,<Leave>以及在ttk.Separator小部件上按下和釋放 B1 時。請參閱下面的修訂測驗代碼。請參閱修訂的測驗代碼。
這個腳本的一個增強是當滑鼠指標進入ttk.Separator我的問題的評論部分中@Atlas435 提到的小部件時,將滑鼠指標外觀轉換為可調整大小的箭頭指示器。這可以通過使用ttk.Separator小部件的游標選項來完成。這種方法也無需實作上述解決方案,并使代碼更加簡潔。請參閱改進的修訂測驗代碼
事后看來,我發布了我寫了一個 python 類來創建一個替代的垂直方向的ttk.PanedWindow小部件使用ttk.Frame和ttk.Separator小部件。@BryanOakley 和 @HenryYik 感謝您向我指出這個事實。
修改后的測驗代碼:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.ttk as ttk
class App(ttk.Frame):
def __init__(self, master):
self.master = master
self.mouse_pointer_x = tk.IntVar()
self.mouse_pointer_y = tk.IntVar()
super().__init__(master, style='App.TFrame', borderwidth=20)
self._set_style()
self._create_widgets()
self.bind('<Motion>', self._store_mouse_pointer_coordinate)
def _set_style(self):
self.style = ttk.Style()
self.style.configure('App.TFrame', background='pink')
self.style.configure('lframe.TFrame', background='green')
self.style.configure('rframe.TFrame', background='orange')
self.style.configure('TSeparator', background='red')
def _create_widgets(self):
self.lframe = ttk.Frame(self, style='lframe.TFrame', borderwidth=20)
self.rframe = ttk.Frame(self, style='rframe.TFrame', borderwidth=20)
self.divider = ttk.Separator(self, orient=tk.VERTICAL)
self.lframe.grid(row=0, column=0, sticky='nsew')
self.divider.grid(row=0, column=1, sticky='nsew', padx=20)
self.rframe.grid(row=0, column=2, sticky='nsew')
harrow = './resize-arrow-24.png'
self.icon_harrow = tk.PhotoImage(file=harrow)
self.harrow = ttk.Label(self, image=self.icon_harrow)
self.harrow.place(x=0, y=0)
self.harrow.place_forget()
self.ltv = self._create_treeview(self.lframe)
self.rtv = self._create_treeview(self.rframe)
self.ltv.grid(row=0, column=0, sticky='nsew')
self.rtv.grid(row=0, column=0, sticky='nsew')
self.divider_bind_enter = self.divider.bind('<Enter>',
self._show_divider)
self.divider_bind_leave = self.divider.bind('<Leave>',
self._hide_divider)
self.divider.bind("<ButtonPress-1>", self._divider_B1_press)
self.divider.bind("<ButtonRelease-1>", self._divider_B1_release)
self.divider.bind("<B1-Motion>", self._divider_B1_press_move)
def _create_treeview(self, parent):
# Create Treeview
SearchCols = ('#01', '#02', '#03', '#04', '#05', '#06')
tv = ttk.Treeview(parent, columns=SearchCols, height=2,
displaycolumn=['#05', '#06', '#01',
'#02', '#03', '#04'],
style='search.Treeview',
selectmode='extended', takefocus=True)
# Setup column & it's headings
tv.column('#0', stretch=0, minwidth=100, width=100, anchor='w')
tv.column('#01', stretch=0, anchor='n', width=70)
tv.column('#02', stretch=0, anchor='n', width=80)
tv.column('#03', stretch=0, anchor='n', width=75)
tv.column('#04', stretch=0, anchor='w')
tv.column('#05', stretch=0, anchor='e', width=80)
tv.column('#06', stretch=0, anchor='n', width=70)
tv.heading('#0', text=' Directory ', anchor='w')
tv.heading('#01', text='#01', anchor='center')
tv.heading('#02', text='#02', anchor='center')
tv.heading('#03', text='#03', anchor='center')
tv.heading('#04', text='#04', anchor='w')
tv.heading('#05', text='#05', anchor='center')
tv.heading('#06', text='#06', anchor='center')
# #0, #01, #02 denotes the 0, 1st, 2nd columns
return tv
# Event Handlers
def _store_mouse_pointer_coordinate(self, event):
self.mouse_pointer_x.set(event.x)
self.mouse_pointer_y.set(event.y)
print(self.mouse_pointer_x.get(), self.mouse_pointer_y.get())
def _show_divider(self, event):
x = self.mouse_pointer_x.get()
y = self.mouse_pointer_y.get()
self.harrow.place_configure(x=x-31, y=y-33)
self.harrow.lower(belowThis=self.divider)
def _hide_divider(self, event):
self.harrow.place_forget()
def _divider_B1_press(self, event):
print('unbind self.divider <Enter> & <Leave> events')
self.divider.unbind('<Enter>', self.divider_bind_enter)
self.divider.unbind('<Leave>', self.divider_bind_leave)
def _divider_B1_release(self, event):
print('bind self.divider <Enter> & <Leave> events')
self.divider_bind_enter = self.divider.bind('<Enter>',
self._show_divider)
self.divider_bind_leave = self.divider.bind('<Leave>',
self._hide_divider)
def _divider_B1_press_move(self, event):
# Configure self.lframe
new_width = self.lframe.winfo_pointerx() - self.lframe['borderwidth']*2
self.lframe['width'] = new_width
print(f'self.lframe["width"]={self.lframe["width"]}')
self.lframe.grid_propagate(0)
# Configure self.harrow
new_height = event.y
self.harrow.place_forget()
self.harrow.place_configure(x=new_width 9, y=new_height-6)
self.harrow.lower(belowThis=self.divider)
self.update_idletasks()
if __name__ == '__main__':
root = tk.Tk()
#root.resizable(width=False, height=False)
root.title('App')
root.geometry('1500x140 0 24')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
app = App(root)
app.grid(row=0, column=0, sticky='nsew')
root.mainloop()
改進的修訂測驗代碼(一個 VerticalPanedWindow 小部件):
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.ttk as ttk
class VerticalPanedWindow(ttk.Frame):
'''A ttk styled Vertical PanedWindow.'''
def __init__(self, master, bg='pink', borderwidth=0,
divider_fg='red', divider_padx=1,
lframe_bg='green', lframe_borderwidth=0,
rframe_bg='orange', rframe_borderwidth=0, ):
self.master = master
self.bg = bg
self.borderwidth = borderwidth
self.divider_fg = divider_fg
self.divider_padx = divider_padx
self.lframe_bg = lframe_bg
self.lframe_borderwidth = lframe_borderwidth
self.rframe_bg = rframe_bg
self.rframe_borderwidth = rframe_borderwidth
self.mouse_pointer_x = tk.IntVar()
self.mouse_pointer_y = tk.IntVar()
super().__init__(master, style='App.TFrame', borderwidth=borderwidth)
self._set_style()
self._create_widgets()
self.bind('<Motion>', self._store_mouse_pointer_coordinate)
def _set_style(self):
self.style = ttk.Style()
self.style.configure('App.TFrame', background=self.bg)
self.style.configure('lframe.TFrame', background=self.lframe_bg)
self.style.configure('rframe.TFrame', background=self.rframe_bg)
self.style.configure('TSeparator', background=self.divider_fg)
def _create_widgets(self):
self.lframe = ttk.Frame(self, style='lframe.TFrame',
borderwidth=self.lframe_borderwidth)
self.rframe = ttk.Frame(self, style='rframe.TFrame',
borderwidth=self.rframe_borderwidth)
self.divider = ttk.Separator(self, orient=tk.VERTICAL,
cursor='sb_h_double_arrow')
self.lframe.grid(row=0, column=0, sticky='nsew')
self.rframe.grid(row=0, column=2, sticky='nsew')
self.divider.grid(row=0, column=1, sticky='nsew',
padx=self.divider_padx)
self.divider.bind("<B1-Motion>", self._divider_B1_press_move)
# Event Handlers
def _store_mouse_pointer_coordinate(self, event):
self.mouse_pointer_x.set(event.x)
self.mouse_pointer_y.set(event.y)
print(self.mouse_pointer_x.get(), self.mouse_pointer_y.get())
def _divider_B1_press_move(self, event):
# Configure self.lframe
eventx = event.x
mpx = self.mouse_pointer_x.get()
new_x = mpx eventx
self.mouse_pointer_x.set(new_x)
self.lframe['width'] = new_x
self.lframe.grid_propagate(0)
print(f' {eventx} {mpx} {new_x} {self.lframe["width"]}')
def _create_treeview(parent):
# Create Treeview
SearchCols = ('#01', '#02', '#03', '#04', '#05', '#06')
tv = ttk.Treeview(parent, columns=SearchCols, height=2,
displaycolumn=['#05', '#06', '#01',
'#02', '#03', '#04'],
style='search.Treeview',
selectmode='extended', takefocus=True)
# Setup column & it's headings
tv.column('#0', stretch=0, minwidth=100, width=100, anchor='w')
tv.column('#01', stretch=0, anchor='n', width=70)
tv.column('#02', stretch=0, anchor='n', width=80)
tv.column('#03', stretch=0, anchor='n', width=75)
tv.column('#04', stretch=0, anchor='w')
tv.column('#05', stretch=0, anchor='e', width=80)
tv.column('#06', stretch=0, anchor='n', width=70)
tv.heading('#0', text=' Directory ', anchor='w')
tv.heading('#01', text='#01', anchor='center')
tv.heading('#02', text='#02', anchor='center')
tv.heading('#03', text='#03', anchor='center')
tv.heading('#04', text='#04', anchor='w')
tv.heading('#05', text='#05', anchor='center')
tv.heading('#06', text='#06', anchor='center')
# #0, #01, #02 denotes the 0, 1st, 2nd columns
return tv
if __name__ == '__main__':
root = tk.Tk()
# root.resizable(width=False, height=False)
root.title('VerticalPanedWindow')
root.geometry('1500x140')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
# Use customs colors and borderwidth values
# color = '#240240237'
# app = VerticalPanedWindow(
# root, bg=color, borderwidth=20,
# divider_fg=color, divider_padx=20,
# lframe_bg=color, lframe_borderwidth=20,
# rframe_bg=color, rframe_borderwidth=20, )
# Use customs borderwidth values
app = VerticalPanedWindow(root, borderwidth=20, divider_padx=20,
lframe_borderwidth=20, rframe_borderwidth=20)
# Use default options value
# app = VerticalPanedWindow(root)
app.grid(row=0, column=0, sticky='nsew')
ltv = _create_treeview(app.lframe)
rtv = _create_treeview(app.rframe)
ltv.grid(row=0, column=0, sticky='nsew')
rtv.grid(row=0, column=0, sticky='nsew')
root.mainloop()
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/352498.html
