MFC中Picture Control 控件中图像遮挡后消失

1 篇文章 0 订阅

1、说明

最近在使用MFC时发现,Picture Control控件中的图像若被其他窗口遮盖、窗口移出屏幕外、最小化等操作时,都会导致图像消失。其原因在于onPaint()函数。

原因:MFC的机制是当窗口大小改变、遮挡、最小化等操作时,会使窗口中部分/全部内容“失效”,当恢复窗口时,会自动产生WM_PAINT消息发送给视图刷新窗口,该消息会触发onPaint()函数进行窗口绘制。也就是说当窗口每经过一次改变(存在“无效”区),都会触发onPaint()函数。

若Picture Control控件中的图像显示操作是一个自定义函数,并未在onPaint()函数中实现或调用,那么每次调用onPaint()函数时都不会刷新Picture Control控件中的内容,这也就是为什么图像会消失的原因。

百度百科对WM_PAINT的解释:https://baike.baidu.com/item/WM_PAINT%E6%B6%88%E6%81%AF

2、解决方案

解决这个问题的方法就是在onPaint函数中添加对应的图像显示代码,也可以在该函数中直接调用自定义的图像显示函数。

(1)自定义图像显示函数:

void ShowMatImgToWnd(CWnd* pWnd, Mat show_image)
{
	if (show_image.empty())
	{
		return;
	}

	CRect drect;
	pWnd->GetClientRect(&drect);

	CClientDC dc(pWnd);
	HDC hDC = dc.GetSafeHdc();

	resize(show_image, show_image, Size(drect.Width(), drect.Height()));
	//Copy image data from memory to the screen
	BYTE *bitBuffer = NULL;
	BITMAPINFO *bitMapinfo = NULL;

	int ichannels = show_image.channels();
	if (ichannels == 1)
	{
		bitBuffer = new BYTE[40 + 4 * 256];
	}
	else if (ichannels == 3)
	{
		bitBuffer = new BYTE[sizeof(BITMAPINFO)];
	}
	else
	{
		return;
	}

	if (bitBuffer == NULL)
	{
		return;
	}

	bitMapinfo = (BITMAPINFO *)bitBuffer;
	bitMapinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	//If the height is positive, the starting position of the bitmap is in the lower-left corner.
	//If the height is negative, the starting position is in the upper-left corner.
	bitMapinfo->bmiHeader.biHeight = -show_image.rows;
	bitMapinfo->bmiHeader.biWidth = show_image.cols;
	//The level of the target device must be 1
	bitMapinfo->bmiHeader.biPlanes = 1;
	//The number of digits required per pixel must be one of 1 (two colors), 4 (16 colors), 8 (256 colors), or 24 (True color)
	bitMapinfo->bmiHeader.biBitCount = ichannels * 8;
	//Bitmap compression type, must be one of 0 (uncompressed), 1 (bi_rle8 compression type), or 2 (bi_rle4 compression type)
	bitMapinfo->bmiHeader.biCompression = BI_RGB;
	//The size of the bitmap, in bytes
	bitMapinfo->bmiHeader.biSizeImage = 0;
	//Bitmap horizontal resolution, prime number per meter image
	bitMapinfo->bmiHeader.biXPelsPerMeter = 0;
	//Bitmap vertical resolution, prime number per meter image
	bitMapinfo->bmiHeader.biYPelsPerMeter = 0;
	//Number of colors in the color table actually used by the bitmap
	bitMapinfo->bmiHeader.biClrUsed = 0;
	//Number of important colors in the bitmap display process
	bitMapinfo->bmiHeader.biClrImportant = 0;

	if (ichannels == 1)
	{
		for (int i = 0; i < 256; i++)
		{
			//Range of color values (0-255)
			bitMapinfo->bmiColors[i].rgbBlue = bitMapinfo->bmiColors[i].rgbGreen = bitMapinfo->bmiColors[i].rgbRed = (BYTE)i;
		}
		//Number of colors in the color table actually used by the bitmap
		bitMapinfo->bmiHeader.biClrUsed = 256;
	}
	SetStretchBltMode(hDC, COLORONCOLOR);

	StretchDIBits(hDC,
		0,
		0,
		drect.right,		//Display window width
		drect.bottom,		//Display window height
		0,
		0,
		show_image.cols,		   //Image width
		show_image.rows,	   //Image Height
		show_image.data,
		bitMapinfo,
		DIB_RGB_COLORS,
		SRCCOPY
	);
	delete[]bitBuffer;
}

(2)onPaint函数:

在onPaint函数中添加图像显示函数即可,首先添加全局布尔变量,用来表示Picture Control控件中是否有图像,若存在图像,则刷新时调用,若没有图像,则无需调用。

发现问题:添加完成测试时发现,窗口被遮盖或移出屏幕外恢复时都可以正常显示图像,但是最小化恢复以后图像还是会消失。单步调试发现,其实onPaint函数正常会调用图像显示函数,且图像会正常显示。但当onPaint函数结束后,窗口又被重新绘制了一次,导致显示的图像再次被刷新掉。(暂时没找到是什么原因导致的。。。)

解决方法:在图像显示前调用UpdateWindow()进行窗口刷新可解决最小化后图像依然消失的问题。

void CGigeCameraDemoDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		INT32 cxIcon = GetSystemMetrics(SM_CXICON);
		INT32 cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		INT32 x = (rect.Width() - cxIcon + 1) / 2;
		INT32 y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}

	//当重绘标志为真时,若窗口中有内容无效,则重新显示图像
	if(repaint_flag)
	{
		UpdateWindow();
		CWnd *target_wnd = NULL;
		target_wnd = this->GetDlgItem(IDC_DST_STATIC);    //IDC_DST_STATIC为picture control控件ID
		ShowMatImgToWnd(target_wnd, paint_result_image);  //调用图像显示函数,paint_result_image为全局Mat
	}
}

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值