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

I'm writing a MIDI application in Tk, and I'd like to use a BrowseEntry widget to offer the user a selection of their existing ALSA MIDI ports, which are being scanned with MIDI::ALSA and put into an array long before the BrowseEntry widget ever gets configured or displayed. (In other words, by the time we get to BrowseEntry(), our array exists and is populated with port names.) I'm seeing some really strange behavior here.

Sometimes, when you run the program, the dropdown list has the first item pre-selected in the entry widget, but the variable is still empty until you actually pick something from the dropdown. This is misleading, because it makes the user believe they have a default value available with no need for them to do anything, when actually it's set to nothing. Other times when you run the program, the entry widget is clear (the true state of the variable, which is actually empty), and you need to pick something from the list to make something appear in the widget and give the variable a value.

What's even weirder is that, as far as I can tell, these two behaviors alternate on alternating runs of the program. What I mean is, you run the program, the entry starts off clear, then you run it again, and it's pre-populated with the first array item. Then you run it again, it's clear. Then you run it again, and it's pre-populated with the first array item. This program doesn't have a config file yet, and doesn't save anything to disk, so I don't know how it would even know whether the last run pre-populated the entry widget or not, as there shouldn't be a way for subsequent invocations of the program to even know that. But wouldn't there have to be some state being saved somewhere outside the program for it to be able to predictably alternate behaviors on successive runs like that?

Anyway, what I would like is for the entry widget contents to match the actual value of the variable at all times, and I don't care whether that's in the form of the entry being clear, or being pre-populated with the first item in the array. Either is fine, but the user should not be given the impression that they have a default setting selected when actually the variable contains nothing. A solution that makes the entry widget clear would be fine, or one that pre-populates it with a value is fine, as long as that's what's really in the variable.

Here's my code. Thanks if anyone can help with this:

my $dropdwnMidiPort = $midiCtrls->BrowseEntry( -choices => \@midi_outdevs, -state => 'readonly', -justify => 'right', -variable => \$midi_outdev, -browsecmd => sub { $midi_indev = $midi_outdev; MidiConSetup('out'); MidiConSetup('in'); }, -font => 'Helvetica -12 bold', -disabledforeground => 'black')->grid( -row => 0, -column => 0); $dropdwnMidiPort->Subwidget('slistbox')->configure( -selectbackground => 'IndianRed4', -selectforeground => 'white');

Replies are listed 'Best First'.
Re: Confusing behavior from Tk::BrowseEntry
by kcott (Archbishop) on May 25, 2020 at 00:23 UTC

    G'day DcmbrAgnt,

    You really haven't shown enough code to be certain; however, I suspect your problem may lie with this:

    sub { $midi_indev = $midi_outdev; ...}

    The $midi_indev is a package (global) variable. You don't actually use it in the sub where it's assigned a value. As you don't show any code where $midi_indev is also used, I won't speculate further.

    You should be using the strict and warnings pragmata: see "perlintro: Safety net".

    What you probably need to do is create a reference to $midi_outdev before constructing the Tk::BrowseEntry widget. Then use that reference something like this:

    my $midi_outdev_ref = \$midi_outdev; ... -variable => $midi_outdev_ref, ... sub { my $midi_indev = $$midi_outdev_ref; ... }, ...

    Here's a very bare-bones example:

    #!/usr/bin/env perl use strict; use warnings; use Tk; use Tk::BrowseEntry; my @choices = 'A' .. 'Z'; my $picked = $choices[0]; my $picked_ref = \$picked; my $mw = MainWindow::->new(); $mw->BrowseEntry( -variable => $picked_ref, -choices => \@choices, )->pack(); $mw->Button( -text => 'Print Choice', -command => sub { print "Choice: $$picked_ref\n"; }, )->pack(); MainLoop();

    This code is fully functional. It always shows 'A' as the initial selection; it always prints the last selected value whenever the "Print Choice" button is used.

    "... ALSA MIDI ports, which are being scanned with MIDI::ALSA and put into an array long before the BrowseEntry widget ever gets configured or displayed."

    There may also be something wrong about that assertion. Do you know for certain or is that an assumption? Without seeing your code, I can't tell.

    If the above suggestions don't help, please create an SSCCE that reproduces your problem. Do keep it short: unless it's relevant, omit anything to do with colours, fonts, justification, and so on.

    You might also like to take a look at the Widget Demo. In case you don't know, just type widget on the command line. I can see two examples using Tk::BrowseEntry under Tix Widgets (items 2 & 3).

    — Ken

Re: Confusing behavior from Tk::BrowseEntry (updated)
by AnomalousMonk (Archbishop) on May 24, 2020 at 23:38 UTC

    Every time I run the following program, the BrowseEntry entry comes up blank. I see no alternating behavior. The only way I can get the entry to show initial content is to uncomment the
        $midi_outdev = 'INITIAL CONTENT';
    statement (update: and then I always get the same initial content :). Can you post a Short, Self-Contained, Correct Example that shows the behavior you're seeing?

    c:\@Work\Perl\monks>perl use strict; use warnings; use Tk; use Tk::BrowseEntry; my $midiCtrls = tkinit; my @midi_outdevs = ( 'the rain in spain', 'the cat in the hat', 'how now brown cow', 'foo bar baz', 'now is the time', ); my $midi_outdev; # $midi_outdev = 'INITIAL CONTENT'; my $midi_indev; my $dropdwnMidiPort = $midiCtrls->BrowseEntry( -choices => \@midi_outdevs, -state => 'readonly', -justify => 'right', -variable => \$midi_outdev, -browsecmd => sub { $midi_indev = $midi_outdev; MidiConSetup('out'); MidiConSetup('in'); }, -font => 'Helvetica -12 bold', -disabledforeground => 'black')->grid( -row => 0, -column => 0); $dropdwnMidiPort->Subwidget('slistbox')->configure( -selectbackground => 'IndianRed4', -selectforeground => 'white'); MainLoop; exit; sub MidiConSetup { print qq{'$_[0]' '$midi_indev' \n}; } __END__ 'out' 'how now brown cow' 'in' 'how now brown cow' 'out' 'now is the time' 'in' 'now is the time' 'out' 'the rain in spain' 'in' 'the rain in spain'
    This doesn't answer your question, but it may at least provide a useful data point.


    Give a man a fish:  <%-{-{-{-<