Jump to content
  • Advertisement
Sign in to follow this  
discman1028

Drop-down menus in a Windows application

This topic is 4409 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm wondering if anyone knows of a simple wrapper class for using drop-down menus. This is for a GDI+ app in C++. I would like the menus to appear when I right-click anywhere within the window. GLUT has a great implementation of this...

Share this post


Link to post
Share on other sites
Advertisement
It's not hard to implement a wrapper of your own. Here's an example:


/ Win32.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "Win32.h"
#include <string>
#include <vector>

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

class ShortcutMenu
{
private:
typedef void (*CommandEvent)(ShortcutMenu *sender);
HMENU m_hmenu;
std::vector<CommandEvent> command_events;
UINT current_item;
friend void DispatchMenuCommand(HWND hWnd,WPARAM wParam,LPARAM lParam);
void OnItem(UINT item)
{
CommandEvent comm=command_events[item];
comm(this);
}
public:
ShortcutMenu():current_item(0)
{
m_hmenu=CreatePopupMenu();
MENUINFO mi;
mi.cbSize=sizeof(mi);
mi.fMask=MIM_MENUDATA|MIM_STYLE;
mi.dwMenuData=(ULONG_PTR)this;
mi.dwStyle=MNS_NOTIFYBYPOS;
SetMenuInfo(m_hmenu,&mi);
}
void AddItem(std::string caption,CommandEvent command_event)
{
command_events.push_back(command_event);
AppendMenu(m_hmenu,MF_ENABLED|MF_STRING,current_item,caption.c_str());
++current_item;
}
void Track(HWND hwnd,int x,int y)
{
POINT p;
p.x=x;p.y=y;
ClientToScreen(hwnd,&p);
TrackPopupMenuEx(m_hmenu,0,p.x,p.y,hwnd,NULL);
}
};

void DispatchMenuCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
MENUINFO mi;
mi.cbSize=sizeof(mi);
mi.fMask=MIM_MENUDATA;
GetMenuInfo((HMENU)lParam,&mi);
ShortcutMenu* menu=(ShortcutMenu*)mi.dwMenuData;
UINT item=GetMenuItemID((HMENU)lParam,wParam);
if (menu)
{
menu->OnItem(item);
}
}

class MyMenu:public ShortcutMenu
{
public:
MyMenu():ShortcutMenu()
{
AddItem("Start",&MyMenu::OnStart);
AddItem("Stop",&MyMenu::OnStop);
}
static void OnStart(ShortcutMenu *sender)
{
MessageBox(0,"Start!","Menu command",MB_OK);
}
static void OnStop(ShortcutMenu *sender)
{
MessageBox(0,"Stop","Menu command",MB_OK);
}
};


MyMenu myMenu;

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32));


// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_RBUTTONDOWN:
myMenu.Track(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_MENUCOMMAND:
DispatchMenuCommand(hWnd,wParam,lParam);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}




All you have to do is derive a class from ShortcutMenu and of course handle WM_RBUTTONDOWN(to show the menu) and WM_MENUCOMMAND.

Share this post


Link to post
Share on other sites
It's not "hard" but there's no doubt time involved. I would if I was adding this to my engine... but I am making a quick and dirty app.

Thank you for the example however. :) And thanks for the TrackPopupMenuEx() link, Colin.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!