Forum und email

Alô Mundo (avançado)

Este tutorial lida com alguma funcionalidade mais avançada que o primeiro tutorial Alô mundo. Aqui, nós criamos uma tela de login na qual o usuário pode escrever o seu nome de usuário e senha. Quando o usuário clica no botão login, os campos de texto são conferidos e uma mensagem de erro é exibida se o usuário esqueceu o seu nome de usuário ou senha.

Aqui esta uma captura de tela de como o programa vai parecer quando estiver terminado:

Primeiro, nós criamos uma janela, definimos o seu titulo e dizemos que loop principal deve ser encerado quando a janela for destruída - você já conhece isso do primeiro tutorial:

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

A próxima tarefa é criar todos os widgets que vamos precisar neste dialogo: a principio, dois campos de texto para o nome de usuário e a senha:

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

Então nós queremos que o usuário saiba qual campo de texto é a senha e qual é o nome de usuário, então nós precisamos de labels descritivos:

//O segundo parâmetro diz que underscore( _ ) deve ser interpretado como sublinhado
$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);

E por fim, nós precisamos de dois botões: um para o login, e outro para cancelar o processo:

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

Você deve notar que o construtor de GtkLabel teve um segundo parâmetro passado, para dizer que o underscore _ é exibido como sublinhado no próximo caractere, mas isso não é feito no construtor de GtkButton: O construtor do botão faz isto automaticamente, enquanto o do label não faz. Este funcionamento pode ser estranho para você, mas é mais comum que você tenha um mnemonic no label do botão do que um label normal tenha.

Agora os labeis precisam saber qual widget precisa ser ativado quando eles são ativados usando o mnemonic. Isto é feito desta maneira:

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

Além disso, nós precisamos determinar qual ação é feita quando os botões são clicados. O botão cancel deve destruir a janela(assim terminado a aplicação) e o botão login deve conferir os campos de texto e tomar a ação posterior:

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

Nós precisamos passar três widgets $wnd, $txtUsername e $txtPassword como parâmetros opcionais para a função (ainda a ser definida) login, porque nós vamos precisar deles lá: Para obter os valores dos campos de texto, e para destruir/esconder a janela se tudo estiver certo.

Agora que nós temos todos os widgets que precisamos, eles são adicionados na janela. Já que GtkWindow é um container to tipo bin, ele pode guardar apenas um widget. então nós precisamos de um container que possa guardar vários widgets e fazer o layout dos elemento bonito. A decisão vai para GtkTable, porque ele provê um meio de manter os labeis em uma coluna, e os campos de entrada de texto em outra:

$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);

(O $lblCredit é apenas um label com uma mensagem). Os botões tem o seu próprio GtkHButtonBox, porque esta classe permite fazer o layout de vários botões de maneira muito bonita:

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

A ultima coisa no layout é adicionar a tabela e a caixa de botões na janela. Isto não é diretamente possível, porque GtkWindow é um GtkBin e pode ter apenas um unico widget filho, nós precisamos de um outro container, desta vez um GtkVBox:

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

Isto deve ser tudo, e nós podemos mostrar a janela:

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

A ultima coisa que esta faltando é a função login que é chamada quando o usuário clica no botão login. Ela deve conferir o valor dos campos com o nome de usuário e senha: Se o seu tamanho for 0 (o usuário não digitou nada neles), uma mensagem de erro será exibida. Se tudo estiver correto, a janela será destruída e o programa pode continuar carregando a janela principal.

Obtendo o texto dos widgets é muito simples, nós apenas usamos o metodo get_text() de GtkEntry:

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

A conferencia é feita atravéz da função normal do php strlen. Se ocorrer um erro, nós queremos mostrar uma caixa de mensagem com uma pequena mensagem. GtkMessageDialog é ideal para isso, já que ela cria automaticamente os icones e botões (Ok, Yes/No):

$dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
$dialog->set_markup("The following errors occured:\r\n<span foreground='red'>" . $errors . "</span>");
$dialog->run();
$dialog->destroy();

Agora tenha certesa de colocar a função login antes(!) do loop principal e execute-o.

Exemplo 3.1. O programa completo

<?php
/**
*   Here we create a login window.
*   It has a username and a password field, and a
*   Cancel and Login button. Some error checking
*   is being done when the user clicks "Login".
*/

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

/**
*   This function gets called as soon as the user 
*   clicks on the Login button.
*
*   @param GtkWindow $wnd           The login window, needed to close it
*                                    when all is ok
*   @param GtkEntry $txtUsername    The username text field, used to get
*                                    the username
*   @param GtkEntry $txtPassword    The password widget to retrieve the
*                                    password
*/
function login(GtkWindow $wnd, GtkEntry $txtUsername, GtkEntry $txtPassword)
{
    //fetch the values from the widgets into variables
    $strUsername = $txtUsername->get_text();
    $strPassword = $txtPassword->get_text();

    //Do some error checking
    $errors = null;
    if (strlen($strUsername) == 0) {
        $errors .= "Username is missing.\r\n";
    }
    if (strlen($strPassword) == 0) {
        $errors .= "No password given.\r\n";
    }

    if ($errors !== null) {
        //There was at least one error.
        //We show a message box with the errors
        $dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
        $dialog->set_markup(
            "The following errors occured:\r\n"
            . "<span foreground='red'>" . $errors . "</span>"
        );
        $dialog->run();
        $dialog->destroy();
    } else {
        //No error. You would need to hide the dialog now
        //instead of destroying it (because when you destroy it,
        //Gtk::main_quit() gets called) and show the main window
        $wnd->destroy();
    }
}

//Create the login window
$wnd = new GtkWindow();
$wnd->set_title('Login');
//Close the main loop when the window is destroyed
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));


//Set up all the widgets we need
$lblCredit   = new GtkLabel('Please provide your data');
//The second parameter says that the underscore should be parsed as underline
$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);
$txtUsername = new GtkEntry();
$txtPassword = new GtkEntry();
$btnLogin    = new GtkButton('_Login');
$btnCancel   = new GtkButton('_Cancel');


//Which widget should be activated when the 
// mnemonic (Alt+U or Alt+P) is pressed?
$lblUsername->set_mnemonic_widget($txtUsername);
$lblPassword->set_mnemonic_widget($txtPassword);
//Hide the password
//$txtPassword->set_invisible_char('*');

//Destroy the window when the user clicks Cancel
$btnCancel->connect_simple('clicked', array($wnd, 'destroy'));
//Call the login function when the user clicks on Login
$btnLogin->connect_simple('clicked', 'login', $wnd, $txtUsername, $txtPassword);


//Lay out all the widgets in the table
$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);


//Add the buttons to a button box
$bbox = new GtkHButtonBox();
$bbox->set_layout(Gtk::BUTTONBOX_EDGE);
$bbox->add($btnCancel);
$bbox->add($btnLogin);


//Add the table and the button box to a vbox
$vbox = new GtkVBox();
$vbox->pack_start($tbl);
$vbox->pack_start($bbox);

//Add the vbox to the window
$wnd->add($vbox);
//Show all widgets
$wnd->show_all();
//Start the main loop
Gtk::main();
?>