Elemar DEV

Tecnologia e desenvolvimento

Windows Native Programming – Menus

Olá. Tudo certo?

Depois de muito tempo, resolvi retomar “Windows Native Programming” aqui no blog. O objetivo é mostrar como é a “conversa” de nossos programas com o sistema operacional. Para isso, utilizo C++.

Já tenho dois posts escritos sobre esse tema. Se é novidade para você, recomendo a leitura de:

  1. Copying files;
  2. Windows Class, Window Object, Message Loop, WndProc

Nesse post, quero falar sobre menus!

Nosso exemplo

Para apresentar conceitos, usarei um exemplo simples.

poor-man

Trata-se de algo bem simples: uma janela, com um menu básico.

Chamei esse exemplo de “Poor-man Menu” porque escrevi o código de forma bem trabalhosa. Optei por não usar Resources em C++. Afinal, a ideia é mostrar as bases do funcionamento de Menus para o sistema operacional.

Código-fonte completo para o exemplo

Afim de facilitar o seu estudo, começo apresentando o código completo.

#include  <Windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

#define IDM_FILE_OPEN	40001
#define IDM_APP_EXIT	40002

#define IDM_BKGND_WHITE	40003
#define IDM_BKGND_GRAY	40004
#define IDM_BKGND_BLACK	40005

#define IDM_HELP_ABOUT	40007

HMENU hMenu;
TCHAR szAppName [] = TEXT("Poor-man Menus");

HMENU CreateMainMenu()
{
	hMenu = CreateMenu();

	HMENU hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING, IDM_FILE_OPEN, L"&Open");
	AppendMenu(hMenuPopup, MF_SEPARATOR, 0, NULL);
	AppendMenu(hMenuPopup, MF_STRING, IDM_APP_EXIT, L"E&xit");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&File");

	hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING | MF_CHECKED, IDM_BKGND_WHITE, L"&White");
	AppendMenu(hMenuPopup, MF_STRING, IDM_BKGND_GRAY, L"&Gray");
	AppendMenu(hMenuPopup, MF_STRING, IDM_BKGND_BLACK, L"&Black");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&View");

	hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING, IDM_HELP_ABOUT, L"&About");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&Help");

	return hMenu;
}

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	PSTR szCmdLine,
	int iCmdShow
	)
{

	HWND hwnd;
	MSG msg;
	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;

	if (!RegisterClass(&wndClass))
	{
		MessageBox(NULL, TEXT("Error registering class."), szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName,
		TEXT("Poor-man Menus - Windows Native Programming"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		CreateMainMenu(),
		hInstance,
		NULL
		);

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

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

	return msg.wParam;
}

LRESULT CALLBACK WndProc(
	HWND hwnd,
	UINT message,
	WPARAM wParam,
	LPARAM lParam
	)
{
	static int currentSelection = IDM_BKGND_WHITE;
	static int idColor[5] = { WHITE_BRUSH, GRAY_BRUSH, BLACK_BRUSH };

	switch (message)
	{
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDM_APP_EXIT:
			SendMessage(hwnd, WM_CLOSE, 0, 0);
			return 0;
		case IDM_HELP_ABOUT:
			MessageBox(hwnd,
				L"Menus with native programming\nElemar Jr (c) 2013\n",
				szAppName,
				MB_ICONINFORMATION | MB_OK);
			return 0;
		case IDM_BKGND_WHITE:
		case IDM_BKGND_GRAY:
		case IDM_BKGND_BLACK:
			CheckMenuItem(hMenu, currentSelection, MF_UNCHECKED);
			currentSelection = LOWORD(wParam);
			CheckMenuItem(hMenu, currentSelection, MF_CHECKED);

			SetClassLong(
				hwnd,
				GCL_HBRBACKGROUND,
				(LONG) GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE])
				);

			InvalidateRect(hwnd, NULL, TRUE);

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

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

A estrutura do programa é bem similar a aquela que apresentei no post anterior.

Todo item de menu tem um identificador

Menus são parte importante da “lógica” do Windows. Todos têm um identificador único que será utilizado posteriormente no laço de mensagens e/ou manipulações.

#define IDM_FILE_OPEN	40001
#define IDM_APP_EXIT	40002

#define IDM_BKGND_WHITE	40003
#define IDM_BKGND_GRAY	40004
#define IDM_BKGND_BLACK	40005

#define IDM_HELP_ABOUT	40007

Criação do Menu

Criar um menu é uma tarefa relativamente simples. No exemplo, isolei a criação em uma função. Há duas funções fundamentais: CreateMenu e AppendMenu.

HMENU CreateMainMenu()
{
	hMenu = CreateMenu();

	HMENU hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING, IDM_FILE_OPEN, L"&Open");
	AppendMenu(hMenuPopup, MF_SEPARATOR, 0, NULL);
	AppendMenu(hMenuPopup, MF_STRING, IDM_APP_EXIT, L"E&xit");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&File");

	hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING | MF_CHECKED, IDM_BKGND_WHITE, L"&White");
	AppendMenu(hMenuPopup, MF_STRING, IDM_BKGND_GRAY, L"&Gray");
	AppendMenu(hMenuPopup, MF_STRING, IDM_BKGND_BLACK, L"&Black");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&View");

	hMenuPopup = CreateMenu();
	AppendMenu(hMenuPopup, MF_STRING, IDM_HELP_ABOUT, L"&About");
	AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuPopup, L"&Help");

	return hMenu;
}

Acho que você entendeu a lógica.

O menu é tão importante que é fornecido para o Windows como argumento durante a criação da janela.

hwnd = CreateWindow(szAppName,
	TEXT("Poor-man Menus - Windows Native Programming"),
	WS_OVERLAPPEDWINDOW,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	NULL,
	CreateMainMenu(),
	hInstance,
	NULL
	);

Escutando mensagens

Como ocorre para tudo no Windows, qualquer ação com a janela é “informada” ao programa através de mensagens.

Há diversas mensagens relacionadas ao processamento de menus. Por agora, vamos nos fixar na mais comum: WM_COMMAND.

Retomando o exemplo:

LRESULT CALLBACK WndProc(
	HWND hwnd,
	UINT message,
	WPARAM wParam,
	LPARAM lParam
	)
{
	static int currentSelection = IDM_BKGND_WHITE;
	static int idColor[5] = { WHITE_BRUSH, GRAY_BRUSH, BLACK_BRUSH };

	switch (message)
	{
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDM_APP_EXIT:
			SendMessage(hwnd, WM_CLOSE, 0, 0);
			return 0;
		case IDM_HELP_ABOUT:
			MessageBox(hwnd,
				L"Menus with native programming\nElemar Jr (c) 2013\n",
				szAppName,
				MB_ICONINFORMATION | MB_OK);
			return 0;
		case IDM_BKGND_WHITE:
		case IDM_BKGND_GRAY:
		case IDM_BKGND_BLACK:
			CheckMenuItem(hMenu, currentSelection, MF_UNCHECKED);
			currentSelection = LOWORD(wParam);
			CheckMenuItem(hMenu, currentSelection, MF_CHECKED);

			SetClassLong(
				hwnd,
				GCL_HBRBACKGROUND,
				(LONG) GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE])
				);

			InvalidateRect(hwnd, NULL, TRUE);

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

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

Pegou a ideia?! Acho que sim.
Era isso.

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 15/03/2013 por em Post e marcado , .

Estatísticas

  • 626,615 hits
%d blogueiros gostam disto: