Montaremos um super-exemplo para entendermos na prática o uso de ShowMessage, MessageDlg, MessageBox, OpenDialog, SaveDialog etc. Veremos também, rapidamente, como tratar erros e criar exceções.
Entendendo e usando ShowMessage, MessageDlg e MessageBox
Para começar vejamos primeiramente como funcionam estas três funções usadas para exibir mensagens ao usuário começando por ShowMessage.
ShowMessage é uma função que exibe uma mensagem em tela, normalmente utilizada apenas para exibir alguma mensagem simples que não exige ícone ou pergunta. Por isso seu único parâmetro é o texto que será exibido ao usuário final. A seguir podemos ver sua declaração original prevista na Unit Dialogs do Delphi.
procedure ShowMessage(const Msg: string);Seu uso também é simplificado. Para testarmos a função, bem como as demais que veremos, entre no Delphi e crie uma nova aplicação usando o menu File|New>Application ou utilize o projeto que o Delphi cria automaticamente pra nós ao abrir o IDE. Salve o formulário como “Mensagens.pas” e a aplicação como “Msgs.dpr”.
Insira um componente GroupBox da paleta Standard e aumente sua altura e largura para que possamos colocar botões grandes dentro dele. Após isso insira um Button(“btnShowMessage”) também da paleta Standard dentro do GroupBox e modifique seu Caption para ShowMessage. Aproveite e insira outros dois buttons no GroupBox mudando seus nomes para “btnMessageDlg” e “btnMessageBox”. Seus Captions deverão ficar como seus nomes retirando apenas o prefixo btn do início do nome. Se preferir veja a sugestão de layout na Figura 1.
Clique duas vezes no btnShowMessage e digite o código a seguir em seu evento OnClick.
ShowMessage(‘Exemplo simples de mensagem com “ShowMessage”.’);Note que o uso é bastante simplificado como já mencionado, bastando apenas passar para à função qual o texto será exibido. Nesse caso a frase "Exemplo simples de mensagem com ShowMessage". O resultado podemos ver na Figura 2.
Como podemos notar, a função ShowMessage exibe um texto simples com apenas o botão Ok no centro da mensagem. Uma coisa interessante a se observar é que o título da janela exibe a palavra Msgs, exatamente o nome que colocamos para o projeto. O ShowMessage captura o nome da aplicação e o coloca automaticamente no título da mensagem.
Pois bem, podemos usar o ShowMessage em qualquer ocasião, mas se precisarmos exibir um ícone de atenção ou alerta precisamos recorrer a algo mais sofisticado.
Vamos à função MessageDlg que também é declarada na Unit Dialogs do Delphi. Sua assinatura padrão pode ser vista logo a seguir:
function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;Nota: Assinatura é a declaração original de uma procedure ou function, ou seja, seu nome e parâmetros de entrada bem como possíveis retornos.
Podemos perceber de início que já complicou um pouco mais. Porém nem tanto assim, vejamos o que cada parâmetro significa, assim temos uma visão macro sobre suas funcionalidades. Seus parâmetros são:
- Msg: Esse parâmetro é do tipo string, ou seja, texto. Contém a mensagem que será exibida ao usuário do sistema;
-
DlgType: Tipo de mensagem, também especifica qual ícone aparecerá na tela; A declaração desse tipo diz que podemos declarar como:
- mtWarning: Aviso;
- mtError: Erro;
- mtInformation: Informação;
- mtConfirmation: Confirmação;
- mtCustom: Personalizado;
-
Buttons: Botões da mensagem. Podem ser:
- mbYes: Sim;
- mbNo: Não;
- mbOK: Ok;
- mbCancel: Cancelar;
- mbAbort: Abortar;
- mbRetry: Repetir;
- mbIgnore: Ignorar;
- mbAll, mbNoToAll e mbYesToAll: “Todos”, “Não para todos” e “Sim para todos”;
- mbHelp: Ajuda;
- HelpCtx: Contexto de Help, ou seja, o valor numérico de atalho para o help do sistema se existir um;
Vejamos na prática. Clique duas vezes no segundo botão e digite o código a seguir:
MessageDlg('Mensagem simples usando "MessageDlg".',
mtInformation, [mbOk, mbNo], 0);Nesse caso estamos definindo que uma mensagem com a frase “Mensagem simples usando MessageDlg.” será exibida na tela. O ícone usado é o de informação (“mtInformation”) e o botão é o Ok (“mbOk”). Como não temos um help, passamos como 0 o último parâmetro.
Antes de visualizarmos o resultado vamos a explicação e uso da terceira função, MessageBox.
MessageBox, visualmente, tem a mesma aparência que a MessageDlg, com uma leve diferença que já vamos notar de início. Inicialmente, quais são e como usar seus parâmetros?
- hWnd: Parâmetro do tipo HWND. Esse parâmetro é o Handle da janela. Podemos passar de diversas formas, tais como: Handle, Application.Handle ou 0 (“zero”);
- lpText: Do tipo PAnsiChar. É um string também, porém terminado com o caracter nulo (#0). Quando precisamos passar mais de uma frase para ele é necessário envolvermos as frases dentro de uma função de conversão, PChar. Veremos mais a seguir;
- lpCaption: É o título da mensagem. Nesse caso devemos dizer à função qual a palavra/frase que deverá ser colocada no título;
- uType: Cardinal. É aqui que escolhemos qual o tipo de mensagem (ícone), botões e defaults.
Nota: Toda janela e/ou objeto no Windows recebe um número de Handle ao ser instanciado (“criado”). É basicamente seu endereço de memória para que o Sistema Operacional possa fazer referência a ele.
Para entendermos melhor digite o código em seguida no evento OnClick do terceiro botão. Logo após execute a aplicação e clique nos botões MessageDlg e MessageBox. Veja as diferenças na Figura 3.
MessageBox(Handle, 'Mensagem simples usando "MessageBox"',
'Texto do título', MB_YESNO + MB_ICONINFORMATION);
A diferença mais nítida que podemos ver está justamente nos botões de ambas as mensagens. A função MessageDlg é nativa do Delphi e exibe sempre os botões em inglês ao contrário da função MessageBox, declarada na Unit Windows, que se adapta a linguagem do sistema operacional onde está rodando, ou seja, como sistema operacional onde tirei as fotos para este artigo estava em português automaticamente os botões são exibidos como “Sim” e “Não”. Se testássemos em uma cópia em inglês do Windows, esses botões estariam como no MessageDlg.
A segunda diferença é mais sutil, mesmo assim podemos notar. O título de ambas é diferente. Como em MessageDlg não definimos qual o título será exibido, o sistema pega pelo tipo de mensagem, nesse caso de informação (Information). Já na MessageBox definimos no segundo parâmetro que o título deveria conter a mensagem “Texto do título”.
Em se tratando de codificação temos diferenças gritantes, pois os parâmetros são bastante incomuns. Um exemplo disso são os parâmetros de tipo de mensagem e botões escolhidos para exibição. Em MessageDlg definimos o tipo da mensagem e os botões separadamente.
No segundo parâmetro informamos o tipo de mensagem, mtInformation, e no parâmetro seguinte os botões que aparecerão. Nesse caso passamos “Sim” e “Não” separados por vírgula e envolvidos em colchetes, ex: [mbYes, mbNo]. Se quiséssemos mais botões, bastaria incluir novos itens, como no caso a seguir onde mostramos os botões “Sim”, “Não”, “Não para todos”, “Sim para todos” e “Cancelar”. O resultado seria como na Figura 4.
MessageDlg('Mensagem simples usando "MessageDlg".',
mtInformation, [mbOk, mbYes, mbNoToAll,
mbYesToAll, mbCancel], 0);
Em MessageBox não é possível obter o mesmo resultado. Porém outras vantagens são obtidas ao usar essa função. Caso seja necessário definir um botão diferente como default (“padrão”) isso só será possível com MessageBox. Imagine uma mensagem de confirmação: “Deseja excluir o arquivo atual?”. E nessa mensagem você queira definir que o segundo botão será o foco principal da mensagem, evitando que o usuário cometa erros. Como faríamos?
Pois bem, com MessageBox é possível escolhermos o botão default, veja:
MessageBox(Handle, 'Confirma exclusão do arquivo',
'Texto do título', MB_YESNO + MB_ICONINFORMATION + MB_DEFBUTTON2);Observe que incluímos uma nova constante: MB_DEFBUTTON2. São quatro ao todo. Nesse caso estamos dizendo que o botão que aparecerá em foco no momento que a mensagem abrir será o segundo botão, o Não.
Se quisermos incluir mais de uma linha em uma mensagem basta usarmos o caractere 13 que equivale ao Enter do teclado. Veja:
MessageBox(Handle, PChar('A exclusão deste arquivo será permanente.'
+ #13 + 'Confirma a exclusão do arquivo'),
'Texto do título', MB_YESNO + MB_ICONINFORMATION +
MB_DEFBUTTON2);E já que estamos falando de erros de usuário, vejamos rapidamente como fazer uso das mensagens para desviar o fluxo do sistema e tratar alguns erros.
Tratando erros e desviando o fluxo
Certamente um sistema sem tratamento de erros e/ou desvio de fluxo de tarefas se torna um tanto quanto perigoso e não muito inteligente. O que veremos a seguir é como fazer uso das mensagens antes explicadas para prever as ações do usuário e desviá-lo para outra tarefa, bem como a criação de exceções.
Insira um novo GroupBox ao formulário e nele um novo Button(“btnMessageDlgComIf”) com o Caption igual a “MessageDlg com If”. Logo abaixo coloque um novo Button(“btnMessageBoxComIf”) e troque seu Caption para “MessageBox com If”. Por fim adicione um Label(“lblResultadoMsg”) abaixo deste último botão. A seguir veremos a assinatura das três funções que vimos na seção anterior:
procedure ShowMessage(const Msg: string);
function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
function MessageBox(hWnd: HWND; lpText: PAnsiChar; lpCaption: PAnsiChar;
uType: Cardinal): Integer;Perceba que na verdade ShowMessage não é uma function (“função”) e sim uma procedure (“procedimento”) o que significa que não retorna resultado, diferentemente das demais funções que retornam um valor do tipo Integer, ou seja, inteiro. É aí que está a parte interessante de tudo. Com MessageDlg ou MessageBox podemos “perguntar” ao usuário o que ele deseja fazer. Pegamos a sua resposta e desviamos o fluxo do sistema para outra parte dele. Experimente, digite o código abaixo no evento OnClick do btnMessageDlgComIf.
if MessageDlg('Você deseja exluir este arquivo?', mtConfirmation,
[mbYes, mbNO], 0) = mrYes then
lblResultadoMsg.Caption := 'Sim, o usuário deseja excluir o arquivo'
else
lblResultadoMsg.Caption := 'Não, o usuário desistiu';Salve, execute a aplicação e clique no botão “MessageDlg com If”. Fizemos uma pequena verificação. Se o usuário escolher “Sim”, o resultado da função é igual a mrYes, ou seja, o Label é atualizado com a mensagem “Sim, o usuário deseja excluir o arquivo”, caso contrário a mensagem é “Não, o usuário desistiu.”. A constante mrYes está declarada na Unit Control do Delphi e contém entre vários retornos, as opções mrNo (“Não”) e mrOk (“Ok”).
Também é possível obtermos o mesmo resultado utilizando MessageBox, porém os retornos são diferentes, veja:
if MessageBox(Handle, 'Você deseja excluir este arquivo?',
'Exclusão', MB_YESNO + MB_ICONQUESTION) = ID_YES then
lblResultadoMsg.Caption := 'Sim, o usuário deseja excluir o arquivo'
else
lblResultadoMsg.Caption := 'Não, o usuário desistiu';O esquema é o mesmo, verificamos se o usuário clicou em ID_YES equivalente ao “Sim” e então atualizamos o Label conforme necessário. (Figura 5).
Agora vamos ver como aplicar mensagens em tratamentos de erros. Arraste para o formulário mais um GroupBox e dentro dele crie um layout como mostrado na Figura 6.
Dê o nome de “btnValidar” ao botão e “lblConversao” ao Label e “edtNumero” ao Edit, o restante mantenha os nomes padrão. No evento OnClick do botão digite o código da Listagem 1.
procedure TForm1.btnValidarClick(Sender: TObject);
begin
try
StrToInt(edtNumero.Text);
lblConversao.Caption := 'Convertido com sucesso';
except
MessageDlg('Erro de conversão', mtError,
[mbOk], 0);
end;
end;Utilizamos nesse código um bloco try..except para validar os dados. Estamos tentando fazer uma conversão de string (texto) para Integer (número) usando a função IntToStr. Caso a conversão seja efetuada, o lblConversao é atualizado e recebe o Caption igual a “Convertido com sucesso”. Caso contrário o MessageDlg é executado e uma mensagem mostrada.
Uma outra abordagem nesse mesmo exemplo seria fazer com que o próprio sistema criasse a exceção gerando a mensagem automaticamente. Modifique o código do evento de forma que fique como na Listagem 2.
procedure TForm1.btnValidarClick(Sender: TObject);
begin
try
StrToInt(edtNumero.Text);
lblConversao.Caption := 'Convertido com sucesso';
except
raise Exception.Create('Erro de conversão');
end;
end;Perceba que trocamos a MessageDlg pela linha:
raise Exception.Create('Erro de conversão');Isso fará com que a aplicação gere uma exceção e conseqüentemente uma mensagem de erro ao usuário final. Normalmente utilizamos essa abordagem em sistemas orietados a objetos, já que dentro das classes não podemos conversar diretamente com a camada externa.
Caixas de diálogo
Nessa última parte do artigo veremos como funcionam os componentes da paleta Dialogs. Esses componentes são usados quando é necessário abrir e salvar arquivos, capturar imagens do disco, configurar a impressora etc.
Para este exemplo criaremos um mini-editor de textos onde será possível abrir, salvar, configurar a impressora, fonte e cor de fundo do texto. Ainda poderemos selecionar uma foto em formato JPEG para exibir à direita da tela.
Clique em File | New > Application e crie uma nova aplicação no Delphi salvando-a como “Dialogos.dpr”. O formulário principal salve-o como “uPrincipal.pas” e troque seu Name para “frmPrincipal”. Desenhe uma tela semelhante à Figura 7.
Na parte superior temos os botões “btnAbrir”, “btnSalvar”, “btnConfigurar”, “btnFonte” e “btnImagem”, todos com seus respectivos Captions.
Na parte central do formulário insira um Memo(“memTexto”) da paleta Standard e um Image(“imgImagem”) da paleta Additional. Por fim adicione um novo componente Button(“btnCorFundo”) logo abaixo do memTexto.
Perceba que inseri também seis componentes da paleta Dialogs. Cada um deles terá uma função crucial em nosso exemplo. Tive o cuidado de manter os nomes originais dos componentes, desta forma fica mais fácil identificar qual tipo de componente devemos selecionar na paleta. A seguir veja uma breve explicação de cada um:
- OpenDialog1: Este componente é responsável por abrir arquivos. Sua propriedade Filter prevê quais tipos de arquivos podem ser abertos;
- SaveDialog1: Ao contrário do OpenDialog, o SaveDialog nos permite salvar arquivos no disco. Ele também possui a propriedade Filter para a mesma finalidade;
- FontDialog1: Esse componente, quando executado, permite modificar a propriedade fonte de determinados componentes de acordo com a fonte selecionada em sua tela;
- PrinterSetupDialog1: Como o próprio nome sugere, esse componente pode ser usado para configurar a impressora;
- ColorDialog1: É possível modificar a propriedade Color de objetos usando a propriedade de mesmo nome deste componente;
- OpenPictureDialog1: Semelhante ao OpenDialog, porém esse componente permite visualizar a foto antes de selecioná-la;
Vamos codificar o exemplo e entender como funcionam esses componentes começando por OpenDialog1 e SaveDialog1.
Ambos componentes possuem as propriedades:
- DefaultExt: É a extensão default (“padrão”). Pode ser usada em conjunto com a propriedade Filter para filtrar os tipos de arquivos que aparecerão na caixa de diálogo;
- Filter: É o filtro de arquivos que podem ser abertos no sistema. Podemos especificar quais tipos de arquivos serão compatíveis com nosso sistema;
- InitialDir: Diretório inicial da caixa de diálogo. Especificando esta propriedade com uma pasta válida, o sistema fará a seleção desta pasta automaticamente;
Vamos entender melhor tudo isso. Vamos atribuir valores às propriedades Filter e InitialDir do componente OpenDialog. Clique duas vezes na propriedade Filter e note que uma caixa de diálogo é aberta (Figura 8).
Observe que na Figura 8 já existem valores digitados, pois incluí alguns itens, porém o padrão desta caixa é vir sempre sem itens. A primeira vez que a propriedade é aberta a grade está vazia para que possamos configurar como desejamos. Pois bem, a coluna da esquerda, Filter Name, é a frase que aparecerá para o usuário final. Já a coluna da direita é o filtro propriamente dito. Portanto a sua esquerda digite “(*.*) Todos os tipos de arquivos” e a esquerda insira o filtro “*.*”. Nas linhas posteriores insira novos valores conforme o que vimos na Figura 8 e então confirme.
Para a propriedade InitialDir crie uma pasta no C:\ e atribua seu nome a esta propriedade. No meu caso coloquei como C:\Temp. O importante é termos essa pasta criada no Windows para que o componente possa selecioná-la.
Repita esses passos para o componente SaveDialog e vamos à codificação.
No evento do botão btnAbrir digite o código a seguir e veja como é simples abrir um arquivo via programação.
if OpenDialog1.Execute then
memTexto.Lines.LoadFromFile(OpenDialog1.FileName);A explicação é simples. Todos estes componentes possuem o método Execute que, evidentemente, executa a caixa de diálogo e mostra-a ao usuário. Mas não é só isso, na verdade quando chamamos este método, a caixa de diálogo é aberta e aguarda a confirmação ou cancelamento do usuário, ou seja, o código que vem logo após o Then da nossa condicional só será executado se o usuário final clicar no botão principal da caixa de diálogo. Nos casos do OpenDialog e SaveDialog são “Abrir” e “Salvar”, respectivamente.
Clicando em Abrir chamamos o método LoadFromFile da propriedade Lines do componente memTexto, assim o texto é aberto no Memo.
O código do botão “Salvar” é bastante semelhante, veja:
if SaveDialog1.Execute then
memTexto.Lines.SaveToFile(SaveDialog1.FileName);Invocamos novamente o método Execute do componente de diálogo e caso seja confirmado chamamos o método SaveToFile, também da propriedade Lines de nosso Memo.
Como podemos ver, não há segredos na abertura e gravação de arquivos. Experimente compilar o projeto e executá-lo. Clique nos botões que codificamos e veja o resultado. Na Figura 9 podemos ver os tipos de arquivos que podemos abrir nesse exemplo.
É claro que a caixa de diálogo não faz nada sozinha. A indicação no filtro “(*.DOC) Documentos” não significa sucesso na abertura deste arquivo. Nesse caso daria erro na chamada do método LoadFromFile ou SaveToFile, já que o componente Memo não é compatível com documentos do Word.
Por isso é necessário que nossa aplicação seja desenvolvida de maneira que se compatibilize com os tipos de arquivos que desejamos abrir e/ou salvar.
Voltando ao exemplo vamos codificar o botão Fonte(“btnFonte”). Ao clicarmos nesse botão poderemos configurar o formato de fonte do componente Memo. Na verdade atribuiremos os valores da propriedade Font do componente à propriedade de mesmo nome do Memo. Clique duas vezes no botão mencionado e digite o código da Listagem 3.
procedure TForm1.btnFonteClick(Sender: TObject);
begin
if FontDialog1.Execute then
begin
memTexto.Font.Name := FontDialog1.Font.Name;
memTexto.Font.Style := FontDialog1.Font.Style;
memTexto.Font.Color := FontDialog1.Font.Color;
memTexto.Font.Size :=FontDialog1.Font.Size;
end;
end;O que estamos fazendo no código que acabamos de digitar foi atribuir os valores das sub-propriedades Name, Style, Color e Size da propriedade Font do componente FontDialog. Perceba que o componente também possui um método Execute e que o mesmo se comporta exatamente como os componentes que já vimos. Salve, compile e execute o programa. Clique no botão Fonte e veja o que acontece (Figura 10).
Experimente agora digitar o código abaixo no evento OnClick do botão “Modificar a cor do fundo do texto”.
if ColorDialog1.Execute then
memTexto.Color := ColorDialog1.Color;Igualamos a propriedade Color do Memo à propriedade de mesmo nome do ColorDialog1. O código para configuração de impressoras consiste apenas em chamar o método Execute do componente PrinterSetupDialog1, veja:
PrinterSetupDialog1.Execute;A última coisa que veremos agora é como carregar imagens em um componente Image da paleta Additional. No evento OnClick do botão “Mostrar Imagem” digite o código a serguir:
if OpenPictureDialog1.Execute then
imgFoto.Picture.LoadFromFile(OpenPictureDialog1.FileName);Veja que estamos novamente utilizando o método Execute juntamente com o LoadFromFile. Poderíamos utilizar tranquilamente um OpenDialog, porém a principal diferença entre o OpeDialog e o OpenPictureDialog está no fato de poder visualizar a imagem antes de confirmar a caixa de diálogo.
A única ressalva que faço é que para utilizar-se de imagens no formato JPEG é necessário declarar a Unit Jpeg no Uses do formulário, do contrário uma exceção será lançada. Veja na Figura 11 a caixa de diálogo OpenPictureDialog em ação.
Conclusão
Neste artigo vimos as principais caixas de mensagens e de diálogos utilizadas no dia-a-dia. Seguindo essas orientações é perfeitamente viável tornar o sistema mais comunicativo e informativo.
Existem dezenas de outras formas de se usufruir de todo poder da VCL do Delphi. Procure modificar e estudar outras propriedades das caixas de diálogo. Tente criar suas próprias caixas de mensagem personalizadas.