quarta-feira, dezembro 13, 2006

Curso de wxWidgets: Uma pausa

Olá, pessoal.

Como perceberam, já tem um tempo que não posto nada sobre o curso de wxWidgets. Bem, vou dar uma pausa nele por enquanto, pois estou terminando trabalhos e provas de final de semestre na Universidade e estou meio sem tempo. O curso voltará na segunda semana de Janeiro, sem falta. :)

quinta-feira, novembro 23, 2006

Hotmail no Mozilla Thunderbird

Se você usa o Mozilla Thunderbird e tem conta no Hotmail, provavelmente já teve vontade de baixar suas mensagens pelo software cliente.

Existem vários programas que intermediam a conexão entre o cliente e o Hotmail. Já usei alguns, mas não me agradaram muito. Enfim, encontrei hoje uma extensão para o Thunderbird.

O nome da extensão é WebMail. Basta você instalar a extensão mais o módulo do Hotmail. Essa extensão possui também módulos para outros serviços de webmails.

O primeiro passo é baixar a extensão do WebMail na página de download. Em seguida, baixe o módulo do Hotmail na mesma página. Após instalar as extensões, reinicie o Thunderbird.

O passo seguinte, é configurar a extensão. Clique em Ferramentas -> Extensões. Selecione a extensão do WebMail e clique em Preferências.

Na janela de preferências, certifique-se de que POP e SMTP estão OK (bola verde e texto Running). Caso não estejam rodando, pode ser que você não esteja com permissões para usar portas baixas. Neste caso, clique na aba Ports e escolha portas acima de 1024 para POP e SMTP. Se você precisar modificar as portas, reinicie o Thunderbird novamente.

Por último, adicione sua conta do Hotmail. Basta adicionar a conta normalmente, como você faria com qualquer outra conta POP3. Só que no momento de especificar o servidor POP de entrada, use localhost. Termine o resto do assistente de nova conta normalmente.

Se você mudou as portas POP e SMTP na extensão, você terá que fazer o mesmo na configuração da sua conta. Clique em Editar -> Configuração de contas. Procure sua conta do Hotmail e clique na seção Configurações do servidor. Configure a porta para o mesmo número que você escolheu na configuração da extensão. Em seguida, vá para Servidor de saída (SMTP), lá no final, e adicione o servidor SMTP localhost com a porta SMTP que você escolheu nas configurações da extensão.

Pronto! Seu Thunderbird está pronto para baixar e-mails do Hotmail. :)

segunda-feira, novembro 20, 2006

Curso de wxWidgets, post 10: Mais sobre arquivos com wxTextFile

Agora será apresentada a classe wxTextFile. Essa classe permite manipular arquivos de texto e possui alguns métodos bastante úteis. Como eu havia comentado no post 8, eu senti falta de alguns métodos interessantes em wxFile, como por exemplo, ler uma linha inteira de um arquivo. Só depois que eu descobri a wxTextFile :P

A abertura de um arquivo para leitura se dá com o método wxTextFile::Open():

wxTextFile File;
File.Open("arquivo.txt");


Caso o arquivo não possa ser aberto ou não exista, wxTextFile::Open() retornará falso.

Agora, basta caminharmos pelas linhas e ler o conteúdo do arquivo. Podemos saber o número de linhas em um arquivo com wxTextFile::GetLineCount() (retornando o número de linhas) e ler cada linha com wxTextFile::GetLine() (retornando um objeto wxString com o conteúdo da linha lida). Veja um exemplo de leitura linha a linha:

for (unsigned int line = 0; line < File.GetLineCount(); line++)
txt_file->AppendText(File.GetLine(line) + wxT("\n"));


O laço acima percorre cada linha do arquivo e adiciona em um objeto do tipo wxTextCtrl.

Após ter lido todo o arquivo, podemos fechá-lo com wxTextFile::Close():

File.Close();


Já no caso de gravações, temos que criar o arquivo com wxTextFile::Create():

wxTextFile File;
File.Create("arquivo.txt");


Caso o arquivo não possa ser criado, wxTextFile::Create() retornará falso.

Agora, basta chamar wxTextFile::AddLine() para adicionar linhas no arquivo:

File.AddLine(wxT("Linha 1"));
File.AddLine(wxT("Linha 2"));
File.AddLine(wxT("Linha 3"));


Por último, devemos gravar as alterações no disco e fechar o arquivo:

File.Write();
File.Close();


Existem também outros métodos interessantes:

wxTextFile::GoToLine(size_t n) leva você até a linha n.

wxTextFile::GetFirstLine(), GetNextLine(), GetPrevLine(), GetLastLine() retornam a primeira linha, a próxima, a anterior e a última respectivamente.

Você também pode inserir uma linha em um local específico com wxTextFile::InsertLine() e pode remover qualquer linha com wxTextFile::RemoveLine().

O exemplo de editor de textos

Modifiquei o programa do post 9 para usar wxTextFile no lugar de wxFile. Vejam o programa alterado abaixo:

/* A Casa de Just - http://jpjust.blogspot.com
* Curso de wxWidgets: Exemplo de um editor de textos usando wxTextFile
*
* O objetivo deste código é demonstrar o uso da classe wxTextFile
* para efetuar leitura e escrita em um arquivo de texto, além
* de mostrar o uso básico das classes wxApp, wxFrame, wxStaticText,
* wxButton, wxTextCtrl e wxBoxSizer, assim como o tratamento de
* eventos e as funções wxFileSelector() e wxMessageBox()
* (tópicos abordados do post 2 ao post 8 do curso).
*
* wxTextCtrl possui dois métodos para carregar e salvar um arquivo
* (wxTextCtrl::LoadFile() e wxTextCtrl::SaveFile()), porém, wxTextFile
* é utilizado para demonstrar seu uso. No trecho onde a leitura e
* escrita são feitas, existem comentários explicando como utilizar
* estes métodos.
*
* Copyright (c) João Paulo Just <jpjust@justsoft.com.br>
* A Casa de Just - http://jpjust.blogspot.com
* 20 de novembro de 2006, 20:25, Ilhéus, BA, Brasil.
*/

#include <wx/wx.h>
#include <wx/textfile.h>

// IDs
enum
{
ID_BTNLOAD,
ID_BTNSAVE
};

// Classe do programa
class MeuPrograma: public wxApp
{
public:
// Método principal
virtual bool OnInit(void);
};

// Classe do frame
class MeuFrame: public wxFrame
{
public:
// Construtor
MeuFrame(void);

// Eventos
void OnLoadClick(wxCommandEvent &event);
void OnSaveClick(wxCommandEvent &event);

DECLARE_EVENT_TABLE()

private:
// Widgets do frame
wxButton *btn_load;
wxButton *btn_save;

wxStaticText *lb_filename;

wxTextCtrl *txt_file;
};

// Inicialização do programa
bool MeuPrograma::OnInit(void)
{
MeuFrame *frame = new MeuFrame();
frame->Show();
SetTopWindow(frame);
return true;
}

// Tabela de eventos
BEGIN_EVENT_TABLE(MeuFrame, wxFrame)
EVT_BUTTON(ID_BTNLOAD, MeuFrame::OnLoadClick)
EVT_BUTTON(ID_BTNSAVE, MeuFrame::OnSaveClick)
END_EVENT_TABLE()

// Construtor do frame
MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Arquivos"))
{
// Sizer e widgets
wxBoxSizer *sizer_h = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *sizer_v = new wxBoxSizer(wxVERTICAL);

btn_load = new wxButton(this, ID_BTNLOAD, wxT("Abrir"));
btn_save = new wxButton(this, ID_BTNSAVE, wxT("Salvar"));

lb_filename = new wxStaticText(this, wxID_ANY,
wxT("Sem titulo.txt"));

txt_file = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);

// Posicionamento
sizer_h->Add(btn_load, 0, wxALL, 5);
sizer_h->Add(btn_save, 0, wxALL, 5);
sizer_h->Add(lb_filename, 1, wxALL, 5);

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

SetSizerAndFit(sizer_v);

// Boas-vindas
wxMessageBox(wxT("Seja bem-vindo(a) a mais um maravilhoso programa! :)"),
wxT("Bem-vindo(a)!"), wxICON_INFORMATION);
}

// Botão de leitura
void MeuFrame::OnLoadClick(wxCommandEvent &event)
{
wxString Filename;

// Abre diálogo de arquivo
Filename = wxFileSelector(wxT("Selecione o arquivo"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxT("*.txt"), wxOPEN | wxFILE_MUST_EXIST);

// Se arquivo inválido, sai do método
if (Filename == wxEmptyString)
return;

// Tenta abrir o arquivo com wxTextFile
wxTextFile File;
if (File.Open(Filename) == false)
return;

// Lê o conteúdo do arquivo linha a linha
for (unsigned int line = 0; line < File.GetLineCount(); line++)
txt_file->AppendText(File.GetLine(line) + wxT("\n"));

// Não é preciso todo este código para ler um arquivo
// e exibí-lo em um wxTextCtrl. O trecho acima foi
// escrito apenas para que você entenda a classe wxTextFile.
// wxTextCtrl possui um método próprio para ler o
// conteúdo de um arquivo. Tente comentar o trecho acima
// e usar o método abaixo para fazer a leitura:

//txt_file->LoadFile(Filename);

// Fecha o arquivo
File.Close();

// Atualiza o nome
lb_filename->SetLabel(Filename);
}

// Botão de salvamento
void MeuFrame::OnSaveClick(wxCommandEvent &event)
{
wxString Filename;

// Abre diálogo de arquivo
Filename = wxFileSelector(wxT("Selecione o arquivo"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxT("*.txt"), wxSAVE | wxOVERWRITE_PROMPT);

// Se arquivo inválido, sai do método
if (Filename == wxEmptyString)
return;

// Tenta criar o arquivo com wxTextFile
wxTextFile File;
if (File.Create(Filename) == false)
return;

// Limpa o arquivo, caso exista conteúdo nele
File.Clear();

// Percorre a caixa de texto gravando o conteúdo
// no arquivo aberto, linha a linha
for (unsigned int line = 0; line < txt_file->GetNumberOfLines(); line++)
File.AddLine(txt_file->GetLineText(line));

// Neste ponto, eu também poderia usar um método
// de wxTextCtrl para salvar o arquivo. Tente
// comentar o trecho de gravação acima e descomente
// a linha abaixo para testar:

//txt_file->SaveFile(Filename);

// Salva o arquivo em disco e fecha
File.Write();
File.Close();

// Atualiza o nome do arquivo
lb_filename->SetLabel(Filename);
}

IMPLEMENT_APP(MeuPrograma)

sábado, novembro 11, 2006

Curso de wxWidgets, post 9: Um exemplo de um editor de textos

Resolvi fazer um exemplo de um editor de textos, usando a maioria das classes estudadas até agora. Além de mostrá-las em ação, vou pagar a semana que fiquei sem postar no mês passado :P. O código completo do exemplo está abaixo. Compile e veja o programa funcionando. Não deixe de ler os comentários, existem algumas informações importantes neles.

/* A Casa de Just - http://jpjust.blogspot.com
* Curso de wxWidgets: Exemplo de um editor de textos usando wxFile
*
* O objetivo deste código é demonstrar o uso da classe wxFile
* para efetuar leitura e escrita em um arquivo de texto, além
* de mostrar o uso básico das classes wxApp, wxFrame, wxStaticText,
* wxButton, wxTextCtrl e wxBoxSizer, assim como o tratamento de
* eventos e as funções wxFileSelector() e wxMessageBox()
* (tópicos abordados do post 2 ao post 8 do curso).
*
* wxTextCtrl possui dois métodos para carregar e salvar um arquivo
* (wxTextCtrl::LoadFile() e wxTextCtrl::SaveFile()), porém, wxFile
* é utilizado para demonstrar seu uso. No trecho onde a leitura e
* escrita são feitas, existem comentários explicando como utilizar
* estes métodos.
*
* Copyright (c) João Paulo Just
* A Casa de Just - http://jpjust.blogspot.com
* 8 de novembro de 2006, 21:03, Ilhéus, BA, Brasil.
*/

#include <wx/wx.h>
#include <wx/file.h>

#define BUF_SIZE 128 // Tamanho do buffer de leitura/escrita

// IDs
enum
{
ID_BTNLOAD,
ID_BTNSAVE
};

// Classe do programa
class MeuPrograma: public wxApp
{
public:
// Método principal
virtual bool OnInit(void);
};

// Classe do frame
class MeuFrame: public wxFrame
{
public:
// Construtor
MeuFrame(void);

// Eventos
void OnLoadClick(wxCommandEvent &event);
void OnSaveClick(wxCommandEvent &event);

DECLARE_EVENT_TABLE()

private:
// Widgets do frame
wxButton *btn_load;
wxButton *btn_save;

wxStaticText *lb_filename;

wxTextCtrl *txt_file;
};

// Inicialização do programa
bool MeuPrograma::OnInit(void)
{
MeuFrame *frame = new MeuFrame();
frame->Show();
SetTopWindow(frame);
return true;
}

// Tabela de eventos
BEGIN_EVENT_TABLE(MeuFrame, wxFrame)
EVT_BUTTON(ID_BTNLOAD, MeuFrame::OnLoadClick)
EVT_BUTTON(ID_BTNSAVE, MeuFrame::OnSaveClick)
END_EVENT_TABLE()

// Construtor do frame
MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Arquivos"))
{
// Sizer e widgets
wxBoxSizer *sizer_h = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *sizer_v = new wxBoxSizer(wxVERTICAL);

btn_load = new wxButton(this, ID_BTNLOAD, wxT("Abrir"));
btn_save = new wxButton(this, ID_BTNSAVE, wxT("Salvar"));

lb_filename = new wxStaticText(this, wxID_ANY,
wxT("Sem titulo.txt"));

txt_file = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);

// Posicionamento
sizer_h->Add(btn_load, 0, wxALL, 5);
sizer_h->Add(btn_save, 0, wxALL, 5);
sizer_h->Add(lb_filename, 1, wxALL, 5);

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

SetSizerAndFit(sizer_v);

// Boas-vindas
wxMessageBox(wxT("Seja bem-vindo(a) a mais um maravilhoso programa! :)"),
wxT("Bem-vindo(a)!"), wxICON_INFORMATION);
}

// Botão de leitura
void MeuFrame::OnLoadClick(wxCommandEvent &event)
{
wxString Filename;

// Abre diálogo de arquivo
Filename = wxFileSelector(wxT("Selecione o arquivo"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxT("*.txt"), wxOPEN | wxFILE_MUST_EXIST);

// Se arquivo inválido, sai do método
if (Filename == wxEmptyString)
return;

// Abre o arquivo para leitura com wxFile
wxFile File(Filename, wxFile::read);

// Verifica se o arquivo foi aberto
if (!File.IsOpened())
return;

// Lê o conteúdo do arquivo em partes
// do tamanho de BUF_SIZE
char buffer[BUF_SIZE] = {0};
txt_file->Clear();

while (!File.Eof())
{
// Lê BUF_SIZE - 1 bytes (deixa um espaço
// para o \0 do final da string
if (File.Read(buffer, BUF_SIZE - 1) > 0)
{
// Converte o conteúdo de buffer, que
// deve estar em UTF8 (ANSI) para o formato
// da sua compilação do wxWidgets
wxString Buf(buffer, wxConvUTF7);
txt_file->AppendText(Buf);
memset(buffer, 0, BUF_SIZE);
}
else
{
wxMessageBox(wxT("Erro de leitura!"),
wxT("Erro"), wxICON_ERROR);
return;
}
}

// Não é preciso todo este código para ler um arquivo
// e exibí-lo em um wxTextCtrl. O trecho acima foi
// escrito apenas para que você entenda a classe wxFile.
// wxTextCtrl possui um método próprio para ler o
// conteúdo de um arquivo. Tente comentar o trecho acima
// e usar o método abaixo para fazer a leitura:

//txt_file->LoadFile(Filename);

// Fecha o arquivo
File.Close();

// Atualiza o nome
lb_filename->SetLabel(Filename);
}

// Botão de salvamento
void MeuFrame::OnSaveClick(wxCommandEvent &event)
{
wxString Filename;

// Abre diálogo de arquivo
Filename = wxFileSelector(wxT("Selecione o arquivo"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxT("*.txt"), wxSAVE | wxOVERWRITE_PROMPT);

// Se arquivo inválido, sai do método
if (Filename == wxEmptyString)
return;

// Abre o arquivo para escrita com wxFile
wxFile File(Filename, wxFile::write);

// Verifica se o arquivo foi aberto
if (!File.IsOpened())
return;

// Percorre a caixa de texto gravando o conteúdo
// no arquivo aberto
for (unsigned int line = 0; line <>GetNumberOfLines(); line++)
{
wxString Buf = txt_file->GetLineText(line);
if (File.Write(Buf + wxT("\n"), wxConvUTF7) < 0)
{
wxMessageBox(wxT("Erro de gravação!"),
wxT("Erro"), wxICON_ERROR);
return;
}
}

// Neste ponto, eu também poderia usar um método
// de wxTextCtrl para salvar o arquivo. Tente
// comentar o trecho de leitura acima e descomente
// a linha abaixo para testar:

//txt_file->SaveFile(Filename);

// Fecha o arquivo
File.Close();

// Atualiza o nome do arquivo
lb_filename->SetLabel(Filename);
}

IMPLEMENT_APP(MeuPrograma)


Screenshot

terça-feira, novembro 07, 2006

Curso de wxWidgets, post 8: Manipulando arquivos

Manipular arquivos em C não é complicado, mas de qualquer forma, irei apresenter uma classe do wxWidgets que o ajuda nesta tarefa, a wxFile.

wxFile é simples de usar. Seu construtor:

wxFile(const char* filename, wxFile::OpenMode mode = wxFile::read)

filename: O caminho do arquivo a ser aberto.

mode: Modo de acesso. Pode ser wxFile::read, wxFile::write ou wxFile::read_write.


Para abrir um arquivo para leitura, basta especificar o caminho do arquivo e usar o modo wxFile::read:

wxFile arquivo("c:\\arquivo.txt", wxFile::read);


Leitura e escrita? Use wxFile::read_write:

wxFile arquivo("c:\arquivo.txt", wxFile::read_write);


Após aberto, já podemos manipular o arquivo. A leitura é feita com o método wxFile::Read():

char linha[256];
int lido, max = 255;

wxFile arquivo("c:\\arquivo.txt", wxFile::read);
lido = arquivo.Read(linha, max);


lido irá conter a quantidade de bytes lidos pelo método. linha irá guardar o conteúdo lido e max indica o máximo de bytes a ser lido (neste caso, usado para delimitar a quantidade de dados que será guardado em linha). No caso de leitura de arquivos de texto, a quantidade de bytes a serem lidos deve ser o tamanho do buffer menos 1, para deixar espaço para o \0 de final de string em C.

Para gravar, simplesmente use o método wxFile::Write()

wxString Linha = wxT("Nova linha de texto!");
bool gravado;

wxFile arquivo("c:\\arquivo.txt", wxFile::read);
gravado = arquivo.Write(Linha);


Este método usa como argumento um wxString. Existe um segundo argumento, usado para fazer conversão do tipo da string. A conversão é utilizada caso você esteja usando wxWidgets em uma compilação (UNICODE, por exemplo) e deseja gravar o arquivo em outro formato (no caso, ANSI).

Se você prefere gravar no formato cru, como no C puro, existe também o método wxFile::Write(const void* buffer, wxFileOffset count) que funciona de forma semelhante ao wxFile::Read(). Ele recebe como argumento uma variável qualquer com algum conteúdo e um valor indicando a quantidade de bytes a serem gravados.

É preciso saber que essas operações serão feitas no início do arquivo. Ou seja, se você pede para ler 10 bytes, a classe wxFile irá ler os primeiros 10 bytes do arquivo. Se logo em seguida você solicitar uma escrita, seu buffer será gravado a partir do 11º byte. Para fazer leituras e escritas em outras partes do arquivo, use wxFile::Seek():

wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart)

ofs: Offset a percorrer.

mode: Origem da busca. Pode ser wxFromStart, wxFromEnd ou wxFromCurrent.


Se você quiser fazer uma leitura a partir do 20º byte, por exemplo, basta usar o método wxFile::Seek() antes do wxFile::Read():

arquivo.Seek(20, wxFromStart);
arquivo.Read(buffer, 100);


O exemplo acima lê 100 bytes a partir do 20°, guardando o conteúdo em buffer. O mesmo vale para escritas, basta usar wxFile::Seek() antes de wxFile::Write().

Caso queira gravar no final do arquivo, use wxFile::SeekEnd():

arquivo.SeekEnd();
arquivo.Write(Linha);


Após ter feito todas as leituras e escritas desejadas, feche o arquivo com wxFile::Close().

Outros métodos interessantes

Além de leitura e escrita, podemos fazer outras coisas com wxFile. Por exemplo, obter o tamanho do arquivo aberto com wxFile::Length():

int tamanho = arquivo.Length();


Ou até verificar se o arquivo existe com wxFile::Exists():

bool existe = wxFile::Exists("c:\\arquivo.txt");


Finalizando

Na minha opinião pessoal, não há uma vantagem grandiosa em usar wxFile. Quero dizer, usar wxFile não nos dá tanta vantagem para tratar arquivos quanto wxString nos dá para tratar strings. Eu senti falta de um método que lesse n bytes, gravando-os em um wxString ou algum método que pudesse ler toda uma linha de uma vez.

Olhei o manual da próxima versão (2.7.2, futuramente 2.8.0) e não vi nada deste tipo em wxFile. Acabei ficando com vontade de implementar isso. :)

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

terça-feira, setembro 26, 2006

Curso de wxWidgets, post 4: Posicionando com sizers

Se você tentou adicionar novos widgets no frame do nosso "Hello, world!", possa ser que tenha tido problemas para posicioná-los. É isto que vamos fazer agora!

Bem, no wxWidgets, você não precisa especificar as coordenadas de cada widget (nem deve). Ao invés disso, usamos os sizers, que são objetos do wxWidgets que auxiliam no posicionamento dos widgets. Funciona mais ou menos como uma tabela, você adiciona sizers horizontais ou verticais e vai inserindo os widgets nas "células" deles.

No post de hoje, vamos fazer a seguinte janela para demonstrar o uso de sizers:



Para que você entenda o funcionamento dos sizers, vou mostrar como ela foi divida por eles:



Nesta janela foram usados dois sizers: um vertical (vermelho) e um horizontal (azul). O sizer horizontal tem dois widgets: um wxTextCtrl e um wxButton. O sizer vermelho tem um wxStaticText e o sizer horizontal. O sizer horizontal vai ficar dentro do vertical, de forma a fazer esta arrumação.

Para fazer esta janela, vamos modificar o nosso "Hello, world!". Na definição da classe do frame, declare os widgets que vamos usar:

class MeuFrame: public wxFrame
{
public:
MeuFrame(void);

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


E no construtor do frame, vamos criar os sizers, os widgets e posicioná-los:

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, wxID_ANY, 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);
}


Vamos entender melhor os sizers. No início do construtor, criamos os dois sizers que vamos utilizar. No wxBoxSizer, você insere os widgets nas "células" e ele os encaixa usando o tamanho mínimo necessário por aquele widget. Como parâmetro do wxBoxSizer, passamos sua orientação, que pode ser wxHORIZONTAL ou wxVERTICAL.

Em seguida, criamos os widgets normalmente, chamando os construtores de cada um deles.

Por último, os widgets são inseridos nos sizers com o método wxSizer::Add(). Neste método, passamos os seguintes parâmetros:

txt_name: o widget a ser inserido.

1: a proporção (se ele deve se esticar na orientação do sizer e em que proporção de acordo com os outros widgets no mesmo sizer).

wxALL | wxEXPAND: flags deste elemento. wxALL diz que deve haver um espaçamento em todas as direções do widget e wxEXPAND diz que esse widget deve expandir para usar todo o espaço dado a ele. Outras flags podem ser encontradas na documentação do wxSizer.

5: o tamanho da borda que será usada com wxALL.

Por último, devemos dizer ao frame qual o sizer principal e que ele deve ser usado como base para o tamanho da janela. Para isso, chamamos o método wxWindow::SetSizerAndFit() e passamos o sizer vertical como parâmetro, já que ele contém todos os widgets e sizers dentro dele.

O uso de sizers é bastante fácil. Basta criar os sizers, criar os widgets e adicionar os widgets nos sizers. Experimente adicionar outros widgets junto com mais sizers, criando arrumações diferentes.

Leia também a documentação do wxWidgets para ver os outros sizers e veja o tópico "Sizer overview", esta página contém informações úteis na utilização de sizers.

PS.: Caso tenha dúvida em qualquer assunto de algum post do curso, deixe um comentário com sua pergunta. Se os leitores participarem no blog, outras pessoas também aprenderão.

sábado, setembro 23, 2006

WinPolicy na rede Globo

Um usuário do WinPolicy postou a seguinte mensagem na comunidade do WinPolicy no Orkut:

"O WinPolicy apareceu por um acaso nessa reportagem da Rede Globulo de Cuiaba. A materia nao trata sobre o WinPolicy, mas sobre senhas na internet e em geral, e em um dos takes de filmagem aparece claramente no computador de uma Lan House láááááááááá de Cuiaba o WinPolicy sendo utilizado:

http://www.youtube.com/watch?v=eJDEjKIP4n0&NR

Aparece logo nos 00:17" de vídeo... muito legal..."

A URL do post original é:

http://www.orkut.com/CommMsgs.aspx?cmm=3711091&tid=2488845812591714844&start=1

Propaganda gratuita na rede Globo! Que legal! rsrs :)

terça-feira, setembro 19, 2006

Curso de wxWidgets, post 3: Entendendo o "Hello, world!" do post 2

Agora sim, vamos ver como aquilo tudo funciona! :) Estou supondo que todos já conseguiram compilar o wxWidgets e botar ele pra trabalhar. Quem ainda não conseguiu, deixe comentários no post 2.

Voltando ao "Hello, world!"... Em primeiro lugar, devemos incluir os cabeçalhos do wxWidgets (acho que isso é óbvio):

#include "wx/wx.h"


Essa linha inclui os principais cabeçalhos do wx, mas você pode também inserir apenas os cabeçalhos das classes que deseja usar. Por exemplo, se em seu programa você estiver usando apenas um wxFrame e um wxButton, você poderia fazer assim:

#include "wx/app.h"    // Este é para o wxApp
#include "wx/frame.h" // Este é para o wxFrame
#include "wx/button.h" // Este é para o wxButton


Iniciando o programa

Como todo programador C/C++ sabe, o programa sempre começa na função main(). Com wxWidgets, essa função não será mais utilizada. Na verdade, ela é utilizada internamente pelo wxApp, então, ao invés de usar main(), no wxWidgets usamos wxApp::OnInit().

Primeiro, precisamos criar uma classe que irá representar nosso programa. Essa classe deverá ser derivada de wxApp. Veja o código:

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


Esse trecho de código vai criar a classe MeuPrograma que é derivada de wxApp (para os novatos em orientação a objetos, isso significa que a nossa nova classe vai herdar todos os atributos e métodos de wxApp. É como um wxApp + os métodos e atributos que criarmos nesta classe). O método sobrecarregado MeuPrograma::OnInit() será o main() do nosso programa. É este método que será chamado ao executarmos o aplicativo.

Criação da janela principal

Porém, queremos criar uma janela para o nosso programa. Uma janela em wxWidgets é um wxFrame. Então, para criarmos nossa janela específica, vamos criar uma classe para a janela. Essa classe deve ser derivada de wxFrame, já que queremos usar todo o "comportamento" de um wxFrame, mas com algumas coisas a mais e específicas que iremos implementar:

class MeuFrame: public wxFrame
{
public:
MeuFrame(void);
};


Como na classe MeuPrograma, a classe MeuFrame é uma classe derivada de wxFrame, todos os métodos e atributos dela serão herdadas por nossa classe.

Implementando o programa

Bem, já temos uma classe para nosso aplicativo (MeuPrograma) e uma para nossa janela (MeuFrame). Agora, vamos voltar ao MeuPrograma::OnInit(). Devemos começar a programar aqui:

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


Primeiro, declaramos um ponteiro do tipo MeuFrame e criamos uma instância da nossa classe. Na segunda linha, chamamos o método wxFrame::Show() para exibir a janela. Esse método faz com que a janela seja mostrada na tela. Na terceira linha, o método wxApp::SetTopWindow() define a janela instanciada em frame como a janela principal do nosso programa. E por último, return true indica que a inicialização do programa foi feita com sucesso e que ele deve continuar rodando. Se algo acontecesse errado, um return false iria fechar o programa imediatamente.

Bem, isto é o que de fato deve ser feito em wxApp::OnInit(). O resto da implementação deve ficar em outras classes. Mas por enquanto, vamos apenas criar nossa janela. Devemos implementar o construtor dela:

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu programa"))
{
}


Nada é feito neste construtor. Na verdade, apenas passamos alguns parâmetros para o construtor do wxFrame. O primeiro parâmetro indica qual janela é pai desta janela. Como esta é a janela principal, ela não tem pai (NULL). O segundo parâmetro diz qual a ID desta janela. Como não fizemos nenhum evento da janela em si, não é preciso especificar uma ID agora (wxID_ANY). O terceiro parâmetro configura o título da janela (wxT("Meu programa")). Verifique a ajuda do construtor do wxFrame para ver os detalhes de todos os parâmetros.

Agora, devemos dizer ao wxWidgets qual é a nossa classe de aplicativo com a macro:

IMPLEMENT_APP(MeuPrograma)


Pronto! Este é o nosso "Hello, world!" explicado. Mas agora, vamos adicionar algumas coisas a ele.

Adicionando objetos

Primeiro, que tal um texto escrito "Hello, world!"? A classe para textos estáticos no wxWidgets é a wxStaticText. Os principais parâmetros do seu construtor (usaremos apenas estes):

wxWindow *parent: a janela pai deste objeto.
wxWindowID id: a ID deste objeto (caso desejamos criar um evento para ele).
wxString &label: o texto que será exibido.

Primeiro, vamos declarar nosso objeto na definição de MeuFrame. Basta adicionar a declaração na definição da classe, vai ficar assim:

class MeuFrame: wxFrame
{
public:
MeuFrame(void);

private:
wxStaticText *text;
};


E em seguida, instanciamos a classe no construtor de MeuFrame, adicionando a seguinte linha:

text = new wxStaticText(this, wxID_ANY, wxT("Hello, world!"));


Vai ficar assim:

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu programa"))
{
text = new wxStaticText(this, wxID_ANY, wxT("Hello, world!"));
}


Compile o programa novamente e execute. Você vai ver o texto "Hello, world!". Explicando os parâmetros:

this: indica que a janela MeuFrame é a janela pai do objeto.
wxID_ANY: indica que não estamos associando nenhuma ID específica ao objeto.
wxT("Hello, world!"): o texto que será exibido.

Uma breve explicação sobre a macro wxT()

Vocês devem ter notado que todas as strings estão envoltas na macro wxT(). Bem, antigamente, as strings eram representadas no formato ASCII, cada caractere ocupava um byte na memória. Porém, alguns idiomas contém caracteres especiais, como o japonês, chinês, árabe..., e um byte não era suficiente para representar todos eles, já que com um byte podemos representar apenas 256 valores diferentes. Surgiram então várias codificações de caracteres para representar cada idioma ou região. Então, para padronizar isso, o padrão UNICODE foi criado. Neste padrão, mais de um byte pode ser utilizado.

Mas o wxWidgets pode estar sendo utilizado em um sistema operacional sem suporte a UNICODE, ou até mesmo, o wxWidgets pode ter sido compilado sem suporte a UNICODE, como eu ensinei no post 2. Para não haver problemas com isso e tornar seu código portável, use a macro wxT(). Essa macro não faz nada em compilações sem UNICODE, mas vai converter a string ASCII para UNICODE, caso sua compilação do wxWidgets esteja usando UNICODE.

Faça mais no "Hello, world!"

Para prática, sugiro criar outros objetos na nossa janela. Algumas sugestões: wxButton, wxTextCtrl, wxComboBox, wxCheckBox e wxRadioBox.

No próximo post, vou mostrar como posicionar os objetos na janela (você vai perceber esse problema quando tentar adicionar novos objetos). Em caso de dúvidas, deixem comentários. :)

segunda-feira, setembro 11, 2006

Curso de wxWidgets, post 2: Configurando uma IDE e compilando o wxWidgets

Bom, vamos começar! Primeiro, escolha uma IDE para programar. Algumas sugestões:

Eclipse: minha IDE favorita. O problema é que não é muito leve, já que foi feita em Java e pra Java :) Mas eu recomendo, tem muitos recursos bons embutidos. Se decidir usar o Eclipse, você precisa instalar um plug-in chamado CDT, ele adiciona recursos para programação em C/C++ no Eclipse (como eu disse, ele foi feito pra Java). http://www.eclipse.org

MinGW Developer Studio: Uma espécie de clone do Microsoft Visual Studio. É leve e bem legal. O problema é que não está mais sendo desenvolvido. http://www.parinyasoft.com

Dev-C++: Uma IDE leve, desenvolvida em Delphi. Não tem muitos recursos como o Eclipse, mas também é agradável de usar. http://www.bloodshed.net

Todas essas IDEs usam o compilador GCC da GNU. O GCC é instalado junto com as IDEs. No caso do Eclipse, você precisa instalar o compilador a parte. Sendo assim, basta baixar o MinGW no site http://www.mingw.org (o link direto para o download da versão 5.0.2 é http://prdownloads.sf.net/mingw/MinGW-5.0.2.exe?download). Baixe também o MSYS (http://prdownloads.sf.net/mingw/MSYS-1.0.11-2004.04.30-1.exe?download), ele é uma espécie de shell para Windows, será necessário mais tarde para compilar o wxWidgets além de possuir alguns programas necessários para o Eclipse.

Se você usa Linux, baixe o Eclipse e certifique-se de que possui o GCC instalado na sua distribuição.

Instalando o MinGW e o MSYS

Se você estiver usando Linux, pule esta parte.

Primeiro, instale o MinGW. O executável vai baixar os pacotes selecionados da Internet e instalar em C:\MinGW. Faça a instalação completa, apesar de precisarmos apenas dos compiladores, do make e da API do Windows (Win32). A instalação é fácil (leia: next, next, next...) :P.

Após instalar o MinGW, vamos ao MSYS. Ele vai fazer uma instalação gráfica e em seguida vai abrir um prompt de comando. Ele vai perguntar onde o MinGW está instalado. Se estiver em C:\MinGW, responda como c:/mingw.

As instalações ainda não acabaram. Precisamos atualizar a variável de ambiente PATH. No Windows NT e seus derivados (2000, 2003 e XP), clique com o botão direito em “Meu Computador -> Propriedades”. Vá na aba “Avançado” e clique no botão “Variáveis de ambiente”. Procure pela variável “PATH” e clique em “Editar”. No final do valor da variável, adicione: ;C:\MinGW\bin;C:\msys\1.0\bin. No Windows 95, 98 e Me, edite C:\autoexec.bat para configurar o valor de PATH.

Isso fará com que os programas instalados possam ser acessados em qualquer diretório pelo prompt do DOS. Então vamos fazer um teste. Abra o prompt do DOS e execute primeiro gcc --version. Será exibida a versão do GCC instalado, significa que o MinGW foi instalado. Em seguida, tente o comando uname -a, esse comando vai mostrar a versão do Windows, significa que o MSYS foi instalado.

Se algum dos comandos não funcionar, tente refazer a instalação do programa que falhou.

Compilando o wxWidgets

Primeiro, baixe a biblioteca do site oficial em http://www.wxwidgets.org. Se estiver no Linux, baixe o wxGTK, no Windows, baixe o wxMSW.

Depois do download, é hora de compilar! No Linux, abra uma janela do terminal ou vá para o modo texto. No Windows, abra o MSYS.

Descompacte o código fonte do wxWidgets em um diretório qualquer e entre neste diretório:

$ cd /caminho/para/o/wx

Agora você vai precisar executar o script de configuração. Geralmente uso da seguinte forma (no Windows, troque o /usr/local/wx/2.6 para algo do tipo /c/wxMSW-2.6:

$ ./configure --prefix=/usr/local/wx/2.6 --disable-debug --enable-shared --disable-unicode

--prefix=/diretorio:
O diretório onde o wxWidgets vai ser instalado

--disable-debug:
Desabilita símbolos de debug (são usados para debugar no GDB)

--enable-shared:
Compila a biblioteca em vários arquivos .so ou .dll


--disable-unicode:
Desabilita o suporte a UNICODE (meio problemático no Windows 9x e NT, pois precisam de uma biblioteca a parte, por isso costumo desabilitar, não vamos escrever programas em árabe mesmo :P)


O script de configuração será executado e vai exibir um pequeno relatório no final. Leia a saída e verifique se condiz com a configuração feita.

Após feita a configuração, compile!

$ make

E depois de toda a compilação (pode demorar um pouco), instale!

$ make install

No Linux, basta agora executar ldconfig pra atualizar a lista de bibliotecas. No Windows, temos que copiar as DLLs pro diretório do sistema:

$ cp -af /c/wxMSW-2.6/lib/*.dll /c/WINDOWS/System32/

Também é necessário copiar uma DLL do MinGW:

$ cp -af /c/MinGW/bin/mingwm10.dll /c/WINDOWS/System32/

Pronto! wxWidgets e compiladores instalados.

Vamos fazer um pequeno teste

Abra sua IDE e copie o seguinte código fonte:

#include <wx/wx.h>

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

class MeuFrame: public wxFrame
{
public:
MeuFrame(void);
};

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

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu Programa"))
{
}

IMPLEMENT_APP(MeuPrograma)


Compile ele na sua IDE. Provavelmente ela ainda não vai estar configurada para usar o wxWidgets, mas você pode compilar manualmente, basta abrir um terminal ou o MSYS no Windows e digitar o comando:

$ g++ -o wx testewx.cpp `wx-config --cxxflags` `wx-config --libs`

No Windows, você vai precisar especificar o caminho do wx-config por completo, /c/wxMSW-2.6/bin/wx-config --cxxflags...):

$ g++ -o wx testewx.cpp `/c/wxMSW-2.6/bin/wx-config --cxxflags` `/c/wxMSW-2.6/bin/wx-config --libs`

E execute o programa:

$ ./wx

Você deverá ver uma janela vazia com o título “Meu Programa”. Esse é nosso “Hello, World”. No próximo post vou explicar esse programa com detalhes.

wxWidgets é isso aí! Se não deu certo, refaça tudo, passo a passo até achar o erro. Por enquanto, tente entender o código sozinho ou até mesmo modificá-lo.

Entendendo o wx-config e configurando sua IDE

Todo programador C/C++ sabe que ao usar a linha de comando, podemos passar alguns argumentos para o gcc e para o g++, como por exemplo, incluir uma biblioteca. Quem nunca usou -lm para incluir o math.h? O que o wx-config faz é justamente isso. Experimente executar wx-config --cxxflags e wx-config --libs no seu terminal. O que você vai ver são os argumentos que devem ser incluídos no g++ na hora de compilar (--cxxflags) e na hora de “linkar” (--libs).

Se você quer usar uma IDE para compilar seus programas em wxWidgets, você precisa inserir esses parâmetros nas propriedades do seu projeto. No Eclipse, por exemplo, basta clicar com o botão direito do mouse na pasta do projeto e escolher a opção “Properties” no menu de contexto. Clique em “C/C++ Build” no painel à esquerda e insira `wx-config --cxxflags` nos argumentos de comando do g++ em “GCC C++ Compiler” e `wx-config --libs` em “GCC C++ Linker”. Veja a figura abaixo:



Se estiver usando Windows, você precisa executar o wx-config no MSYS, copiar a saída e inserir no Eclipse. Ou, você pode configurar cada configuração individualmente (Preprocessor, Directories, Optimization...)

OBSERVAÇÃO: No Eclipse do Windows, substitua o /c da saída do wx-config por c:/. Por exemplo: ao invés de -I/c/wxMSW-2.6/include, use -Ic:/wxMSW-2.6/include.

terça-feira, setembro 05, 2006

Windows Vista

Estava eu curioso para ver o sucessor do Windows XP, o Vista. Então, abri o aMule e fiz uma busca. Baixei o DVD do Windows Vista beta 2 e instalei em um computador com a seguinte configuração de hardware:

Pentium 4 HT 3.0 GHz
512 MB de memória RAM
Plca de vídeo on-board
HD de 80 GB (não lembro a marca)
Placa de rede on-board SiS
Placa de rede off-board D-Link AirPlus G+ (rede sem-fio)

Comecei a instalação. Concordo que o novo instalador está realmente bonito, isso me deixou mais ansioso pra ver a cara do novo Windows.

Ao final da instalação, os tambores batiam enquanto o Windows Vista carregava nesse computador. Efetuei logon e entrei no sistema. Papel de parede bonito...

Bem, logo de cara pude perceber que a nova barra de tarefas do Windows Vista parece o painél do KDE, o botão "Iniciar" virou um círculo preto com o logotipo do Windows (estilo o menu K). As bordas das janelas parecem ter sido inspiradas nos inúmeros temas existentes para o GNOME e KDE. Os botões parecem com os do Mac e a cara do Windows Explorer me lembrou uma mistura de Nautilus (GNOME) com Konqueror (KDE) - não falando do tema, mas da organização das coisas.

Ora, mas ficou bonito!!! Isso é que importa. Mais importante que essa beleza toda (que eu já havia saboreado no Linux) é minha memória RAM. Esse Vista é um ladrão! Basta efetuar logon no sistema para consumir 380 MB (inserimos um pen drive USB e o consumo de memória subiu pra 400 MB).

Pra quem gosta de jogar paciência, campo minado e aqueles joguinhos do Windows, sugestão: compre uma placa 3D. Ao abrir Paciência, ele me avisou que eu não tenho placa aceleradora 3D, portanto, o jogo poderia ficar lento... e ficou (e como!!!). Ah! Se você pretende ver vídeos no seu Vista, compre uma placa 3D também, pois sem ela o Media Player nem abre o vídeo (pelo menos não abriu nessa on-board).

Bem, o novo KDE 3.5 roda suavemente em um laptop Pentium III 600 MHz com 312 MB de RAM e é mais bonito que o Windows Vista.

Não escrevi esse post pra esculhambar a Microsoft, mas acho que ela poderia ter feito um trabalho melhor. E não falo de interface gráfica bonita, mas de programação eficiente que não sugue tantos recursos da máquina. Minha opinião é que esse tipo de coisa é proposital, pra alavancar o consumo de hardwares caros.

Pelo menos o WinPolicy rodou sem problemas no Windows Vista. :)

sexta-feira, setembro 01, 2006

Curso de wxWidgets em C++

Olá, pessoal.

Decidi finalmente começar meu curso de wxWidgets através do meu blog. Eu já vinha idealizando ele desde o meu primeiro dia de blogueiro. É um tipo de "Aprenda você mesmo wxWidgets em x posts" (o "x" significa que não sei em qual post vou parar). O objetivo é ensinar como fazer bons softwares com interfaces gráficas usando C++.

Muita gente pensa que programar em C e C++ é extremamente complicado. A culpa é da API do Windows! Realmente ela é um pouco chata de aprender, pelo menos esta é minha opinião. Aí, infelizmente, as pessoas tendem a correr pro Java.

OBSERVAÇÃO: A partir deste ponto, é necessário avisar que no percurso deste curso, e provavelmente em alguns outros posts do meu blog, você verá frases e afirmações não muito amigáveis à esta linguagem. Não tenho nada contra Java, até conheço um pouco da linguagem (não tanto quanto C e C++), mas faço isso porque gosto de pirraçar programadores Java, é meu esporte favorito.

Voltando ao curso, minha tarefa aqui é resgatar as pobres almas perdidas no mundo do Java, Delphi, Visual Basic e outros, trazendo-as pro lado do C/C++. Você vai aprender que programar com interfaces gráficas em C++ usando wxWidgets é ainda mais fácil que programar em Java.

"O que eu NÃO vou aprender?"

Processos de desenvolvimento de software, documentação, análise, etc. Bem, provavelmente eu fale um pouco sobre essas coisas, mas não vou entrar em detalhes. O objetivo do curso é o wxWidgets no C++.

"O que é preciso para estudar através deste curso?"

Bem, se você já souber C e C++, já é o suficiente. Mas se você sabe pouco ou nada sobre estas linguagens, não se desespere! Existe um curso on-line de C da UFMG em http://ead1.eee.ufmg.br/cursos/C/ . Mas é bom lembrar que você precisa saber pelo menos o básico de orientação a objetos em C++, já que o wxWidgets é orientado a objetos.

"Que bom! Quais serão os tópicos estudados?"

Não tenho um cronograma fixo para seguir, mas pretendo começar da seguinte forma:

- Introdução a wxWidgets, como configurar, instalar e usar;
- "Hello, world" em wxWidgets;
- E aí vamos nos infiltrando nas outras classes da Framework...

Referências bibliográficas

Para dúvidas de C++, uso o livro "C++: Como Programar" de Deitel. Para dúvidas sobre o wxWidgets, uso a documentação on-line no endereço http://www.wxwidgets.org/
Mais uma vez, recomendo o curso de C da UFMG.

Outros detalhes

Tentarei escrever um post por semana, isso vai dar tempo para os visitantes estudarem o post e para que eu possa preparar o próximo ("tentarei", porque preciso dividir meu tempo com outras coisas, inclusive o lazer). Cada post também terá um código de exemplo do assunto abordado e os visitantes poderão deixar comentários, podendo tirar dúvidas com outros visitantes ou comigo mesmo, ou até mesmo sugerir alguma coisa.

Então, espero que isso dê certo. Além de divulgar o conhecimento, pretendo também melhorar o meu próprio conhecimento. :)

domingo, agosto 20, 2006

Produtividade na programação (ou no desenvolvimento de softwares)

Quem está no curso de Ciência da Computação da UESC sabe dos últimos e-mails que rolaram na lista de discussão dos alunos, sobre a utilização de ferramentas RAD para criar interfaces gráficas em C++. Um dos colegas do curso defendeu o uso de ferramentas RAD nesta etapa do desenvolvimento.

Bem, ele defende veementemente qualquer ferramenta que se propôe a facilitar e agilizar alguma etapa do desenvolvimento de um software, mas acho que ele esquece de analisar se essa ferramenta não vai acabar atrapalhando e atrasando etapas posteriores do desenvolvimento, resultando em um projeto mais demorado do qual se não fosse utilizada tal ferramenta.

Eu dei minha contribuição na lista de discussão. Argumentei que nem sempre agilizar uma etapa agiliza o todo. Como a discussão era sobre criação de interfaces gráficas, também argumentei que essa etapa do desenvolvimento leva pouco tempo e que se feita corretamente, o tempo dela pode se tornar desprezível em relação ao todo.

O e-mail que eu postei na lista de discussão está abaixo. Ele vai ser o post de hoje do meu blog:

"A conversa sobre usar ou não uma ferramenta RAD pra criar interfaces gráficas me fez pensar sobre produtividade na programação. Então, vou expôr o que eu pensei e o que eu acho sobre isso.

As empresas estão atrás de produtividade. É verdade, claro. E também é verdade que devemos ser produtivos, para assim termos um emprego, ganhar dinheiro e nos manter, sempre pensando em ter algo mais pra entretenimento e futilidades extras. "Mas Just é um cara tão GNU!! Como pode dizer isso??" Ora, eu também gosto de dinheiro :)

Entrando na conversa de programação, não adianta muito fazer as janelas (ou outras interfaces gráficas) bem rapidamente. O cara abre a IDE, desenha tudo rapidinho e depois vem a pergunta: "E agora? O que eu faço?" É preciso programar! Escrever código, claro!

Aí entram as grandes empresas. Essas sim precisam ser muito produtivas e rápidas. Como já foi discutido na lista antes e continuou sendo essa semana, empresas grandes e importantes exigem experiência. Bem, um programador experiênte consegue criar uma interface gráfica na mão tão rapidamente quanto usando uma IDE RAD. E ainda, criar a interface na mão pode fazer o desenvolvimento se tornar mais rápido por um todo.

O que eu quero dizer, é que se você desenha a interface com uma IDE RAD, ela fica pronta rapidamente, mas dá trabalho pra fazer algumas alterações. Se você faz via código, dependendo da sua experiência na framework e na linguagem utilizada, você cria a janela tão rapidamente quanto se usasse uma IDE RAD. E ainda, se quiser fazer alterações futuras, fica bem simples. É só adicionar uma linha, ou alterar outra, e por ai vai.

Mas ainda não acabei. Acrescento ainda, que durante todo o processo de desenvolvimento de um software, a interface gráfica pode ser algo em torno de 10% do projeto total. Vou citar como exemplo o WinPolicy (todo mundo já deve tá de saco cheio dele :P). Fiz as interfaces dele via código (aproveitei essa etapa pra aprender wxWidgets, hoje eu criaria a mesma interface muito mais rápido que antes). Depois de fazer as interfaces, foi só programação das funcionalidades. Lancei a versão 3.0. Adicionava algum recurso, corrigia bugs, 3.0.1, 3.0.2, 3.1, 3.1.1, 3.1.2 e agora está em 3.1.3. Quer dizer, a criação da interface gráfica tomou em torno de 10% do tempo e do código do software inteiro. O importante é programar bem pra fazer o resto com velocidade e qualidade.

Citando outro exemplo, estou terminando um outro projeto. Como já sabia mais de wxWidgets, a interface gráfica foi um tapa! Depois disso, fui implementando as funções do software. Essa semana terminei a versão beta. Pretendo lançar ele em breve.

Concluindo: não viagem nessa de querer uma ferramenta que faça tudo pra vocês, ou então a única experiência que vocês vão ter vai ser em clicar nos botões de uma ferramenta específica. No dia que ela cair em desuso, lascou-se! Se você aprende a programar bem, você não fica dependente de ferramenta. Além disso, essa experiência vai ajudar muito pra aprender outras linguagens e frameworks."

Explicando um pouco mais, acho melhor aprender a programar bem do que usar uma ferramenta bem. Se você entende bem a programação e o uso das frameworks, caso seja preciso aprender outra linguagem ou framework, vai ficar mais fácil do que se treinar em uma nova ferramenta de "clique-e-arraste".

Estão aí meus argumentos. Acredito estar correto. Espero receber comentários sobre o assunto. :)

sexta-feira, agosto 04, 2006

Backports (Debian)

Todo usuário do Debian sarge deve ter um problema em comum: apesar do sistema ser realmente estável, alguns softwares estão bastante desatualizados. Exemplos:

- Firefox 1.0.4
- Thunderbird 1.0.2
- OpenOffice.org 1.1.3
- Gaim 1.2.1
- e por aí vai...

Existe a opção de você não utilizar os pacotes Debian desses softwares e baixar o fonte no site oficial e compilar. Mas qual a graça de usar Debian sem o apt?

Essa semana, enquanto pesquisava sobre como instalar o Catalyst no Debian sarge (ele tem pacotes no testing e no unstable, mas não no stable), encontrei um site chamado Debian Backports, que fornece os pacotes do Debian testing (alguns do unstable), compilados com as libs do stable (sarge). E lá estava o libcatalyst-perl, que é do testing, mas preparado para o sarge :)

O Backports funciona assim: você inclui o repositório deles em /etc/apt/sources.list e pode instalar os pacotes mais recentes com o apt-get:

deb http://www.backports.org/debian/ sarge-backports main contrib non-free

Depois é preciso adicionar essas linhas em /etc/apt/preferences (isso vai desativar os pacotes do Backports e fazer o apt usar os pacotes do sarge como padrão):

Package: *
Pin: release a=sarge-backports
Pin-Priority: 200

Para instalar um pacote que está no Backports:

# apt-get update
# apt-get -t sarge-backports install mutt

Pronto. Seja feliz no Debian sarge! :)

quarta-feira, julho 26, 2006

OpenOffice.org 2 no Debian sarge (stable)

Como os usuários Debian sabem, a versão do OpenOffice.org no Debian sarge (stable) é a 1.1.3, a versão 2 só está presente no etch (testing) e no sid (unstable).

Porém, eu decidi fazer um downgrade. Usava o Debian etch em casa, e decidi voltar para o sarge. Porque? Porque alguns pacotes sempre faltam nas versões testing do Debian, além de eu desconfiar que o atual X.Org do testing está com o desempenho um pouco abalado e que algumas fontes estão estranhas (paranóia minha).

Eu sempre sentia um pouco de vontade de voltar pro sarge, mas duas coisas me impediam, na verdade, a falta delas: o OpenOffice.org do sarge é o 1.1.3 e o Firefox é o 1.0.4.

Bem, o Firefox eu posso baixar a versão mais nova no site oficial e instalar. O OpenOffice.org também... mas como muitos devem ter notado, o antigo instalador standalone do OpenOffice.org sumiu!!! Agora são apenas RPMs... que droga... e eles não dão pacotes .deb.

Mas nem tudo está perdido. Descobri recentemente que o site brasileiro do OpenOffice.org fornece pacotes .deb (que bom!). E mesmo que você decida usar os pacotes oficiais (RPM), isso é possível com uma ferramenta chamada alien, um conversor de "quase qualquer coisa" para ".deb". E antes que eu me esqueça (e você também):

# apt-get install alien

Então, se você baixar o BrOffice, basta descompactar o arquivo e fazer:

# dpkg -i *.deb

Mas se você prefere a versão oficial em inglês, descompacte o arquivo baixado e entre no diretório criado por ele. Lá dentro, você verá um diretório chamado "RPMS", "cd nele". Agora, vamos ao alien:

# alien *.rpm

Os RPMs irão se transformar em .deb. Após isso:

# dpkg -i *.deb

Pronto! OpenOffice.org 2 instaldo no Debian sarge. Mas isso é muito simples, ainda não está digno de um post no meu blog. Vamos ao problema!

Se seu Debian sarge estiver atualizado, após instalar o OpenOffice.org, tente abrir o Impress. Tentou? Acho que você levou um belo CRASH! Ele simplesmente fecha e abre o Writer. E se você fizer alguma coisa mais elaborada no Writer, ele também fecha.

"Qual o problema?", você me pergunta. Após passar uma noite de ódio com esse problema (eu tava querendo fazer um trabalho pra Universidade), acabei descobrindo após fuçar no oráculo. O OpenOffice.org 2 está conflitando com a versão 2.1.7-2.5 do libfreetype6. A solução é fazer um downgrade para a versão 2.1.7-2.4.

# apt-get install libfreetype6=2.1.7-2.4

Agora, tente abrir o Impress e verá que ele funciona. :)