Интерфейсы в перл (Tk)
Решил немного попрактиковаться в написании скриптов с интерфейсом на perl.
Начать решил с базового модуля - Tk (да я знаю про Qt, но решил использовать Tk).
В качестве примера реализовал скрипт, который скачивает композиции из пользовательской библиотеки Last.fm
В итоге скрипт будет выглядеть примерно так:
Итак начнем. Сначала подключим необходимые модули:
1 2 3 4 5 6 7 8 9 |
use strict; #По просьбам трудящихся use warnings; use IO::Socket; use Tk; #Основной модуль Tk use Tk::ProgressBar; #Модуль прогресс-бара use Tk::HList; #Модуль для создания иерархического списка use Tk::LabFrame; #Модуль для создания рамки с заголовком use Digest::MD5 qw(md5_hex); #Необходим, т.к. пароль передается в виде хеша use encoding 'utf-8'; #Чтобы избежать проблем с кодировкой в окне |
Для начала несколько переменных, которые понадобятся далее
1 2 3 |
$|=1; my $percent_done; #Процент заполнения прогресс-бара my %buf = (); #Ассоциативный массив для хранения списка треков |
Теперь создадим окно и разместим необходимые элементы управления
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#Создаем объект окна и устанавливаем заголовок my $main = MainWindow->new(title => "LastFM library downloader"); #Отключаем масштабируемость $main->resizable(0,0); #Задаем размеры $main->geometry("378x230"); #Рамка для таблицы со списком треков my $lframe = $main->LabFrame( -label => "Tracklist", #Заголовок рамки -height => 130, #Высота рамки -width => 353, #Ширина рамки )->place( -x => 8, -y => 28); #Положение на форме #Рамка для прогресс-бара my $pframe = $main->LabFrame( -label => "Progress", -height => 20, -width => 283, )->place( -x => 8, -y => 185); #Прогресс-барр my $progress = $pframe->ProgressBar( -width => 15, -length => 282, -from => 0, #Минимальное значение прогресс-бара -to => 500, #Максимальное -blocks => 25, #Количество блоков(на которые будет разделен прогресс-бар) -gap => 1, #Расстояние между блоками -variable => \$percent_done, #Переменная задающая % заполненности -colors => [0, 'green'], #Цвет полосы (начиная с 0) )->place(-x => 1, -y => 0); |
Создадим и заполним таблицу для композиций
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#Заголовки столбцов таблицы my @headers = ( "ID", "Artist", "Track name", "Size"); #Непосредственно таблица my $grid = $lframe->Scrolled( 'HList', -head => 1, #Устанавливает наличие заголовков столбцов -columns => scalar @headers, #Количество столбцов -scrollbars => 0, #Наличие полосы прокрутки -width => 58, -height => 10, -background => 'white', #Цвет фона )->grid(-column => 1, -row => 0,)->place(-x => 0, -y => 0); #Поместим заголовки в таблицу for(0..scalar @headers - 1) { $grid->header( 'create', $_, #Порядковый номер -text => $headers[$_], #Текст заголовка -headerbackground => 'gray', #Цвет фона заголовка ); } |
Далее размещаем элементы управления, кнопки и поля для ввода логина, пароля.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#Подписи к полям для ввода $main->Label( -text => 'Login:', )->place( -x => 10, -y => 10); $main->Label( -text => 'Password:', )->place( -x => 145, -y => 10); #Поле для ввода логина my $log = $main->Entry( -width => 15, )->place( -x => 45, -y => 10); #Поле для ввода пароля my $pwd = $main->Entry( -width => 15, -show =>'*', #Символ маскирующий вводимые символы )->place( -x => 200, -y => 10); #Кнопка для получения списка композиций $main->Button( -text => 'Get list', #Текст кнопки -command => sub {dopre($log->get, $pwd->get)}, #функция выполняемая при нажатии на кнопку #Соотвественно при нажатии берутся данные, которые были введены в поля логин, пароль и передаются #в функцию dopre )->place(-x => 327, -y => 8); #Кнопка для скачивания выбранного трека $main->Button( -text => 'Download', #Текст кнопки -command => sub {getit($grid->selectionGet())}, #Порядковый номер выбранного элемента в списке передается в функцию getit )->place(-x => 310, -y => 200); MainLoop; |
Опишем функции используемые в программе
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
#Вообще можно соединить эту функцию и функцию getmp3, но неважно sub getit { my $id = $_[0]; #Присваиваем переменной $id значение первого параметра переданного функции if(defined $id && $id =~ /^\d+/) #Проверяем существование и корректность полученного значения { #А тут наверное лучше использовать fork, чтобы исключить подтормаживание главного окна и дать возможность одновременно качать несколько треков getmp3($buf{$id}); #Передаем в функцию getmp3 выбранный элемент из ассоциативного массива } } #Функция для заполнения таблицы композициями sub dopre { my $session = doauth($_[0], $_[1]); #Получим значение сессии, для этого передадим в функцию doauth логин и пароль pre($session); # my %list = list($session); #Получаем список композиций my $lnum = 0; #Переменная для нумерации строк в таблице $grid->delete('all'); #Предварительно очистим таблицу (необходимо в случае нескольких получений списка) foreach my $key (keys %list) #Цикл по элементам списка list { $lnum++; $grid->add($lnum); #Добавляем строку c идентификатором $lnum my ($name, $size) = split /::/, $key; #Разделяем идентификатор трека и размер #print "$lnum - $name [$size kb]\n"; $buf{$lnum} = $list{$key}."::".$key; #Заносим параметры в ассоциативный массив my ($artist, $track) = split / - /, $name; #Разделяем идентификатор трека на исполнителя и название композиции my @list = ($lnum, $artist, $track, $size." kb"); #Создаем массив для последующего внесения в таблицу for(0..scalar @list - 1) { $grid->itemCreate( $lnum, $_, -text => $list[$_] ); #Добавляем элементы в таблицу } } } #Функция для авторизации в сервисе sub doauth { my $login = $_[0]; my $passw = $_[1]; my $sock = sock("ws.audioscrobbler.com"); #Соединяемся с адресом ws.audioscrobbler.com my $request = "GET /radio/handshake.php?version=1.5.4.24567&platform=win32&platformversion=Windows%20XP&username=".$login."&passwordmd5=".md5_hex($passw)."&language=ru&player=winamp HTTP/1.1\r\n". "Host: ws.audioscrobbler.com\r\n\r\n"; #Формируем необходимый запрос print $sock $request; #Выполняем запрос к сервису read $sock, my $answ, 1024; #Читаем часть ответа if($answ =~ /Set-Cookie: Session=(.+?);/) #Парсим значение сессии { return $1; #Возвращаем значение сессии } else { return 0; } } #Функция для соединения с сервером sub sock { my $sock = new IO::Socket::INET ( PeerAddr => $_[0], #Адрес сервера PeerPort => 80, #Номер порта PeerProto => 'tcp', #Протокол TimeOut => 10, #Таймаут соединения ) or die "Can't connect\n"; return $sock; } #Функция для скачивания mp3 файла с сервера sub getmp3 { my ($url, $name, $size) = split /::/, $_[0]; my $sock = sock("play.last.fm"); my $request = "GET $url HTTP/1.1\r\n". "Host: play.last.fm\r\n". "User-Agent: Last.fm Client 1.5.4.24567 (Windows)\r\n\r\n"; print $sock $request; read $sock, my $answ, 512; close $sock; $answ =~ /Location: (.+)/s; my $rurl = $1; #Парсим адрес редиректа (на прямой линк до mp3 файла) $rurl =~ /http:\/\/(.+?)\//; my $host = $1; #Парсим хост $sock = sock($host); $request = "GET $rurl HTTP/1.1\r\n". "Host: $host\r\n". "User-Agent: Last.fm Client 1.5.4.24567 (Windows)\r\n\r\n"; print $sock $request; $answ = undef; print "Starting download: ".$name."\n"; my $bufsize = 2048; #Количество байт читаемое за раз из сокета my $step = $size / 500; #Устанавливаем размер шага прогресс-бара my $cnt = 0; #Переменная для подсчета прогресса скачивания open F, ">", $name.".mp3" || die $!; #Открываем файл для последующей записи binmode F; #Переключаем в бинарный режим while(read $sock, my $buf, $bufsize) #Цикл чтения из сокета { my $progress = ($cnt * $bufsize / 1024); $percent_done = int $progress / $step; #Задаем % заполнния прогресс-бара (можно объединить с предыдущей строкой) $main->update; #Обновляем окно (иначе окно "подвиснет" до момента завершения скачивания) $cnt++; print F $buf; #Пишем полученные данные в файл print "[Received: ".$progress." of ".$size." kb]\r"; } print "\nDownload Complete!"; close F; } #Функция для проверки доступности сервиса sub pre { my $session = $_[0]; my $sock = sock("ws.audioscrobbler.com"); my $request = "GET /radio/adjust.php?session=".$session." HTTP/1.1\r\n". "Host: ws.audioscrobbler.com\r\n". "User-Agent: Last.fm Client 1.5.4.24567 (Windows)\r\n\r\n"; print $sock $request; read $sock, my $answ, 512; close $sock; if($answ =~ /response=(.+?)\n(.+?)stationname=(.+)/s) { if($1 eq "OK") { print "Response: $1 ; Station: $3\n"; } else { print "Response: $1 \n"; } } } #Функция для получения списка композиций sub list { my $session = $_[0]; my $sock = sock("ws.audioscrobbler.com"); my $request = "GET /radio/xspf.php?sk=".$session."&discovery=1&desktop=1.5.4.24567 HTTP/1.1\r\n". "Host: ws.audioscrobbler.com\r\n". "User-Agent: Last.fm Client 1.5.4.24567 (Windows)\r\n\r\n"; print $sock $request; my $answ = undef; while(read $sock, my $buf, 1024) { $answ .= $buf; } my %list = (); close $sock; #Парсим url, название трека, исполнителя и длительность while($answ =~ /(.+?)<\/location>(.+?)(.+?)<\/title>(.+?)(.+?)<\/creator>(.+?)(.+?)<\/duration>/sg) { #Размер вычисляется примерно , возможно несоответствие в 10-100 кб #Для точно вычисления надо посмотреть сколько занимает 1 секунда звучания #в соответствии с используемым аудиокодеком my $size = ($7 / 1000) * 16 - 50; $list{"$5 - $3::$size"} = $1; } return %list; } |
Скачать исходник одним файлом можно тут: lastfm.txt
P.S. Код далеко не идеален, но щито поделать...
Я мечтаю, когда на Python уже сделают нормальный Tk - под виндой есть еще Tix, но бля под линухом(мну собирал Питон 2.6 из исходников) их тоже нужно качать вместе с Tcl/tk :( А также мечтаю когда увижу ttk в стандартной поставке (в py3k уже есть) По сабжу то тоже недавно писал, правда на том же питоне скрипт с Гуем и тоже на Тк - получилось кривовато, но мну радует что вообще хоть что-то получилось :) А так однозначно плюс за Гуй, и моя имха такова - всякие Qt должны быть исключительно Гуевыми либами, а не тем чем они сейчас являются. Слишком там дохера лишнего
Библиотека гавно сама по себе..
Надо использовать Qt4
Tk супер самая интуитивно понятная GUI
А можно готовую программулину выложить?
Можно, выкладывайте
Да не не Вы выложите как на скриншоте и код допилите а то я каким то перл отладчиком проверял и там туева хуча ошибок и неполучилось себе скомпилить
У меня нет перл отладчика, только перл дизассемблер, под ним все ок работает
А чем скомпилить чтобы был .exe и работало?
Это же скрипт, зачем его в exe компилировать? А так были программы типа perlapp и perl2exe, только я ими не пользовался можно сказать
Вы меня простите пожалуйста, но как его запустить? Что для этого скачать и какое расширение должно быть у файла?
Скачать, например, ActivePerl.
.pl
Блин, сделайте лучше из скрипта простой и понятный exe файл :/
Зачем? Это вообще статья про программирование, а не статья-релиз
Шоп люди могли тоже пользоватся, тем кому программирование ненужноа нужна хорошая софтинка для lastfm
Я скачала его, и расширение поставила нужное. Но ничего не происходит. Просто при запуске файла возникает черное окошко и тут же исчезает. Поэтому я и спросила.
Все, спасибо, я нашла как его запустить через консоль.
Несёте компьютерную грамотность в массы. Перепробовала 3 версии ActivePerl, пока не нашла нужную, потом понадобилось установить модуль Tk, нашла как, установила. И наконец работает! Ура! В следующий раз будет легче.
Скиньте готовый файл пожалуйста, у меня не получается скомпилировать, разные ошибки в коде дает, например:
C:\Documents and Settings\Admin\Мои документы\p2x-11.00-Win\perl2exe-11.00-Win>p
erl2exe.exe -gui lastfm.pl
Error: Can't open source file
Backslash found where operator expected at C:\Documents and Settings\Admin\Мои д
окументы\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1, near "Settings\"
syntax error at C:\Documents and Settings\Admin\Мои документы\p2x-11.00-Win\perl
2exe-11.00-Win\_main.pl line 1, near "Settings\"
Backslash found where operator expected at C:\Documents and Settings\Admin\Мои д
окументы\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1, near "Admin\"
Unrecognized character \214 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \256 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \250 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \244 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \256 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \252 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \343 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \254 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \245 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \255 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \342 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Unrecognized character \353 ignored at C:\Documents and Settings\Admin\Мои докум
енты\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1.
Backslash found where operator expected at C:\Documents and Settings\Admin\Мои д
окументы\p2x-11.00-Win\perl2exe-11.00-Win\_main.pl line 1, near "Win\"
Execution of C:\Documents and Settings\Admin\Мои документы\p2x-11.00-Win\perl2ex
e-11.00-Win\_main.pl aborted due to compilation errors.
C:\Documents and Settings\Admin\Мои документы\p2x-11.00-Win\perl2exe-11.00-Win>
Также делал cpan Tk
Все скачало, а под конец dmake не является внутренней командой файлом лалала.
Чесно, уже 3 подхода было скомпилировать это, ну никак - ошибки ошибки ошибки.
А зачем это "компилировать"?
Ура, наконец то. Все просто.
1)Качаем ActivePerl (http://www.activestate.com/activeperl/downloads)
2)Пуск -> Выполнить -> cmd -> cd c:\perl\bin
3)Потом пишем в том же окне: ppm install http://www.bribes.org/perl/ppm/Tk.ppd
4)Копируем lastfm.pl в папку c:\perl\bin
5) Пишем в консоли: perl.exe lastfm.pl
6) Видим окно программы :3
Microsoft Windows XP [Версия 5.1.2600]
(С) Корпорация Майкрософт, 1985-2001.
C:\Documents and Settings\Админ>perl.exe lastfm.pl
Can't open perl script "lastfm.pl": No such file or directory
C:\Documents and Settings\Админ>cd c:\perl\bin
C:\Perl\bin>perl.exe lastfm.pl
No such class F at lastfm.pl line 184, near "open my F"
syntax error at lastfm.pl line 184, near "my F,"
Bareword "MainLoop" not allowed while "strict subs" in use at lastfm.pl line 85.
Execution of lastfm.pl aborted due to compilation errors.
C:\Perl\bin>
Кстате печально что нету рабочего exe варианта програмки а только трах с каким то Perl
Тут, кажется, уже отписывали, что статья - мануал по тому, как использовать Tk в Perl, а не готовый софт...