求教vvyang讲解这片代码,300分敬上,谢谢啦(300分)

  • 主题发起人 主题发起人 Alucard
  • 开始时间 开始时间
A

Alucard

Unregistered / Unconfirmed
GUEST, unregistred user!
这是你回答我那个问题的代码,虽然解决问题了,但是有几处有点迷糊,还望大侠指点一下。
var
hdcScr, hdcMem: HDC;
bmpMem, bmpOld: HBITMAP;
cnv: TCanvas;
begin
hdcScr := GetDC(0);
bmpMem := CreateCompatibleBitmap(hdcScr, 200, 200);
ReleaseDC(0, hdcScr);
hdcMem := CreateCompatibleDC(0);
bmpOld := SelectObject(hdcMem, bmpMem);

cnv := TCanvas.Create;
cnv.Handle := hdcMem;
cnv.Brush.Color := clYellow;
cnv.Pen.Color := clRed;
cnv.FillRect(Rect(0, 0, 200, 200));
cnv.Ellipse(0, 0, 200, 200);
Self.Canvas.CopyRect(Rect(100, 100, 300, 300), cnv, Rect(0, 0, 200, 200));
cnv.Free;

SelectObject(hdcMem, bmpOld);
DeleteDC(hdcMem);
DeleteObject(bmpMem);
end;

== 以下是我的疑问 ============================================================
hdcScr := GetDC(0);
bmpMem := CreateCompatibleBitmap(hdcScr, 200, 200);
ReleaseDC(0, hdcScr);
hdcMem := CreateCompatibleDC(0);
bmpOld := SelectObject(hdcMem, bmpMem);
我以前用的是:
hdcScr := CreateCompatibleDC(0);
bmpMem := CreateCompatibleBitmap(hdcScr, 200, 200);
SelectObject(hdcScr, bmpMem);
结果是不正常的,为什么?

还有这块:
bmpOld := SelectObject(hdcMem, bmpMem);
...
SelectObject(hdcMem, bmpOld);
这两句的工作是做什么的?
 
我的理解是DC是一个可绘制物件的接口,任何操作都是在这个上面执行,与具体的物件无关。

hdcScr := GetDC(0);
这句是获取本窗体的DC

CreateCompatibleBitmap(hdcScr, 200, 200);
这句就是创建一个兼容该DC的Bitmap

ReleaseDC(0, hdcScr);
这句是解除hdcScr变量与本窗体DC的关联。

hdcMem := CreateCompatibleDC(0);
这句是创建一个新的兼容本窗体DC的DC

bmpOld := SelectObject(hdcMem, bmpMem);
这句是将hdcMem与bmpMem关联起来,并保存hdcMem以前关联的物件

SelectObject(hdcMem, bmpOld);
这句是解除hdcMem与bmpMem的关联。

我的理解对吗?
 
1、“大侠”不敢当,只是个 Delphi 业余爱好者。300 分有点多,你其实随便发个 0 分的帖就行了。
2、GDI 对象包括设备环境、位图、矢量图、画笔、画刷、区域、路径等等,他们的内存结构我们一般是无法看到的,它经过内核的 N 次映射才呈现在我们面前,只能通过 GDI 句柄(GDI 资源的唯一代号)进行操作。
所谓“设备环境”就是系统提供给用户一个操作“输出设备”的接口,这个输出设备可以是显示器(屏幕)、内存、打印机、绘图仪,但一般显示器设备环境和内存设备环境用的多。
3、要在内存中画图,首先要获得“内存设备环境”(hdcMem):
hdcMem := CreateCompatibleDC(0);
而要想画的图被保存下来,还必须创建一个与显示器兼容的位图(bmpMem),然后用 SelectObject 将位图选入内存设备环境(hdcMem),这样对 hdcMem 所有的绘图操作都会被记录到位图中。与显示器兼容的位图是这样创建的:
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP;
而其中的 DC 参数就是显示器(屏幕)设备环境,所以在此之前还要用 GetDC(0) 获得显示器的设备环境。
按照先后顺序排出来就是这样:
hdcScr := GetDC(0);//获得显示器设备环境句柄
bmpMem := CreateCompatibleBitmap(hdcScr, 200, 200);//创建与显示器兼容的位图
ReleaseDC(0, hdcScr);//位图创建好了,显示器的设备环境句柄就没用了,还给 GDI
hdcMem := CreateCompatibleDC(0);//创建内存设备环境
bmpOld := SelectObject(hdcMem, bmpMem);//把已经创建好的位图选入内存设备环境。由于创建的设备环境一般都有默认的位图、区域、画笔、画刷等对象与之关联,所以内存设备环原有的默认位图对象(bmpOld)要给人家保存下来,以便将来还给 GDI。SelectObject 实际上是个置换函数,它将对象选入设备环境,同时把原来关联的对象置换出来。
4、结束前,要把资源句柄销毁或还给 GDI,不然会导致 GDI 对象无限增多。一般销毁的顺序与创建的顺序是相反的:
SelectObject(hdcMem, bmpOld);//把原来内存设备环境的位图还给 GDI
DeleteDC(hdcMem);//销毁内存设备环境
DeleteObject(bmpMem);//把自己创建的位图对象销毁
其中,SelectObject(hdcMem, bmpOld) 和 DeleteObject(bmpMem) 可以合为一句:DeleteObject(SelectObject(hdcMem, bmpOld)),但一般不要这么写,问题多多。
5、至于您出现的错误,是这样的:
hdcScr := CreateCompatibleDC(0);
bmpMem := CreateCompatibleBitmap(hdcScr, 200, 200);
SelectObject(hdcScr, bmpMem);
CreateCompatibleDC(0) 和 GetDC(0) 是完全不同的,前者是建立内存设备环境,后者是获取显示器设备环境。您的代码首先创建了一个与内存兼容的设备环境,然后又创建了一个与内存设备环境兼容的位图,而内存设备环境的调色板显然是黑白的,那位图当然也是黑白的了。
简单来说,设备环境是解决往哪画的问题,而位图是解决画什么的问题,二者相对独立。你要往显示器上贴图,就必须创建与显示器设备兼容的位图;而你要把位图先画在内存中然后再贴上去,当然就要建立与内存兼容的设备环境了。
CreateCompatibleDC(0) 和 GetDC(0) 是固定用法,记住就行了,没什么道理可言。实际上微软大多数的 API 都他妈没有道理可言,就跟英文单词和法文语法一样,目的是考验人类的体力,而不是智商。
6、编写 GDI 程序一般要把 Windows 任务管理器[查看]->[选择列]->[GDI 对象]选中,这样可以观察是否有 GDI 对象泄露。参考资料可以看 MSDN 和网上的电子书,多得数不胜数。
 
谢谢啦...接受答案了...
 
后退
顶部