问题
I need to know how to make an animated loading sign in Perl for keeping people entertained while my program's checking for updates.
I've already tried using
print ".";
sleep(0.1);
print ".";
but that doesn't seem to work. Somebody please help me!
print ".";
sleep(0.1);
print ".";
isn't working
I just want the program to wait 1/10th of a second to print the next .
回答1:
Using Time::HiRes for sub-second timing needs, a few ways
use warnings;
use strict;
use feature 'say';
use Time::HiRes qw(sleep);
STDOUT->autoflush(1); # or $| = 1;
my $tot_sleep = 0;
# Print dots
print "Loading ";
while (1) {
$tot_sleep += sleep 0.1; print ".";
last if $tot_sleep >= 2;
}
say " done\n"; $tot_sleep = 0;
# Print "spinning" cursor while waiting
print "Loading ... ";
WAIT: while (1) {
for (qw(- \ | /)) {
print; $tot_sleep += sleep (0.1); print "\b";
last WAIT if $tot_sleep >= 2;
}
}
say "\b done\n";
# Print (overwrite) percentile completed (if you know the job size)
my $tot_percent = 0;
while ($tot_percent < 100) {
$tot_percent += 5;
print "Loading ... $tot_percent%\r";
sleep 0.1;
}
say "\n";
I simulate "completion" (of loading) by adding up waits to 2 seconds. The if checks of this time thus stand for checks of whether "loading" completed, what presumably can be done at that point in the code (if it is a separate thread/process, or if this code runs in a forked process).
For a perhaps nicer "spinner" can use
use Time::HiRes qw(sleep);
use utf8;
use open qw(:std :encoding(UTF-8));
STDOUT->autoflush(1);
print "Waiting ... ";
WAIT: {
my $tot_sleep;
while (1) {
for ('◑', '◒', '◐', '◓') {
print; $tot_sleep += sleep 0.1; print "\b";
last WAIT if $tot_sleep >= 5;
}
}
};
say "\b done";
Idea for symbols borrowed from Term::Spinner::Color.
Such "spinners" of course don't give the visual clues of how long they wait(ed), like dots do.
回答2:
The existing solutions assume you actually want to sleep/wait. They're not easily adapted to replacing the sleep/wait with actual work. My solution is for when you're you're doing actual work (e.g. loading), not just waiting for something.
use Time::HiRes qw( );
$| = 1;
{
my @syms = qw( - \ | / );
my ( $i, $t );
sub start_spinner {
$t = Time::HiRes::time;
$i = 0;
print $syms[$i];
}
sub update_spinner {
my $now = Time::HiRes::time;
return if $now - $time < 0.1; # Prevent spinner from spinning too fast.
$time = $now;
$i = ( $i + 1 ) % @syms;
print "\b$syms[$i]";
}
sub stop_spinner {
print "\b \b";
}
}
start_spinner();
for (1..500) {
update_spinner(); # Call this as often as possible.
Time::HiRes::sleep(0.01); # Simulate a little bit of work.
}
stop_spinner();
The key is using Time::HiRes's higher-resolution time (and sleep, if necessary), as well a rate limiter (return if $now - $time < 0.1;).
If you really do want to print a line of dots, the same approach can be used.
{
my $t;
sub start_spinner {
$t = Time::HiRes::time;
}
sub update_spinner {
my $now = Time::HiRes::time;
return if $now - $time < 0.1; # Prevent spinner from spinning too fast.
$time = $now;
print ".";
}
sub stop_spinner {
print "\n";
}
}
回答3:
The standard sleep function operates in integer seconds. You can use the sleep functions from Time::HiRes as a drop-in replacement that supports fractional seconds.
use strict;
use warnings;
use Time::HiRes 'sleep';
sleep 0.1;
回答4:
Yet another way, without using a module is by abusing select():
use warnings;
use strict;
$|=1;
while (1){
print '.';
select(undef, undef, undef, 0.1);
}
Or, a FreeBSD-style spinner for fun (uses a Linux system call to refresh screen. On Windows, change clear to cls):
while (1){
for (qw(- \ | / -)){
system 'clear';
print $_;
select(undef, undef, undef, 0.1);
}
}
来源:https://stackoverflow.com/questions/57011212/how-can-you-make-an-animated-loading-sign-in-perl