Welcome, guest | Sign In | My Account | Store | Cart

A way to disallow user input in a more user (and programmer) friendly way than setting the widget's state to "disabled".

Tcl, 33 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Disable all key sequences for widget named in variable hWnd, except
# the cursor navigation keys (regardless of the state ctrl/shift/etc.)
# and Ctrl-C (Copy to Clipboard).

bind $hWnd <KeyPress> {
    switch -- %K {
        "Up" -
        "Left" -
        "Right" -
        "Down" -
        "Next" -
        "Prior" -
        "Home" -
        "End" {
        }

        "c" -
        "C" {
            if {(%s & 0x04) == 0} {
                break
            }
        }

        default {
            break
        }
    }
}

# Addendum: also a good idea disable the cut and paste events.

bind $hWnd <<Paste>> "break"
bind $hWnd <<Cut>> "break"

The most common way I see that people disallow user input to text and entry windows (such as, for example, a text widget used as a read-only log) is to configure the widget with state "disabled". The problems: you can't select text to copy the clipboard with the keyboard, and you have to temporarily set the widget state to "normal" before your script inserts text.

By binding the KeyPress event, and using "break" for all key presses that you want to discard (which prevents further bind code from being executed), you can avoid both these problems. The user can still use the navigation keys to move around (and select) the text, and you don't need to switch the widget state around all the time. If the "c" key is pressed, it's passed through only if the control key is down (%s state bit 4 is set). If you're using a different keymapping for the copy text function than Ctrl-C, you'll need to modify that part appropriately.

Addendum:

I agree that using bindtags would be better, the focus here was more on the bindings themselves than on most effective use of bindtags. Also, amended to disable cut/paste events which may come from somewhere other than the keyboard and would bypass the read-only state of the entry/text.

3 comments

Gerald Lester 19 years, 7 months ago  # | flag

Creating new ReadOnlyText and ReadOnlyEntry bindtags would be better. Taking the bindings for Text and Entry and creating two new bindtags ReadOnlyText and ReadOnlyEntry would be more in the spirit of Tcl/Tk. Of course these new bindings should go either in tklib or the core, but that is another story.

Len Morgan 18 years, 10 months ago  # | flag

How do I get them back? If I wanted to make fields Read-Only using this method but not always, how would I get them back the way they were? For example, let's say user1 reads a record in a database that is currently being "used" by user2 and therefore should not be allowed to make any changes. At some time in the future, this record COULD be edited by user1 (i.e., it's not a user rights issue), just not while someone else is working with it. Or they could just want to move on to another record that they CAN play with. Is there a simple way to revert the bindings to what they were? Thanks?

Len Morgan 18 years, 10 months ago  # | flag

How do I get them back? If I wanted to make fields Read-Only using this method but not always, how would I get them back the way they were? For example, let's say user1 reads a record in a database that is currently being "used" by user2 and therefore should not be allowed to make any changes. At some time in the future, this record COULD be edited by user1 (i.e., it's not a user rights issue), just not while someone else is working with it. Or they could just want to move on to another record that they CAN play with. Is there a simple way to revert the bindings to what they were? Thanks?

Created by Michael Kirkham on Tue, 9 Apr 2002 (MIT)
Tcl recipes (162)
Michael Kirkham's recipes (3)

Required Modules

  • (none specified)

Other Information and Tasks