【问题标题】:Where to define PAINTSTRUCT and why to define HDC?在哪里定义 PAINTSTRUCT 以及为什么要定义 HDC?
【发布时间】:2014-03-05 03:50:23
【问题描述】:

我的问题很简单,也不是很重要。

  1. 我开始学习编写 Win32 应用程序。当我阅读其他人的代码时,我经常看到他们将PAINTSTRUCT ps; 放在WndProc 的switch 语句之前。他们为什么不把这个放进箱子WM_PAINT?他们为ps分配内存然后不使用?

  2. 我总是看到PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps);。但是我多次检查了ps.hdc 的值,ps.hdchdc 的值每次都相等。定义hdc 是否还有其他原因,而不仅仅是可读性或编写更少的代码?

(很抱歉,如果我的英语不好并且问题不在这个社区的水平)

【问题讨论】:

  • 他们通常只是在 WndProc 中将其设为静态,因此它只分配一次,而不是每次调用 switch 语句时。此外,由于 HDC 是一种指针类型,如果在 case 语句中声明,它会导致 case 语句被丢弃,因此它通常也在 WndProc 而不是 switch 语句中定义。否则,您的案例陈述将需要括号。除此之外,它只是可读性。

标签: c++ winapi memory gdi


【解决方案1】:

回答第 1 点:Win32 API 是为 C 设计的(它已经很老了)并且将 PAINTSTRUCT ps; 放在 case 语句中需要将 case 的内容放在大括号 {} 中C 不允许内联声明。 C++ 在不带大括号的情况下在 case 语句中声明变量时也可能存在问题——调用析构函数而不调用构造函数。你很快就会发现switch() case... 风格维护起来会很尴尬,功能会变得非常庞大和笨拙,并且不能很好地与 Intellisense 之类的东西配合使用。很多时候,您会看到开发人员使用地图将函数与特定消息相关联:-

WindowProc (args)
{
  func_ptr = some_map.GetValue (message_type)
  if func_ptr not null
    call func_ptr
  else
    DefWindowProc (args)
}

至于第 2 点,当出现错误时,hdc 的值将是 null,并且使用 hdc 而不是 ps.hdc 看起来更简洁。此外,hdcps 更容易传递给其他函数。但除此之外,文档没有说明为什么ps.hdcBeginPaint 的结果不同的任何原因。

【讨论】:

  • 谢谢大家的回答。当我制作 Win32 应用程序时,我学到了很多关于如何正确设计代码的知识。我目前看的书中还没有提到这些小细节。
【解决方案2】:

当我阅读其他人的代码时,我经常看到他们把 PAINTSTRUCT ps;在 WndProc 中的 switch 语句之前。他们为什么不把这个放到 WM_PAINT 的箱子里?

几种可能性:

  1. 他们正在使用或曾经使用旧式 C 语言,其中所有局部变量都必须在函数的开头定义。
  2. 根据您的编译器及其警告级别,您可能会在尝试在 switch 语句的 case 中声明变量时收到警告。
  3. 他们只是马虎。

窗口过程可能不应该“处理”消息,而是将它们分派给特定于消息的处理程序。因此,WndProc 中的 WM_PAINT 案例可能应该调用一个单独的函数来进行绘制,并且 PAINTSTRUCT 可以是该单独函数的本地函数。但我们正在冒险发表意见,所以我会保留它。

我总是看到PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps);

我似乎记得有一个模糊的情况,即返回的设备上下文句柄可能与 PAINTSTRUCT 中的不同,但可能极为罕见,并且可能不存在于现代版本的 Windows 中。

认为返回的 HDC 很方便。如果您的绘画很简单并且不需要 PAINTSTRUCT 中的任何其他字段,这为您提供了一种简单的方法来引用设备上下文。

【讨论】:

    【解决方案3】:
    1. 这确实没有区别,并且许多实现将在每次调用窗口过程时“分配”内存,无论变量是在函数顶部声明还是在开关的WM_PAINT 情况下声明。

    2. BeginPaint 不仅仅是简单地返回 ps.hdc

    【讨论】:

    • 1.它的确有所作为。声明范围过宽的变量会降低代码的可读性,并且更容易出错。 2. 你完全没抓住重点。问题是为什么要声明本地 hdc 而不是使用 ps.hdc
    • 我知道BeginPaint 不仅仅是简单地返回ps.hdc。但是,如果hdcps.hdc相等,我不必将BeginPaint的返回值存储在变量中,因为我需要的所有值都已经存在于ps中。
    • @DavidHeffernan 我同意你的第 2 点(尽管这个问题在这一点上不能被认为是完全清楚的),但是关于第 1 点,是你“完全错过了这一点”,因为他的问题似乎关于“分配”,而不是“可读性”。当然,最好为每个事件定义单独的函数。谁会不同意呢?
    • @ooga 好的,提问者询问了分配。但这没关系。堆栈上的单个绘制结构的成本是多少?
    【解决方案4】:

    我经常看到他们将PAINTSTRUCT ps; 放在WndProc 的switch 语句之前。他们为什么不把这个放进箱子WM_PAINT?他们为 ps 分配内存然后不使用它?

    这样做是不好的做法。最佳做法是调用一个单独的函数来进行绘制,并避免使用页面长的窗口过程。但是,如果您必须在窗口过程中进行绘制,请尽可能使用本地范围声明您的变量。

    除了可读性或编写更少的代码之外,定义 hdc 是否还有其他原因?

    这是一种方便。由于绘制函数一次又一次地引用设备上下文,因此将其存储在局部变量中很方便,从而使代码不那么冗长。是的,当BeginPaint 成功时,保证BeginPaint 返回的HDC 等于paint 结构中的HDC

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 2018-09-15
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      相关资源
      最近更新 更多