Kurs PHP-GTK cz. 2

Już minęło sporo czasu od pojawienia się pierwszej części kursu PHP-GTK. Chciałem mocno przeprosić za to, że musieliście czekać, niestety w sporej mierze to wina mojego lenistwa…

Dzisiaj zajmiemy się czymś bardziej skomplikowanym. Stworzymy formularz logowania, który pokaże komunikat błędu jeśli wpiszemy złe hasło/login.


Screeny

Free Image Hosting at www.ImageShack.us Free Image Hosting at www.ImageShack.us Free Image Hosting at www.ImageShack.us

Zaczynamy

Na początku tworzymy nowy obiekt-okno, nadajemy mu tytuł, oraz tworzymy proste dowiązanie przerywające główną pętlę (Gtk::main).

<?php
$wnd = new GtkWindow();
$wnd->set_title('Login');
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));
?>

Później tworzymy dwa pola, do których będziemy mogli wpisać login i hasło. Podobnie jak w wypadku labela tworzymy dwie zmienne, które będą po prostu obiektami.

$txtUsername = new GtkEntry();
$txtPassword = new GtkEntry();

Dodatkowo do tych pól stwórzmy etykietki, aby rozróżnić oba pola.

$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);

Zwróćcie uwagę, że dodano jeszcze drugi parametr. Jest on opcjonalny, a gdy jest ustawiony na true, to literka przed którą będzie znak ‘_’, będzie podkreślona.

Pozostało nam jeszcze stworzenie dwóch przycisków – “Login” i “Cancel”.

$btnLogin    = new GtkButton('_Login');
$btnCancel   = new GtkButton('_Cancel');

W odróżnieniu od GtkLabel(), w przypadku GtkButton() nie musimy podawać drugiego parametru aby kolejna litera po ‘_’ była podkreślona.

Teraz ustawimy połączenie pomiędzy GtkLabel, a GtkEntry. Ktoś się spyta, co to takiego? Już tłumaczę. To podkreślenie, które ustwiliśmy jest niczym innym jak skrótem klawiszowym. Po wciśnięciu kombinacji [Alt]+[u] pole Username zostanie aktywowane, podobnie jest z drugim polem. Aby stworzyć takie połączenie wykorzystujemy metodę set_mnemonic_widget.

$lblUsername->set_mnemonic_widget($txtUsername);
$lblPassword->set_mnemonic_widget($txtPassword);

Pozostaje nam jeszcze najważniejsze. Ustawienie odpowiednich zdarzeń, które muszą nastąpić po wciśnięciu na Buttony.

$btnCancel->connect_simple('clicked', array($wnd, 'destroy'));
$btnLogin ->connect_simple('clicked', 'login', $wnd, $txtUsername, $txtPassword);

Po wciśnięciu “Cancel” program po prostu się wyłączy. Po wciśnięciu “Login” zostanie wywołana (jeszcze nie opisana) funkcja “login”, zmienne $wnd, $txtUsername, $txtPassword są po prostu parametrami przesyłanymi do funkcji.

Już wcześniej wspominałem, że okno może trzymać bezpośrednio tylko jeden widżet. Rozwiązaniem są różne kontenery, które wszystko przetrzymują wewnątrz, a potem są “doklejane” do głównego okna. W tym wypadku posłużymy się GtkTable, które w przejrzysty sposób utrzyma nasze widżety (zmienna $lblCredit, będzie jedynie przechowywała krótki komunikat).

Aby zamieścić nasze widżety w tabelkę należy wykonać coś takiego:

$tbl = new GtkTable(3, 2);
$tbl->attach($lblCredit, 0, 2, 0, 1);
$tbl->attach($lblUsername, 0, 1, 1, 2);
$tbl->attach($txtUsername, 1, 2, 1, 2);
$tbl->attach($lblPassword, 0, 1, 2, 3);
$tbl->attach($txtPassword, 1, 2, 2, 3);

Niestety umieszczanie elementów w tabeli wydaje się IMO wyjątkowo udziwnione. Żeby to jakoś ułatwić, postaram się króciutko wyjaśnić co oznaczają kolejne parametry.

void attach(GtkWidget child, int left_attach, int right_attach, int top_attach, int bottom_attach [, GtkAttachOptions xoptions = Gtk::EXPAND|Gtk::FILL [, GtkAttachOptions yoptions = Gtk::EXPAND|Gtk::FILL [, int xpadding = Gtk::EXPAND|Gtk::FILL [, int ypadding = Gtk::EXPAND|Gtk::FILL]]]]);

Taki jest początek opisu tej metody. Nie chcę straszyć nikogo także wytłumaczę tylko czym są te cyferki ;-)

int left_attach – oznacza miejsce od lewej strony
int right_attach – oznacza miejsce od prawej strony
int top_attach – oznacza miejsce od góry
int bottom_attach – oznacza miejsce od dołu

Możliwe, że źle zrozumiałem sposób umiejscowienia w tabelce elementów, także poprawcie mnie jeśli się mylę.

Przyciski dostaną swój własny kontener.

$bbox = new GtkHButtonBox();
$bbox->set_layout(Gtk::BUTTONBOX_EDGE);
$bbox->add($btnCancel);
$bbox->add($btnLogin);

Stworzyliśmy dwa osobne kontenery, ale główne okno, może mieć “przyczepiony” tylko jeden widżet, także oba kontenery dodamy do kolejnego.

$vbox = new GtkVBox();
$vbox->pack_start($tbl);
$vbox->pack_start($bbox);

Dopiero teraz możemy dodać nasze widżety na główne okno (konkretniej dodajemy kontener, który przechowuje wszystkie widżety).

$wnd->add($vbox);
$wnd->show_all();
Gtk::main();

Teraz pozostaje nam zapis funkcji logowania. Jeśli jakieś z pól pozostanie puste, wyświetli się komunikat o błędzie. Jeśli uda nam się zalogować to dostaniemy komunikat, że wszystko jest ok, po czym program się wyłączy.

Aby wyciągnąć zawartość pól “Username” i “Password”, posługujemy się metodą get_text() dołączoną do klasy GtkEntry.

$strUsername = $txtUsername->get_text();
$strPassword = $txtPassword->get_text();

Poprawność wpisanego tekstu sprawdzamy poprzez zwykłe funkcje PHP (nie zapominajcie, że to jest tylko dodatek do PHP ;-] ).

W celu wyświetlenia okna dialogowego wystarczy wpisać:

$dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
$dialog->set_markup("W I A D O M O S C");
$dialog->run();
$dialog->destroy();

Na koniec załączam gotowy kod (można go również pobrać z phpfi):

<?php
if (!class_exists('gtk')) {
    die("Please load the php-gtk2 module in your php.ini\r\n");
}

/**
*   Ta funkcja zostaje wywołana po kliknieciu buttona "Login"
*
*   @param GtkWindow $wnd           Okno logowania, potrzebne, zeby je pozniej 
*                                   zamknac
*   @param GtkEntry $txtUsername    Pole tekstowe, potrzebny zeby wyciagnac 
*                                   tekst
*   @param GtkEntry $txtPassword    Tak samo jak wyzej
*/

function login(GtkWindow $wnd, GtkEntry $txtUsername, GtkEntry $txtPassword)
{
    //pobranie wartosci pol tekstowych
    $strUsername = $txtUsername->get_text();
    $strPassword = $txtPassword->get_text();
 
    //sprawdzanie potrzebnych rzeczy
    $errors = null;
    if (strlen($strUsername) == 0) {
        $errors .= "Brakuje nazwy uzytkownika.\r\n";
    }
    if (strlen($strPassword) == 0) {
        $errors .= "Brakuje hasla.\r\n";
    }
 
    if ($errors !== null) {
        //Jesli byl przynajmniej blad to powinno sie pokazac okno dialogowe
        $dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
        $dialog->set_markup(
            "Wystapily pewne problemy:\r\n"
            . "<span foreground='red'>" . $errors . "</span>"
        );
        $dialog->run();
        $dialog->destroy();
    } else {
        $msg = "Witaj $strUsername!\r\n";
        $msg .= "Twoje magiczne haslo to: $strPassword ;-]";

        $dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK, $msg);
        $dialog->set_markup($msg);
        $dialog->run();
        $dialog->destroy();
        $wnd->destroy();
    }
}
 
$wnd = new GtkWindow();
$wnd->set_title('Login');
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));

// stworzenie pol tekstowych
$txtUsername = new GtkEntry();
$txtPassword = new GtkEntry();

// stworzenie etykiet
$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);
$lblCredit = new GtkLabel('Please login');

// stworzenie buttonow
$btnLogin    = new GtkButton('_Login');
$btnCancel   = new GtkButton('_Cancel');

// ustawienie skrotow klawiszowych
$lblUsername->set_mnemonic_widget($txtUsername);
$lblPassword->set_mnemonic_widget($txtPassword);

// polaczenie zdarzen
$btnCancel->connect_simple('clicked', array($wnd, 'destroy'));
$btnLogin ->connect_simple('clicked', 'login', $wnd, $txtUsername, $txtPassword);

// stworzenie tabelki
$tbl = new GtkTable(3, 2);
$tbl->attach($lblCredit, 0, 2, 0, 1);
$tbl->attach($lblUsername, 0, 1, 1, 2);
$tbl->attach($txtUsername, 1, 2, 1, 2);
$tbl->attach($lblPassword, 0, 1, 2, 3);
$tbl->attach($txtPassword, 1, 2, 2, 3);

// kontener na przyciski
$bbox = new GtkHButtonBox();
$bbox->set_layout(Gtk::BUTTONBOX_EDGE);
$bbox->add($btnCancel);
$bbox->add($btnLogin);

// kontener przechowujacy tabelke i buttony
$vbox = new GtkVBox();
$vbox->pack_start($tbl);
$vbox->pack_start($bbox);

$wnd->add($vbox);
$wnd->show_all();
Gtk::main();
?>

Przypominam, że póki co ten kurs jest jedynie tłumaczeniem oficjalnego kursu, którego można znaleźć na stronie php.net

12 Responses to “Kurs PHP-GTK cz. 2”

  1. Walker September 2, 2007 at 1:11 pm #

    Hmm… stosuj Boxy zamiast tabel, a dobrze na tym wyjdziesz ;) . Zarowno semantycznie jak i wygodowo. Wiem, bo sam sie przekonałem (choć to było w Pythonie a nie PHP).

  2. radmen September 2, 2007 at 1:11 pm #

    Hmm w jakim sensie semantycznie? :>

  3. Walker September 2, 2007 at 1:11 pm #

    Hmm.. no można porównać tabelki z GTK do tabelek w HTML, oraz analogicznie boxy do divów, rozumiesz :) ? Kiedyś czytałem na ten temat artykuł, ale nie mam pojęcia gdzie.

  4. radmen September 2, 2007 at 1:11 pm #

    Taka tabelka jaką przedstawiłem, raczej jest trudna do porównania do tej z HTMLa ;-)

  5. Walker September 2, 2007 at 1:11 pm #

    Zamiast tej tabeli, co w nią wrzuciłeś labels i entries dajesz boxy.

  6. D4rky September 2, 2007 at 1:11 pm #

    GTK jest ostro popieprzone jesli chodzi o ukladanie elementow. Probowalem juz kiedys zrobic jakas aplikacje, i sie poddalem. Innym razem ;)

  7. Amused Monkey September 2, 2007 at 1:11 pm #

    Shoes w Ruby on Rails rlz, serio. Rzuć to PHP-GTL ;-D

  8. Livio September 2, 2007 at 1:11 pm #

    W GTK podoba mi się właśnie pomysł układania elementów w tabelki – ideologicznie poprawne ;) .

    W Windows wszystko ustawia się co do piksela i jest to moim zdaniem niewygodne…

  9. Walker September 2, 2007 at 1:11 pm #

    Probowałeś zrobić kiedyś całość na boxach zamiast tabelek?

  10. Livio September 2, 2007 at 1:11 pm #

    VBox/HBox masz na myśli?

  11. Walker September 2, 2007 at 1:11 pm #

    Exactly.

  12. Livio September 2, 2007 at 1:11 pm #

    Używałem :P . Czasami nawet musiałem użyć tabelki, a w niej *Boksa :] .