segunda-feira, janeiro 29, 2007

Curso de wxWidgets, post 12: Adicionando uma barra de status

O post de hoje vai ser bem simples e rápido, iremos apenas adicionar uma barra de status ao nosso editor de textos. Essa barra de status irá informar o nome do arquivo que estamos editando.

Para a barra de status, vamos usar a classe wxStatusBar. O construtor é bem simples:

wxStatusBar(wxWindow* parent, wxWindowID id = wxID_ANY, long style = wxST_SIZEGRIP,
const wxString& name = "statusBar")

parent: A janela que vai conter a barra de status.

id: ID da barra, para os eventos.

style: Estilo da barra. Existe apenas o estilo wxST_SIZEGRIP, que exibe um "puxador" no canto
direito da barra no Windows.

name: Nome da barra.


Nenhum dos parâmetros são obrigatórios, existe o construtor sem parâmetros também. Mas recomenda-se usar this como primeiro parâmetro, para associar a barra com a janela que a está contendo. E é assim que nós iremos fazer no nosso editor de textos. Na definição da classe MeuFrame, temos que adicionar a barra como um atributo em private:

private:
wxStatusBar *stbar;


No construtor de MeuFrame, iremos instanciar o objeto e definir um texto inicial para a barra de status:

// Barra de status
stbar = new wxStatusBar(this);
stbar->SetStatusText(wxT("Sem título"));


O método wxStatusBar::SetStatusText() recebe dois parâmetros: o primeiro, é o texto que você irá colocar na barra, o segundo e opcional, é o número do campo da barra que irá receber o texto.

No nosso exemplo, estamos usando apenas um campo de texto, mas podem existem barras com vários. Você pode ajustar o número de campos da sua barra com o método wxStatusBar::SetFieldsCount(). Por exemplo, se quiser três campos na sua barra, use o método da seguinte forma:

stbar->SetFieldsCount(3);


E para alterar o texto do segundo campo, use:

stbar->SetStatusText(wxT("Campo 2"), 1);
// O primeiro campo é o zero


Como temos apenas um campo em nossa barra, não precisamos especificar o número dele.

Em seguida, devemos "colar" esta barra de status na janela. Fazemos isso com o método wxFrame::SetStatusBar(), ainda no construtor:

SetStatusBar(stbar);


Pronto, a barra já está criada e dentro da nossa janela. Vamos agora atualizar os métodos MeuFrame::Abrir() e MeuFrame::Salvar(), que deverão modificar o texto da barra de status.

No código do nosso editor de textos, procure as linhas:

lb_filename->SetLabel(Filename);


Essas linhas modificam o nome do arquivo no nosso wxStaticText. Iremos remover essas linhas e no lugar delas, colocar:

stbar->SetStatusText(Filename);


Agora o editor de textos já está com a barra pronta. Já que não vamos mais usar o lb_filename, podemos removê-lo do construtor e da definição de MeuFrame.

Compile o novo código e veja a barra em funcionamento:



Código-fonte atualizado

O código completo e atualizado está abaixo. No novo código, eu removi o lb_filename, como mostrado neste post. Também removi btn_load e btn_save, já que agora temos a barra de ferramentas. Além disso, criei o método MeuFrame::Novo(), para criar um novo arquivo e seu respectivo botão na barra de ferramentas. Também removi a mensagem de boas-vindas. Olhe o código inteiro para ver as modificações e entendê-las.

/* A Casa de Just - http://jpjust.blogspot.com
* Curso de wxWidgets: Um editor de textos
*
* O objetivo deste código-fonte é demonstrar diversas classes
* ensinadas no curso de wxWidgets do blog "A Casa de Just".
*
* As aulas do curso de wxWidgets podem ser encontradas em forma
* de posts no blog: http://jpjust.blogspot.com
*
* Copyright (c) João Paulo Just <jpjust@justsoft.com.br>
* A Casa de Just - http://jpjust.blogspot.com
* 29 de janeiro de 2007, 9:48, Ilhéus, BA, Brasil.
*/

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

// IDs
enum
{
ID_TBAR_NEW,
ID_TBAR_LOAD,
ID_TBAR_SAVE,
ID_TBAR_ABOUT
};

// 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 OnToolBarClick(wxCommandEvent &event);

// Métodos auxiliares
void Novo(void);
void Abrir(void);
void Salvar(void);
void Sobre(void);

DECLARE_EVENT_TABLE()

private:
// Widgets do frame
wxTextCtrl *txt_file;
wxToolBar *tbar;
wxStatusBar *stbar;
};

// Inicialização do programa
bool MeuPrograma::OnInit(void)
{
wxInitAllImageHandlers(); // Inicia todos os hadlers de imagens do wxBitmap

MeuFrame *frame = new MeuFrame();
frame->Show();
SetTopWindow(frame);
return true;
}

// Tabela de eventos
BEGIN_EVENT_TABLE(MeuFrame, wxFrame)
EVT_TOOL_RANGE(ID_TBAR_NEW, ID_TBAR_ABOUT, MeuFrame::OnToolBarClick)
END_EVENT_TABLE()

// Construtor do frame
MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Editor de textos - http://jpjust.blogspot.com"))
{
// Sizer e widgets
wxBoxSizer *sizer_v = new wxBoxSizer(wxVERTICAL);

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

// Barra de ferramentas
tbar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_TEXT);

tbar->AddTool(ID_TBAR_NEW, wxString(wxT("Novo")), \
wxBitmap(wxT("/usr/share/pixmaps/gedit-icon.png"), wxBITMAP_TYPE_PNG));

tbar->AddTool(ID_TBAR_LOAD, wxString(wxT("Abrir")), \
wxBitmap(wxT("/usr/share/pixmaps/gnome-folder.png"), wxBITMAP_TYPE_PNG));

tbar->AddTool(ID_TBAR_SAVE, wxString(wxT("Salvar")), \
wxBitmap(wxT("/usr/share/pixmaps/gnome-cd.png"), wxBITMAP_TYPE_PNG));

tbar->AddSeparator();

tbar->AddTool(ID_TBAR_ABOUT, wxString(wxT("Sobre")), \
wxBitmap(wxT("/usr/share/pixmaps/gnome-info.png"), wxBITMAP_TYPE_PNG));

tbar->Realize();

// Barra de status
stbar = new wxStatusBar(this);
stbar->SetStatusText(wxT("Sem título"));

// Posicionamento
sizer_v->Add(txt_file, 1, wxALL | wxEXPAND, 5);

SetSizerAndFit(sizer_v);

// Insere a barra de ferramentas e a barra de status
SetToolBar(tbar);
SetStatusBar(stbar);
}

// Limpa a tela para um novo arquivo
void MeuFrame::Novo(void)
{
int msg = wxMessageBox(wxT("Deseja salvar o arquivo atual antes de criar um novo?"), \
wxT("Novo arquivo"), wxYES_NO | wxCANCEL);

if (msg == wxYES) // Salva
Salvar();
else if (msg == wxCANCEL) // Cancela a operação
return;

// Cria um novo arquivo
txt_file->Clear();
stbar->SetStatusText(wxT("Sem título"));
}

// Abre um arquivo
void MeuFrame::Abrir(void)
{
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;

txt_file->LoadFile(Filename);

// Atualiza o nome
stbar->SetStatusText(Filename);
}

// Salva o arquivo aberto
void MeuFrame::Salvar(void)
{
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;

txt_file->SaveFile(Filename);

// Atualiza o nome do arquivo
stbar->SetStatusText(Filename);
}

// Janela "Sobre"
void MeuFrame::Sobre(void)
{
wxMessageBox(wxT("Curso de wxWidgets\n\nhttp://jpjust.blogspot.com"), wxT("Sobre"), wxICON_INFORMATION);
}

// Método para a barra de ferramentas
void MeuFrame::OnToolBarClick(wxCommandEvent &event)
{
switch (event.GetId())
{
case ID_TBAR_NEW:
Novo();
break;

case ID_TBAR_LOAD:
Abrir();
break;

case ID_TBAR_SAVE:
Salvar();
break;

case ID_TBAR_ABOUT:
Sobre();
break;
}
}

IMPLEMENT_APP(MeuPrograma)

2 comentários:

Unknown disse...

Para Guilherme:

Desculpe a demora de responder seu comentário, mas estive fora esta semana.

Nunca trabalhei com impressão no wx, inclusive, é uma idéia para um post futuro. Olhando a documentação, achei esta página
http://www.wxwidgets.org/manuals/stable/wx_printingoverview.html#printingoverview

que dá uma geral sobre as classes de impressão.

Como você resolveu o problema, poste sua solução aqui para que todos nós possamos ver. :)

Anônimo disse...

a grande questao eh q nao resolvi o problema... soh matei o probelma dos \t e dos \n... dos \t, eh mto simples... faz um for pra varrer cada caractere da string, e adicioálos a uma outra string vazia... a nao ser q eles sejam iguais a \t, aih substitui por 8 espaços...
e pros \ns, eh fazer um for pro numero de \ns, fazendo o seguinte... copia o valor da string a imprimir pra uma outra, faz o DrawText com o conteudo antes do primeiro \n, e remove esse conteudo... Aih acrescenta no parametro y do DrawText o tamanho da linha, q pode ser pego com o GetTextExtent... O for se encarrega de fazer outro DrawText, e outro, e outro... se quiser o cdigo manda pro email pq por aqui ficou mto confuso... Mas a questao é q ele não consegue delimitar uma área fixa (se a linha for muito grande, ela é cortada na lateral, e não desenhada na linha de baixo) e também não imprime mais de uma página, ssimplesmente corta tudo o que estiver abaixo do fim da primeira página... Esses problemas é q devem ser resolvidos...