Forum und email

Conectando os dois

Deve estar claro agora que se você quer reagir a uma ação, você deve conectar o sinal ao manipulador de sinal que você escreveu, assim o PHP-GTK 2 pode chamar a função sempre que o sinal seja disparado. Vamos fer como você pode conectar os sinais aos manipuladores de sinal.

Existem 4 funções principais que você pode usar para conectar sinais a callbacks:

  • connect_simple
  • connect_simple_after
  • connect
  • connect_after

Os metodos *_after são usados se você quer que seus manipuladores de sinal sejam invocados depois daqueles conectados usando connect e connect_simple. Nós estaremos discutindo apenas connect_simple e connect. Os metodos *_after respectivos funcionam da mesma maneira, exceto pelo fato de que o manipulador de sinal é garantidamente chamado apenas após aqueles conectados com connect ou connect_simple tenham sido.

Conecções Simples

Primeiro nós iremos ver como conectar um sinal a um manipulador de sinal da maneira mais simples. Nós estaremos usando, você adivinhou, o metodo connect_simple.

Claro, é vital que você saiba os nomes dos sinais aos quais você quer conectar. A documentação do PHP-GTK 2 contém uma lista de todos os sinais que são importantes para um widget em particular. Uma vez que você sabe disto, é uma vez que você já tenha escrito uma função que contenha o código que você quer que seja executado quando o sinal é gerado, tudo o que você tem que fazer é:

${widget}->connect_simple('{signal-name}', '{callback-name}');
 
aonde, {widget} é o objeto ao qual você quer conectar o sinal, {signal-name} é o nome do sinal, o qual deve ser relevante para {widget}, e {callback-name} é o nome da função de callback.

Manipuladores de sinal são invocados sempre que um sinal seja gerado, por qualquer meio. Lembre-se que é possível gerar sinais atráves de funções, é assim a geração de um sinal não garante que o usuário tenha realizado uma ação.

Para tornar as coisas mais claras, vamos ver um exemplo completo. Aqui nós adicionamos um botão a janela. Quando o usuário clica no botão, a aplicação termina:

Exemplo 9.1. Uma conexão simples

<?php

$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');

$win->add($but);
$win->show_all();

$but->connect_simple('clicked', 'quit');

function quit()
{
    echo "You have quit!\n";
    Gtk::main_quit();
}

Gtk::main();

?>

É um programa muito simples. Nós criamos um botão e uma janela, adicionamos o botão a janela e os mostramos. A linha na qual estamos interessados é:

$but->connect_simple('clicked', 'quit');
 
Como você pode ver, nós conectamos o sinal "clicked" de um widget GtkButton ao manipulador de sinal chamado quit. Simples, não é? A função quit será chamada quando o sinal clicked for emitido a partir de nosso botão, ou quando o usuário clicar em nosso botão.

Você pode ver na definição da função quit que nós mostramos uma mensagem e então chamamos a função Gtk::main_quit() para sair do programa.

Multiplas Conexões

O que acontece se eu conectar o mesmo sinal duas vezes para callbacks diferentes?, Eu ouço você perguntar. Bem, os manipuladores de sinal irão simplesmente ser chamados na ordem no qual eles foram conectados.

Se qualquer um dos nossos manipuladores de sinal retornar true então mais nenhum dos manipuladores de sinal serão chamados para o sinal que esta sendo manipulado atualmente. Isto é uma maneira útil de controlar a lógica quando você tem manipuladores de sinal múltiplos.

Um exemplo para fazer as coisas claras como cristal:

Exemplo 9.2. Conexão de multiplos sinais

<?php

$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');

$win->add($but);
$win->show_all();

$but->connect_simple('clicked', 'first');
$but->connect_simple('clicked', 'second');
$but->connect_simple('clicked', 'third');

function first()
{
    echo "I am the first function!\n";
}

function second()
{
    echo "I am the second function!\n";
}

function third()
{
    echo "And I'm the function that's going to stop this program!\n";
    Gtk::main_quit();
}

Gtk::main();

?>
Execute o programa e você verá que os manipuladores de sinal são invocados na ordem que foram conectados.

Certo, mas se eu conectar o sinal ao mesmo callback uma centena de vezes? O callback será invocado uma centena de vezes. Mas não existe razão para alguem queree fazer isto.

Posso conectar multiplos sinais para o mesmo callback? Sim, e de fato isso é muito útil. Várias aplicações terão multiplas maneiras de sair de um programa: o botão de fechar normal, um item "sair" no menu arquivo, etc. Você pode conectar sinais para cada um deles para uma unica função sair. Você não tem que se preocupar da onde o sinal veio, você apenas sabe que o usuário quer sair da aplicação.

Personalizando Conexões

Algumas vezes, é útil saber qual widget disparou um sinal em particular. Se sua aplicação tem mais de um botão, e você conectou todos os sinais clicked deles para um único callback, você definitivamente quer saber de qual botão o sinal veio. É fato que é eficiente escrever um único manipulador de sinal para multiplos sinais.

Aqui é aonde o metodo connect vem para a foto. Este metodo passa o objeto do widget que gerou o sinal como o primeiro parâmetro do manipulador de sinal.

$button1 = new GtkButton('Primeiro');
$button2 = new GtkButton('Segundo');

$button1->connect('clicked', 'show');
$button2->connect('clicked', 'show');

function show($whichbutton)
{
    echo $whichbutton->get_label();
}
 
No exemplo acima, você terá como saída "Primeiro" ou "Segundo" dependendo de qual botão foi clicado.

Também é útil algumas vezes se você puder passar parâmetros para os seus manipuladores de sinal. O PHP-GTK 2 provê esta funcionalidade nos metodos connect e connect_after. Você pode simplesmente passar os seus parâmetros depois dos seus argumentos para ambos os metodos separados por vírgulas como por exemplo:

Exemplo 9.3. Passando parâmetros personalizados

<?php

$win = new GtkWindow();
$but = new GtkButton('Move over me!');

$win->add($but);
$win->show_all();

$win->connect_simple('destroy', array('gtk', 'main_quit'));
$but->connect_simple('enter-notify-event', 'showMessage', true, 'You moved the mouse');
$but->connect_simple('leave-notify-event', 'showMessage', false, 'You moved the mouse');

function showMessage($enter, $message)
{
    if ($enter) {
        echo $message." over the button!\n";
    } else {
        echo $message." away from the button!\n";
    }
}

Gtk::main();

?>
Neste exemplo, nós passamos dois parâmetros personalizados para o nosso manipulador de sinal que ajuda-nos a diferenciar quando o mouse entrou no botão ou deixou-o. Note que o nossos parâmetros personalizados podem ser de qualquer tipo: string, boleano, inteiro, um array ou até mesmo um objeto, contando que sejá um tipo válido no PHP. De fato, é uma necessidade muito comum passar objetos de widgets como parâmetros para manipuladores de sinal, porque um callback conectado a um sinal disparado por algum widget pode necessitar modificar outro widget. Você pode passar quantos parâmetros personalizados quanto quiser. Apenas certifique-se que o seu manipulador de sinal é designado para receber o mesmo número de parâmetros, ou você terá avisos.

Para maiores informações sobre sinais como enter-notify-event, veja a seção sobre eventos, porque tem mais sobre isso do que seus olhos podem ver.

Conexões Orientadas a Objeto

Vamos ver uma linha que você deve ter visto frequentemente:

$window->connect_simple('destroy', array('gtk', 'main_quit'));
 
Porque um array como segundo argumento?

Lembre-se de que em qualquer lugar que você conectar funções de callback em um contexto orientado a objetos, o segundo argumento das funções connect_* devem ser uma matriz. O primeiro elemento da matriz deve apontar para a classe que contém o callback e o segundo elemento deve conter o nome do callback em sí.

Quando o callback é estatico por natureza (como Gtk::main_quit()), nós geralmente especificamos o nome da classe como uma string. Entretanto, se o callback não é estatico por natureza, mas é menbro da classe atual, o primeiro elemento deve ser a variável especial $this. De uma olhada no tutorial Programação Orientada a Objeto para exemplos de utilização neste contexto. O ponto é de alguma maneira fazer o primeiro elemento da array apontar para a classe que contém o callback e o segundo elemento apontar para o callback.