segunda-feira, outubro 30, 2006

Curso de wxWidgets, post 7: Interagindo com o usuário

Já sabemos criar janelas no wxWidgets, podemos interagir com o usuário através delas, mas existem outras formas de fazer isso, sem precisarmos criar janelas cheias de widgets.

Nesse post vamos conhecer wxMessageBox(), wxGetTextFromUser(), wxGetPasswordFromUser(), wxGetColourFromUser(), wxGetFontFromUser() e wxFileSelector().

wxMessageBox()

Jà vimos o wxMessageBox() em posts anteriores, com ele podemos mostrar janelas pop-up para o usuário, emitindo avisos e até mesmo fazendo perguntas:

int wxMessageBox(const wxString& message, const wxString& caption = "Message",
int style = wxOK, wxWindow *parent = NULL, int x = -1, int y = -1)

message: A mensagem a ser exibida.

caption: O título da janela.

style: Estilo. Pode ser wxYES_NO, wxCANCEL, wxOK, wxICON_EXCLAMATION, wxICON_HAND,
wxICON_ERROR, wxICON_QUESTION e wxICON_INFORMATION.

parent: A janela mãe do pop-up.

x, y: Coordenadas da janela pop-up.


Apenas o parâmetro message é obrigatório. Os mais importantes são message, caption e style. Os estilos indicam qual a configuração da janela pop-up, como os botões que ela vai ter e o ícone. Tente combinar os estilos e criar algumas janelas.

wxMessageBox(wxT("Está gostando do curso?"), wxT("A casa de Just"),
wxICON_QUESTION | wxYES_NO);




wxGetTextFromUser() e wxGetPasswordFromUser()

Uma boa ajuda para obter textos do usuário, como um scanf() no C, mas em janela :)

wxString wxGetTextFromUser(const wxString& message, const wxString&
caption = "Input text", const wxString& default_value = "",
wxWindow *parent = NULL, int x = wxDefaultCoord, int y = wxDefaultCoord,
bool centre = true)

wxString wxGetPasswordFromUser(const wxString& message,
const wxString& caption = "Input text", const wxString& default_value = "",
wxWindow *parent = NULL, int x = wxDefaultCoord, int y = wxDefaultCoord,
bool centre = true)

message: Mensagem a ser exibida.

caption: Título da janela.

default_value: Valor padrão.

parent: A janela mãe do pop-up.

x, y: Coordenadas da janela.

centre: Centraliza a mensagem.


Como no wxMessageBox(), apenas message é obrigatório. Essa função retorna um objeto do tipo wxString com o texto que o usuário digitou. Em wxGetPasswordFromUser(), o texto que o usuário digita fica mascarado com asteriscos, é utilizado para obter senhas.

wxString nome = wxGetTextFromUser(wxT("Qual seu nome?"));




wxString senha = wxGetPasswordFromUser(wxT("Digite sua senha:"));




wxGetColourFromUser()

Quer solicitar alguma cor ao usuário? O wxWidgets pode ajudar com uma janela pronta para escolha de cores.

wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit)

parent: A janela mãe do pop-up.

colInit: Uma cor pré-selecionada para o pop-up.


Todos os parâmetros são opcionais. A função retorna um objeto do tipo wxColour com a cor que o usuário escolheu.

wxColour cor = wxGetColourFromUser();




wxGetFontFromUser()

Também é possível solicitar uma fonte ao usuário. Da mesma forma que com wxGetColourFromUser(), uma simples função pode fazer isso.

wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit)

parent: A janela mãe do pop-up.

fontInit: Uma fonte pré-selecionada para o pop-up.


Novamente, todos os parâmetros são opcionais. A função retorna um objeto do tipo wxFont.

wxFont fonte = wxGetFontFromUser();




wxFileSelector()

Vamos agora selecionar arquivos.

wxString wxFileSelector(const wxString& message, const wxString& default_path = "",
const wxString& default_filename = "", const wxString& default_extension = "",
const wxString& wildcard = "*.*", int flags = 0, wxWindow *parent = NULL,
int x = -1, int y = -1)

message: Mensagem a ser exibida.

default_path: Diretório inicial.

default_filename: Nome de arquivo inicial.

default_extension: Extensão para o arquivo que será selecionado.

wildcard: Curinga para exibição dos arquivos. Exemplo: "Bitmaps|*.bmp|Todos os arquivos|*.*".
Este exemplo faz um menu dropdown com as duas opções.

flags: Estilo da janela. Pode ser wxOPEN, wxSAVE, wxOVERWRITE_PROMPT, wxFILE_MUST_EXIST,
wxMULTIPLE ou 0. A janela pode abrir, salvar, perguntar caso sobrescreva, etc.

parent: A janela mãe do pop-up.

x, y: Coordenadas do pop-up.


Apenas message é obrigatório. A função retorna um objeto do tipo wxString com o caminho completo do arquivo.

wxString arquivo = wxFileSelector(wxT("Selecione o arquivo"));




Finalizando

Existem também outras funções para interação com o usuário, você pode vê-las na página "Dialog functions".

Como foi mostrado, não é necessário ficar fazendo janelas para coisas comuns como solicitar um arquivo ou uma cor. Explore as outras funções para descobrir coisas novas. :)

quinta-feira, outubro 26, 2006

Blog atrasado

Olá, pessoal.

Como já puderam perceber, o blog e o curso de wxWidgets andam atrasados. O fato é que nessas duas últimas semanas eu não tive tempo para elaborar o próximo post do curso. Estou fazendo provas na UESC e também estou usando meu tempo para resolver outros problemas adversos.

Mas na próxima semana, o curso de wxWidgets voltará normalmente. O próximo post é sobre interação com usuário. Se alguém tiver uma sugestão, é só deixar um comentário. :)

Desculpem-me a falta de posts. A Casa de Just não morreu!!! :D

quarta-feira, outubro 11, 2006

Curso de wxWidgets, post 6: Strings com wxString

Até aqui, você já tem condições de criar um aplicativo simples em wxWidgets, com uma interface gráfica razoável e alguns eventos. Agora, gostaria de falar sobre o tratamento de strings no wxWidgets.

Quando alguém aprende a programar em C (não C++), sente um pouco de dificuldade com o tratamento de strings no início. Como nós sabemos, as strings em C são na verdade vetores de char terminados com \0. A manipulação dessas strings se dá através de funções da biblioteca string.h: strcmp(), strcat(), strtok(), strstr()...

Já com C++, surge uma classe chamada string, da biblioteca string, com o objetivo de facilitar a manipulação das strings em C++ (quanta string! :P). Essa classe possui alguns métodos interessantes como string::append(), string::assign(), string::compare() e, inclusive, um método que retorna a string no formato de vetor do C padrão, a string::c_str().

Com a classe string do C++, evitamos problemas de referência de ponteiros e de manipulação de strings em geral, que podiam acontecer no C padrão. Mas agora que estamos usando wxWidgets, temos em mãos uma nova classe chamada wxString. Uma classe para manipulação de strings, como a classe string do C++, mas com algumas facilidades a mais.

Nada melhor que exemplos para demonstrar a classe wxString. Primeiro, vamos declarar um objeto do tipo wxString e atribuir um valor a ele:

wxString Texto;
Texto = wxT("Nossa nova string!");


Você pode fazer tudo em uma linha só, se preferir:

wxString Texto = wxT("Nossa nova string!");


Agora já temos um objeto wxString com a string "Nossa nova string!" atribuída a ele. O que podemos fazer em seguida? Vamos começar adicionando mais string:

Texto.Append(wxT(" Com wxString, claro."));


O método wxString::Append() adiciona texto ao final da string contida no objeto. O conteúdo do objeto Texto agora é "Nossa nova string! Com wxString, claro.".

Também é possível alterar todo o conteúdo do objeto. Podemos fazer isto com uma nova atribuição:

Texto = wxT("Aprendendo wxWidgets com Just.");


Depois da linha acima, o conteúdo do objeto será alterado para "Aprendendo wxWidgets com Just.". Vamos agora criar outra string:

wxString Texto2 = wxT("Aprendendo wxWidgets com Just.");


Temos agora dois objetos: Texto e Texto2. Podemos compará-los:

if (Texto == Texto2)
wxMessageBox(wxT("São iguais."));


Com esse trecho de código, iremos ver uma caixa de mensagem que dirá "São iguais.". Atenção! As string são sensíveis à capitulação, ou seja, "Just", "just" e "JuSt" são todas diferentes entre si.

Podemos também verificar se uma string está dentro da outra. Por exemplo:

if (Texto.Contains(wxT("wxWidgets")))
wxMessageBox(wxT("Texto encontrado."));


O método wxString::Contains() verifica se a string passada como parâmetro está contida na string atribuída ao objeto, retornando true ou false.

Os amantes do C puro (como eu) que nunca abrem mão do sprintf, têm uma alternativa com a classe wxString. Vamos criar uma string formatada, com alguns trechos dependentes de variáveis. Por exemplo:

int a, b;
a = 2;
b = 3;
wxString Soma;
Soma.Printf(wxT("A soma de %d com %d é %d."), a, b, a + b);


Qual será o conteúdo do objeto Soma? Se você pensou em "A soma de 2 com 3 é 5.", acertou em cheio. Com o método wxString::Printf(), podemos atribuir uma string ao objeto da mesma forma que fazemos isso em um vetor de char com a função sprintf do C. Existe também um método static que tem a mesma função, o wxString::Format(). Com esse método, não precisamos de um objeto instanciado para criar strings formatadas. Veja:

wxMessageBox(wxString::Format(wxT("A soma de %d com %d é %d."), a, b, a + b));


wxMessageBox() irá mostrar a mesma string do exemplo anterior, sem precisarmos instanciar um objeto para isso.

Temos também o método wxString::c_str(), caso queiramos obter um vetor de char, como no C puro:

char *soma_c = Soma.c_str();


Na versão ANSI do wxWidgets, wxString::c_str() retorna a string no formato ANSI. Esse mesmo método retorna a string no formato UNICODE, na versão UNICODE do wxWidgets. Se quiser obter o formato ANSI, independentemente da versão da compilação da biblioteca, use wxString::mb_str(). Para o mesmo, no formato UNICODE, temos wxString::wc_str().

Acredito ter mostrado exemplos suficientes dos métodos da classe wxString. Como sempre recomendo, leiam a documentação da classe para ver os outros métodos e utilizações dela. Recomendo também o tópico "wxString overview".

Por último, já que estamos usando wxWidgets, vamos usar wxString para manipular nossas strings. Dessa forma, a coisa toda fica mais fácil e temos mais opções, como demonstrei acima. :)

terça-feira, outubro 03, 2006

Curso de wxWidgets, post 5: Criando eventos

Bem, já criamos um programa, fizemos uma janela e colocamos widgets nela (um wxStaticText, um wxTextCtrl e um wxButton). Mas que tal se esse botão fizesse alguma coisa além de enfeitar a janela? :)

Aí é que entram os eventos. O que vamos fazer é associar um evento a um método da classe que será responsável pela ação deste evento. Na nossa janela, iremos associar um evento de clique no botão "Hello!" a um método que iremos criar na classe MeuFrame.

Vamos começar criando um ID para o evento. Basta usar um #define ou um enum para isto. No nosso exemplo, usaremos um enum:

enum
{
ID_BTN_HELLO
};


Esse ID será usado na criação do widget do botão, no lugar do famoso wxID_ANY. Agora, vamos ao método. Ele vai se chamar OnHelloClick(). Eu gosto de colocar "On" como prefixo de um evento e a ação como sufixo, no caso, "Click", mas você pode usar o nome que desejar, como CliqueNoBotao(), por exemplo. Na definição da classe, adicionamos o protótipo do método:

public:
MeuFrame(void);
void OnHelloClick(wxCommandEvent &event);


O método deve retornar void. No caso de um evento de clique em um wxButton, o parâmetro é um objeto do tipo wxCommandEvent, mas isso vai variar de evento para evento (detalhes mais adiante).

Em seguida, implementamos o método:

void MeuFrame::OnHelloClick(wxCommandEvent &event)
{
if (txt_name->GetValue() == wxEmptyString)
wxMessageBox(wxT("Digite um nome na caixa de texto."), wxT("Aviso"), wxICON_EXCLAMATION);
else
wxMessageBox(wxT("Olá, ") + txt_name->GetValue() + wxT("!"), wxT("Olá"), wxICON_INFORMATION);
}


O que acontece acima? Primeiro, verificamos se existe uma string na caixa de textos. Se não houver, a mensagem "Digite um nome na caixa de texto" é exibida. Se houver uma string, ela será usada para exibir a mensagem "Olá, (string)!". Não se preocupe com o conteúdo desse método por enquanto, no próximo post falarei sobre a classe wxString. Porém, vou adiantar um pouco sobre métodos dos widgets.

Logo na primeira linha do método acima, chamamos wxTextCtrl::GetValue(), esse método retorna um objeto do tipo wxString, contendo a string digitada na caixa de texto. Recomendo que você dê uma olhada na relação dos métodos dos widgets ao utilizá-los pela primeira vez, isso é bom para que você saiba o que pode ser feito com cada widget.

Precisamos declarar a tabela de eventos (que será criada ainda). Fazemos isso na definição da classe:

private:
wxStaticText *lb_hello;
wxTextCtrl *txt_name;
wxButton *btn_say;

DECLARE_EVENT_TABLE()


Depois de criar o método e declarar a tabela de eventos da classe, vamos montá-la. Uma tabela de eventos começa com a macro BEGIN_EVENT_TABLE(classe, tipo) e termina com a macro END_EVENT_TABLE(). Entre essas duas macros, outras são inseridas, associando eventos a métodos. No caso do clique do botão, usaremos a macro EVT_BUTTON(id, func):

BEGIN_EVENT_TABLE(MeuFrame, wxFrame)
EVT_BUTTON(ID_BTN_HELLO, OnHelloClick)
END_EVENT_TABLE()


Na macro EVT_BUTTON(), passamos como parâmetro a ID do evento e o método que será chamado. Para saber qual macro usar em cada tipo de widget, basta olhar na sua própria documentação. Por último, basta fazer uma alteração na criação do widget do botão, trocando o valor wxID_ANY por ID_BTN_HELLO (o parâmetro ID do construtor do widget):

lb_say = new wxButton(this, ID_BTN_HELLO, wxT("Hello!"));


Agora, é só compilar e executar o nosso exemplo:



Agora tente criar novos botões e eventos para eles. Leia o tópico "Event handling overview", do manual do wxWidgets. Na seção "Event macros summary" você encontra uma lista de classes de eventos, como a wxCommandEvent usada no exemplo do botão. Lembre-se que para saber qual macro usar em cada evento, basta ler a documentação do widget em questão.

Como está nosso programa até agora?

Após quatro posts de código (do 2 até este), pode ser que as coisas tenham ficado embaralhadas para alguns visitantes. Colei abaixo o código completo do nosso programa.

#include "wx/wx.h"

enum
{
ID_BTN_HELLO
};

class MeuPrograma: public wxApp
{
public:
virtual bool OnInit(void);
};

class MeuFrame: public wxFrame
{
public:
MeuFrame(void);
void OnHelloClick(wxCommandEvent &event);

private:
wxStaticText *lb_hello;
wxTextCtrl *txt_name;
wxButton *btn_say;

DECLARE_EVENT_TABLE()
};

bool MeuPrograma::OnInit(void)
{
MeuFrame *frame = new MeuFrame();
frame->Show();
SetTopWindow(frame);
return true;
}

BEGIN_EVENT_TABLE(MeuFrame, wxFrame)
EVT_BUTTON(ID_BTN_HELLO, MeuFrame::OnHelloClick)
END_EVENT_TABLE()

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu Programa"))
{
// Criação dos sizers
wxBoxSizer *sizer_v = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *sizer_h = new wxBoxSizer(wxHORIZONTAL);

// Criação dos widgets
lb_hello = new wxStaticText(this, wxID_ANY, wxT("Digite seu nome na caixa:"));
txt_name = new wxTextCtrl(this, wxID_ANY);
btn_say = new wxButton(this, ID_BTN_HELLO, wxT("Hello!"));

// Posicionamento dos widgets
sizer_h->Add(txt_name, 1, wxALL, 5);
sizer_h->Add(btn_say, 0, wxALL, 5);

sizer_v->Add(lb_hello, 0, wxALL, 5);
sizer_v->Add(sizer_h, 0, wxALL | wxEXPAND, 5);

SetSizerAndFit(sizer_v);
}

void MeuFrame::OnHelloClick(wxCommandEvent &event)
{
if (txt_name->GetValue() == wxEmptyString)
wxMessageBox(wxT("Digite um nome na caixa de texto."), wxT("Aviso"), wxICON_EXCLAMATION);
else
wxMessageBox(wxT("Olá, ") + txt_name->GetValue() + wxT("!"), wxT("Olá"), wxICON_INFORMATION);
}

IMPLEMENT_APP(MeuPrograma)


Slackware 11.0 lançado

Eu já estava agoniado com tantos RCs do Slackware 11.0, mas nessa madrugada, às 1:05, recebi um e-mail da lista slackware-announce que dizia: Slackware 11.0 is released!

Nessa nova versão, tem o kernel 2.4.33.3 ainda como padrão, o 2.6.17.13 como opção no diretório /extra e o 2.6.18 no diretório /testing. O KDE é o 3.5.4, XFCE 4.2.3.2, últimas versões do Firefox e Thunderbird, SeaMonkey 1.0.5 (substituindo a suíte Mozilla), além de glibc 2.3.6, gcc 3.4.6, X11R6.9.0 da X.Org, etc.

Bem, o recado está dado! Visitem o site oficial do Slackware para baixar essa nova versão. Hoje mesmo vou atualizar um dos meus servidores :P