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

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:24   2475   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
 }
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP