Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Tk bind key scrolled Text

by Takamoto (Beadle)
on Sep 15, 2019 at 20:45 UTC ( #11106210=perlquestion: print w/replies, xml ) Need Help??

Takamoto has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks

I use the following (simplified) code to be able to decide the order of widget switching when using the TAB key. This works fine except when the cursor enters a text widget. Here the tab has its own behavior (inserting a tab in a text), which makes sense. However, in my application, I would like to overwrite this behavior and would like the tab to allow further switching. Any idea?

use strict; use warnings; use Tk; my $mw = MainWindow->new(); my $entry1 = $mw->Entry()->pack(); my $entry2 = $mw->Entry()->pack(); my $entry3 = $mw->Entry()->pack(); my $text = $mw->Scrolled('Text')->pack(); my %after = ( $entry1 => $entry3, $entry3 => $entry2, $entry2 => $text, $text => $entry1, ); $mw -> bind('all','<Tab>',sub{ ($after{$_[0]} // $_[0])->focus; } ); $mw->MainLoop(); exit(0);

Replies are listed 'Best First'.
Re: Tk bind key scrolled Text
by jcb (Chaplain) on Sep 15, 2019 at 23:41 UTC

    I have had similar problems, except that I usually wanted to allow tabs to be inserted into the Text widget.

    Interestingly, Shift-<Tab> still reverses the sequence according to Tk's builtin order, including to get out of a Text widget.

    The most elegant solution would be to adjust the stacking order so that Tk's builtin focus order matches what you want, see "focusNext" in Tk::focus and "raise" in Tk::Widget. This approach also preserves the "tab-in" behavior of focusing the first widget when the user presses <Tab> and no widget has the focus within the window.

    Finding a solution to this, producing <Tab> key behavior not unlike that in the browser I am using to compose this reply, required some time with the Tk manual and was quite enlightening along the way. I recommend installing Tk::Pod if you do not already have it — tkpod makes navigating the sprawling Tk manual easy. In the below code, I have also added a binding that exits the program upon typing Control-Q for convenience in testing and initialized the Text widget to contain a dump of its own bindings, which revealed a class binding for <Tab> that inserts a tab character. This is overridden on line 17 to instead do nothing, allowing the default global binding for focusNext to work. Removing the binding also works, but leaves the default InsertKeypress binding to run, which inserts a tab, then the global binding changes focus. Maddening at first...

    use strict; use warnings; use Tk; my $mw = MainWindow->new(); my $entry1 = $mw->Entry()->pack(); my $entry2 = $mw->Entry()->pack(); my $entry3 = $mw->Entry()->pack(); my $text = $mw->Scrolled('Text')->pack(); my @order = ($entry1 , $entry3, $entry2, $text); for (my $i = 1; $i < @order; $i++) { $order[$i]->raise($order[$i-1]) } $mw->bind('<Control-q>', sub {exit 0}); $text->Subwidget('xscrollbar')->configure(-takefocus => 0); $text->Subwidget('yscrollbar')->configure(-takefocus => 0); $text->Subwidget('scrolled')->bind('Tk::Text','<Tab>', 'NoOp'); $text->insert('1.0', join('',$text->Subwidget('scrolled')->bindDump)); $mw->MainLoop(); exit(0);

    Dumping the default bindings also reveals that <Control-Tab> executes focusNext even on a Tk::Text widget.

      Thank you very much for your example, which works very good! A limitation it seems to have is that - different to my approach - you can not 'leave out' some widget from this behavior. If you use the following in your code:

      my @order = ($entry1 , $entry3, $text);

      where $entry2 simply needs to be jumped, it does not work, i.e. it does not jump it. So, perfect solution if you want to use all widgets displayed, but not if you want just a set of widget to be affected.

        You can leave out $entry2 by using $entry2->configure(-takefocus => 0); to omit $entry2 from the tabbing order, like my example did for the scrollbars. An Entry widget with -takefocus => 0 will still get the focus if the user clicks on it, however.

Re: Tk bind key scrolled Text
by tybalt89 (Parson) on Sep 16, 2019 at 08:53 UTC
    #!/usr/bin/perl use strict; use warnings; use Tk; my $mw = MainWindow->new(); my $entry1 = $mw->Entry()->pack(); my $entry2 = $mw->Entry()->pack(); my $entry3 = $mw->Entry()->pack(); my $text = $mw->Scrolled('Text')->pack(); my %after = ( $entry1 => $entry3, $entry3 => $entry2, $entry2 => $text, $text->Subwidget('scrolled') => $entry1, ); $mw->bind('Tk::Text', '<Tab>', 'NoOp'); $mw -> bind('all','<Tab>', sub{ ($after{$_[0]} // $_[0])->focus; }); $mw->MainLoop; exit(0);
Re: Tk bind key scrolled Text
by Anonymous Monk on Sep 16, 2019 at 07:18 UTC
    Tk::Text provides bindings. UTSL to read how it works the override on your $instance as appropriate

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11106210]
Approved by johngg
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (9)
As of 2019-10-17 13:50 GMT
Find Nodes?
    Voting Booth?