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

3 comentários:

Andrei Regiani disse...

Parabens, muito bom, sempre quiz fazer um Notepage =], gosto muito do seu curso!

Anônimo disse...

Apenas uma pequena falta de atenção na codificação, Justin.

errado:
for (unsigned int line = 0; line <> GetNumberOfLines(); line++)

correto:
for (unsigned int line = 0; line != txt_file->GetNumberOfLines(); line++)

Anônimo disse...

Gostei visse, caba bom.