tkinter PanedWindow.sash_place在bind_class中为什么不起作用?

huangapple go评论229阅读模式
英文:

Why does tkinter PanedWindow.sash_place not work in bind_class?

问题

I wanted to customize the way the sash on a tkinter PanedWindow looked based on if the user is clicking on it, so I cam up with this.

import tkinter as tk
from tkinter import ttk

class PanedTest(tk.Tk):
    def __init__(self, master=None):
        super().__init__(master)
        
        self.style = ttk.Style()
        
        self.style.configure('TPanedwindow', background='black')
        self.style.configure('Clicked.TPanedwindow', background='blue')
        self.style.configure('Sash', sashthickness=8)
        
        self.bind_class('TPanedwindow', '<Button-1>', lambda e: e.widget.configure(style='Clicked.TPanedwindow'))
        self.bind_class('TPanedwindow', '<B1-Motion>', lambda e: e.widget.sash_place(0, e.x, e.y))
        self.bind_class('TPanedwindow', '<ButtonRelease-1>', lambda e: e.widget.configure(style='TPanedwindow'))
        
        self.paned1 = ttk.PanedWindow()
        self.paned1.pack()
        
        self.frame1 = ttk.Frame(self.paned1, width=200, height=200)
        self.paned1.add(self.frame1)
        
        self.frame2 = ttk.Frame(self.paned1, width=200, height=200)
        self.paned1.add(self.frame2)
        
        
        self.paned2 = ttk.PanedWindow(orient='horizontal')
        self.paned2.pack()
        
        self.frame3 = ttk.Frame(self.paned2, width=200, height=200)
        self.paned2.add(self.frame3)
        
        self.frame4 = ttk.Frame(self.paned2, width=200, height=200)
        self.paned2.add(self.frame4)
    
if __name__ == "__main__":
    app = PanedTest()
    app.mainloop()

Unfortunately, this results in an error:

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

So after a lot of testing, I managed to get it to work with this:

import tkinter as tk
from tkinter import ttk

class PanedTest(tk.Tk):
    def __init__(self, master=None):
        super().__init__(master)
        
        self.style = ttk.Style()
        
        self.style.configure('TPanedwindow', background='black')
        self.style.configure('Clicked.TPanedwindow', background='blue')
        self.style.configure('Sash', sashthickness=8)
        
        self.bind_class('TPanedwindow', '<Button-1>', lambda e: e.widget.configure(style='Clicked.TPanedwindow'))
        self.bind_class('TPanedwindow', '<B1-Motion>', lambda e: e.widget.sash(0, (e.x if str(e.widget.cget('orient')) == 'horizontal' else e.y)))
        self.bind_class('TPanedwindow', '<ButtonRelease-1>', lambda e: e.widget.configure(style='TPanedwindow'))
        
        self.paned1 = ttk.PanedWindow()
        self.paned1.pack()
        
        self.frame1 = ttk.Frame(self.paned1, width=200, height=200)
        self.paned1.add(self.frame1)
        
        self.frame2 = ttk.Frame(self.paned1, width=200, height=200)
        self.paned1.add(self.frame2)
        
        
        self.paned2 = ttk.PanedWindow(orient='horizontal')
        self.paned2.pack()
        
        self.frame3 = ttk.Frame(self.paned2, width=200, height=200)
        self.paned2.add(self.frame3)
        
        self.frame4 = ttk.Frame(self.paned2, width=200, height=200)
        self.paned2.add(self.frame4)
    
if __name__ == "__main__":
    app = PanedTest()
    app.mainloop()

I can now drag the paned windows, but it does also give this error:

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

Here's the difference between the two scripts:

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

vs

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

Why does only the second one work, and not the function that is specifically for what I am trying to do?

Oh, and converting e.widget.cget('orient') to str is just because the result is a <class '_tkinter.Tcl_Obj'>.

英文:

I wanted to customize the way the sash on a tkinter PanedWindow looked based on if the user is clicking on it, so I cam up with this.

import tkinter as tk
from tkinter import ttk

class PanedTest(tk.Tk):
    def __init__(self, master = None) -&gt; None:
        super().__init__(master)
        
        self.style = ttk.Style()
        
        self.style.configure(&#39;TPanedwindow&#39;, background=&#39;black&#39;)
        self.style.configure(&#39;Clicked.TPanedwindow&#39;, background=&#39;blue&#39;)
        self.style.configure(&#39;Sash&#39;, sashthickness = 8)
        
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;Button-1&gt;&#39;, lambda e : e.widget.configure(style = &#39;Clicked.TPanedwindow&#39;))
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash_place(0, e.x, e.y))
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;ButtonRelease-1&gt;&#39;, lambda e : e.widget.configure(style = &#39;TPanedwindow&#39;))
        
        self.paned1 = ttk.PanedWindow()
        self.paned1.pack()
        
        self.frame1 = ttk.Frame(self.paned1, width = 200, height = 200)
        self.paned1.add(self.frame1)
        
        self.frame2 = ttk.Frame(self.paned1, width = 200, height = 200)
        self.paned1.add(self.frame2)
        
        
        self.paned2 = ttk.PanedWindow(orient = &#39;horizontal&#39;)
        self.paned2.pack()
        
        self.frame3 = ttk.Frame(self.paned2, width = 200, height = 200)
        self.paned2.add(self.frame3)
        
        self.frame4 = ttk.Frame(self.paned2, width = 200, height = 200)
        self.paned2.add(self.frame4)
    
if __name__ == &quot;__main__&quot;:
    app = PanedTest()
    app.mainloop()

Unfortunately, this results in an error

Exception in Tkinter callback
Traceback (most recent call last):
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 1921, in __call__
    return self.func(*args)
  File &quot;paned_test.py&quot;, line 15, in &lt;lambda&gt;
    self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash_place(0, e.x, e.y))        
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 4490, in sash_place
    return self.sash(&quot;place&quot;, index, x, y)
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 4464, in sash
    self.tk.call((self._w, &#39;sash&#39;) + args)) or ()
_tkinter.TclError: wrong # args: should be &quot;.!panedwindow2 sashpos index ?newpos?&quot;

So after a lot of testing, I managed to get it to work with this

import tkinter as tk
from tkinter import ttk

class PanedTest(tk.Tk):
    def __init__(self, master = None) -&gt; None:
        super().__init__(master)
        
        self.style = ttk.Style()
        
        self.style.configure(&#39;TPanedwindow&#39;, background=&#39;black&#39;)
        self.style.configure(&#39;Clicked.TPanedwindow&#39;, background=&#39;blue&#39;)
        self.style.configure(&#39;Sash&#39;, sashthickness = 8)
        
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;Button-1&gt;&#39;, lambda e : e.widget.configure(style = &#39;Clicked.TPanedwindow&#39;))
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash(0, (e.x if str(e.widget.cget(&#39;orient&#39;)) == &#39;horizontal&#39; else e.y)))
        self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;ButtonRelease-1&gt;&#39;, lambda e : e.widget.configure(style = &#39;TPanedwindow&#39;))
        
        self.paned1 = ttk.PanedWindow()
        self.paned1.pack()
        
        self.frame1 = ttk.Frame(self.paned1, width = 200, height = 200)
        self.paned1.add(self.frame1)
        
        self.frame2 = ttk.Frame(self.paned1, width = 200, height = 200)
        self.paned1.add(self.frame2)
        
        
        self.paned2 = ttk.PanedWindow(orient = &#39;horizontal&#39;)
        self.paned2.pack()
        
        self.frame3 = ttk.Frame(self.paned2, width = 200, height = 200)
        self.paned2.add(self.frame3)
        
        self.frame4 = ttk.Frame(self.paned2, width = 200, height = 200)
        self.paned2.add(self.frame4)
    
if __name__ == &quot;__main__&quot;:
    app = PanedTest()
    app.mainloop()

I can now drag the paned windows, but it does also give this error

Exception in Tkinter callback
Traceback (most recent call last):
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 1921, in __call__
    return self.func(*args)
  File &quot;paned_test.py&quot;, line 48, in &lt;lambda&gt;
    self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash(0, (e.x if str(e.widget.cget(&#39;orient&#39;)) == &#39;horizontal&#39; else e.y)))
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 4463, in sash
    return self._getints(
  File &quot;C:\Program Files\Python310\lib\tkinter\__init__.py&quot;, line 1467, in _getints
    return tuple(map(self.tk.getint, self.tk.splitlist(string)))
TypeError: splitlist() argument must be str, bytes or bytearray, not int

Here's the difference between the two scripts

self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash_place(0, e.x, e.y))

vs

self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;, lambda e : e.widget.sash(0, (e.x if str(e.widget.cget(&#39;orient&#39;)) == &#39;horizontal&#39; else e.y)))

Why does only the second one work, and not the function that is specifically for what I am trying to do?

oh, and converting e.widget.cget(&#39;orient&#39;) to str is just because the result is a &lt;class &#39;_tkinter.Tcl_Obj&#39;&gt;.

答案1

得分: 1

这可能是tkinter上的一个错误。对于你的第一个使用e.widget.sash_place(0, e.x, e.y)的代码,它实际上只是内部调用了self.sash('place', index, x, y),因为.sash()只接受两个参数,即indexpos(即你在第二个代码块中使用.sash()的方式)。

然而,在.sash()内部,它对self.tk.call(...)的结果调用了self._getints(),而这个结果是一个整数,但self._getints()期望一个字符串。这就是第二个错误的含义。

要避免第二个错误,你可以直接使用e.widget.tk.call()而不是.sash()

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

This may be a bug on tkinter. For your first code that uses e.widget.sash_place(0, e.x, e.y), it just internally calls self.sash(&#39;place&#39;, index, x, y) which raises the invalid number of arguments error because .sash() expects two arguments, index and pos, only (i.e. how you use .sash() in your second code block.

However inside .sash() it calls self._getints() on the result of self.tk.call(...) which is an integer, but self._getints() expects a string. That is what the second error means.

To avoid the second error, you can use e.widget.tk.call() directly instead of .sash():

self.bind_class(&#39;TPanedwindow&#39;, &#39;&lt;B1-Motion&gt;&#39;,
                lambda e: e.widget.tk.call(e.widget, &quot;sash&quot;, 0, (e.x if str(e.widget[&quot;orient&quot;]) == &quot;horizontal&quot; else e.y)))

huangapple
  • 本文由 发表于 2023年6月13日 09:41:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定