python-3.x 为什么tkinter PanedWindow.sash_place在bind_class中不起作用?

c9qzyr3d  于 2023-06-25  发布在  Python
关注(0)|答案(1)|浏览(134)

我想根据用户是否点击它来定制tkinter PanedWindow上的窗扇的外观,所以我用这个来做。

  1. import tkinter as tk
  2. from tkinter import ttk
  3. class PanedTest(tk.Tk):
  4. def __init__(self, master = None) -> None:
  5. super().__init__(master)
  6. self.style = ttk.Style()
  7. self.style.configure('TPanedwindow', background='black')
  8. self.style.configure('Clicked.TPanedwindow', background='blue')
  9. self.style.configure('Sash', sashthickness = 8)
  10. self.bind_class('TPanedwindow', '<Button-1>', lambda e : e.widget.configure(style = 'Clicked.TPanedwindow'))
  11. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash_place(0, e.x, e.y))
  12. self.bind_class('TPanedwindow', '<ButtonRelease-1>', lambda e : e.widget.configure(style = 'TPanedwindow'))
  13. self.paned1 = ttk.PanedWindow()
  14. self.paned1.pack()
  15. self.frame1 = ttk.Frame(self.paned1, width = 200, height = 200)
  16. self.paned1.add(self.frame1)
  17. self.frame2 = ttk.Frame(self.paned1, width = 200, height = 200)
  18. self.paned1.add(self.frame2)
  19. self.paned2 = ttk.PanedWindow(orient = 'horizontal')
  20. self.paned2.pack()
  21. self.frame3 = ttk.Frame(self.paned2, width = 200, height = 200)
  22. self.paned2.add(self.frame3)
  23. self.frame4 = ttk.Frame(self.paned2, width = 200, height = 200)
  24. self.paned2.add(self.frame4)
  25. if __name__ == "__main__":
  26. app = PanedTest()
  27. app.mainloop()

不幸的是,这会导致错误

  1. Exception in Tkinter callback
  2. Traceback (most recent call last):
  3. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 1921, in __call__
  4. return self.func(*args)
  5. File "paned_test.py", line 15, in <lambda>
  6. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash_place(0, e.x, e.y))
  7. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 4490, in sash_place
  8. return self.sash("place", index, x, y)
  9. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 4464, in sash
  10. self.tk.call((self._w, 'sash') + args)) or ()
  11. _tkinter.TclError: wrong # args: should be ".!panedwindow2 sashpos index ?newpos?"

所以经过大量的测试,我设法让它和这个一起工作

  1. import tkinter as tk
  2. from tkinter import ttk
  3. class PanedTest(tk.Tk):
  4. def __init__(self, master = None) -> None:
  5. super().__init__(master)
  6. self.style = ttk.Style()
  7. self.style.configure('TPanedwindow', background='black')
  8. self.style.configure('Clicked.TPanedwindow', background='blue')
  9. self.style.configure('Sash', sashthickness = 8)
  10. self.bind_class('TPanedwindow', '<Button-1>', lambda e : e.widget.configure(style = 'Clicked.TPanedwindow'))
  11. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash(0, (e.x if str(e.widget.cget('orient')) == 'horizontal' else e.y)))
  12. self.bind_class('TPanedwindow', '<ButtonRelease-1>', lambda e : e.widget.configure(style = 'TPanedwindow'))
  13. self.paned1 = ttk.PanedWindow()
  14. self.paned1.pack()
  15. self.frame1 = ttk.Frame(self.paned1, width = 200, height = 200)
  16. self.paned1.add(self.frame1)
  17. self.frame2 = ttk.Frame(self.paned1, width = 200, height = 200)
  18. self.paned1.add(self.frame2)
  19. self.paned2 = ttk.PanedWindow(orient = 'horizontal')
  20. self.paned2.pack()
  21. self.frame3 = ttk.Frame(self.paned2, width = 200, height = 200)
  22. self.paned2.add(self.frame3)
  23. self.frame4 = ttk.Frame(self.paned2, width = 200, height = 200)
  24. self.paned2.add(self.frame4)
  25. if __name__ == "__main__":
  26. app = PanedTest()
  27. app.mainloop()

我现在可以拖动窗格窗口,但它也给予这个错误

  1. Exception in Tkinter callback
  2. Traceback (most recent call last):
  3. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 1921, in __call__
  4. return self.func(*args)
  5. File "paned_test.py", line 48, in <lambda>
  6. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash(0, (e.x if str(e.widget.cget('orient')) == 'horizontal' else e.y)))
  7. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 4463, in sash
  8. return self._getints(
  9. File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 1467, in _getints
  10. return tuple(map(self.tk.getint, self.tk.splitlist(string)))
  11. TypeError: splitlist() argument must be str, bytes or bytearray, not int

下面是两个脚本之间的区别

  1. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash_place(0, e.x, e.y))

vs

  1. self.bind_class('TPanedwindow', '<B1-Motion>', lambda e : e.widget.sash(0, (e.x if str(e.widget.cget('orient')) == 'horizontal' else e.y)))

为什么只有第二个函数起作用,而不是专门针对我要做的事情的函数?
哦,把e.widget.cget('orient')转换成str只是因为结果是<class '_tkinter.Tcl_Obj'>

xfyts7mz

xfyts7mz1#

这可能是tkinter上的一个bug。对于使用e.widget.sash_place(0, e.x, e.y)的第一个代码,它只是在内部调用self.sash('place', index, x, y),这会引发参数数量无效错误,因为.sash()只需要两个参数,indexpos(即indexpos)。如何在第二个代码块中使用.sash()
但是在.sash()内部,它在self.tk.call(...)的结果上调用self._getints()self.tk.call(...)是一个整数,但是self._getints()需要一个字符串。这就是第二个错误的含义。
为了避免第二个错误,可以直接使用e.widget.tk.call()而不是.sash()

  1. self.bind_class('TPanedwindow', '<B1-Motion>',
  2. lambda e: e.widget.tk.call(e.widget, "sash", 0, (e.x if str(e.widget["orient"]) == "horizontal" else e.y)))

相关问题