0

I have no problem with binding ctrl-h. However, when I do the ctrl-h, I notice that the last character is also removed from the entry. I think this might be the default ctrl-h binding of python. How can I disable that?

---Update---

I have added the return 'break' thing. But it still doesn't work. The last character is immediately removed before the askstring dialog shows up. Here is the code that is bound.

def replace(self):
    target = simpledialog.askstring(title = 'Replace', prompt = 'Replace Target')
    if not target:
        return 'break'
    withValue = simpledialog.askstring(title = 'Replace', prompt = 'Replace With')
    if not withValue:
        return 'break'
    for entry in self.entries.values():
        setEntry(entry, entry.get().replace(target, withValue))
    return 'break'

By the way I bind it with the master not the entry because I have a lot of entries. Binding with the master is way easier.

This is how I bind it.

self.master.bind('<Control-h>', lambda event: self.replace())

self.master is defined here:

class Generator(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
        ## init variables
        self.master = master

This is what I pass in.

root = Tk()
gui = Generator(root)
gui.pack()
root.title('Generator')
root.mainloop()
Seaky Lone
  • 992
  • 1
  • 10
  • 29
  • `return "break"` in your handler to cancel the default handling of the key. – jasonharper Jan 14 '19 at 16:35
  • Please provide a simple code example of your problem. Also [documented here](https://www.tcl.tk/man/tcl8.4/TkCmd/entry.htm) it says ***The BackSpace key and Control-h delete the selection, if there is one in the entry. If there is no selection, it deletes the character to the left of the insertion cursor.*** – Mike - SMT Jan 14 '19 at 16:35
  • Possible duplicate of [disable tkinter keyboard shortcut (2)](https://stackoverflow.com/questions/6813219/disable-tkinter-keyboard-shortcut-2) – Mike - SMT Jan 14 '19 at 16:45
  • Please show how you are binding `find` to control-h by providing a [mcve] – Bryan Oakley Jan 14 '19 at 17:04
  • @BryanOakley I have updated it. Sorry for the confusion, it is replace not find function. – Seaky Lone Jan 14 '19 at 17:08

1 Answers1

2

Because you are binding to the root window rather than an individual widget, there's nothing you can do in your function. Bindings are processed in this order:

  1. bindings on a specific widget
  2. bindings on a widget class
  3. bindings on the toplevel window in which the widget exists
  4. bindings on the special tag "all"

If at any time in the processing of those bindings a function returns the string "break", no further processing will happen. Thus, if you have a binding on a specific widget and return "break", the default class binding won't be processed. However, if you return "break" from a binding to the root window, that binding isn't processed until after the class binding. Therefore, it's impossible for this sort of binding to prevent the default behavior.

However, tkinter bindings are remarkably customizable, so there are solutions. Given that you potentially want to inhibit the default behavior, the most straight-forward solution is to either bind to the class so that you completely replace the default behavior, or bind to each widget individually so that you can prevent the class binding from happening.

If you really want the binding to be universal by binding to the root window, then the easiest solution might be to change the order of processing for all widgets that have default bindings for control-h.

For example, to move the handling of root-level bindings before class-level bindings, you can do something like this:

entry = tk.Entry(root)
bindtags = entry.bindtags()
entry.bindtags((bindtags[2], bindtags[0], bindtags[1], bindtags[3]))

For more information on exactly how bindings are processed, you might want to look at the following questions:

Here is a simple example that binds to the root window, but changes the bind tags so that the default binding can be defeated by returning "break":

import tkinter as tk

def custom_backspace(event):
    entry.insert("insert", "<backspace>")
    return "break"

root = tk.Tk()
entry = tk.Entry(root)
entry.pack(fill="x")
bindtags = entry.bindtags()
entry.bindtags((bindtags[2], bindtags[0], bindtags[1], bindtags[3]))

root.bind("<Control-h>", custom_backspace)

root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685