Executing commands using Button widget in Perl-Tk - linux

#!/usr/local/bin/perl
use Tk;
# Main Window
$mw = new MainWindow;
$label = $mw -> Label(-text=>"Hello World") -> pack();
$button = $mw -> Button(-text => "Quit",
-command => sub { exit }) -> pack();
MainLoop;
In this code when the button $button is pressed it closes the program. Because it executes the exit command. I want to modify the code so that when the user clicks on the button it will flush the iptables rule (iptables -F). How can I do this?
I tried this:
$button = $mw -> Button(-text => "Flush the rules",
-command => system ( iptables -F )) -> pack();
Why isn't this working? Should I have to make a subroutine for it (then writing the iptables -F command there) and then call that subroutine? Can't I directly put the command as I did in above code?

You need to specify a code reference - a callback - which will be executed when the button is pressed, so yes you should place your system call in a sub { }.
What you've written is a call to system() at the point that the Button is defined, so you're specifying the return value from system() as the coderef for the callback - which won't work. The system() function will be called when Button is defined, not when its pressed - which isn't what you want.

Related

How to catch ctrl+c and close file descriptor in Perl

I have Perl script - simple server. Wait for connect in the loop, and write it to the new file on disc. The server should be stopped when ctrl + c are pressed. Before exit, I want to close all files descriptor. It's not so easy, because terminal shows error.
Yes, I read this thread:
How can I check if a filehandle is open in Perl?
But it's not working for me.
There is my main loop:
my $my_socket = new IO::Socket::INET(
LocalHost => $local_host,
LocalPort => $local_port,
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "Couldn't create: my_socket $!n " unless $my_socket;
print "Send files.. \n";
while(1) {
my $accepter = $my_socket->accept();
my $count = 0;
#print "$directory.$save_dir/$my_data";
$datetime = localtime();
$datetime =~ s/(?<=\w)\s(?=\w)/_/g;
open my $fh, '>', "$direc/$save_dir/$datetime"
or die "Couldn't open the file";
while(<$accepter>){
chomp;
#last if $count++ ==10;
#print($accepter);
say $fh $_;
}
$SIG{'INT'} = sub {
print "Caught One!\n";
close $fh;
}; #It gives me error. Close fd which is not opened.
}
#print "Received. End \n";
#close $fh;
close $my_socket;
The code in the signal handler closes that filehandle -- and lets the loop continue. So the next time round that filehandle is indeed closed so you get warnings. (I'd expect issues first with printing to it on the next pass, if the problem is described well, but there may be reasons that that's avoided.)
The fix, in short -- set a flag in the signal handler, nothing else. Check for it at a suitable place in the code and if it is set then close the file and exit the loop by last.† (Or perform some other action, as suitable for your code.)
There's more I'd like to comment about the signal handler though. The %SIG is a very global creature. By setting $SIG{INT} you've changed it for all of the code in the interpreter.
Why not use local $SIG{INT} instead? Then it is changed only inside the scope in which it is defined; see local. And I'd pull that definition outside of all loops possible. (If you actually want it global place it right at the beginning so it's loud and clear and not hidden away.)
So something like
SOME_SCOPE:
{
my $got_signal;
local $SIG{INT} = sub {
#say "Caught: #_";
$got_signal = 1;
};
while (1) {
...
open my $fh, '>', ... or die $!;
while (<$accepter>) {
...
if ($got_signal) {
close $fh;
# $got_signal = 0; # if used again (reset it)
last;
}
say $fh $_;
}
...
}
};
This is still a sketch, even as it may work as it stands in a simpler case. I have to assume some things, in the first place that there is a lot more going on in your code. If a contained and complete runnable example can help let me know and I can add it.
† Can't do last in a signal handler's sub (it's not inside of a loop, even if it's defined there in the code). And in general, using last in a sub is not a good idea, to say the least, as it would lead to confusing and opaque code. It also sports very specific behavior
last cannot return a value from a block that typically returns a value, such as eval {}, sub {}, or do {}. It will perform its flow control behavior, which precludes any return value.
(it comes with a warning, too)   In this case you don't need to return a value but (even if it worked) you absolutely would not want to do that out of a signal handler.
To note, even as it is linked in the question, that one can check whether a filehandle is open using Scalar::Util::openhandle. That can come handy in this code.
If you want the server to truly exit when Ctrl-C is pressed, simply put an exit statement in the interrupt handler. That will automatically close all the file handles as Perl exits.
If you want the read loop to terminate when Ctrl-C is pressed but the program will otherwise carry on, do this. However might I suggest Ctrl-\ as a better alternative which sends a SIGQUIT signal. Most people don't expect graceful exits from Ctrl-C; they expect crash stop now.
our $doloop = 1;
$SIG{QUIT} = sub { $doloop = 0; };
while ($doloop) { ... }
$SIG{QUIT} = "IGNORE";
cleanup;
exit;
If you need to check if the filehandle is open before trying to close it, just use -e. For other kinds of open tests see perlfunc -X.
close $fh if -e $fh;
HTH

Multi Clicks With the Same Keyboard Shortcuts to Run a Ahk Script

I want to do Multi Clicks with the same Keyboard Shortcuts to Run a Ahk Script.
I now in Autohotkey Languages, you can write a code that can execute a part of Code, if a certain Keyboard Shortcut combination is pressed.
But i want on my Windows System, to Click a count of the same keystroke combinations to execute a part of Code.
The pros are: you do not have to move your fingers to a other place on that keyboard, Click it again and it will run a other Code. (this will improve my keyboard Movements and i have more options to do keystrokes.)
Example:
Click - Ctrl + (1x)c - to CopyText
DoubleClick - Ctrl + (2x)c - to CopyText + GoogleSearch
multiClick - Ctrl + (5x)c - ?
If you look to this Example Script then you can see what i mean.
(note - Hotkey > [^cc::] or hotkeystring > [:*:^cc::]- this does not work, is there another way to solved this)
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
#SingleInstance force
;MultiClicks the Same Keyboard Shortcuts to Run a Ahk Script
;Click Ctrl + c to [copy text]
^c::
send ^c
;msgbox script1
return
;DoubleClick Ctrl + (2x)c [copy text] + [do a google search]
^cc::
send ^c
sleep 200
run https://www.google.com/?q=%clipboard%
;msgbox script2
return
;MultiClicks Ctrl + (5x)c to run script5
^ccccc::
;?
;msgbox script5
return
esc::exitapp
^c::
{
count++
SetTimer, actions, 400 ;время за которое нужно нажать комбинацию
}
return
actions:
{
if (count = 1)
{
msgbox CTRL+C
}
else if (count = 2)
{
msgbox CTRL+CС
}
else if (count = 5)
{
msgbox CTRL+CСССС
}
count := 0
}

Perl TK multiple commands on a single button

I would like to do is to have a button to close my window (button_window), but also call a function (user_info):
my $btn = $main -> Button (-text => 'Start',
-command => sub {$button_window -> destroy},
-command => \&user_info)
-> pack ();
its executing only the last command
thanks in advance
The sub can take any number of calls to other subs.
my $btn = $main->Button(
-text => 'Start',
-command => sub {
user_info();
# do something else...
$button_window->destroy;
},
)->pack();
It's executing only the last command because a hash parameter can have only one '-command' key, so is overwritten.

Separating and Comparing Strings from a Text File in AHK

I'm running into a bit of a problem, but I feel so close to solving it. I have a text file with Usernames and Passwords separated with a pipe:
;info.txt
user1|pass1
user2|pass2
user3|pass3
user4|pass4
user5|pass5
user6|pass6
user7|pass7
user8|pass8
user9|pass9
user10|pass10
and here's the code:
Gui, -SysMenu
Gui, Add, Button, , Log in
getUsers()
Gui, Add, Button, , Exit
Gui, Show
Return
getUsers()
{
userList := ""
loop
{
FileReadLine, line, info.txt, %A_Index%
if ErrorLevel
Break
getUsers := StrSplit(line, "|")
userList .= getUsers[1] "|"
}
Gui, Add, ListBox, h100 vChoice, %userList%
}
ButtonLogin:
MsgBox, You chose %Choice%.
Gui, Submit, NoHide
Return
ButtonExit:
ExitApp
Return
I used StrSplit() to separate the User from Pass and then delimit the Users to get them into proper format for the ListBox. Everything loads just fine, but when I select one from the list and hit "Log in," the first one doesn't give me any result then the correct results are delayed by one. Example:
Click user1 > You chose .
Click user5 > you chose user1.
Click user3 > you chose user5.
Also, if anyone has a better way of doing this, please let me know.
Ah, I figured it out. It was a problem with:
ButtonLogin:
MsgBox, You chose %Choice%.
Gui, Submit, NoHide
Return
The MsgBox was happening BEFORE Submit was going through. Fixed:
ButtonLogin:
Gui, Submit, NoHide
MsgBox, You chose %Choice%.
Return

How to wait for user input inside function using c#

I have One Window application by Which User Can Print Their Product Barcode Value And Also Can Scan it,
Now i am searching for some threading or some other way,
If user Enter 5 value for Print after Printing First value, Function wait for user input in text box (i call textbox up event for capturing scanning value)
and if value is correct so, my function continue its execution or wait until user Scan Proper barcode,
so how can i make method or function which can wait for user input and then continue executions.
private void myFunction1()
{
for (i = 0; i < intPrintNo; i++) // Number Of Print
{
// here I write Code For Print My Barcode
// Now I want to wait For user Input in my text box
jumphere :
txtBarcode.Text = "";
txtBarcode.Enabled = true;
txtBarcode.Visible = true;
txtBarcode.Focus();
if (keyUp()== false)
{
txtBarcode.Text = "";
txtBarcode.Enabled = true;
goto jumphere;
}
// If return True than for loop Continue for next Printing
}
}
From what i've understood from your question, you want to print the barcode of value specified by the user and then user can scan the same to verify if printed properly or not.
You can achieve this functionality in Windows forms using following steps
User enters the value (to print barcode) in txtInput
Presses print button (btnPrint)
The print button event handler will first disable itself and the input textbox (btnPrint.Enabled = txtInput.Enabled = false; Application.DoEvents();) and then print the barcode and set focus on textbox txtVerify.
User will scan the barcode in textbox txtVerify.
User will click on verify button (btnVerify) which will compare the value in txtInput and txtVerify.
If everything fine, clear the txtInput, txtVerify, enable txtInput and btnPrint, set focus to txtInput for next value
If error, do the needful.
EDIT: As per OPs comment (minimum user effort)
You can change the setting of barcode scanner to suffix newline (Enter) after every scan (you can find how to do this setting in the manual provided with the barcode)...... so now,
step 4. User will scan the barcode in textbox txtVerify (the scanning will provide Enter press at the end of scan). txtVerify.TextChanged event handler will check if key pressed in Enter, if so, call the code to verify (compare the values in txtInput and txtVerify)
step 5. Remove this step from above
step 6. If everything fine, clear the txtInput, txtVerify, enable txtInput and btnPrint, set focus to txtInput for next value
step 7. If error, do the needful.
Also, you can modify the first textbox to print the barcode when user presses enter key (so, no need to click on Print button)
So, after above modifications, the user will enter the text press enter (this will print barcode) then scan (as focus is already in txtVerify). If everything is fine, new value can be entered.
To reset the screen, you can provide a 'Reset' button.
Glad to help! Please remember to accept the answer if you found it helpful.

Resources