8.4  常用资源的应用

8.4 常用资源的应用

  • 最近更新2018年10月18日

特殊说明:版权归个人所有,请勿转载,谢谢合作。

本节重点讲解菜单、对话框,通过这两个资源的讲解,会对其他资源进行简单的描述。位图资源在应用软件中应用较为广泛,会在第9章重点讲解。

8.4.1    菜单资源

菜单是Windows图形界面窗口中,最重要的组成部分。菜单通常出现在主窗口的顶部,用文字或图标列出各种选项,供用户选择或操纵。菜单不仅可以直观地了解应用程序提供的各项功能,而且通过加速键资源,可以使菜单的操作更加灵活。菜单分为两种类型:普通菜单以及弹出式菜单。普通菜单由以下五个部分组成(如图8.11所示):

  • 菜单栏;
  • 下拉式菜单;
  • 热键标识;
  • 加速键标识;
  • 菜单项分隔线。

  • 图8.11 普通菜单组成

弹出式菜单可在桌面或应用程序窗口随意弹出,但它没有窗口菜单栏。弹出式菜单,通常使用鼠标右键盘弹出,如图8.12所示。

  • 图8.12 弹出式菜单

 

在Win32 SDK编程中,菜单的应用需要一个过程,在资源视图中添加菜单资源,即在资源视图中,点击鼠标右键,在弹出的菜单中,选择【Insert…】项,如图8.13所示。

  • 图8.13 插入菜单项

在弹出的插入资源对话框中,选择【Menu】项,并点击【New】按钮,确认创建,如图8.14所示。

  • 图8.14 选择插入菜单资源

 

在新创建的窗口中,点击鼠标右键,在新弹出的菜单中,选择【Properties】项,操作如图8.15所示。

  • 图8.15 菜单属性

在弹出的菜单项属性窗口中的【Caption】处输入“操作(&O)”,此处输入的是顶级菜单显示的内容项。其中“(&O)”是菜单的热键,按ALT+O即可展开菜单。当然也可以输入其他内容,操作如图8.16所示。

  • 图8.16 顶层菜单名称

 

项层菜单输入完成后,即可输入子菜单项,在出现的空白菜单处,点击鼠标右键,在弹出的菜单项中,选择【Properties】项,操作如图8.17所示。

  • 图8.17 菜单属性

 

在弹出的菜单项属性窗口中,在【ID】处输入菜单的ID,本例输入“ID_OPTION_START”(要注意的是此ID名称要唯一,根据代码规范,ID要大写),并在【Caption】处输入菜单名称“开始(&S)”,如图8.18所示。

  • 图8.18 子项菜单ID与名称

以同样方式,添加子菜单项“结束(&E)”与“退出(&X)”,并将ID分别设置为“ID_OPTION_END”与“ID_OPTION_EXIT”。将结束与退出功能之前加分隔符,分隔符添加方法是在菜单项属性中,选择【Separator】即可,如图8.19所示。

  • 图8.19 设置分隔线

 

最终设置结果如图8.20所示。

  • 图8.20 菜单设置结果

 

菜单设置完成后,根据代码规范的要求,还要将菜单的ID进行更改(这里是菜单的ID,并不是菜单子项的ID)。在资源视图中,选择【Menu】资源中的菜单项【IDR_MENU1】,点击鼠标右键,在弹出的菜单中,选择【Properties】项,在弹出的菜单属性中,将【ID】内容更改为“IDR_MAIN_MENU”,如图8.21所示。

  • 图8.21 更改菜单ID

 

到目前为止,菜单项已经添加完成,但需要将菜单加载到应用程序中,加载方法有两种,菜单的一种加载方法是在设计窗口类时,将WNDCLASSEX结构体的lpszMenuName参数设置为“IDR_MAIN_MENU”。需要注意的是,IDR_MAIN_MENU的类型与lpszMenuName参数的类型是不匹配的,所以需要进行强制类型转换,如图8.22所示。

  • 图8.22 加载菜单

程序运行后的结果如图8.23所示。

  • 图8.23 菜单加载完成

 

菜单的第二种加载方法是,使用LoadMenu函数加载菜单,使用SetMenu函数设置菜单,最后使用DestroyMenu函数,实现菜单的销毁。三个函数的原型如下:

HMENU LoadMenu(HINSTANCE hInstance, LPCTSTR lpMenuName); 
BOOL SetMenu(HWND hWnd, HMENU hMenu); 
BOOL DestroyMenu(HMENU hMenu);

 

虽然菜单已经加载成功,但菜单没有任何响应。Win32中,当菜单项被选择、按钮被按下、或者其他控件被操作会产生命令响应消息(WM_COMMAND)。在响应WM_COMMAND消息时,wParam参数为菜单项、或按钮的ID值,而lParam参数为控件(控件的概念将在第10章节中讲解)的句柄。【例8-1】示例,当点击“开始”与“结束”菜单项时,分别弹出相应的提示框,点击“退出”时退出系统。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  PAINTSTRUCT ps;						// 结构体包含了用于绘制
                // 窗口客户区的信息
  HDC  hdc;						// 设备环境句柄

  // 消息处理
  //
  switch (message) 
  {
    // 菜单响应事件
  case WM_COMMAND:
    
    if(wParam == ID_OPTION_START)
    {
      MessageBox(hWnd, "点击了开始菜单项。", "提示", MB_OK);
    }
    else if(wParam == ID_OPTION_END)
    {
      MessageBox(hWnd, "点击了结束菜单项。", "提示", MB_OK);
    }
    else
    {
      // 退出系统
      DestroyWindow(hWnd);
    }//end if

    break;

    // 图形绘制事件
  case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    EndPaint(hWnd, &ps);
    break;
  
    // 窗口销毁消息,关闭窗口时响应。
  case WM_DESTROY:
    PostQuitMessage(0);
    break;

  default:
    // 调用系统默认消息处理,即交给系统处理。
    return DefWindowProc(hWnd, message, wParam, lParam);
  }//end switch

  return 0;
}

 

程序中,捕获了WM_COMMAND消息,通过wParam参数来判断当前选择了哪个菜单项,并对相应的菜单项作出响应,执行结果如图8.24所示。

  • 图8.24 菜单示例

 

8.4.2    对话框资源

对话框是一种特殊的窗口,通常包含编辑框、按钮、单选按钮(radio button)、复选框(check box)和其他控件。用户可以通过对话框输入数据或选择某些功能。如果一个应用程序中包含对话框,那么就必须包含对话框的过程处理函数,这个过程处理函数与应用程序的过程处理函数相同,主要目的是捕获对话框所产生的消息。

对话框是一种非常重要的资源,Windows中大部分应用功能,都是以对话框模式进行交互的。对话框窗口分为两种:模式对话框窗口与无模式对话框窗口。模式对话框窗口也称为模态对话框窗口,是指用户在Win32应用程序的对话框中,想要对对话框以外的应用程序进行操作时,必须先对该对话框进行响应,如单击【确定】或【取消】按钮等操作将该对话框关闭。相对应的另一个对话框是无模式对话框,即可以在不关闭当前的对话框窗口的情况下操作其他窗口。

在资源文件中,定义对话框资源后,即可使用DialogBox函数来显示对话框。DialogBox函数原型如下:

int DialogBox(
  HINSTANCE hInstance,     // handle to application instance
  LPCTSTR lpTemplate,      // identifies dialog box template
  HWND hWndParent,         // handle to owner window
  DLGPROC lpDialogFunc     // pointer to dialog box procedure
);

 

参数hInstance,当前进程的实例句柄。

参数lpTemplate,标识对话框模板。此参数可以是指向一个以NULL结尾的字符串的指针,该字符串指定对话框模板名,或是指定对话框模板的资源标识符中的一个整型值。可以使用MAKEINTRESOURCE宏指令创建此值。

参数hWndParent,父窗口的句柄,如果为NULL说明此窗口无父窗口,从而将变成无模式对话框。

参数lpDialogFunc,响应该对话框消息的回调函数。

 

下面是基于8.4.1节的示例做了一些简单的修改,当点击菜单上的开始项时,弹出相应的对话框(如何创建对话框资源,在8.3节已经详细地讲解过,这里不过多叙述)。

第一步,根据代码规范要更改对话框的ID。在资源视图中,选择对话框资源,点击鼠标右键,在弹出的菜单中选择【Properties】项,如图8.25所示。

  • 图8.25 修改对话框ID

 

在弹出的对话框属性对话框中的【ID】处,更改ID内容为“IDD_START_DLG”,如图8.26所示。

  • 图8.26 修改后的ID

 

第二步,在程序首部,声明对话框的过程处理函数(函数名任意,这里以DlgProc为例)。此函数用来处理对话框所产生的所有消息事件。代码如下所示:

// 回调函数,用于处理对话框的消息事件。
LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

 

第三步,对话框的过程处理函数的实现。此函数与应用程序的过程处理函数有所不同,因为对话框属性与窗口所有不同,所以处理方法也不相同。对话框只关心上面的按钮即可,如下代码所示,在WM_COMMAND消息中,捕获了按钮ID“IDOK”与“IDCANCEL”,如果在窗口中,点击了这两个按钮,则使用EndDialog函数关闭对话框(要注意,关闭对话框的函数是EndDialog)。

LRESULT CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
  case WM_INITDIALOG:
    return TRUE;
    
  case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    {
      EndDialog(hDlg, LOWORD(wParam));
      return TRUE;
    }
    break;
  }
    return FALSE;
}

 

第四步,在应用程序的回调函数中,将开始按钮的消息处理进行修改,使用DialogBox函数将对话框创建并显示,代码如下所示。

if(wParam == ID_OPTION_START)
{
  //MessageBox(hWnd, "点击了开始菜单项。", "提示", MB_OK);
  DialogBox(g_hIns, (LPCTSTR)IDD_START_DLG, hWnd,(DLGPROC)DlgProc);
}

 

第五步,如果此时编译,系统会出现错误,原因是DialogBox函数的第一个参数,它是进程实例句柄类型,这个值需要的是当前进行的实例句柄,即WinMain函数的第一个参数,所以需要定义全局变量g_hIns,并将WinMain函数的hInstance句柄进行保存,代码如下所示。

// 在程序的首部,定义全局变量,用来存放WinMain函数的hInstance句柄。
HINSTANCE g_hIns = NULL;

 

同时在WinMain函数的开始部分,将hInstance句柄进行保存,代码如下所示。

// 保存进程实例句柄
g_hIns = hInstance;

 

【例8-2】是实现对话框功能的全部代码(修改的位置已经加入底纹)。

//************************************************************
// NAME		: Demo_08.cpp
//************************************************************
// POWER	: Copyright (c) 2012 for lixinghua.
// AUTHOR	: 2012-7-24 20:00 Create by lixinghua for functions.
// VERSION	: V1.0.0.1
// NOTE		: 手工整理的创建窗口的代码,本程序只创建一个名称为
//            MyWin的窗口。
//************************************************************
//
#include <windows.h>
#include <stdio.h>
#include "resource.h"

// 回调函数,用于系统消息的处理。
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// 回调函数,用于处理对话框的消息事件。
LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE g_hIns = NULL;

//-----------------------------------------------------------------------------
//	FUNC	:	入口函数
//-----------------------------------------------------------------------------
//	IN	:	hInstance,进程的实例句柄;
//			hPrevInstance,前一个进程实例句柄,默认为NULL即可;
//			lpCmdLine,命令行参数;
//			nCmdShow,当前窗口显示状态。
//	OUT	:	void
//	RETURN	:	返回为整型,代表窗口的状态,其中APIENTRY描述了压栈的顺序。
//	AUTHOR	:	2012-2-6 11:18 Create by lixinghua for functions.
//	NOTE	:	此函数为Win32入口函数。
//-----------------------------------------------------------------------------
//
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  // 定义所用到的参数
  //
  char szWindowClass[] = { "WinClsName" };
            // 窗口类的名称
  HWND hWnd = NULL;			// 用于存放窗口句柄
  //char szTitle[] = { "五子棋" };		// 窗口标题名称
  char szTitle[] = { "MyWin" };		// 窗口标题名称
  MSG  msg;				// 存放消息的结构体,
            // 由系统提供

  // 保存进程实例句柄
  g_hIns = hInstance;

  // 1. 设计一个窗口类
  //
  WNDCLASSEX wcex;
  
  wcex.cbSize = sizeof(WNDCLASSEX); 
  
  wcex.style		= CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc	= (WNDPROC)WndProc;
  wcex.cbClsExtra		= 0;
  wcex.cbWndExtra		= 0;
  wcex.hInstance		= hInstance;
  wcex.hIcon		= NULL;
  wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName	= (LPCSTR)IDR_MAIN_MENU;
  wcex.lpszClassName	= szWindowClass;
  wcex.hIconSm		= NULL;

  // 2. 注册窗口
  //
  RegisterClassEx(&wcex);

  // 3. 创建窗口
  //
  HMENU hMenu = NULL;
  hWnd = CreateWindow(szWindowClass, szTitle, 
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 
0, CW_USEDEFAULT, 0, NULL, hMenu, hInstance, NULL);

  // 判断创建是否成功
  if (!hWnd)
  {
     return FALSE;
  }//end if

  // 4. 显示并更新窗口
  ShowWindow(hWnd, nCmdShow);	// 请注意 nCmdShow 参数
  UpdateWindow(hWnd);

  // 5. 进入消息循环
  while (GetMessage(&msg, NULL, 0, 0)) 
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }//end while
  
  return 0;
}

//-----------------------------------------------------------------------------
//	FUNC	:	回调函数
//-----------------------------------------------------------------------------
//	IN	:	hWnd,窗口句柄;
//			message,要处理的消息ID,以此来区分消息;
//			wParam,消息参数,根据消息的不同内容也有所不同;
//			lParam,消息参数,根据消息的不同内容也有所不同。
//	OUT	:	void
//	RETURN	:	void
//	AUTHOR	:	2012-2-6 11:36 Create by lixinghua for functions.
//	NOTE	:	此函数用于系统消息的处理。
//-----------------------------------------------------------------------------
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  PAINTSTRUCT ps;				// 结构体包含了用于绘制窗口客
            // 户区的信息
  HDC  hdc;				// 设备环境句柄

  // 消息处理
  //
  switch (message) 
  {
    // 菜单响应事件
  case WM_COMMAND:
    if(wParam == ID_OPTION_START)
    {
      //MessageBox(hWnd,"点击了开始菜单项。","提示", MB_OK);
      DialogBox(g_hIns, (LPCTSTR)IDD_START_DLG, hWnd,
 (DLGPROC)DlgProc);
    }
    else if(wParam == ID_OPTION_END)
    {
      MessageBox(hWnd, "点击了结束菜单项。", "提示", MB_OK);
    }
    else
    {
      // 退出系统
      DestroyWindow(hWnd);
    }//end if

    break;

    // 图形绘制事件
  case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    EndPaint(hWnd, &ps);
    break;
  
    // 窗口销毁消息,关闭窗口时响应。
  case WM_DESTROY:
    PostQuitMessage(0);
    break;

  default:
    // 调用系统默认消息处理,即交给系统处理。
    return DefWindowProc(hWnd, message, wParam, lParam);
  }//end switch

  return 0;
}
//-----------------------------------------------------------------------------
//	FUNC	:	对话框回调函数
//-----------------------------------------------------------------------------
//	IN	:	hWnd,窗口句柄;
//			message,要处理的消息ID,以此来区分消息;
//			wParam,消息参数,根据消息的不同内容也有所不同;
//			lParam,消息参数,根据消息的不同内容也有所不同。
//	OUTPUT	:	NULL
//	RETURN	:	VOID
//	AUTHOR	:	2012-7-25 14:47 Create by lixinghua for functions.
//	NOTE	:	此处用于处理对话框的消息事件。
//-----------------------------------------------------------------------------
//
LRESULT CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
  case WM_INITDIALOG:
    return TRUE;
    
  case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    {
      EndDialog(hDlg, LOWORD(wParam));
      return TRUE;
    }
    break;
  }
    return FALSE;
}

 

程序执行结果如图8.27所示。

  • 图8.27 执行结果
分享到 :
相关推荐

发表回复

登录... 后才能评论