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

I'm having a little trouble with JComboBox for Tk. I am using ActiveState perl version 5.6.1 and JComboBox version .02 or at least I think it's version .02 on a win2k box. Here's the scenario:

I have a window for used for searching a database with widgets used for selecting a subset of criteria and one of these widgets is a JComboBox. The same window also contains a button that will bring up a dialog used to define the whole set of search criteria. The dialog also includes a JComboBox widget that is linked to the same data as the first JComboBox I mentioned.

The problem is that when I change the value of the JComboBox in the dialog, it makes the first JComboBox drop down it's list. Subsequent changes to the JComboBox in the dialog can cause more lists to be shown in various places on the screen that don't go away even when the dialog is closed. I have tried to set the first JComboBox's -state=>'disabled' before showing the dialog but that didn't help. Even though the combobox on the first window is disabled, it still pops up the list. Wow, that even confused me a little. Here is a much abbreviated example of the problem:

#!c:\perl\bin\perl.exe use strict; use warnings; use Tk; use Tk::JComboBox; use Tk::Dialog; my $form; my %choices = ( 'a'=>1, 'b'=>2, 'c'=>3 ); my $selected = "a"; CreateMainForm(); MainLoop(); exit; sub CreateMainForm { $form = MainWindow->new(); $form->title("Test for JComboBox Problem"); my $testbox1 = $form->JComboBox(-textvariable=>\$selected,-validat +e=>'match',-mode=>'editable',-relief=>'sunken',-highlightthickness=>0 +); for my $x(keys %choices) { $testbox1->addItem("$x"); } $testbox1->pack(-side=>'left'); my $button = $form->Button(-text=>"Dialog",-command=>sub{CallDialo +g($testbox1)})->pack(-side=>'right'); return; } sub CallDialog { my $otherbox = shift; $otherbox->configure(-state=>'disabled'); my $dialog = $form->Dialog(-title=>"Part2 of test",-buttons=>["Sub +mit","Cancel"],-default_button=>"Submit"); my $testbox2 = $dialog->JComboBox(-textvariable=>\$selected,-valid +ate=>'match',-mode=>'editable',-relief=>'sunken',-highlightthickness= +>0); for my $x(keys %choices) { $testbox2->addItem("$x"); } $testbox2->pack(-side=>'left'); my $retval = $dialog->Show(-popover=>$form,-overanchor=>'c',-popan +chor=>'c',-global); if($retval eq "Cancel") { $otherbox->configure(-state=>'normal'); return; } elsif($retval eq "Submit") { $otherbox->configure(-state=>'normal'); #SaveConfig(); return; } else { #should never happen return; } }

Am I doing something terribly wrong here? Is there a different/better combo box I can use?

NOTE: I have modified the JComboBox.pm slightly to handle what I like to call a loose-match in addition to the match and cs-match modes. This allows the user to enter a value not in the list as well as match items in the list while typing. This problem occurs in both the original version and my modified version.

Janitored by Arunbear - added readmore tags, as per Monastery guidelines

Replies are listed 'Best First'.
Re: Help with JComboBox
by JamesNC (Chaplain) on Nov 17, 2004 at 04:12 UTC
    Ok, here is the solution. First, you are using the same textvariable reference and that is why the box pops up, use a second one and that issue goes away. The other problems are caused by the fact that you keep creating instances of dialog boxes and JCombo's. Create a single instance, and then use the Show() method in your CallDialog sub. Here is your version hacked up to work:
    use strict; use warnings; use Tk; use Tk::JComboBox; use Tk::Dialog; my $form; my %choices = ( 'a'=>1, 'b'=>2, 'c'=>3 ); my $selected_1 = "a"; my $selected = "a"; my $dialog; my $testbox1; my $testbox2; CreateMainForm(); MainLoop(); sub CreateMainForm { $form = MainWindow->new(); $form->title("Test for JComboBox Problem"); $testbox1 = $form->JComboBox( -textvariable=>\$selected_1, -validate=>'match', -mode=>'editable', -relief=>'sunken', -highlightthickness=>0, ); for my $x(keys %choices) { $testbox1->addItem("$x"); } $testbox1->pack(-side=>'left'); my $button = $form->Button( -text=>"Dialog", -command=>sub{CallDialog($testbox1)} )->pack(-side=>'right'); $dialog = $form->Dialog ( -title=>"Part2 of test", -buttons=>["Submit","Cancel"],-default_button=>"Submit" ); $testbox2 = $dialog->JComboBox(-textvariable=>\$selected, -validate=>'match',-mode=>'editable', -relief=>'sunken',-highlightthickness=>0 ); for my $x(keys %choices) { $testbox2->addItem("$x"); } $testbox2->pack(-side=>'left'); } sub CallDialog { $testbox1->configure(-state=>'disabled'); my $retval = $dialog->Show( -popover=>$form, -overanchor=>'c', -popanchor=>'c'); if($retval eq "Cancel") { $testbox1->configure(-state=>'normal'); } elsif($retval eq "Submit") { $testbox1->configure(-state=>'normal'); $testbox1->setSelected($selected ); #(optional?) } }


    Cheers,
    JamesNC
      Thanks. Your example does work, however, I need the combobox in the dialog to show the correct value. With this modification, I still have the same problem.
      sub CallDialog { $testbox1->configure(-state=>'disabled'); ############################### # Added this line so the displayed value is correct $selected = $selected_1; ############################### my $retval = $dialog->Show( -popover=>$form, -overanchor=>'c', -po +panchor=>'c'); if($retval eq "Cancel") { $testbox1->configure(-state=>'normal'); } elsif($retval eq "Submit") { $testbox1->configure(-state=>'normal'); $testbox1->setSelected($selected ); #(optional?) } }
      I also tried to set the variable in the callback for the button on the main window and got the same problem.
      my $button = $form->Button( -text=>"Dialog", -command=>sub{$selected= +$selected_1;CallDialog($testbox1);} )->pack(-side=>'right');
      I have also tried passing the variable $selected to the sub CallDialog in the callback. Same problem.

      What does work is to use the setSelected method as you mentioned below at the beginning of the sub CallDialog along with a seperate variable. This way the problem does not show up and the correct value is displayed to the user in the dialog. Also, I found that there is no need to disable the first combobox since it doesn't really disable the background activities of the combobox.
      use strict; use warnings; use Tk; use Tk::JComboBox; use Tk::Dialog; my $form; my %choices = ( 'a'=>1, 'b'=>2, 'c'=>3 ); my $selected_1 = "a"; my $selected = "a"; my $dialog; my $testbox1; my $testbox2; CreateMainForm(); MainLoop(); sub CreateMainForm { $form = MainWindow->new(); $form->title("Test for JComboBox Problem"); $testbox1 = $form->JComboBox( -textvariable=>\$selected_1,-valida +te=>'match', -mode=>'editable',-relief=>'sunken', -highlightthicknes +s=>0 ); for my $x(keys %choices) { $testbox1->addItem("$x"); } $testbox1->pack(-side=>'left'); my $button = $form->Button( -text=>"Dialog", -command=>sub{CallDi +alog();} )->pack(-side=>'right'); $dialog = $form->Dialog ( -title=>"Part2 of test", -buttons=>["Su +bmit","Cancel"],-default_button=>"Submit" ); $testbox2 = $dialog->JComboBox(-textvariable=>\$selected, -validat +e=>'match',-mode=>'editable', -relief=>'sunken',-highlightthickness=> +0); for my $x(keys %choices) { $testbox2->addItem("$x"); } $testbox2->pack(-side=>'left'); } sub CallDialog { $testbox2->setSelected($selected_1); my $retval = $dialog->Show( -popover=>$form, -overanchor=>'c', -po +panchor=>'c'); if($retval eq "Cancel") { $testbox1->configure(-state=>'normal'); } elsif($retval eq "Submit") { $testbox1->setSelected($selected ); #(optional?) } }
      Thanks again for your help. ++Too bad I can vote only once per node.
        I think you did it again... do this to set the dialog windows combo box to the main window combo box, should probably rename these to avoid the Who's on first, what's on second...
        ############################### # Added this line so the displayed value is correct #$selected = $selected_1; #<-- not this $testbox2->setSelected( $selected1 ); #<-- but this ###############################
Re: Help with JComboBox
by graff (Chancellor) on Nov 17, 2004 at 05:32 UTC
    This part of your complaint caught my eye:
    Even though the combobox on the first window is disabled, it still pops up the list.
    The issues pointed out in JamesNC's reply are bound to be helpful. But apart from that, my own experience with JComboBox showed an odd behavior when using the attributes  -textvariable => \$scalar_var, -mode => 'editable', -validate => 'match' .

    (update: fixed spelling and code tags above)

    I came across this when I wanted users to be able to type and/or chose from a list to set a field in a database, and also show the an existing field value from the database when the user ran a query. Funny thing was, whenever I used a query result to set the value of the textvariable, the JCombobox list menu would pop up, and wouldn't go away until there was a mouse click. Very ugly. I had to work around it by invoking the widget's "hidepopup" method every time I set the textvariable's value. The following mindless script demonstrates the problem:

    #!/usr/bin/perl use strict; use Tk; use Tk::JComboBox; my @choice = sort qw/Foo Bar Baz Red Green Blue Orange White Black/; my $chosen; my $mw = MainWindow->new(); $mw->Label(-text => 'Pick/type a value from JComboBox:')->pack(); my $cb = $mw->JComboBox(-width => 15, -textvariable => \$chosen, -choices => \@choice, -maxrows => 5, -mode => 'editable', -validate => 'match', -relief => 'sunken', )->pack(); $mw->Label(-text => 'or just push this button:')->pack(); $mw->Button(-text => 'Make a random choice', -command => sub { my $c = int(rand( scalar @choice )); print "$choice[$c] chosen at random\n"; $chosen = $choice[$c]; # uncomment the next line to fix errant JComboBox popup: # $cb->hidePopup(); } )->pack(); MainLoop;
    It seems that the "validate => 'match'" thing is mostly responsible -- comment that out, and the popup isn't a problem. But then, you never get the popup when actually typing into the entry box either -- you don't get to see the next full choice based on what you've typed so far -- which defeats one of the big reasons for using this widget in the first place.
      I actually would expect this same behavior for some of the same reasons above. (I don't like the behavior)
      Instead of $chosen = $choice[$c]; try $cb->setSelected($choice[$c]); and you won't have to do a hide. I have just learned to use the  setSelected() method to avoid this issue.
Re: Help with JComboBox
by jdtoronto (Prior) on Nov 16, 2004 at 22:43 UTC
    JComboBox is rather flaky in some respects! I use it, but only as a last resort - I need something where I can use a descriptive contect made visible with an id which is not visible.

    The only similar widget is the Tk:Optionmenu which has other challenges, at least in my application.

    jdtoronto

      Thanks for the comment. At least now I know there are at least two others who have had trouble with it. Tk::OptionMenu doesn't give the option of typing in a value that is not in the list and Tk::BrowseEntry doesn't try to match the list while I'm typing. I suppose I'll just have to try and fix JComboBox. Wish me luck. I'm going to need lots of it.
Re: Help with JComboBox
by diakonos (Hermit) on Nov 16, 2004 at 20:12 UTC
    DUDE! I have see this before. Couldn't get it workin. Does it seem to behave even worse when you change the state of the combo box to readonly?
      I did try to change the mode to readonly but it didn't help any.