-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
gh-75666: Tkinter: "unbind(sequence, funcid)" now only unbinds "funcid" #111322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
f8ad1a9
ba53020
776293a
3e71c69
f8b58bc
be3ba6a
c5b05e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -1527,10 +1527,21 @@ def bind(self, sequence=None, func=None, add=None): | |||||
return self._bind(('bind', self._w), sequence, func, add) | ||||||
|
||||||
def unbind(self, sequence, funcid=None): | ||||||
"""Unbind for this widget for event SEQUENCE the | ||||||
function identified with FUNCID.""" | ||||||
self.tk.call('bind', self._w, sequence, '') | ||||||
if funcid: | ||||||
"""Unbind for this widget the event SEQUENCE. | ||||||
|
||||||
If FUNCID is given, only unbind the function identified with FUNCID | ||||||
and also delete that command. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make clearer that this will not delete the Python function passed to the binding call, but only the binding-specific (tcl) wrapper (as the bind docstring promises).
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is "the binding-specific tcl wrapper function"? This term is not mentioned in the documentation and will confuse users. It deletes the Tcl command and removes a reference to Python function. These details are not documented, but experienced users can discover this. I do not know what to write here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it does not work with keyboard events. I used different events for different tests to avoid possible order dependencies or chain reaction of failures after failing in one test. It was easy with keyboard events, it also minimizes risk of generating even by a user during running tests. But it may be not so easy to find a dozen different non-keyboard events (and we can add more tests in future). Is it necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I withdraw the suggestion above. Either insert 'tcl' before 'command' or wait until someone reports being confused. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||||||
""" | ||||||
if funcid is None: | ||||||
self.tk.call('bind', self._w, sequence, '') | ||||||
else: | ||||||
lines = self.tk.call('bind', self._w, sequence).split('\n') | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without seeing what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually it looks like:
if it only contains bindings added by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked -- IDLE uses this in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's useful to manually register a string (to reuse functions multiple times or to directly call a Tk method), but that would entirely reasonably preclude using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, you wrote that. This comment only serves to explain what I did not review in detail and why I requested the test change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TeamSpen210 If you manually register a string to directly call a Tk method, |
||||||
prefix = f'if {{"[{funcid} ' | ||||||
keep = '\n'.join(line for line in lines | ||||||
if not line.startswith(prefix)) | ||||||
if not keep.strip(): | ||||||
keep = '' | ||||||
self.tk.call('bind', self._w, sequence, keep) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea if it is legal to bind a multiple-script script, hence test should require that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is supported, but neither documented nor tested. I have not touched this, because it can mean doubling or tripling the number of tests. |
||||||
self.deletecommand(funcid) | ||||||
|
||||||
def bind_all(self, sequence=None, func=None, add=None): | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Change the behavior of :mod:`tkinter` widget's ``unbind()`` method with two | ||
serhiy-storchaka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
arguments. Previously, ``widget.unbind(sequence, funcid)`` destroyed the | ||
current binding for *sequence*, leaving *sequence* unbound, and deleted the | ||
*funcid* command. Now it removes only *funcid* from the binding for | ||
*sequence*, keeping other commands, and deletes the *funcid* command. It | ||
leaves *sequence* unbound only if *funcid* was the last bound command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To properly test the unbind code (see comment), I think this should bind 3 scripts and unbind the middle one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also like to test that the other two funcids still work in unbind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a separate test,
test_bind_events()
, that tests that registered functions are called when the event occurs. Although it does not cover unbinding.It is not so easy to make it working. For example, currently I cannot make it working in this test, an I do not know why. Maybe it does not work with keyboard events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I found how to do this. Will see whether it works on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expanded test, not visible above, is what I proposed. When I just ran test_misc, whether by itself or with test_tkinter, whether directly or with regrtest, test_bind_events hangs with two blank tk windows on the screen. Hence the CI test timed out. When I close the first of the two windows, tests 'continue' after this error:
This is due to the added "self.frame.wait_visibility()" in BindTest.setUp. With root deleted to let tests continue, the remaining BindTest functions fail with various messages.
DefaultRootTest.test_default_root
also fails, with"AttributeError: module 'tkinter' has no attribute '_default_root'.". A bad inter-testcase dependency? The following
DefaultRootTest.test_getboolean
and everything after passes.With the the test_bind_events wait_visibility commented out, there is this error.
With the setUp wait_visibility instead commented out, there is this error:
With the setUp call instead moved into test_unbind2 either at the top or as
f.wait_visibility()
before the generate events call, there is no error.