From: Óscar Fuentes on
Robert Heller <heller(a)deepsoft.com> writes:

>> >> Is there a simple mechanism for disabling all keyboard input for a
>> >> given toplevel and enabling it later?
>> >
>> > man grab
>> > man focus
>> >
>> > Trick: create a canvas, but never map it. Set grab and focus there
>> > during times that things are 'busy'. Keyboard / mouse events are
>> > flushed away.
>>
>> It seems that it is not possible to set the focus on an unmapped widget.
>>
>
> Huh? Sure it is -- I do this all of the time. By 'unmapped' what I
> mean is creating a widget (such as a canvas, which normally will accept
> both keyboard and mouse events) on the same toplevel as you are
> displaying and then never packing, placing, or gridding it. I would
> normally do this on the toplevel widget, which is generally always
> displayed.

I did

if { ! [winfo exists .toplevel.sucker] } {
canvas .toplevel.sucker
}
focus .toplevel.sucker
grab .toplevel.sucker
<do-something>
puts [focus]
grab release .toplevel.sucker

This prints nothing and the keypresses made while <do-something> are
cached and processed normally after the grab is released.

From your description, it seems like 3 or 4 lines of code would do the
trick. Care to share them?

Thanks.
From: Robert Heller on
At Wed, 10 Feb 2010 22:04:02 +0100 =?utf-8?Q?=C3=93scar_Fuentes?= <ofv(a)wanadoo.es> wrote:

>
> Robert Heller <heller(a)deepsoft.com> writes:
>
> >> >> Is there a simple mechanism for disabling all keyboard input for a
> >> >> given toplevel and enabling it later?
> >> >
> >> > man grab
> >> > man focus
> >> >
> >> > Trick: create a canvas, but never map it. Set grab and focus there
> >> > during times that things are 'busy'. Keyboard / mouse events are
> >> > flushed away.
> >>
> >> It seems that it is not possible to set the focus on an unmapped widget.
> >>
> >
> > Huh? Sure it is -- I do this all of the time. By 'unmapped' what I
> > mean is creating a widget (such as a canvas, which normally will accept
> > both keyboard and mouse events) on the same toplevel as you are
> > displaying and then never packing, placing, or gridding it. I would
> > normally do this on the toplevel widget, which is generally always
> > displayed.
>
> I did
>
> if { ! [winfo exists .toplevel.sucker] } {
> canvas .toplevel.sucker
> }
> focus .toplevel.sucker
> grab .toplevel.sucker
> <do-something>
> puts [focus]
> grab release .toplevel.sucker
>
> This prints nothing and the keypresses made while <do-something> are
> cached and processed normally after the grab is released.
>
> From your description, it seems like 3 or 4 lines of code would do the
> trick. Care to share them?

What you have should work. *Depending* on what <do-something> is.
Generally in my code, <do-something> is usually a tkwait of some sort
(depends on what is going on). For example:

if {[catch {open "|foo -bar whatever" r} pipefp]} {
tk_messageBox -type ok -icon error -message "$pipefp"
return
}

# processpipe reads the pipe and does something (maybe updates a log
# and/or progress bar). Incr's pipeeof on eof.
# (Mostly my code would do this inside of a snit type / widget /
# widgetadpator and use object variables and methods, rather than
# globals.)
set ::pipeeof 0
fileevent $pipefp readable [list processpipe $pipefp]
set oldfocus [focus]
focus .toplevel.sucker
grab .toplevel.sucker
tkwait variable ::pipeeof
if {"$oldfocus" ne ""} {focus $oldfocus}
grab release .toplevel.sucker

My guess is that your <do-something> is NOT causing the event-loop to be
reentered. If the event-loop is not re-entered, then the events will be
neither discarded nor processed. They will just accumulate until the
event-loop is reentered, probably after the grab has been released.


>
> Thanks.
>

--
Robert Heller -- 978-544-6933
Deepwoods Software -- Download the Model Railroad System
http://www.deepsoft.com/ -- Binaries for Linux and MS-Windows
heller(a)deepsoft.com -- http://www.deepsoft.com/ModelRailroadSystem/

From: Óscar Fuentes on
Robert Heller <heller(a)deepsoft.com> writes:

>> >> >> Is there a simple mechanism for disabling all keyboard input for a
>> >> >> given toplevel and enabling it later?
>>
>> I did
>>
>> if { ! [winfo exists .toplevel.sucker] } {
>> canvas .toplevel.sucker
>> }
>> focus .toplevel.sucker
>> grab .toplevel.sucker
>> <do-something>
>> puts [focus]
>> grab release .toplevel.sucker
>>
>> This prints nothing and the keypresses made while <do-something> are
>> cached and processed normally after the grab is released.
>
> What you have should work. *Depending* on what <do-something> is.
> Generally in my code, <do-something> is usually a tkwait of some sort
> (depends on what is going on). For example:

[snip]

> My guess is that your <do-something> is NOT causing the event-loop to be
> reentered. If the event-loop is not re-entered, then the events will be
> neither discarded nor processed. They will just accumulate until the
> event-loop is reentered, probably after the grab has been released.

Good point but, if that were all of the history, doing

update
grab release .toplevel.sucker

would take care of the pending keypresses. Putting the grab as early as
possible and releasing it as late as possible makes things better, but
the problem still happens if you press keys fast enough (I measured the
time elapsed for a fast two-key sequence: it is easy to get less than 20
milliseconds). The sequence, as shown on the console with the help of
some `puts', is:

grab
start processing first key event
process second key event
finish processing first key event
ungrab

Now, I don't know enough about tk's event loop, but AFAIK this shouldn't
happen. Even if some library call on the middle executes an `update',
this shouldn't be a problem since there is a grab. I confirmed that, at
the ungrab point, the current grab is the right one.
From: jdc on
When using 8.6, you might want to check [tk busy].
From: Uwe Klein on
jdc wrote:
> When using 8.6, you might want to check [tk busy].

which previously had a single home in the blt package.

uwe