Here's a working (albeit barebones) example to show the techniques you'll probably need. (See Notes at the end.)
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Tk;
use Tk::Pane;
my $mw = MainWindow->new();
$mw->geometry('200x250+50+50');
my $connection_file = './pm_tk_dynamic_buttons_connection.txt';
my $action_F = $mw->Frame()->pack(-side => 'bottom');
$action_F->Button(
-text => 'Change Connections',
-command => [\&change_connections, \$connection_file],
)->pack;
$action_F->Button(-text => 'Exit', -command => sub { exit })->pack;
my $pane_F = $mw->Frame()->pack(-fill => 'both', -expand => 1);
$pane_F->pack(-fill => 'both', -expand => 1);
my $button_P = $pane_F->Scrolled('Pane',
-scrollbars => 'osoe', -sticky => 'nsew'
)->pack(-fill => 'both', -expand => 1);
my $text_F = $mw->Frame()->pack(-fill => 'both', -expand => 1);
my $pressed_T = $text_F->Scrolled('Text',
-scrollbars => 'osoe', -wrap => 'none', -height => 10
)->pack(-fill => 'both', -expand => 1);
my $delay = 100;
$mw->repeat($delay,
[\&check_connections, \$connection_file, \$button_P, \$pressed_T]
);
MainLoop;
{
my %connect_button_for;
my $last_mod;
sub check_connections {
my ($file_ref, $but_win_ref, $out_win_ref) = @_;
if (-e $$file_ref) {
my $cur_mod = -M $$file_ref;
return if defined $last_mod && $cur_mod == $last_mod;
$last_mod = $cur_mod;
$_->destroy for values %connect_button_for;
%connect_button_for = ();
open my $fh, '<', $$file_ref;
/handle=(\d+)/ and ++$connect_button_for{$1} while <$fh>;
close $fh;
for my $handle (sort keys %connect_button_for) {
$connect_button_for{$handle} = $$but_win_ref->Button(
-text => "Handle $handle",
-command => sub {
$$out_win_ref->insert(
end => "Clicked 'Handle $handle' button.\n
+"
);
$$out_win_ref->yview('end');
},
)->pack;
}
}
}
}
BEGIN {
my @all_connections = (
['>' => 1],
['>>' => 2, 3],
['>' => 2, 4],
['>>' => 5, 3],
['>'],
);
my $connection_index = -1;
sub change_connections {
my ($file_ref) = @_;
my $index = ++$connection_index % @all_connections;
my @connectons = @{$all_connections[$index]};
my $mode = shift @connectons;
open my $fh, $mode, $$file_ref;
print $fh "... handle=$_ ...\n" for @connectons;
close $fh;
}
}
END { unlink $connection_file }
Notes
-
I don't have hcitool nor do I know what its output looks like: I've just used some dummy data ("... hanhdle=number ...") for test purposes.
-
The BEGIN and END blocks are just for testing.
You may want something similar if you want to update the hcitool output manually from the GUI.
-
I've set the delay for check_connections() to 100ms.
Set this to whatever you want but bear in mind that the human eye is unlikely to register more than about 25 changes per seconds; setting this to less than 40ms will be pointless from a visual perspective and wasteful from a processing perspective.
-
When the hcitool output changes, all existing buttons are destroyed and a new set is created.
If you have data associated with the buttons, you may want to change this such that buttons are only destroyed if they no longer appear in the updated output.
-
Scrollbars will automatically appear in the Tk::Pane ($button_P) when they are needed.
The same is true for the Tk::Text ($pressed_T); although, I only added that for demo purposes.
-
I didn't need Tk::fileevent in this instance; however, if you're appending data to your output file, this may be appropriate.
Note that my tests both wrote data to a newly created output file and appended data to an existing file: the logic I've shown may suffice for your needs.
-
I think everything else should be reasonably straightforward but do ask if there's something you don't understand.
Update:
I had a misplaced closing brace in check_connections() (putting the for loop outside the if (-e $$file_ref) block — it should've been inside that block).
This didn't affect how the routine currently functioned but may have introduced a weird bug if subsequent changes were made.
Fixed and successfully retested.
|