程序本来是想实现鼠标单击改变背景颜色。可是,程序运行时,为什么没有任何消息触发,背景颜色就一直不断的改变了?WM_PAINT怎么被触发的

#include <windows.h>
#include <stdlib.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void DrawRectangle (HWND) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("SetBackgroundColor") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("注册失败!"),
szAppName, MB_ICONERROR) ;
return ;
} hwnd = CreateWindow (szAppName, TEXT ("SetBackgroundColor"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ; while(GetMessage(&msg,NULL,,))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam ;
} LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static RECT r;
HDC hdc;
HBRUSH hBrush;
switch (iMsg)
{
case WM_PAINT:
hBrush = CreateSolidBrush(RGB(rand()%,rand()%,rand()%));
hdc=GetDC(hwnd);
FillRect (hdc, &r, hBrush) ;
ReleaseDC (hwnd, hdc) ;
DeleteObject (hBrush) ;
return ; case WM_SIZE:
GetClientRect(hwnd,&r);
return ; case WM_LBUTTONDOWN:
InvalidateRect(hwnd,&r,true);
return ; case WM_DESTROY:
PostQuitMessage () ;
return ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

回答:这个基础,看一下《windows程序设计》第三章吧

wm_paint是有无效区域的时候产生的消息,所以应首先恢复该区域,才不会一直循环下去

wm_paint中应该用beginpaint与endpaint这两个api,参数是PaintStruct类型,它们的功能正是使无效区域恢复
而不是getDC与releaseDC

invalidaterect也有使区域无效的功能,可用它手动触发wm_paint事件重绘

http://zhidao.baidu.com/question/112410452.html

--------------------------------------------------------------------------------------

对比Delphi代码:

procedure TWinControl.WMPaint(var Message: TWMPaint);
var
DC, MemDC: HDC;
MemBitmap, OldBitmap: HBITMAP;
PS: TPaintStruct;
begin
if not FDoubleBuffered or (Message.DC <> ) then // 消息里已经自带DC,用这个绘制就可以了
begin
if not (csCustomPaint in ControlState) and (ControlCount = ) then // 针对Windows自带控件,其包含的子控件数量为0,且没有自绘标记。
inherited // 走向1,主要是针对Windows系统原生控件,微软定义的基本控件,总不会有错,应该内含BeginPaint了吧?
else
PaintHandler(Message); // 走向2,主要是针对Delphi的自绘控件,内含BeginPaint
end
else
begin
DC := GetDC(); // 走向3,消息里没有自带DC,那么就现取,内含BeginPaint
MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
ReleaseDC(, DC);
MemDC := CreateCompatibleDC();
OldBitmap := SelectObject(MemDC, MemBitmap);
try
DC := BeginPaint(Handle, PS);
Perform(WM_ERASEBKGND, MemDC, MemDC);
Message.DC := MemDC;
WMPaint(Message);
Message.DC := ;
BitBlt(DC, , , ClientRect.Right, ClientRect.Bottom, MemDC, , , SRCCOPY);
EndPaint(Handle, PS);
finally
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
DeleteObject(MemBitmap);
end;
end;
end;

procedure TWinControl.PaintHandler(var Message: TWMPaint);
var
I, Clip, SaveIndex: Integer;
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC;
if DC = then DC := BeginPaint(Handle, PS);
try
if FControls = nil then PaintWindow(DC) else
begin
SaveIndex := SaveDC(DC);
Clip := SimpleRegion;
for I := to FControls.Count - do
with TControl(FControls[I]) do
if (Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and
(csOpaque in ControlStyle) then
begin
Clip := ExcludeClipRect(DC, Left, Top, Left + Width, Top + Height);
if Clip = NullRegion then Break;
end;
if Clip <> NullRegion then PaintWindow(DC);
RestoreDC(DC, SaveIndex);
end;
PaintControls(DC, nil);
finally
if Message.DC = then EndPaint(Handle, PS);
end;
end;

就是说,TWinControl无论是否双缓冲,都会调用BeginPaint和EndPaint函数,来消除自绘。整个Controls.pas单元也只有这两处调用BeginPaint。

另外,我没有找到TWinControl的DoubleBuffered被初始化的过程,说明编译器自动把它初始化成了False

终于懂了:WM_PAINT中应该用BeginPaint与EndPaint这两个api,它们的功能正是使无效区域恢复(所以WM_PAINT里即使什么都不做,也必须写上BeginPaint与EndPaint)——Delphi里WM_PAINT消息的三个走向都做到了这一点 good的更多相关文章

  1. TWinControl、TCustomControl和TGraphicControl对WM_PAINT消息的三种不同处理(虚函数的特点就是升升降降)

    -------------------- TWinControl收到WM_Paint消息(以后找个例子)-------------------- 1. 消息函数 TWinControl.WMPaint ...

  2. 4.redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?

    作者:中华石杉 面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当 ...

  3. 终于懂了:TWinControl.DefaultHandler里的CallWindowProc(FDefWndProc)还挺有深意的,TButton对WM_PAINT消息的处理就是靠它来处理的(以前不明白为什么总是要调用inherited,其实就是没有明白TWinControl.DefaultHandler的真正用处)

    我忽然发现:TButton既没有处理WM_PAINT,又没有Paint()或者PaintWindow(),那么它是什么时候被绘制的? Form1上放2个TButton,然后设置代码: procedur ...

  4. 终于懂了:WM_PAINT 与 WM_ERASEBKGND(三种情况:用户操作,UpdateWindow,InvalidateRect产生的效果并不相同),并且用Delphi代码验证 good

    一直对这两个消息的关系不是太了解,借重新深刻学习windows编程的机会研究一番. 1)当窗口从无效变为有效时,比方将部分覆盖的窗口恢复时会重绘窗口时:程序首先会通过发送其他消息调用DefWindow ...

  5. 终于懂了:FWinControls子控件的显示是由Windows来管理,而不是由Delphi来管理(显示透明会导致计算无效区域的方式有所不同——透明的话应减少剪裁区域,所以要进行仔细计算)

    在研究TCustomControl的显示过程中,怎么样都找不到刷新FWinControls并重新显示的代码: procedure TWinControl.PaintHandler(var Messag ...

  6. 终于懂了:Delphi消息的Result域出现的原因——要代替回调函数的返回值!(MakeObjectInstance不会帮助处理(接收)消息回调函数的返回值)

    MakeObjectInstance应该不会帮助处理(接收)消息回调函数的返回值,可是有时候又确实需要这个返回值,这可怎么办呢?我是看到这段文字的时候,想到这个问题的: 当WM_PAINT不是由Inv ...

  7. css笔记——关于css中写上charset “utf-8”

    当css文件中写上 charset "utf-8" 时需要将body和html的样式分开写 例如: html,body{margin:0;padding:0;font-family ...

  8. 用RelativeLayout布局可以在imageview中写上文字

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  9. 终于懂了:Delphi消息的Result完全是生造出来的,不是Windows消息自带的(Delphi对Windows编程体系的改造越大,学习收获就越大)——消息是否继续传递就看这个Result

    Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样. t ...

随机推荐

  1. hdu1695 GCD

    http://acm.hdu.edu.cn/showproblem.php?pid=16951 /** 大意: a<=x<=b , c<= y <= d ,求在此范围内 有多少 ...

  2. cocos2d-x游戏开发系列教程-超级玛丽06-CMGameScene

    背景 在CMMenuScene中,当用户点击开始游戏时,导演让场景进入到CMGameScene 头文件 class CMGameScene : public cocos2d::CCLayer,publ ...

  3. 第一篇:NSTread线程的创建

    #import "ViewController.h" //导入头文件 #import <pthread.h> @interfaceViewController () @ ...

  4. BestCoder Round #50 (div.1) 1003 The mook jong (HDU OJ 5366) 规律递推

    题目:Click here 题意:bestcoder 上面有中文题目 分析:令f[i]为最后一个木人桩摆放在i位置的方案,令s[i]为f[i]的前缀和.很容易就能想到f[i]=s[i-3]+1,s[i ...

  5. Activity跳转

    本例中MainActivity为:FirstActivity.java FirstActivity如下: package com.wyl.intentmultiactivitytest; import ...

  6. pycharm+QT4的helloworld

    # -*- coding: utf-8 -*- from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 exc ...

  7. Altera FPGA中的pin简介

    第一步要看的肯定是pin planner ,这个是黑金四代EP4CE15F17C8的视图 先就是发现他们pin有不同的颜色区域,分别对应不同的bank,应该是有的设计里面要求pin在同一个bank吧( ...

  8. Impossible WPF Part 2: Binding Expressions

    原文 http://www.11011.net/wpf-binding-expressions Back in April I posted an idea for building an expre ...

  9. [置顶] 浏览器模式和标准对于javascript的影响

    今天在编写代码的时候遇到了一个莫名其妙的问题,请看下面 <html> <head> <title> Test </title> <!--<m ...

  10. android4.0移植,拨号异常

    D/dalvikvm( 2274): GC_CONCURRENT freed 206K, 12% free 6571K/7431K, paused 2ms+3ms D/dalvikvm( 2274): ...