sexta-feira, 6 de abril de 2012

Criando Dialogs com C++ em ambientes Windows

Criar dialogs (janelas) em ambientes Windows é algo fácil e muitos programadores não se interessam pelo C++ por não ter essa facilidade como no Delphi e Visual Studio, por exemplo.
Mal sabem eles que é muito mais fácil do que imaginam.

Existem várias formas fáceis para criação de dialogs, tanto em matéria de performace, quanto em tamanho em bytes.
Usaremos aqui um editor de recursos (ResEdit) e um IDE (Code::Blocks) usando um compilador GCC 4.6.1, com um conjunto de funções da API do Windows: CreateDialog, DialogBox, EndDialog, PostQuitMessage, IsDialogMessage, GetMessage, TranslateMessage, DispatchMessage, DialogProc, entre outras.

Caso ainda não tenha um ambiente de desenvolvimento leia esse artigo escrito pelo meu amigo Thiago Suchorski, nele é ensinado passo a passo como faze-lo.

Nosso projeto terá 4 arquivos (mais abaixo está para download o projeto todo):
  • main.cpp -- arquivo com nossas funções.
  • resource.h -- cabeçalho do recusro, onde são definidos os IDs.
  • resource.rc -- arquivo com os recursos.
  • manifest.xml -- arquivo de manifest, responsável pelo uso dos temas na dialog

No main.cpp segue o código:

#include <windows.h>
#include "resource.h"

HINSTANCE hInstance;

/* função de eventos da janela sobre */
BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CLOSE:
            EndDialog(hwnd, 0);
            return TRUE;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case ID_ABOUT_OK:
                    EndDialog(hwnd, 0);
                    return TRUE;
            }
    }
    return FALSE;

}
/* função de eventos da janela principal    */
BOOL CALLBACK WindowProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_CLOSE:
            PostQuitMessage(0);
            return TRUE;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case ID_OK:
                case IDM_SAIR1:
                    PostQuitMessage(0);
                    return TRUE;

                case IDM_SOBRE1:
                    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, (DLGPROC)DialogProc);
                    return TRUE;

                default:
                    return TRUE;
            }
    }

    return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    hInstance = hInst;
    HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, WindowProcedure);
    if (!hWnd) return 1;
    MSG Msg;
    while(GetMessage(&Msg, NULL, 0, 0) && hWnd)
    {
       if(!IsDialogMessage(hWnd, &Msg))
       {
           TranslateMessage(&Msg);
           DispatchMessage(&Msg);
       }
    }
    return Msg.wParam;
}

Vamos destacar as funções CreateDialog e DialogBox com suas respectivas funções de tratamento de eventos. Mas porque usar EndDialog ao invés de PostQuitMessage na DialogProc da DialogBox? Porquê a PostQuitMessage indica que o aplicativo está sendo finalizado e não que a janela está sendo fechada, por isso o uso da EndDialog. Mas o uso da PostQuitMessage nas funções de tratamento da DialogBox é válido.

Arquivo resource.h

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define IDD_DIALOG1                             100
#define IDR_MENU1                               101
#define IDD_DIALOG2                             102
#define ID_OK                                   1000
#define ID_ABOUT_OK                             1001
#define IDM_SOBRE1                              40000
#define IDM_SAIR1                               40001

E o resource.rc

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Menu resources
//
LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
IDR_MENU1 MENU
{
    POPUP "Arquivo"
    {
        MENUITEM "Sair", IDM_SAIR1
    }
    POPUP "Ajuda"
    {
        MENUITEM "Sobre", IDM_SOBRE1
    }
}
//
// Dialog resources
//
LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
IDD_DIALOG1 DIALOG 0, 0, 186, 76
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "Tela de exemplo"
MENU IDR_MENU1
FONT 8, "Ms Shell Dlg"
{
    DEFPUSHBUTTON   "Fechar", ID_OK, 69, 58, 50, 14
    GROUPBOX        "Informação", IDC_STATIC, 4, 4, 178, 48
    CTEXT           "Um simples exemplo de como criar telas com c++ facilmente sem o uso do visual studio =)", IDC_STATIC, 11, 21, 166, 23, SS_CENTER
}
LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
IDD_DIALOG2 DIALOG 0, 0, 143, 68
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "Sobre"
FONT 8, "Ms Shell Dlg"
{
    DEFPUSHBUTTON   "OK", ID_ABOUT_OK, 46, 50, 50, 14
    CTEXT           "Sobre o autor\n\nNome: Gilson Fabiano\nEmail: theafien@gmail.com", IDC_STATIC, 4, 4, 135, 35, SS_CENTER
}
//
// Manifest resources
//
LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
1                  RT_MANIFEST    ".\\manifest.xml"

E por fim o manifest.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

Se você for um bom programador e seguir toda a lógica e fluxo dos códigos irá entender o funcionamento, do contrário releia até entender.

Downloads


Erros de português revisado pelo André Luiz.

Att, Gilson Fabiano.

Nenhum comentário:

Postar um comentário