Forum und email

Um pouco mais de complexidade

Nós não usamos a maioria do poderoso suporte a orientação a objetos do PHP 5 ainda. Vamos fazer uma aplicação que abra um arquivo de texto e mostre o seu conteúdo para você, uma aplicação simples parecida com o bloco de notas. Por favor note que esta é uma aplicação muito muito simples apenas para fins educativos e não tem uma funcionalidade pratica. Aqui esta o código, leia-o, e não seja intimidado pelo seu tamanho. Uma explicação detalhada segue o código:

Exemplo 8.2. Um simples bloco de nota

<?php

class Notepad extends GtkWindow
{
    protected $currentFile;
    protected $buffer;
    protected $status;
    protected $context;
    protected $lastid;

    function __construct($fileName = null)
    {
        parent::__construct();
                
        $mainBox  = new GtkVBox();
        $textBuff = new GtkTextBuffer();
        $textView = new GtkTextView($textBuff);
        $statusBar= new GtkStatusBar();

        $mainBox->pack_start($this->buildMenu(), false, false);
        $mainBox->pack_start($textView, true, true);
        $mainBox->pack_start($statusBar, false, false);

        $this->currentFile = $fileName;
        $this->buffer = $textBuff;
        $this->status = $statusBar;

        $this->connect_simple('destroy', array($this, 'quit'));
        $this->set_title('Simple Notepad');
        $this->maximize();
        $this->add($mainBox);
        $this->show_all();

        $this->loadFile();
    }

    function buildMenu()
    {
        $menuBar  = new GtkMenuBar();
        $fileMenu = new GtkMenu();
        $menuName = new GtkMenuItem('_File');
        
        $quit = new GtkImageMenuItem('gtk-quit');
        $quit->connect_simple('activate', array($this, 'quit'));
        $quit->connect_simple('enter_notify_event', 
                                array($this, 'updateStatus'), 1);
        $quit->connect_simple('leave_notify_event', 
                                array($this, 'updateStatus'), 0);
        
        $fileMenu->append($quit);
        $menuName->set_submenu($fileMenu);
        $menuBar->add($menuName);

        return $menuBar;
    }
   
    function loadFile()
    {
        if($this->currentFile != null) {
            $contents = file_get_contents($this->currentFile);
            $this->buffer->set_text($contents);
        }
    }

    function updateStatus($enter)
    {
        if($enter) {
            $id = $this->status->get_context_id("Message");
            $lastMsg = $this->status->push($id, "Quits the Application");
            $this->context = $id;
            $this->lastid = $lastMsg;
        } else {
            $this->status->remove($this->context, $this->lastid);
        }
    }
    
    function quit()
    {
        Gtk::main_quit();
    }

}

new Notepad('simple.phpw');
Gtk::main();

?>

O construtor

A estrutura da classe é semelhante ao que nós vimos antes, exceto pela adição de algumas propriedades da classe e funções. Primeiro vamos dar uma olhada no construtor. O construtor leva um parâmetro opcional que o padrão é null. Este parâmetro é (caminho de) o nome do arquivo que você quer abrir. Se você não passar um parâmetro para o construtor, ele simplesmente irá abrir nada.

OK, assim nós primeiro construimos o parent (um GtkWindow) e então criamos alguns widgets que iremos usar. Um GtkVBox para o nosso layout, um GtkTextBuffer e um GtkTextView para mostrar o conteúdo do arquivo e um GtkStatusBar para mostrar algumas mensagens. Nós configuramos o layout e adicionamos os respectivos widgets para o VBox.

Próximo nós definimos as propriedades da classe:

$this->currentFile = $fileName;
$this->buffer = $textBuff;
$this->status = $statusBar;
 
Estas três linhas definem valores para as propriedades de classe. Propriedades de classe são uma parte essencial de todas as aplicações orientadas a objeto em PHP-GTK 2. Elas são úteis porque você pode precisar acessar um widget em particular em uma função na qual ele não foi criado. Quando nós criamos um widget, o escopo para o objeto é apenas a função na qual ele foi criado. Por exemplo nós criamos a barra de status no construtor da nossa classe, mas nós obviamente precisamos acessa-la em outros lugar (quando nós precisarmos colocar algumas mensagens nela). Mas já que a variável $statusBar pode ser acessada apenas no construtor, nós definimos um propriedade de classe chamada status) para ela. Agora nós podemos acessar a barra de status em qualquer função da classe usando $this->status.

Simplesmente extenda este conceito para os outros widgets também. Basicamente, você precisa definir propriedades de classes para os widgets que você acha que vai precisar em todo o escopo da classe. Ataulamente, propriedades de classes podem ser usadas eficientemente para gardar quaisquer dados que você precise em toda a classe. Um exemplo disso em nossas aplicações é a propriedade currentFile. Isto irá simplesmente guardar o caminho para o arquivo atualmente aberto, ou null se nenhum estiver. Nós podemos então saber o arquivo atualmente aberto em qualquer função da classe. Propriedades de classe tem outros usos também, um dos que eu posso pensar é como marcador. Para a nossa aplicação de bloco de notas, você deve querer adiionar um propriedade chamada saved a qual tem um um valor booleano para indicar quando o arquivo atual foi salvo em disco ou não.

Note que todas as propriedades de classe foram definidas como protected. Isto é simplesmente uma boa pratica de orientação a objetos. Nós não queremos que sejam publicas, mas nós também queremos que qualquer classe que estenda a nossa possa acessa-las.

E finalmente, nós definios o titulo da janela, maximizamos ela, adicionamos o layout e mostramos todos os widgets. E então nós chamamos a função loadFile() para mostrar o conteúdo do nosso arquivo no text buffer que nós tinhamos criado.

A função buildMenu()

Note agora como nós chamamos esta função a partir do construtor:

$mainBox->pack_start($this->buildMenu(), false, false);
 
Nós fazemos assim porque nós queremos dividir a nossa classe em vários módulos como for possível. Ao invés de todo o nosso layout no construtor em sí, é melhor dividir o layout em partes principais e dedicar uma função para cada parte. Aqui nós temos uma função para fazer a barra do menu, mas não para o text view ou para a barra de status porque eles precisam apenas duas linhas para serem construídos!

Nesta função, nós apenas criamos a nossa barra de menus, adicionamos um menu file (arquivo) com um único item "Quit" (sair). Vamos dar uma olhada nestas linhas:

$quit->connect_simple('activate', array($this, 'quit'));
$quit->connect_simple('enter_notify_event', array($this, 'updateStatus'), 1);
$quit->connect_simple('leave_notify_event', array($this, 'updateStatus'), 0);
 
Aqui nós conectamos activate, enter-notify-event e leave-notify-event aos seus respectivos manipuladores. Olhe o segundo parâmetro das funções connect_simple(). è uma matriz com dois elementos. O primeiro elemento é a variável especial $this e o segundo elemento é uma string. Se você leu o tutorial Alô mundo, você deve ter visto uma linha como essa:
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));
 
Compare a utilização e você deve notar que quando você quiser conectar um sinal para uma função callback a qual seja de uma classe, você deve especificar o callback como uma matriz, o primeiro elemento o qual aponta para uma classe, e o segundo elemento o qual é o nome do callback. Assim, nós conectamos os vários eventos do nosso botão de "quit" para this quit() e updateStatus().

Algumas vezes é possível passar parâmetros para funções para poder usar estes objetos nas funções. Como uma regra, se você tem mais de uma função que usa um objeto em particular, é melhor dedicar uma propriedade de classe para ele; mas se houver apenas uma única função que precise do objeto, ao invés é melhor passar o objeto como parâmetro. Uma ocorrencia comum para esta situação é ao conectar sinais para callbacks. de uma olhada no tutorial sobre sinais e callbacks para mais sobre isto e sobre como passar parâmetros personalizados para os callbacks.

Voltando para a função, nós retornamos o widget superior em nosso menu, a barra de menus, após adicionar a ela o submenu. O construtor então recebe este objeto e adiciona-o ao VBox principal.

A função loadFile()

O proposito desta função é carregar o conteúdo do arquivo que será aberto e mostra-lo no text view. Primeiro nós conferimos se a propriedade de classe currentFile não é null, e então usamos o metodo set_text() na propriedade de classe buffer.

A função updateStatus()

Esta função serve como callback para os sinais enter-notify-event e leave-notify-event. Aqui nós acessamos a barra de status via a propriedade de classe status e adicionamos/removemos uma mensagem dependendo quando o mouse esta entrando ou saindo do botão de menu "Quit".

A função quit()

Esta é a mais simples função de todas, apenas uma que sai do loop principal do GTK. Você deve imaginar porque nós temos uma função de apenas uma linha chamada "quit" quando nós podiamos conectar os sinais diretamente a main_quit como isto:

$this->connect_simple('destroy', array('Gtk', 'main_quit'));
 
A razão para isto é, em aplicações, você provavelmente quereria fazer alguma limpesa antes da aplicação terminar, e esta função é a sua change de faze-lo. Para a nossa simples aplicação bloco de notas, uma adição que é possível aqui é conferir se a marcação saved (novamente, uma propriedade de classe) e perguntar ao usuário se ele quer salvar o arquivo se não estiver salvo.

As ultimas duas linhas:

new Notepad('simple.phpw');
Gtk::main();
 
Cria uma instancia de um objeto da nossa classe (e portanto abre o arquivo simple.phpw localizado no mesmo diretório) e começa o loop principal do GTK. Você pode também mudar Gtk::main() para o construtor da nossa classe.