Elemar DEV

Negócios, tecnologia e desenvolvimento

Windows Native Programming – GDI+

Olá. Tudo certo?!

Esta é uma série onde falo sobre desenvolvimento nativo, direto com a API do Windows e C++.

Até aqui tivemos:

  1. Copying files
  2. Window class, Window object, Message Loop, WndProc
  3. Menus
  4. Mouse Down! Mouse Move!

No post/exemplo de hoje, mostro os fundamentos para programação com GDI+.

O que é GDI+?

Pegando a definição da Wikipedia:

GDI, ou Graphics Device Interface, é um dos três subsistemas principais do Microsoft Windows. É um padrão desse sistema operacional para representar objetos gráficos e transmiti-los para dispositivos de saída, como monitores e impressoras.

É responsável por tarefas como desenhar linhas, curvas e fontes, providenciando todo um API específico para a execução dessas operações.

A capacidade mais relevante do GDI é a abstração dos dispositivos finais de visualização. Utilizando o mesmo código fonte pode-se esperar resultados idênticos em qualquer monitor ou impressora.

O exemplo de hoje

O exemplo de hoje é, novamente, bem simples:

gdiO que há no exemplo?

  • Quando você inicia a aplicação uma janela é apresentada;
  • Se clicar com o botão direito, o diálogo de “abertura de arquivo” é apresentado;
  • Se o usuário selecionar um arquivo JPG, ele será “pintado” no fundo da janela;
  • O usuário pode trocar a imagem clicando novamente com o botão direito.

Bacana, não?!

Código-fonte completo

Como sempre, para ajudar, apresento o código-fonte completo do exemplo:

#include <Windows.h>
#include <gdiplus.h>

using namespace Gdiplus;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM RegisterClass(HINSTANCE, TCHAR []);
BOOL CreateAndShowWindow(HINSTANCE, TCHAR [], TCHAR [], int iCmdShow);

Bitmap* gpBitmap;

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    PSTR szCmdLine,
    int iCmdShow
    )
{
	static TCHAR szAppName [] = TEXT("HelloGdiPlus");
	static TCHAR szWindowTitle [] = TEXT("Hello GDI+ Programming World");

	MSG msg;

	RegisterClass(hInstance, szAppName);
	CreateAndShowWindow(hInstance,
		szAppName,
		szWindowTitle,
		iCmdShow);

	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if (gpBitmap) delete gpBitmap;
	GdiplusShutdown(gdiplusToken);

	return msg.wParam;
}

ATOM RegisterClass(HINSTANCE hInstance, TCHAR szAppName[])
{
	WNDCLASS wndClass;

	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = szAppName;

	return RegisterClass(&wndClass);
}

BOOL CreateAndShowWindow(
	HINSTANCE hInstance,
	TCHAR szAppName[],
	TCHAR szWindowTitle[],
	int iCmdShow)
{
	HWND hwnd;

	hwnd = CreateWindow(szAppName,
		szWindowTitle,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
		);

	if (!hwnd)
		return FALSE;

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	return TRUE;
}

void OpenJpgFile(HWND hWnd)
{
    OPENFILENAME ofn;
    wchar_t szFileName[MAX_PATH] = L"";
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hWnd;
    ofn.lpstrFilter = L"JPEG Files (*.jpg)\0*.jpg\0All Files (*.*)\0*.*\0";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
    ofn.lpstrDefExt = L"jpg";
    if(GetOpenFileName(&ofn))
    {
		if(gpBitmap)
		{
			delete gpBitmap;
		}
		gpBitmap = new Bitmap(szFileName);

		InvalidateRect(hWnd, NULL, TRUE);
		UpdateWindow(hWnd);
    }
}

void OnPaint(HDC hdc)
{
	if (!gpBitmap) return;

	Graphics graphics(hdc);
	graphics.DrawImage(gpBitmap, 0, 0);
}

LRESULT CALLBACK WndProc(
    HWND hwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
    )
{
    HDC hdc;
    PAINTSTRUCT ps;

    switch (message)
    {
	case WM_RBUTTONDOWN:
		OpenJpgFile(hwnd);
		return 0;
    case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		OnPaint(hdc);
 		EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

Para conseguir compilar o programa, lembre-se de adicionar a lib do gdiplus nas propriedades do linker.

lib

Entendendo a dinâmica

Na verdade, há bem pouco de diferente nesse código. Vamos analizar:

  • No main, iniciei o contexto do GDI Plus. Isso é muito importante para que o subsistema possa ser inicializado. Depois, quando o programa for encerrado, “desligo” o GDI Plus;
  • Mantenho uma variável global com um ponteiro para o Bitmap que estou manipulando. Esse bitmap é instanciado quando o usuário clica com o botão direito  do mouse e seleciona um arquivo para ser processado;
  • Sempre que a tela é atualizada, utilizo um objeto Graphics para “pintar” o bitmap na tela.

Era isso.

Um comentário em “Windows Native Programming – GDI+

  1. Pingback: Loading Images (using MFC) | Elemar DEV

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às 24/03/2013 por em Post e marcado , , .

Estatísticas

  • 693,519 hits
%d blogueiros gostam disto: