【问题标题】:GDI Graphics in a dialog对话框中的 GDI 图形
【发布时间】:2016-07-05 19:12:35
【问题描述】:

我写了一个 Vis。 Studio 对话框应用程序可远程控制一台设备,其中包括我们需要从对话框中查看的小型 LCD 图形显示器。 V.Studio 对话框编辑器似乎没有提供固定解决方案。作为一名 Windows 程序员,需要而不是业余爱好,我所做的是:

  • 在对话框中添加了一个编辑控件。
  • 当 LCD 图像更新到达时,在编辑控件上创建 CClientDC
  • 调用 GDI 函数设置像素值

这看起来很麻烦,但在图像到达时确实有效。重绘对话框时显然不会重绘图像。该代码保存图像数据以进行重绘,但在重绘对话框时尝试找到某个地方调用图像重绘函数并不愉快。

  • 添加重绘调用作为对话框 OnPaint() 函数中的最后一条语句会创建图像,但在 OnPaint() 返回时会立即消失。
  • 在 OnPaint() 中发布自定义 WM_DRAWLCD_MESSAGE 时结果相同 - 图像已创建,但已删除。
  • 框架似乎没有调用 EndPaint(),因此无法在那里重绘图像。

两个问题:
1. 有没有普遍接受的方法来达到这个目的?
2. 如果没有,重绘对话框时代码在哪里调用重绘函数?

@zeromus: 我的“烤面包机”已连接到对话应用程序并且通信良好。所讨论的 LCD 图像是安装在机器上供操作员使用的 LCD 面板的内容。当我远程诊断时,通过单击图像下方的对话框按钮控件来执行控制/状态操作并查看响应会更简单,而不是通过其他方式复制所有机器功能。只要对话框保持在顶部,事情就会按预期工作。当对话框不在顶部时,将其重新置于顶部不会恢复图像 - 创建位图的数据和代码不是 CEdit 控件的一部分。所以问题是(1)是否有向导批准的方式来显示和恢复对话应用程序中不断变化的位图图像(而不是显示静态图像)和(2)如果没有,对话代码中是否有一些地方在重绘对话框期间拼接对我的位图绘图函数的调用?谢谢!

【问题讨论】:

  • 解决方案很简单:将CBitmap 对象作为成员添加到您的对话框类中。每当数据到达时,更新位图数据,并调用InvalidateRect 触发更新。在您的OnPaint-handler 中,只需渲染位图。如果您需要在对话框资源中使用占位符,请使用不可见的静态控件。由于您都沉迷于使用 MFC 向导,您应该考虑退后两步:1 学习 Windows API,2 深入了解 MFC 预处理器宏。如果您跳过任一步骤,MFC 将使 Windows 编程变得更加困难。

标签: visual-studio mfc dialog gdi


【解决方案1】:

请记住,自从 .net 发布之日起,我就没有使用过 MFC,我建议您及时返回并复制一个策略,在 windows 中执行此操作的正常方法是维护一个包含以下内容的 CBitmap液晶显示器。然后简单地在 OnPaint 中绘制它——直接在对话框上将是最简单的。在 Windows 中,您应该在 OnPaint 上完成所有绘图,但您可以提前做好任何您想做的事情。您对 Edit 控件的参与不可能有任何帮助。

由于即使使用 MFC 在 Windows 中绘制东西也需要非常神秘的步骤,所以我将粘贴我的测试代码。这可能会冒犯 MFC 的老手,但它可以完成工作,给予或接受相同的对象生命周期管理。它可能包含一些细微的错误,因为一切都很困难,但它显示了绘制位图的原理。此外,如果您毕竟绘制到对话框的背景,您可能希望在“erasebackground”事件中进行,我不知道。

//create bitmap with updated contents
bmp = new CBitmap();
bmp->CreateCompatibleBitmap(this->GetDC(), 100,100);
__int32* buf = (__int32*)malloc(100*100*4);
int r=rand(),g=rand(),b=rand(),a=255;
for(int y=0;y<100;y++) for(int x=0;x<100;x++) buf[y*100+x] = b|(g<<8)|(r<<16)|(a<<24);
bmp->SetBitmapBits(100*100*4,buf);
free(buf);

//when painting
CPaintDC dc(this);
CDC bitmapDC;
bitmapDC.CreateCompatibleDC(&dc); 
bitmapDC.SelectObject(bmp);
dc.BitBlt(0,0,100,100,&bitmapDC,0,0,SRCCOPY);

【讨论】:

  • 混合mallocnew 很尴尬。创建兼容的位图,然后忽略位深度是一个错误。不考虑扫描线对齐也是一个错误。建议在 WM_ERASEBKGND 消息处理程序中使用 CPaintDC 是错误的。在许多错误之间隐藏的有用信息真的很少。
  • @IInspectable 是来自CreateCompatibleBitmap 的位图不保证是现代显示器的 32 位吗?这里正确的用法应该是bmp-&gt;CreateBitmap(100, 100, 1, 32, buf),但是如果显示器不支持32位那就是同样的问题。
  • @BarmakShemirani: CreateCompatibleBitmap 返回一个位图,它与提供的设备上下文兼容。这与 设备无关 位图不同。正确的用法是使用兼容的位图,并使用请求的位深度实现代码。
  • 感谢您指出在 win32 和 MFC 中完全正确执行此操作所需的所有可怕细节。
  • 感谢您的回复,非常感谢。回覆。由于对使用 MFC 的鄙视,我通过设计和构建嵌入式控制系统而不是构建 Windows 应用程序来谋生。这是自从我开始使用 Visual C++ 5.0 编写 Windows hack 以来,MFC 编辑器和向导第一次无法满足我的简单需求。
【解决方案2】:
Here's what's working for me:

Add two member variables to the dialog class:

  CImage  m_lcdImage;
  CStatic m_lcdStatic;

In the init dialog callback:

  m_lcdStatic.Create( "Static",
    WS_CHILD | WS_BORDER | WS_VISIBLE | SS_BITMAP | SS_CENTERIMAGE, 
    CRect( <rectangle coordinates> ), this );

  m_lcdImage.Create( <bitmap extent + color depth> );
  m_lcdStatic.SetBitmap( HBITMAP( m_lcdImage ));
  drawLCD();

Add member function drawLCD() called in init or when bitmap changes:

{
  //
  // app-specific m_lcdImage.SetPixel() calls 
  // to update the bitmap
  //

  m_lcdStatic.InvalidateRect( NULL );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    • 2012-12-08
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 2010-12-07
    • 2014-04-27
    相关资源
    最近更新 更多