Tutorial de wxhaskell

Tutorial de wxhaskell

(Parte 1 de 13)

Interfaces Gráficas em Haskell com WxHaskell

Tutorial

Elton M. Cardoso Lucília Figueiredo

Capítulo 11
Introdução1
1.1 – WxWindows e FFI1
1.2 – Criando uma janela2
1.3 – Compilando e executando a aplicação:3
1.4 – Atributos e Propriedades:5
1.4.1 – Eventos e tratadores de eventos6
1.4.1.1 – Eventos de mouse7
1.4.1.2 – Eventos de teclado9
1.4.1.3 – Outros eventos:1
1.5 – Layouts1
14
1.6 – Variáveis Mutáveis:16
2 – Controles de interface gráfica16
2.1 – Window17
2.2 - Frames18
2.3 – MDI Frames20
2.4 - Panel21
2.5 – Notebook2
2.6 – Button23
2.7 – TextCtrl23
2.9 – Check Box25
2.10 – Choice26
2.1 – ComboBox27
2.12 – ListBox28
2.13 – RadioBox29
2.14 – Spin Control29
2.15 – Slider30
2.16 – Gauge31
2.17 – Static text32
2.18 – Splitter Window32
2.19 – Image List34
2.20 – List Control35
2.21 – Tree Control36
2.2 – Timer:38
2.23 – Menu38
2.24 – Tool bar39
2.25 – Status Bar40
3 – Diálogos40
3.1 – Diálogos predefinidos:40
3.1.1 - Mensagens40
3.1.2 – Arquivos:41
3.1.3 – Miscelânia:42
3.2 – Escrevendo os próprios diálogos:42
4 – O módulo Draw4
4.1 – Atributos de DC oriundos da classe Draw4

Índice analítico _ i

4.3 – funções para desenho de formas básicas:46
5 – Processamento de Som e imagens47
5.1 – Recursos para imagens:47
5.2 – Recursos para Som:48

4.2 – Atributos de DC oriundos da classe Brushed..............................................................46 _ i

Capítulo 1 Introdução

1.1 – WxWindows e FFI

A biblioteca WxHaskell [2] provê uma interface para o uso, em programas Haskell [1], de classes da biblioteca WxWindows [3], escrita na linguagem C++. As classes da biblioteca WxWindows provêm funcionalidades para criação de componentes de interfaces gráficas (tais como widgets (janelas), containers (componentes usados para conter outros componentes gráficos), buttons (botões) etc), assim como para tratamento de eventos que ocorrem nessas interfaces gráficas.

Para prover essa interface, a biblioteca WxHaskell é construída com base em funções disponíveis na biblioteca FFI (Foregin Function Interface) [4], a qual possibilita o uso de código escrito em outras linguagens, dentro de programas Haskell. A biblioteca FFI provê uma interface programável entre o contexto de Haskell e o contexto de uma linguagem externa (tal como C++, Java, Pascal etc). Como resultado, threads de Haskell podem fazer acesso a dados de um contexto externo, assim como invocar funções que serão executadas nesse contexto externo, e vice-versa. Neste tutorial, não iremos entrar em detalhes sobre a biblioteca FFI e suas aplicações. Entretanto, pode ser útil ter uma compreensão mínima sobre como WxWindows foi “portada” para Haskell, o que comentamos a seguir.

De maneira bastante simplificada, podemos dizer que WxHaskell faz um mapeamento dos tipos da biblioteca WxWindows para tipos de dados em Haskell. Note que, como C++ é uma linguagem orientada a objetos, a biblioteca WxWindows pode possuir variáveis cujo conteúdo tem tipo definido dinamicamente, em face do mecanismo de subtipos e ligação dinâmica existente em linguagens orientadas a objetos. Em contraposição, Haskell possui um sistema de tipos totalmente estático. Como solução, a implementação de WxHaskell introduz o tipo abstrato Object a, onde o parâmento “a” pode ser usado para expressar relações da hierarquia de classes de WxWindows. Além desse mapeamento entre tipos, WxHaskell cria tipos abstratos correspondentes às classes C++ da biblioteca WxWindows (tais como Button, Window, EvtHandler etc.) e mapeia as relações de hierarquia existentes entre estas classes.

Note, portanto, que, em um programa Haskell que utiliza a biblioteca WxHaskell, a criação e manutenção de uma interface gráfica não é executada no contexto de Haskell, mas sim no contexto externo, de C++. Por outro lado, a interação do programa com essa interface é feita por meio dos tipos e construções naturais de Haskell.

_ 1.2 – Criando uma janela

Como um ponto de partida para explorar a biblioteca WxHaskell, apresentamos a seguir um exemplo que ilustra a criação de uma janela com um único botão, que permitirá fechá-la.

module MyFirstProgram where

{- importa a biblioteca gráfica WxHaskell. -} import Graphics.UI.WX

{- função principal que inicia a interface gráfica -} main :: IO () main = start interface

{- função que gera a interface gráfica propriamente dita. -} interface :: IO () interface = do f frame [text := "Criando uma janela simples"] b button f [text := "Fechar", on command := close f] set f [layout := margin 4 (floatCentre (widget b) ), clientSize := sz 280 100]

A função main chama a função start :: IO a IO (), que “inicia” a interface gráfica.

A função interface consiste no seqüenciamento de ações que criam os objetos de interface, com propriedades pré-definidas. O primeiro objeto criado é um frame (de tipo Frame), um tipo de container para outros objetos. A assinatura função que cria o frame é:

Esta função tem como parâmetro uma lista de propriedades de Frame – propriedades e atributos de um Frame são discutidas mais adiante – e retorna um valor do tipo IO (Frame ()). Este tipo indica que o valor retornado, quando avaliado, resulta na ação de exibir na tela do computador o Frame encapsulado no valor deste tipo.

No corpo da função interface, o operador ( ) é então usado desencapsular o Frame e atribuir o valor correspondente à variável f.

Em seguida. É criado um botão, por meio da função button: button :: Window a [Prop (Button () ) ] IO (Button ())

Por fim, especificamos o layout da janela principal. Este é um passo obrigatório pois, caso não seja realizado, os widgets serão “empilhados” no canto superior esquerdo da janela. O layout é um atributo comum a todos os containeres de widgets. No nosso exemplo, utilizamos a função widget, que extrai um layout de um controle:

widget :: Widget w => w Layout

A assinatura da função widget indica que, para extrair um layout de um objeto, este deve ser uma instância da classe Widget. Na prática, todos os objetos criados a partir da classe Window são instâncias de Widget. Note que, aqui, estamos falando de classes de Haskell, e não de C++. Lembre-se que, em Haskell, classes são usadas para especificar o tipo de funções sobrecarregadas, e instâncias dessas classes constêm definições dessas funções para tipos específicos. Em contraposição, em linguagens orientadas a objetos, classes são usadas para definir tipos de objetos em um contexto de polimorfismo de subtipagem, e não de polimorfismo de sobrecarga.

Uma vez extraído o layout, é usada a função floatCentre :: Layout Layout para centralizar o layout na janela. Ao layout resultante, adicionamos uma margem de 4 pixels, pela aplicação da função margin, com argumento igual a 4.

1.3 – Compilando e executando a aplicação:

Depois de digitar e salvar o programa, vamos executá-lo. Recomendamos o uso do compilador Haskell GHC-6.2.2 [1]. Se a biblioteca WxHaskell estiver corretamente instalada em seu sistema, basta abrir um prompt de comando no diretório onde você salvou seu arquivo e digitar:

ghci -package wx NomeDoPrograma.hs.

É obrigatório informar o parâmetro -package wx, para que o GHC saiba que deve ser usada a biblioteca WxHaskell. Se você estiver ussando algum ambiente de programação (p.ex., JCreator), poderá configurá-lo para iniciar o GHC já com este parâmetro. A janela do GHC terá então a seguinte aparência:

Figura 1 - Janela do GHCi como o programa carregado.

Note que os módulos da biblioteca WxHaskell foram carregados. Basta digitar main e teremos o resultado:

Figura 2 - Resultado da execução do programa.

Também é possível gerar código binário a partir do programa, mas isto irá depender do tipo e da versão do compilador que você estiver usando. No caso do GHC-6.2.2, deve ser usado o seguinte comando, para compilar o programa:

ghc –package wx -main-is MyFirstPogram --make MyFirstPogram.hs

O compilador irá então gerar os códigos objetos e ligá-los em um código executável. Em geral, a biblioteca é de linkagem estática, o que significa que o programa executável conterá todas as funções da biblioteca, mesmo as que não são usadas no programa. Isto faz com que o código executável fique enorme! Uma solução para esse problema é usar o strip [referência], um programa capaz de vasculhar o código executável e remover símbolos que não são utilizados .

_ 1.4 – Atributos e Propriedades:

Objetos em geral possuem atributos, que são representados por variáveis (de instância) de um determinado tipo, podendo assumir certos valores. Em WxHaskell atributos estão definidos da seguinte forma:

data Attr w a onde w é um Widget (um objeto de interface) e a é o tipo do atributo em questão. Esta construção pode, portanto, ser interpretada da seguinte maneira: o Widget w possui um atributo do tipo a. Um atributo muito comum é o text, com o seguinte tipo:

text :: Attr (Window a) String

Isto significa que todo objeto derivado da classe Window possui um atributo text. Os atributos podem ser somente de leitura, somente de escrita ou de leitura-escrita, o que é mais comum.

Uma propriedade é um atributo associado a um valor, sendo definida como segue:

Observe que existem quatro construtores para o tipo.

•:= Associa um valor a um atributo, ou seja, constrói a propriedade a partir de um atributo e de seu respectivo valor. Ex: text := “Haskell”

•: Constrói a propriedade a partir de uma função de atualização. Isto é, o valor da propriedade é obtido pela aplicação de uma função ao valor atual. Ex: text :~ (++”_Op”)

•::= Associa um atributo a um valor, com o uso de uma função que leva em conta o widget que estamos modificando.

•:: Atualiza o valor de uma propriedade com uso de uma função que leva em conta o widget que estamos modificando

Podemos ler e modificar as propriedades de um objeto de interface por meio das funções get, set e swap:

•get :: w Attr w a IO a: Recebe um widget e um atributo deste widget, ao qual se deseja saber o valor associado, e retorna o valor da propriedade. Ex.: get w text retorna um valor do tipo IO (String)

Ex.: set w [text := “WxHaskell”, color := red,].

•set :: w [Prop w] IO (): Atribui uma lista de propriedades ao widget. _ data Prop w = forall a . (:=) (Attr w a) a | forall a . (:~) (Attr w a) (a a)

(Parte 1 de 13)

Comentários