[MSCE C++]如何在.r对话框中显示一个图片


.r(resource的缩写,即资源的意思)对话框是nativeCode(本机代码)C++,即MDL,原生的写界面的方法。其有方便之处也有不方便之处。对于在一个.r对话框中如何显示一个图片,则需要如下较为复杂的步骤。

1、头文件.h中定义相关的资源ID。比如:

#define DIALOGID_DisplayImage     5

#define GENERICID_DisplayImage    2

#define HOOKITEMID_DisplayImage   5

【说明】:保证每一类资源的id编号不同即可。比如,以上定义中对话框ID和对话框条目(item,等同于Windows中的控件的概念)钩子ID不属于一类,所以,它们两个都定义为5没有问题。

2、资源文件.r中定义如下对话框和一个通用条目。

DialogBoxRsc DIALOGID_DisplayImage =
{
	DIALOGATTR_DEFAULT,	31.0*XC, 15.0*YC, NOHELP, LHELPCMD, NOHOOK, NOPARENTID,
	"Display Image Demo",
	{
		{ { 1.5*XC, 0.5*YC, 28.0*XC, 14*YC }, Generic, GENERICID_DisplayImage, ON, 0, "", "" },
	}}
    extendedIntAttributes
    {{
    {EXTINTATTR_DLOGATTRS, DIALOGATTRX_NOMINIMIZEBOX}
    }
};

DItem_GenericRsc GENERICID_DisplayImage =
{
	NOHELP, MHELP, HOOKITEMID_DisplayImage, NOARG
};

【说明】:①该对话框中仅含有一个通用条目(generic item),该条目没有任何默认动作,其动作完全依靠条目钩函数来控制;②为了取消对话框标题栏右侧的最下化按钮,使用了对话框的扩展属性DIALOGATTRX_NOMINIMIZEBOX。请密切注意如何给对话框添加扩展属性,这里的写法比较怪异;③给通用条目增加了钩函数ID的定义,通过该HOOKITEMID_DisplayImage去关联实际的钩函数displayImage_genericHook。

3、在源代码文件.cpp中增加如下代码:

void displayImage(WCharCP unparsed)
{
	MSDialog::Open(NULL, DIALOGID_DisplayImage);
}
void displayImage_genericHook(DialogItemMessageP dimP)
{
	DialogItemP diP = dimP->dialogItemP;
	RawItemHdrP riP = diP->rawItemP;
	dimP->msgUnderstood = TRUE;
	switch (dimP->messageType) 
	{
	case DITEM_MESSAGE_INIT: 
	{
		BeFileName 	fullFileSpec;
		WString image(L"D:\\Foo-src\\MDL.CE\\File\\images\\path2.bmp");
		dimP->u.init.initFailed = TRUE;
		if (SUCCESS != mdlFile_find(&fullFileSpec, image.GetWCharCP(), NULL, NULL))
		{
			mdlDialog_dmsgsPrint(L"Problem with image");
			dimP->u.init.initFailed = FALSE;
			break;
		}
		byte* rgbBufferP = NULL;
		Point2d	itemSize;
		itemSize.x = diP->rect.corner.x - diP->rect.origin.x + 1;
		itemSize.y = diP->rect.corner.y - diP->rect.origin.y + 1;
		if (SUCCESS == mdlImage_readFileToRGB(&rgbBufferP, NULL, fullFileSpec, ImageFileFormat::IMAGEFILE_BMP, &itemSize))
		{
			//	Store a pointer to the image in the generic item's userDataP member variable
			riP->userDataP = rgbBufferP;
			dimP->u.init.initFailed = FALSE;
		}
		break;
	}
	case DITEM_MESSAGE_DRAW:
	{
		Int32  i, rowLength;
		byte   *redP, *greenP, *blueP;
		//	Get image pointer from generic item's userDataP member variable
		if (redP = (byte*)riP->userDataP)
		{
			rowLength = diP->rect.corner.x - diP->rect.origin.x + 1;
			greenP = redP + rowLength;
			blueP = greenP + rowLength;
			for (i = diP->rect.origin.y; i <= diP->rect.corner.y; i++)
			{
				mdlDither_drawRow(dimP->db, diP->rect.origin.x, diP->rect.corner.x, i, redP, greenP, blueP);
				redP += 3 * rowLength;
				greenP += 3 * rowLength;
				blueP += 3 * rowLength;
			}
		}
		mdlDialog_rectDrawEdge (dimP->db, &diP->rect, TRUE);
		break;
	}
	case DITEM_MESSAGE_DESTROY:
	{
		byte* tempBufferP = (byte*)riP->userDataP;
		dlmSystem_mdlFree(tempBufferP);
		break;
	}
	default:
		dimP->msgUnderstood = FALSE;
		break;
	}
}
/*--------------------------------------------------------
| MdlMain
+-------------------------------------------------------*/
DialogHookInfo uHooks[] =
    {
	{ HOOKITEMID_DisplayImage,       (PFDialogHook)displayImage_genericHook},
    };
extern "C" DLLEXPORT void MdlMain(int, WCharCP[])
{
   mdlResource_openFile (&g_rscFileH, NULL, RSC_READONLY);
   
   mdlSystem_registerCommandNumbers (cmdNumbers);
   mdlParse_loadCommandTable(NULL);
   
   mdlDialog_hookPublish(sizeof(uHooks) / sizeof(DialogHookInfo), uHooks);
   ......
}

【说明】:①在MdlMain中通过调用mdlDialog_hookPublish发布了一个全局钩函数名和钩函数ID的对照表uHooks,因而将资源文件中的HOOKITEMID_DisplayImage和源代码中的函数displayImage_genericHook对应了起来;②函数入口是displayImage,在该函数中调用MSDialog::Open打开了我们的对话框DIALOGID_DisplayImage。你需要用一个命令和该函数关联(以上代码没有详细描述这一部分)。或者简单起见,你可以直接在MdlMain中去调用它;③displayImage_genericHook中在获得条目初始化消息DITEM_MESSAGE_INIT时调用函数mdlImage_readFileToRGB读取了一个指定的bmp文件到内存中,指针为条目下的userDataP;④displayImage_genericHook中在获得条目绘制消息DITEM_MESSAGE_DRAW时调用函数mdlDither_drawRow将内存中的像素点绘制到了通用条目上;⑤displayImage_genericHook中在获得条目销毁消息DITEM_MESSAGE_DESTROY时调用dlmSystem_mdlFree释放了内存。

4、执行该程序后显示的对话框如下: