in reply to Re^2: Perl - TK - Listbox insertion problem
in thread Perl - TK - Listbox insertion problem

In your case, you should not use STDIN, but the socket as the source of the events (I am not sure whether it is possible, but if not, you can try sending the lines from the socket to a file and use its filehandle...).
  • Comment on Re^3: Perl - TK - Listbox insertion problem

Replies are listed 'Best First'.
Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 26, 2010 at 03:34 UTC
    I'm not sure why the error message i was receiving was no such file or directory sense all that needs to be done is the text inserts into a listbox widget. What does that have to do with a file or directory. Its a weird error to me.
      Citing the documentation (emphasis mine):
      $listbox->insert(index, ?element, element, ...?)

      Inserts zero or more new elements in the list just before the element given by index. If index is specified as end then the new elements are added to the end of the list. Returns an empty string.

      You cannot use or die for functions returning always the empty string. See also the definition of $! in perlvar.

Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 26, 2010 at 19:39 UTC
    I understand the produces an empty string but this is not the case when i am using end it is producing a string. Its producing the first response from the server and inserting it into my listbox its not until after that does the program end and give the error. When i remove the or die it does not even do this. It wont even insert the first response from the server it does nothing. So this is why this problem is a weird one to me.
      No, you do not understand. The insert method inserts a string into a widget, but it returns an empty string (see return). You can use or die only on functions that return something on succes and undef (emtpy string, zero) on failure. insert does not behave this way, therefore, it cannot be used in or die construction.
Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 26, 2010 at 20:02 UTC
    I understand that it inserts into the widget and it is inserting into the widget like i said its only inserting the first response from the server and it works for me on my other routines such as below.
    if ($postSplit[0] eq "/join") { #Check for erros if ($postSplit[1] eq "") { &error("Incorrect format must me /join #channel"); } # Begin Error Routine # Used to simplify error reporting sub error { my $error = $_[0]; my $errorMessage = "*** ERROR *** $error *** ERROR ***"; + # Our standard Error message $scrolledText -> insert('end', "$errorMessage"); # +Insert the Error into the listbox } # End Error Routine
    That right their inserts into the listbox at the 'end' every time and its not an empty string! So Why wont it work the same way with the response from the server????
      You still do not understand. Try adding or die to your insert in the working code to understand my point.
Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 27, 2010 at 00:15 UTC
    And secondly return; has nothing to do with it. It has to do with inserting into the list box it makes zero difference if return is their or not.
Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 27, 2010 at 12:08 UTC
    I added the or die to the working code and it still worked just fine. It inserted into the list box over and over and never ended the program. So no i do not know what your talking about sense it worked.
      Really? Can you post the code? The following code does not work for me, I have to remove or die as shown in the commented line to make it work:
      use strict; use warnings; use Tk; use Tk::Listbox; my $top = MainWindow->new; my $f = $top->Frame->pack; my $lb = $f->Listbox()->pack; open my $STDIN,'-'; $top->fileevent($STDIN, readable => sub { chomp(my $line = <>); # # $lb->insert('end',$line); # $lb->insert('end',$line) or die; }); MainLoop;
Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 27, 2010 at 13:54 UTC
    I'm just gonna go ahead and post all of the code. Thanks for trying to help figure this out by the way. Maybe by posting the whole program you might see something I'm not.
    #!/usr/bin/perl # This is a irc client useing Tk # Date started 3-22-10 # use Tk; use strict; # Set some global variables # Used for the MessageBox sub routines # As well as the label sub routines. # Entry, Save routines use vars qw($message $type $icon $messageBox @mainEntry @settings $soc +k); # Our Main Window my $mainWindow = new MainWindow; # Title the window $mainWindow -> title( 'Perl Tk Irc Client' ); # Create a frame for our widgets my $frameMain = $mainWindow -> Frame( -relief => 'sunken', ); $frameMain -> pack( -expand => '1', -fill => 'both' ); # Our Options menu my $menuBar = $mainWindow -> Menu(); $mainWindow -> configure( -menu => $menuBar ); # The Menu Buttons my $file = $menuBar -> cascade( -label => 'File', -underline => '0', -tearoff => '0' ); my $help = $menuBar -> cascade( -label => 'Help', -underline => '0', -tearoff => '0' ); # End Menu Buttons # File Menu Options # Settings Option $file -> command( -label => 'Settings', -underline => '0', -command => \&settings ); # Quit Option $file -> command( -label => 'Quit', -underline => '0', -command => \&quit ); # End File Menu Options # Help Menu Options # About Option $help -> command( -label => 'About', -underline => '0', -command=> \&about ); # End Help Menu Options # Text entry to chat! my $textEntry = $frameMain -> Entry( -state => 'normal', -background => 'white', #-foreground => 'black', -width => '100' ); $textEntry -> pack( -expand => '0', -fill => 'x', -side => 'bottom' ); # When the return key is hit the routine getData will run $textEntry -> bind('<Return>' => \&getData); # Scrolled text where the chat and status apears my $scrolledText = $frameMain -> Scrolled( 'Listbox', -scrollbars => 'oe', -background => 'white', #-foreground => 'black', -width => '90', -height => '30' ); $scrolledText -> pack( -fill => 'both', -expand => '1', -side => 'left' ); # Scrolled text for the usernames in the chat room my $scrolledNicks = $frameMain -> Scrolled( 'Listbox', -scrollbars => 'eo', -background => 'white', #-foreground => 'black', -width => '10', -height => '30' ); $scrolledNicks -> pack( -fill => 'both', -side => 'right', ); # Sub Routines To be moved to another file #MainLoop; # Sub Routines for the File Menu sub quit { #my $response = $mainWindow -> messageBox(-message => "Would you l +ike to exit?", -type => 'yesno', -icon => 'question'); $message = "Would you like to exit?"; $type = 'yesno'; $icon = 'question'; &messageBox($message,$type,$icon); if ($messageBox eq "Yes") { exit; } } # Sub routine to run our settings dialog box. sub settings { # Make our top level window for the settings dialog box my $settingsTopLevel = $mainWindow -> Toplevel(); # Title the Top Level Window $settingsTopLevel -> title( 'User Settings' ); # Set the defualt size of our Top Level Window # Use Geometry $settingsTopLevel -> geometry("500x300"); # Button To close our Dialog my $closeButton = $settingsTopLevel -> Button( -text => 'Cancel', -command => sub { destroy $settingsTopLevel; } ); $closeButton -> grid( -column => 1, -row => 3, -pady => 10, -sticky => 's' ); # Button to save our settings my $saveButton = $settingsTopLevel -> Button( -text => 'Save', -command => \&saveSettings ); $saveButton -> grid( -column => 2, -row => 3, -pady => 10, -sticky => 's' ); # Create our labels # Options go in this order # Title, Window, Column, Row &Label("Nickname:", $settingsTopLevel, 0, 0); &Label("Username:", $settingsTopLevel, 0, 1); &Label("Real Name:", $settingsTopLevel, 0, 2); # Create our Entries # Options go in this order # Window, Column, Row &Entry($settingsTopLevel, 2, 0); &Entry($settingsTopLevel, 2, 1); &Entry($settingsTopLevel, 2, 2); } # End Settings Routine # End Sub Routines for the File Menu # Sub Routines for the Help Menu sub about { $message = "Tk Irc Script v1.0\nWritten by: Andrew Medeiros\nE-mai +l: amedeiros0920\@gmail.com"; $type = 'ok'; $icon = 'info'; &messageBox($message,$type,$icon); } # End Sub Routines for Help Menu # Sub routine to get the data from the text entry field when the retur +n key is hit. # For the moment it just prints the text. But we will need to clear th +e text entry and take the text and run it against potential commands. sub getData { my $post = $textEntry -> get(); # Get the entered data + from the text entry $textEntry -> delete(0, 'end'); # Clear the text entry] my @postSplit = split(/ /, $post); # Split the entry in +to an array removing the white spaces. For checking commnads if ($post eq "") { # If blank dont post return; #print "Empty\n"; # Testing purposes } if ($postSplit[0] eq "/server") { # Check for blanks if ($postSplit[1] eq "" or $postSplit[1] != /[^0-9]/) { &error("Incorrect format either server name is missing or +is just a number!"); } elsif ($postSplit[2] eq "" or $postSplit[2] == /[^0-9]/ ) { &error("Incoreect format either port number is missing or +is not a number!"); } else { &connection($postSplit[1], $postSplit[2]); } } if ($postSplit[0] eq "/join") { #Check for erros if ($postSplit[1] eq "") { &error("Incorrect format must be /join #channel"); } # If good join the channel else { &raw("JOIN $postSplit[1]"); } } $scrolledText -> see('end'); # So the scrolledText +will auto scroll allowing to see the conversation } # End Get Data Routine # Sub routine to create Custom labels by passing some options through # This will make it so we dont have to make a new label for every reas +on sub Label { # The options we need to create some basic labels my $label = $_[0]; my $window = $_[1]; my $column = $_[2]; my $row = $_[3]; # Lets make them shits my $mainLabel = $window -> Label( -text => "$label" ); $mainLabel -> grid( -column => $column, -row => $row, -pady => 20, -sticky => 'w' ); } # End Label Routine # Create a entry routine to make our entrys # For the settings my $num = 0; # This is so we can define each entry differently +and get-> them each sub Entry { my $window = $_[0]; my $column = $_[1]; my $row = $_[2]; # Lets make them shits $mainEntry[$num] = $window -> Entry( -state => 'normal', -background => 'white', #-foreground => 'black', -width => '40' ); $mainEntry[$num] -> grid( -column => $column, -row => $row, -pady => 20, -sticky => 'e' ); $num++; } # Sub routine to save our settings use Config::General qw(SaveConfig); sub saveSettings { my $num = 0; while ($num != 3) { my $settings = $mainEntry[$num] ->get(); $settings[$num] = $settings; if ( $settings eq "" ) { $num = 2; # Send our error box for an empty entry # Message, Type, Icon &messageBox("You are missing an entry!", 'ok', 'error'); } else { # Open the configuration file my $conf = new Config::General("settings.conf"); # Create our database in a hash my %database = ( database => { nickname => "$settings[0]", username => "$settings[1]", realname => "$settings[2]" } ); # Save our database SaveConfig("settings.conf", \%database); } $num++; } } # End Save Settings Routine # Sub Routine to create Custom Message Box's by passing the options th +rough. # This will make it so i do not have to make a new message box for eve +ry reason. sub messageBox { my $message = $_[0]; my $type = $_[1]; my $icon = $_[2]; $messageBox = $mainWindow -> messageBox( -message => $message, -type => $type, -icon => $icon ); return; } # End messageBox Routine # Begin Error Routine # Used to simplify error reporting sub error { my $error = $_[0]; my $errorMessage = "*** ERROR *** $error *** ERROR ***"; + # Our standard Error message $scrolledText -> insert('end', "$errorMessage"); + # Insert the Error into the listbox } # End Error Routine # Begin Connection routine # This will connect us to our server use IO::Socket; sub connection { # Get our server and port from the /server server port command. my $server = $_[0]; my $port = $_[1]; # Open the configuration file my $conf = new Config::General("settings.conf"); # Get all the information from the settings file my %config = $conf ->getall(); # Store the nickname from the settings my $nick = $config{'database'}->{'nickname'}; # Store the username from the settings my $username = $config{'database'}->{'username'}; # Store the realname from the settings my $realname = $config{'database'}->{'realname'}; # Print results for testing purposes #print "$nick\n$username\n$realname"; # Make our Connection to the server port given $sock = IO::Socket::INET->new(PeerAddr => "$server", PeerPort => "$port", Proto => 'tcp', Timeout => '30') or die("Can Not Connect +: $!\n"); # Setup some extra information to be sent my $hostname = "localhost"; my $servername = "localhost"; # Send our basic information to the irc server &raw("NICK $nick"); &raw("USER $username $hostname $servername $realname"); # Fork it into two process's my $kidpid; die "Cant Fork: $!" unless defined($kidpid = fork()); if ($kidpid) { while (defined ( my $line = <$sock> ) ){ chomp($line);# = $_); $line =~ s/(\x0a|\x0d)//g; # Display response from server &show($line); #print "<< $line\n"; $line =~ s/^://; my ($pre, $tag) = split(/ :/, $line, 2); my @parts = split(/ /, $pre); my @user = split(/!/, $parts[0]); # This is going to get + the users nick who posted to the channel for a command or did a ctcp + and so fourth. So the bot can reply to that user. my @phrase = split(/ /, $tag); # This is going to be use +d do split up the users text to pick it a part for specific things # Check for ping request if ($parts[0] eq 'PING') { # Reply with proper PONG response &raw("PONG :$tag"); } my $event = uc($parts[1]); if ($event eq "PRIVMSG" && $phrase[0] eq "VERSION") { my $response = "Is useing Perl Tk Irc Client by k0rn"; &raw("VERSION $user[0] $nick $response"); print "Got version request!\n"; } } } } # Begine raw subroutine # Used to send data to the server sub raw { my($l) = @_; print ">> $l\n"; print $sock "$l\n"; } # End Connection Sub Routine # Begin Show Sub Routine # To Display data from server sub show { my $line = shift; print "<< $line\n"; $scrolledText ->insert('end',"<< $line"); # Insert the text int +o the Listbox $scrolledText return; } # End Show Sub Routine MainLoop;
      You do not use fileevent. I constructed a simple toy server and client, they work just ok.

      Server:

      #!/usr/bin/perl use IO::Socket::INET; use IO::Select; use strict; use warnings; my $listen = new IO::Socket::INET(Listen => 1, LocalPort => 8889); my $sel = new IO::Select($listen); { my $fh; print STDERR "1\n"; sleep 1 until ($fh) = $sel->can_read; print STDERR "2\n"; my $new = $listen->accept; $sel->add($new); print STDERR $new->sockhost," 2.5\n"; } while (1){ print STDERR "3\n"; foreach my $fh ($sel->can_write){ print STDERR "4\n"; print $fh rand(100),"\n" or die "4:$!\n"; } sleep 1; }

      Client:

      #!/usr/bin/perl use Tk; use Tk::Listbox; use IO::Socket::INET; use strict; use warnings; my $top = MainWindow->new; my $f = $top->Frame->pack; my $lb = $f->Listbox()->pack; my $socket = IO::Socket::INET->new(PeerAddr => 'localhost', PeerPort => 8889, Proto=>'tcp') or die "Cannot connect: $!\n"; $top->fileevent($socket, readable => sub { chomp(my $line = <$socket>); print STDERR "$line"; $lb->insert('end',":$line"); # $lb->insert('end',$line) or die; }); MainLoop;

      First, run the server. Then, run the client, it will connect to the server and it will start sending it numbers that will be shown in the listbox.

Re^4: Perl - TK - Listbox insertion problem
by k0rn (Acolyte) on Apr 27, 2010 at 20:36 UTC
    So basically what your saying is i need to rewrite how i handle the connection to the server to make this work and use fileevent.
      I am not sure about the connection, I haven't read the whole code. But as stated in my first reply, I'd start with fileevent.
      I have tried fileevent before and could not make it work so its one of a few things either A im not doing it right most likely. B I'm have all these problems due to the splitting into two process probably not. Or C how I'm handling the connection. Or D all of the above lol.

      UPDATE: It was D all of the above! I got it to work. The only problem is while(<$sock>) seems not to work only if its if (<$sock>) Thanks man!!!