找了一个OpenGL的文章
Delphi图形图像设计
[前言:]Delphi不仅有优秀的数据库访问能力,而且在图形处理方面也有非常强大的能力。在这个专辑中我们将看到Delphi在图形处理方面的卓越性能。
DELPHI图形编辑技巧二则
界面色彩渐变效果是通过用渐变的画刷刷绘依次相邻的矩形块实现的。下面列举实例说明
做一个OpenGL控件
OpenGL是一个独立于窗口的图形库,而图形最终是在窗口系统里绘制出来的,那么OpenGL的绘图命令是怎么在窗口里生成输出的呢
用DELPHI中Canvas特性开发图形软件
以往开发Windows图形软件大多用vc++作为开发工具,vc++强大的图形功能可以让程序员编制出许多优秀的与图形相关的软件,Delphi中也有一个与CDC相类似的类Tcanvas, 它封装了Delphi 中的绘图函数。我们可以把Delphi和VC中相同或相近的方法做个有趣的比较
改变图片效果
想不想另图片有另一番效果,使用下列语句实现吧,增加两个TImage图片框,分别为Image1、Image2,用Image1引入一张图片,按下按钮就可以在Image2上出现惊人的效果
用Delphi 显示122种图形特效
在开发多媒体软件时,经常需要编写各种图形显示特效,近日在网上找到TPicShow 2.3 for Delphi 3,4,5这一控件,据介绍能显示122种不同的图形特效。经下载按装后,可在Delphi件面板的Samples组中可发现一个相机状的图标。下面来看其具体应用
实战Delphi数据网格色彩特效
Delphi中的数据网格控件(TDbGrid)对于显示和编辑数据库中大量的数据起着十分重要的作用;然而,在使用数据网格控件的同时,也往往因为表格中大量的数据不易区分,而令操作者眼花缭乱。如何提高网格控件的易用性,克服它的此项不足呢?本文从改变数据网格的色彩配置角度,提出了一种解决办法
OpenGL简介
OpenGL是OpenGraphicsLib的缩写,是一套三维图形处理库,也是该领域的工业标准。计算机三维图形是指将用数据描述的三维空间通过计算转换成二维图像并显示或打印出来的技术
OpenGL的原理
在OpenGL中是以面边界(B-REP)模型来描述物体的,或者说是使用多边形造型系统。在OpenGL中每个物体都只是一组平面,这组平面记录了该物体的表面。显然这些平面越小画出不断的物体越逼真
基于Delphi的图像漫游
在开发多媒体应用中,经常会遇到需要在有限区域内显示大图像的情况,有不少文章对此提出过解决方法,如通过调用Windows的API函数,直接读写内存等
用Delphi进行OpenGL编程学习心得
在开发图形程序时,尤其是三维的图形程序,因为感觉OpenGL没有DirectX那么庞杂,所以选择了DelphiOpenGL,凭感觉而言,Delphi也没有C++那么繁杂而且更加人性化,于是选择Delphi+OpenGL进行工作
DELPHI图形编辑技巧二则
一、界面色彩渐变效果的实现
界面色彩渐变效果是通过用渐变的画刷刷绘依次相邻的矩形块实现的。下面列举实例说明:
1.新建一个表单,假设其Width为500,设置一个按钮Button1,按此按钮将把表单置为由左向右由黄变白的渐变效果。
2.Button1按钮的代码如下:
procedure TForm1.Button1Click(Sender: TObject);
var i,j:Integer;
Dct:TRect;
begin
j:=Form1.height;
//获得表单高度
for i:=0 to 255 do
//此处设置RGB()中一个颜色值
begin
Canvas.Brush.Color:=RGB(255,255,i);
//每次画矩形的画刷颜色
Dct:=Rect(i*2,0,(i+1)*2,j);
//每次刷绘的矩形区域
Canvas.FillRect(Dct);
//填充颜色
end;
end;
二、图形整体拉出效果
单纯的图形整体拉出效果比较简单,动态地改变图形区域的大小就可以实现,但事先应将图形的“Stretch”设置为“True”。
举例说明下拉效果:
1.在表单上放置一图片,高度为200,属性“Height”设为0,“Stretch”设置为True。添加“Timer”构件,“Interval”设为200,“Enable”设为Ture。
2.在Timer1Timer中添加代码:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Image1.Height:=Image1.Height+20;
//设置增量
if image1.Height=200 then Timer1.Enabled:=FALSE;
//图形整体拉出完毕
end;
做一个OpenGL控件
OpenGL是一个独立于窗口的图形库,而图形最终是在窗口系统里绘制出来的,那么OpenGL的绘图命令是怎么在窗口里生成输出的呢?
这就是各个系统上的OpenGL实现者需要做的工作了。在Windows里是通过wgl库完成的,在X-Windows里是通过glx服务器来完成的,至于这些OpenGL实现具体是怎么工作的,请参考sgi发布的sample implement源码,不过那个代码是用C写的。
在MS-Windows里,wgl库负责将OpenGL的绘制设备RenderContext与GDI的DeviceContext联系起来,使得发到OpenGL的RC里的命令生成的位图能够在GDI DC里绘制出来,你可以把它想象成OpenGL在RC里有一个FrameBuffer,记录着生成的图案,而wgl则负责把FrameBuffer的内容BitBlt到DC上。当然,这并不是它实际的工作方法,如果想了解更多请参考SGI发布的SDK资料或联系MS公司。
为了使GDI DC能够接受OpenGL RC的输出,必须为DC选定特别的像素格式,然后建立RC,再用wglMakeCurrent把当前要使用的RC和DC联系起来。此后我们就可以用OpenGL命令正常工作了。在一个程序里可以创建多个RC和多个DC,程序中的OpenGL命令会发到被wglMakeCurrent指定为当前的那一组合中。
我并不认为这个初始化过程是个很有意思的工作,这个世界上有很多聪明的程序员也这么想,所以他们发明了glaux库和glut库。glaux是在著名的OpenGL Programmer Guide里提出的,这本书是OpenGL编程的官方文档,因为它的封皮是红色的,所以通常简称为RedBook。故名思意,glaux是一套输助库,它使得你无须关心在具体窗口系统里初始化、消息响应的细节,而是使用传统的c/dos程序风格编制OpenGL程序。
int main(int argc, char** argv)
{ auxInitDisplayMode( AUX_SINGLE|AUX_RGB|AUX_DEPTH16);//使用单缓冲、RGB彩色模式、16位浓度
auxInitPosition(0,0,250,250);
auxInitWindow("Title"
;//以上两行在(0,0)片建立了一个大小为250X250的窗口,其标题为"Title"。
myinit();//建立OpenGL透视投影环境
auxReshapeFunc(myReshape);//指定窗口大小变化的响应函数
auxMainLoop(display);//指定绘制函数
return 0; }
由于glaux是为教学目的开发的,所以实用价值很限,所以又有程序员开发了glut,这套库被广泛使用,它的工作方式与glaux极为类似,但功能完善得多,特别是对交互、全屏等的支持要理想得多,所以许多的OpenGL演示程序使用它,比如SGI网站 Windows/macos/os2/xwindows等系统上都能使用的程序,那么应该选择这套库。
我并不认为一个Delphi程序员会喜欢glaux或glut,因为那意味着你不能利用Delphi的可视开发能力,另外任何真正实用的Delphi程序想直接在其它操作系统上编译运行好象也不现实,即glut的跨平台能力也没有什么吸引力。我们应该开发一个VCL控件,把初始化工作封装起来。
我认为从TCustomPanel派生一个子类比较方便,让我们称它为TGLPanel吧。初始化过程要在WMCreate里完成,之所以要放在这里是因为这个时候Window Handle已经建立,但还没启用。
在WMCreate中会
①调用initDC完成DC调整工作,initDC会以本窗口使用的DC调用PreparePixelFormat,而PixelFormat则真正完成像素格式调整。
②然后WMCreate会调用InitGL完成OpenGL透视投影环境的设定。
③最后调用OnInit给用户一个调整透视投影环境的机会。
注意,如果要在MDI环境中的子窗体中使用OpenGL,还有些附加工作要做,这就是给窗口类的Params.Style加上WS_CLIPCHILDREN和WS_CLIPSIBLINGS属性,这得在Window Handle建立之前就完成,因此要写在CreateParams里。由于SDI应用并不需要该代码,所以应该定义OnPreInit事件,让用户在需要的时候自己加上,在Create里调用OnPreInit。以下代码定义了OnPreInit,但并没有定义CreateParams,如果需要自己加上吧。
在TGLPanel类中实际所做工作的详细说明(按成员可见性组织):
私有
1、加入DC/RC/Pal私有变量
2、定义初始化DC/RC的私有方法
保护:
3、加入FOnPaint,FOnResize,FOnInit,FOnPreInit四个事件响应变量。
4、继承/重载虚方法CreateParams,Paint,Resize
5、响应以下消息
WM_CREATE, TWMCreate, WMCreate
WM_DESTROY, TWMDestroy, WMDestroy
WM_PALETTECHANGED, TWMPaletteChanged, WMPaletteChanged
WM_QUERYNEWPALETTE, TWMQueryNewPalette, WMQueryNewPalette
WM_ERASEBKGND, TWMEraseBkgnd, WMEraseBkgnd
公开:
6、定义建构与析构方法
7、定义必要的其它方法以提供各种特性
发布:
8、以下继承来的属性
__property Alignment;
__property Align;
__property DragCursor;
__property DragMode;
__property Enabled;
__property ParentFont;
__property ParentShowHint;
__property PopupMenu;
__property ShowHint;
__property TabOrder;
__property TabStop;
__property Visible;
9、以下继承来的方法
__property OnClick;
__property OnDblClick;
__property OnDragDrop;
__property OnDragOver;
__property OnEndDrag;
__property OnEnter;
__property OnExit;
__property OnMouseDown;
__property OnMouseMove;
__property OnMouseUp;
__property OnStartDrag;
10、加入以下事件
//初始化OpenGL状态
__property TNotifyEvent OnInit = {read=FOnInit,write=FOnInit};
//专用于修改显示BPP模式
__property TNotifyEvent OnPreInit = {read=FOnPreInit,write=FOnPreInit};
11、重载以下事件
__property TNotifyEvent OnResize = {read=FOnResize,write=FOnResize};
__property TNotifyEvent OnPaint = {read=FOnPaint,write=FOnPaint};
12、将消息与其响应函数连接起来(Delphi中这一步是在定义函数时指定的)
源代码
unit GLPanel;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls,OpenGL;
type
TGLPanel = class(TCustomPanel)
private
{ Private declarations }
DC: HDC;
RC: HGLRC;
procedure initDC;
procedure initGL;
procedure PreparePixelFormat(var DC: HDC);
protected
{ Protected declarations }
FOnPaint:TNotifyEvent;
FOnInit:TNotifyEvent;
FOnPreInit:TNotifyEvent;
FOnResize:TNotifyEvent;
procedure Paint;override;
procedure Resize;override;
procedure WMDestroy(var Msg: TWMDestroy);message WM_DESTROY;
procedure WMCreate(var Msg:TWMCreate); message WM_CREATE;
public
{ Public declarations }
constructor Create(Owner:TComponent);override;
published
{ Published declarations }
property Alignment;
property Align;
property DragCursor;
property DragMode;
property Enabled;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
property OnInit:TNotifyEvent read FOnInit write FOnInit;
property OnPreInit:TNotifyEvent read FOnPreInit write FOnPreInit;
property OnResize:TNotifyEvent read FOnResize write FOnResize;
property OnPaint:TNotifyEvent read FOnPaint write FOnPaint;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents(’Samples’, [TGLPanel]);
end;
//---------------------------------------------
constructor TGLPanel.Create;
begin
inherited;
end;
//---------------------------------------------
procedure TGLPanel.WMDestroy(var Msg: TWMDestroy);
begin
wglMakeCurrent(0, 0);
wglDeleteContext(RC);
ReleaseDC(Handle, DC);
end;
//---------------------------------------------------
procedure TGLPanel.initDC;
begin
DC := GetDC(Handle);
PreparePixelFormat(DC);
end;
//---------------------------------------------------
procedure TGLPanel.initGL;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glOrtho(-1, 1, -1, 1, -1, 50);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glEnable(GL_DEPTH_TEST);
//注意下面这一行是为了做练习程序时可以直接用glColor指定材质而加的,
// 可能使得光照或表面材质发生意想不到的变化,
// 如果不需要可以去掉或在程序中用glDisable(GL_COLOR_MATERIAL);关闭
glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
gluLookAt(2, 4, 6, 0, 0, 0, 0, 1, 0);
SwapBuffers(DC);
end;
//---------------------------------------------
procedure TGLPanel.PreparePixelFormat(var DC: HDC);
var
PFD : TPixelFormatDescriptor;
ChosenPixelFormat : Integer;
begin
FillChar(PFD, SizeOf(TPixelFormatDescriptor), 0);
with PFD do
begin
nSize := SizeOf(TPixelFormatDescriptor);
nVersion := 1;
dwFlags := PFD_DRAW_TO_WINDOW or
PFD_SUPPORT_OPENGL or
PFD_DOUBLEBUFFER;
iPixelType := PFD_TYPE_RGBA;
cColorBits := 16; // 16位颜色
cDepthBits := 32; // 32位深度缓冲
iLayerType := PFD_MAIN_PLANE;
{ Should be 24, but we must allow for the clunky WKU boxes }
end;
ChosenPixelFormat := ChoosePixelFormat(DC, @PFD);
if ChosenPixelFormat = 0 then
Raise Exception.Create(’ChoosePixelFormat failed!’);
SetPixelFormat(DC, ChosenPixelFormat, @PFD);
end;
procedure TGLPanel.WMCreate(var Msg:TWMCreate);
begin
//在这里做初始化工作
//修改DC的象素格式,使之支持OpenGL绘制
initDC;
RC := wglCreateContext(DC);
wglMakeCurrent(DC, RC);
//初始化GL绘制系统
initGL;
if Assigned(FOnInit) then
begin
if (wglMakeCurrent(DC,RC)=false) then
ShowMessage(’wglMakeCurrent:’ + IntToStr(GetLastError));
FOnInit(self);
end;
end;
//
procedure TGLPanel.Paint;
begin
//TCustomPanel:
aint();
if Assigned(FOnPaint) then
begin
wglMakeCurrent(DC,RC);
FOnPaint(self);
SwapBuffers(DC);
end;
end;
//
procedure TGLPanel.Resize;
begin
inherited;
if Assigned(FOnResize) then
begin
wglMakeCurrent(DC,RC);
glViewport(0,0,ClientWidth,ClientHeight);
FOnResize(self);
end;
end;
end.
以上代码仅用来说明原理及建立一个基本的练习环境,您可以自由使用,转载请注明出处。如果使用从本人主页下载的TGLPanel请遵守内附使用说明的版权申明。如果实际做东西,建议使用Mike Lischke的GLScene控件组(http://www.lischke-online.de/)。
end
else
删除注册表项....................... end;初始化扩展是通过IShellExtInit实现的,当外壳调用IShellExtInit.Initialize时,它传递一个数据对象包含来文件对应的目录的PIDL标识符。Initialize方法需要从数据对象中提取文件名,并把文件名和PIDL标识符保存起来为了以后使用。
function TCXPropSheet.SEIInitialize(pidlFolder: PItemIDList;
lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
szFile: array[0..MAX_PATH+1]of Char;
filecount: integer;begin
Result:=E_FAIL;
if(lpdobj=nil)then
begin
Result:=E_INVALIDARG;
messagebox(0, ’1’, ’错误’, mb_ok);
Exit;
end;
with FormatEtc do
begin
cfFormat:=CF_HDROP;
ptd:=nil;
dwAspect:=DVASPECT_CONTENT;
lindex:=-1;
tymed:=TYMED_HGLOBAL;
end;
Result:=lpdobj.GetData(FormatEtc, StgMedium);
if Failed(Result)then
Exit;
//如果只有一个文件被选中,获得文件名并保存。
filecount:=DragQueryFile(stgmedium.hGlobal, $FFFFFFFF, nil, 0);
if filecount=1 then
begin
Result:=NOERROR;
DragQueryFile(stgmedium.hGlobal, 0, szFile, SizeOf(szFile));
FFilename:=strpas(szFile);
end;
ReleaseStgMedium(StgMedium);end;添加页面的操作是通过IShellPropSheetExt接口来实现的。如果属性页是和文件相关联,外壳会调用IShellPropSheetExt.AddPages给属性页添加一个页面。如果属性页同控制面板程序相关联,外壳调用IShellPropSheetExt.ReplacePage来替换页面。
IShellPropSheetExt.AddPages方法有两个参数,lpfnAddPage是一个指向AddPropSheetPageProc回调函数的指针,回调函数用来提供要添加的页面信息给外壳。lParam是一个用户自定义的值,这里我们用它来返回给回调函数对象。
一般的IShellPropSheetExt.AddPages方法实现步骤是:
给PROPSHEETPAGE结构设定正确的值,特别是:
把扩展的对象引用记数变量付值给pcRefParent成员,这可以防止页面还在显示时,扩展对象被卸载。
实现PropSheetPageProc回调函数来处理页面创建和销毁的情况。
调用CreatePropertySheetPage函数来创建页面。
调用lpfnAddPage指向的函数来来添加创建好的页面。
function TCXPropSheet.AddPages(lpfnAddPage: TFNADDPROPSHEETPAGE;
lParam: LPARAM): HResult;var
PSP: TPropSheetPage;
HPSP: HPropSheetPage;begin
result:=E_FAIL;
try
psp.dwSize:=SizeOf(psp);
psp.dwFlags:=PSP_USEREFPARENT or PSP_USETITLE or PSP_USECALLBACK;
psp.hInstance:=hInstance;
//这里我们使用了事先储存在wave.res中的对话框模板,模板是用delphi5自带的
//resource workshop编辑的,使用delphi5/bin/brcc32.exe编译的。
psp.pszTemplate:=MakeIntResource(100);
//标题名
psp.pszTitle:=’波文件信息’;
//设定回调函数
psp.pfnDlgProc:=@DialogProc;
psp.pfnCallBack:=@PropCallback;
//设定对象引用记数变量
psp.pcRefParent:=@comserver.objectcount;
//用lParam向回调函数传递对象
psp.lParam:=integer(self);
HPSP:=CreatePropertySheetPage(psp);
if HPSP$#@60;$#@62;nil then begin
if not lpfnAddPage(HPSP, lParam)then begin
DestroyPropertySheetPage(HPSP);
end else begin
_addref;//增加引用记数,否则一脱离这个方法的作用域,delphi自动释放对象。
result:=S_OK;
end
end
except
on e: exception do begin
e.message:=’添加页面’+e.message;
messagebox(0, pchar(e.message), ’错误’, mb_ok);
end;
end;end;
function TCXPropSheet.ReplacePage(uPageID: UINT;
lpfnReplaceWith: TFNADDPROPSHEETPAGE; lParam: LPARAM): HResult;begin
Result:=E_NOTIMPL;//同文件关联时,外壳不调用ReplacePage,所以不用实现end;回调函数处理属性页的消息,主要要响应WM_INITDIALOG消息来初始化页面显示信息,响应WM_COMMAND消息来处理用户交互,响应WM_NOTIFY消息来处理页面切换或关闭后处理操作结果。
function DialogProc(hwndDlg: HWnd; Msg: UINT; wParam: wParam;
lParam: LPARAM): Bool; stdcall;
var
PageObj: TCXPropSheet;
filename: string;
displayName : string;
SheetHWnd: HWnd;
begin
result:=false;
try
if Msg=WM_INITDIALOG then begin//初始化界面
//获得lparam传递过来的对象
pageObj:=TCXPropSheet(PPropSheetPage(lParam)^.lParam);
//保存对象信息
SetWindowLong(hwndDlg, DWL_USER, integer(pageObj));
//设置界面显示波文件信息
SetDlgItemText(hwndDlg, 100, PChar(ExtractFileName(PageObj.FFileName)));
OpenMedia(PageObj.FFileName);
SetDlgItemText(hwndDlg, 101, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_AVGBYTESPERSEC))));
SetDlgItemText(hwndDlg, 102, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_BITSPERSAMPLE))));
SetDlgItemText(hwndDlg, 103, PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_CHANNELS))));
CloseMedia;
SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);
Result:=TRUE;
end
else if(Msg=WM_COMMAND)then begin
if Lo(wParam)=110 then//用户点击了关于按钮(id=110)
MessageBox(0,’作者:hubdog’+#13#10+’email:hubdog@263.net’,’关于...’,MB_OK);
end else if(msg=WM_NOTIFY)then begin
sheetHwnd:=getparent(hwndDlg);//获得属性页的窗口句柄
case PNMHdr(lparam)^.code of
//页面失去焦点
PSN_KILLACTIVE:
begin
SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);
Result:=TRUE;
end;
end;
end;
except
on e: exception do begin
e.message:=’回调处理’+e.message;
messagebox(0, pchar(e.message), ’错误’, mb_ok);
end;
end;
end;
建立同驱动器相关联的属性页扩展用
同上面讲的有两点不同:
IShellExtInit.Initialize方法传递过来的数据对象包含的驱动器路径可能是CFSTR_MOUNTEDVOLUME格式而不是CF_HDROP格式的?曜记??魇荂F_HDROP格式的,而在NTFS文件系统中映射的远程设备则是CFSTR_MOUNTEDVOLUME格式的。
注册表项是HKEY_CLASSES_ROOT/Drive/Shellex/PropertySheetHandlers子键。
建立控制面板属性页扩展
同上面讲的有两点不同:
控制面板程序调用IShellPropSheetExt.ReplacePage方法来替换页面,它不调用IShellPropSheetExt。AddPages方法。
注册方式:子键可以在不同位置创建,这依赖于扩展是针对用户还是针对机器的。对用户方式子键是HKEY_CURRENT_USER/REGSTR_PATH_CONTROLPANEL,否则子键是HKEY_LOCAL_MACHINE/REGSTR_PATH_CONTROLSFOLDER。
本程序在Delphi5,Win NT 4.0,K6-233系统下调试成功。例子程序可以到http://chaozhi.com/lgc去下载
用DELPHI中Canvas特性开发图形软件
以往开发Windows图形软件大多用 VC ++ 作为开发工具, VC++强大的图形功能可以让程序员编制出许多优秀的与图形相关的软件。
VC++ 中与绘图相关的函数都封装在CDC及其衍生的CClientDC,CpaintDC,CwindowDC中。
Delphi中也有一个与CDC相类似的类Tcanvas, 它封装了Delphi 中的绘图函数。我们可以把Delphi和VC中相同或相近的方法做个有趣的比较。
(一)Canvas和 CDC绘图方法比较:
我们可以从以下表格中看到Tcanvas和 CDC相似的函数:
表 1--1
Canvas方法 CDC方法 功能
Arc Arc 画一个椭圆弧
Chord Chord 画一根玄。
CopyRect 拷贝指定矩形区域中图象到指定矩形
Draw BitBlt 拷贝位图
Ellipse Ellipse 画椭圆
FillRect PaintRgn 使用刷子填充一个又一个矩型
FloodFill FloodFill 用当前刷子填充区域
FrameRect FrameRect 画一个矩形框
Lineto Lineto 画线到
Moveto Moveto 移 到
Pie Pie 画扇形
Polygon Polygon 画多边形
PolyLine PolyLine 画多根相连的线
Rectangle Rectangle 画一个实心矩形
RoundRect RoundRect 画一个圆角的矩形
StretchDraw StretchBlt 从源图象中
移动图象到指定矩形
TextWidth GetCharWidth 返回字符宽
TextOut TextOut 在指定坐标写字
TextRect ExtTextOut 在制定矩形中写字
上表中,我们只列出部分绘图函数,详细了解,请参阅有关Delphi和VC书籍.
与VC++ 相类似, Delphi也提供了绘图工具,如 Tpen,Tbrush等,与VC不同的是, Delphi的绘图工具封装在Tcanvas中。Delphi也提供字形及字体大小的类Tfont,下面我们用具体例子来分析它们的用法。
(二)用Delphi 制作Window95/NT图形软件。
象使用VC 一样,我们先用Delphi的Wizard 建立一个 SDI 应用程序。Delphi 自动建立SDI 框架, 先运行一次。程序现在还不能干任何事。下一步开始添加代码。
编辑主菜单。 增加Write,Draw俩个下拉菜单项。 在"Write"下增加"HelloWorld!!","Iamateacher ","Font.."菜单项.在 aw"下增加"Arc","Line", "Polygon","RoundRect","Rectangle","color." ,"LineStyle","WidthLine". 在"LineStyle" 菜单下增加"Solid","Dash","Dot","DashDot", "DashDotDot" 子菜单。
相应的在SdiForm中增加ColorDialog,FontDialog, 控件。
在OnPaint事件中增加如下代码:
procedureTSDIAppForm.FormPaint(Sender:TObject);
begin
canvas.FillRect(rect);{清空桌面画布}
withSDIappformdo
posx:=clientwidthdiv2;
posy:=clientheightdiv2;{确定客户区中心点}
casedetectIof
1:
begin
setpenstate;
canvas.Ellipse(posx-50,posy-50,posx+50,posy+50);
//penwidth:=oldwidth;
end;{在客户区中心点画圆}
2:
begin
setpenstate;
canvas.MoveTo(posx-60,posy-60);
canvas.LineTo(posx+60,posy+60);
//penwidth:=oldwidth;
end;{在客户区画直线}
3:
begin
fposx:=trunc(50*cos(pi/6));
fposy:=trunc(50*sin(pi/6));
setpenstate;
Canvas.Polygon([Point(posx-fposy,posy-fposx),
Point(posx+fposy,posy-fposx),
Point(posx+50,posy),Point(posx+fposy,posy+fposx),
point(posx-fposy,posy+fposx),point(posx-50,posy)]);
//penwidth:=oldwidth;
end;{在客户区中心点画多边形}
4:
begin
setpenstate;
canvas.RoundRect(posx-100,posy-50,posx+100,posy+50,
20,20);
end;{在客户区中心点画带圆角的矩形}
5:
begin
setpenstate;
sdiappform.Canvas.Brush.Color:=clred;
canvas.Rectangle(posx-100,posy-50,posx+100,posy+50);
sdiappform.Canvas.Brush.Color:=bcolor;
end{在客户区中心点用红色刷子画矩形}
else
begin
canvas.Font:=formfont;
canvas.TextOut(30,posy,str);
end;
end;{写字}
end;
上面程序中出现的变量在事件OnCreate中初始化。
procedureTSDIAppForm.FormCreate(Sender:TObject);
begin
str:=;{要写在画布上的字符串}
formfont:=canvas.font;{字体和大小}
detectI:=0;{确定画布上出现何种图形的参数}
rect:=sdiappform.ClientRect;{客户区矩形}
oldwidth:=sdiappform.Canvas.Pen.Width;{最初画笔宽度}
penwidth:=oldwidth;{画笔宽度}
penstyle:=sdiappform.Canvas.Pen.Style;{画笔类型}
pencolor:=sdiappform.Canvas.Pen.Color;{画笔颜色}
bcolor:=sdiappform.Canvas.Brush.Color;{画刷颜色}
end;
为了减少代码,定义了一个Public过程,设定画笔。代码如下:
procedureTSDIAppForm.setpenstate;
begin
withsdiappform.Canvas.Pendo
begin
color:=pencolor;
style:=penstyle;
width:=penwidth;
end;
end;
响应每一个菜单项OnClick事件本程序设计得非常简单,如果有兴趣,读者也可以加上一些代码,完成许多复杂的工作。
procedureTSDIAppForm.LineColor1Click(Sender:TObject);
begin
ifcolordialog1.Executethen
begin
pencolor:=colordialog1.Color;
SdiAppForm.Canvas.Pen.Style:=psInsideFrame;
ifpenwidth$#@60;1then
SdiAppForm.Canvas.Pen.Width:=3;
SdiAppForm.Canvas.Pen.Color:=pencolor;
invalidate;
end;
end;{完成画笔颜色设定}
//{完成画笔笔形设定}
procedureTSDIAppForm.Solid1Click(Sender:TObject);
begin
penStyle:=pssolid;
invalidate;
end;
procedureTSDIAppForm.Dot1Click(Sender:TObject);
begin
PenStyle:=psdot;
invalidate;
end;
procedureTSDIAppForm.Dash1Click(Sender:TObject);
begin
penStyle:=psdash;
invalidate;
end;
procedureTSDIAppForm.DashDot1Click(Sender:TObject);
begin
PenStyle:=psdashdot;
invalidate;
end;
procedureTSDIAppForm.DashDotDot1Click(Sender:TObject);
begin
penStyle:=psdashdotdot;
invalidate;
end;
//////////////////////////////////
procedureTSDIAppForm.RoundRect1Click(Sender:TObject);
begin
detectI:=4;
invalidate;
end;
procedureTSDIAppForm.Rectangle1Click(Sender:TObject);
begin
detectI:=5;
invalidate;
end;
procedureTSDIAppForm.Helloworld1Click(Sender:TObject);
begin
detectI:=0;
str:=helloworld!!;
Invalidate;
end;
procedureTSDIAppForm.Imateacher1Click(Sender:TObject);
begin
detectI:=0;
str:=Iamateacher!!;
Invalidate;
end;
procedureTSDIAppForm.Fonts1Click(Sender:TObject);
begin
iffontdialog1.Executethen
begin
detectI:=0;
formfont:=fontdialog1.font;
invalidate;
end;
end;{设定字体和大小}
编译并运行,可以看到画图的效果。
(三)图形的拷贝和剪贴
通过剪贴板可以完成拷贝和剪贴的功能。Canvas 不直接支持剪贴板,完成Canvas上图画拷贝和张贴关键技巧是通过一个Tbitmap变量,把Canvas 上的图形先复制到Tbitmap上,再把Tbitamp和window的剪贴板连起来,反过来也一样。
Delphi通过鉴定Wizard建立的SDI程序中,有关 Edit命令的Click事件定义在ActionList控件中,相关代码如下:
//拷贝图形到剪贴板
procedureTSDIAppForm.EditCopy1Execute(Sender:TObject);
var
bmp:tbitmap;//设置一个图形变量
begin
bmp:=tbitmap.Create;
bmp.Width:=rect.Right+10;
bmp.Height:=rect.Bottom+10;
bmp.canvas.CopyRect(rect,sdiappform.canvas,rect);
clipboard.Assign(bmp);
bmp.free;
end;
//从剪贴板上复制
procedureTSDIAppForm.EditPaste1Execute(Sender:TObject);
var
bmp:tbitmap;//设置一个图形变量
begin
ifclipboard.HasFormat(CF_BITMAP)then
begin
bmp:=tbitmap.create;
bmp.Assign(clipboard);
sdiappform.Canvas.draw(0,0,bmp);
bmp.free;
end
elseifclipboard.HasFormat(CF_TEXT)then
begin
str:=clipboard.AsText;
detectI:=0;
invalidate;
end;
end;
//剪下图形拷贝到剪贴板
procedureTSDIAppForm.EditCut1Execute(Sender:TObject);
begin
EditCopy1Execute(sender);
withsdiappform.Canvasdo
begin
copymode:=cmwhiteness;
copyRect(rect,sdiappform.Canvas,rect);
CopyMode:=cmSrcCopy;
end;
end;
也可以把已有的图形文件直接拷贝在Canvas上,本程序通过菜单Open命令完成这一操作。
procedureTSDIAppForm.FileOpen1Execute(Sender:TObject);
var
bmp:Tbitmap;
currentfile:string;
begin
ifOpenDialog.Executethen
begin
currentfile:=OpenDialog.filename;
ifcurrentfile$#@60;$#@62;then
try
bmp:=tbitmap.Create;
bmp.LoadFromFile(currentfile);
sdiappform.Canvas.StretchDraw(rect,bmp);
finally
bmp.Free;
end;
end;
end;
本程序只是简单的讨论了Canvas绘图功能,离图形软件包还相差很远,而且打开图形文件显示在Canvas中还有些问题,希望读者中编程高手能帮我改正。
改变图片效果
想不想另图片有另一番效果,使用下列语句实现吧,增加两个TImage图片框,分别为Image1、Image2,用Image1引入一张图片,按下按钮就可以在Image2上出现惊人的效果:
procedure TForm1.Button1Click(Sender: TObject);
begin
Image2.Canvas.Brush.Style := bsCross;
Image2.Canvas.CopyMode := cmMergeCopy;
Image2.Canvas.Draw(0,0, Image1.Picture.Graphic);
end;
用Delphi 显示122种图形特效
在开发多媒体软件时,经常需要编写各种图形显示特效,近日在网上找到TPicShow 2.3 for Delphi 3,4,5这一控件,据介绍能显示122种不同的图形特效。经下载按装后,可在Delphi件面板的Samples组中可发现一个相机状的图标。下面来看其具体应用。
首先:在form1中放入PicShow1,Button1,Spinedit1(Spinedit1在Samples组中)控件各一个。
其次:按F12后依次输入下列代码
unit Unit1;
nterface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
PicShow, StdCtrls, Spin;
type
TForm1 = class(TForm)
PicShow1: TPicShow;
Button1: TButton;
SpinEdit1: TSpinEdit;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure ShowNextImage;
procedure LoadNextImage;
public
{ Public declarations }
end;
var
Form1: TForm1;
i:integer;
implementation
{$R *.DFM}
procedure TForm1.ShowNextImage;
begin
if PicShow1.Busy then
PicShow1.Stop
else
begin
PicShow1.Execute;
LoadNextImage;
end;
end;
procedure TForm1.LoadNextImage;
begin
if i=1 then
begin i:=0; PicShow1.Picture.LoadFromFile('c:/1.bmp'); end
else
begin i:=1; PicShow1.Picture.loadfromfile('c:/2.bmp'); end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
i:=1;
LoadNextImage;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
picshow1.style:=spinedit1.Value;
showNextImage;
end;
end.
最后:按F9运行,Spinedit1中的值决定图形显示的特效,范围是1~122,再按Button1则示图形。此控件可在http://www.crosswinds.net/~khojasteh/处下载。下载后解压还可发现readme,其中有它的主要属性,方法,事件,具体情况读者可自行研究。
实战Delphi数据网格色彩特效
Delphi中的数据网格控件(TDbGrid)对于显示和编辑数据库中大量的数据起着十分重要的作用;然而,在使用数据网格控件的同时,也往往因为表格中大量的数据不易区分,而令操作者眼花缭乱。如何提高网格控件的易用性,克服它的此项不足呢?本文从改变数据网格的色彩配置角度,提出了一种解决办法。
以下为数据网格控件的6种特殊效果的实现方法,至于数据网格控件与数据集如何连接的方法从略。
1. 纵向斑马线效果:实现网格的奇数列和偶数列分别以不同的颜色显示,以区别相邻的数据列。
file://在DbGrid的DrawColumnCell事件中编写如下代码:
Case DataCol Mod 2 = 0 of
True: DbGrid1.Canvas.Brush.Color:= clBlue; file://偶数列用蓝色
False: DbGrid1.Canvas.Brush.Color:= clAqua; file://奇数列用浅绿色
End;
DbGrid1.Canvas.Pen.Mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
2. 纵向斑马线,同时以红色突出显示当前单元格效果:以突出显示当前选中的字段。
file://将上述代码修改为:
Case DataCol Mod 2 = 0 of
True: DbGrid1.Canvas.Brush.Color:= clBlue; file://偶数列用蓝色
False: DbGrid1.Canvas.Brush.Color:= clAqua; file://奇数列用浅绿色
End;
If ((State = [gdSelected]) or (State=[gdSelected,gdFocused])) then
If Not DbGrid1.SelectedRows.CurrentRowSelected then
DbGrid1.Canvas.Brush.Color:=clRed; file://当前选中单元格显示红色
DbGrid1.Canvas.Pen.Mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
上述两种方法突出了列的显示效果。
3.在数据网格中以红色突出显示当前选中的行。
设置DbGrid控件的Options属性中的dgRowSelect属性为真,Color属性为clAqua(背景色), 在DbGrid的DrawColumnCell事件中编写如下代码:
if ((State = [gdSelected]) or (State=[gdSelected,gdFocused])) then
DbGrid1.Canvas.Brush.color:=clRed; file://当前行以红色显示,其它行使用背景的浅绿色
DbGrid1.Canvas.pen.mode:=pmmask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
4.行突显的斑马线效果:既突出当前行,又区分不同的列(字段)。
file://其它属性设置同3,将上述代码修改为:
if ((State = [gdSelected]) or (State=[gdSelected,gdFocused])) then
begin
Case DataCol Mod 2 = 0 of
True : DbGrid1.Canvas.Brush.color:=clRed; file://当前选中行的偶数列显示红色
False: DbGrid1.Canvas.Brush.color:=clblue; file://当前选中行的奇数列显示蓝色
end;
DbGrid1.Canvas.pen.mode:=pmmask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
end;
5.横向斑马线, 同时以红色突显当前行效果。
file://其它属性设置同3,将上述代码修改为:
Case Table1.RecNo mod 2 = 0 of file://根据数据集的记录号进行判断
True : DbGrid1.Canvas.Brush.color:=clAqua; file://偶数行用浅绿色显示
False: DbGrid1.Canvas.Brush.color:=clblue; file://奇数行用蓝色表示
end;
if ((State = [gdSelected]) or (State=[gdSelected,gdFocused])) then file://选中行用红色显示
DbGrid1.Canvas.Brush.color:=clRed;
DbGrid1.Canvas.pen.mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
6.双向斑马线效果:即行间用不同色区分,同时,选中行以纵向斑马线效果区分不同的列。
file://其它属性设置同3,将上述代码修改为:
Case Table1.RecNo mod 2 = 0 of file://根据数据集的记录号进行判断
True : DbGrid1.Canvas.Brush.color:=clAqua; file://偶数行用浅绿色显示
False: DbGrid1.Canvas.Brush.color:= clblue; file://奇数行用蓝色表示
end;
If ((State = [gdSelected]) or (State=[gdSelected,gdFocused])) then
Case DataCol mod 2 = 0 of
True : DbGrid1.Canvas.Brush.color:=clRed; file://当前选中行的偶数列用红色
False: DbGrid1.Canvas.Brush.color:= clGreen; file://当前选中行的奇数列用绿色表示
end;
DbGrid1.Canvas.pen.mode:=pmMask;
DbGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
上述6种方法分别就数据网格控件的列和行的色彩进行了设置,读者可以根据自己的需要设置特效。该程序在Delphi5中测试通过。
OpenGL简介
OpenGL是OpenGraphicsLib的缩写,是一套三维图形处理库,也是该领域的工业标准。
计算机三维图形是指将用数据描述的三维空间通过计算转换成二维图像并显示或打印出来的技术。
OpenGL就是支持这种转换的程序库,它源于SGI公司为其图形工作站开发的IRIS GL,在跨平台移植过程中发展成为OpenGL。SGI在1992年7月发布1.0版,后成为工业标准,由成立于1992年的独立财团OpenGL Architecture Review Board (ARB)控制。SGI等ARB成员以投票方式产生标准,并制成规范文档(Specification)公布,各软硬件厂商据此开发自己系统上的实现。只有通过了ARB规范全部测试的实现才能称为OpenGL。1995年12月ARB批准了1.1版本,最新版规范是1999.5通过的1.2.1。
OpenGL被设计成独立于硬件,独立于窗口系统的,在运行各种操作系统的各种计算机上都可用,并能在网络环境下以客户/服务器模式工作,是专业图形处理、科学计算等高端应用领域的标准图形库。它低端应用上的主要竞争对手是MS-Direct3D,该图形库是以COM接口形式提供的,所以极为较复杂,稳定性差,另外微软公司拥有该库版权,目前只在Windows平台上可用。D3D的优势在速度上,但现在低价显卡都能提供很好的OpenGL硬件加速,所以做3D使用Direct3D已没有特别的必要,在专业图形处理特别是高端应用方面目前还没有出现以Direct3D技术为基础的例子,而游戏等低端应用也有转向OpenGL的趋势。
微软在Windows NT对OpenGL的支持始于3.51,在Windows9x中的支持始于Win95 OEM Service Release 2。Windows下常用的OpenGL库有两种,MS实现的和SGI实现的,MS-OpenGL调用会自动检测是否存在显示卡制造商提供的ICD(Installable Client DeviceDriver)驱动程序,有则调用ICD中的例程,否则才用CPU进行计算,所以能利用显示卡的OpenGL加速能力。对开发者来说使用方法并没有区别,只是有ICD驱动时更快些。SGI的版本是纯软件实现不能利用硬件加速并且SGI已经在1999年宣布停止支持,但这套库便于调试程序,仍有不少开发者使用。
近日SGI宣布与Intel联手针对当前及未来IA体系的Internet流化SIMD扩展优化OpenGL。这显然意味着OpenGL未来在intel体系及internet应用领域将大放光彩。
SGI曾经宣布研发OpenGL++,该图形库最大的特点是面象对象,提供了树形场景支持,大大 ×耸褂肙penGL处理复杂场景的工作量。后来(1999)SGI宣布与M$合作开发Ferihant,即Windows的下一代图形处理体系,包括DirectX与OpenGL的低级图形处理接口和以场景图支持为特点的高级接口,并且就此停止对其在Windows下的OpenGL实现的支持以示决心。此举世瞩目,大家都以为Windows图形处理快要过上幸福生活了,然而,不久,SGI宣布中止合作,并撤回派出的科学家,Ferihant基本上夭折。SGI 称终止合作的原因是M$不肯积极合作,光想把SGI 的技术合并进DirectX,真正内幕不详。不过以SGI在图形处理界的老大地位来说,还是有几分可信度的,因为M$初支持OpenGL就不积极。
虽然早在WinNT3.51 时代M$就已经实现了它的OpenGL 版本,但不肯随其Windows95 时提供,称该API 适合高端应用,而Win95面向一般消费者的用不到,并且在其win3.x下开发的wing 图表库的基础上搞出了GameSDK,即后来的DirectX 库,称这套库是专门为高性能游戏开发设计的,在当时的硬件条件下,这无疑是非常有道理的,并且很快成为Windows环境下游戏开发的标准API 。该库实质上是提供了绕过Windows 直接访问显存的途径,从而很好的解决了GDI 体系性能方面的不足,但由于是以COM接口形式提供的,所以相当复杂,而稳定性也不是很好,所以有人称Direct3D 是为追求速度而不择手段的公司才用的。然而也就在这个时期,三维图形加速卡开始走向商用和家用,也就是在这时期S3公司以其性价比极高的带三维图形加速的显示芯片、板卡向当时Trident 公司的霸主地位发起了挑战。另外这时实时三维游戏开始流行,以Dos 下的第一人称射击游戏--暗杀希特勒(3d worlf) 大获成功、红极一时ID Software 的开始铸辉煌,推出了Doom 、Quake1 ,相信这两个名字在今天(2000.4) 的游戏圈子里应该是无人不知无不晓吧?1996.12.ID Software 的高手John Carmack 在开发下一代三维图形引擎时在其.plan 中写上了以下字句:
Direct-3D IM is a horribly broken API. It inflicts great pain and suffering on the programmers using it, without returning any significant advantages. I don’t think there is ANY market segment that D3D is apropriate for, OpenGL seems to work just fine for everything from quake to softimage. There is no good technical reason for the existance of D3D.
I’m sure D3D will suck less with each forthcoming version, but this is an oportunity to just bypass dragging the entire development community through the messy evolution of an ill-birthed API.
此后以他为代表的一大批游戏开发人员开始多方呼吁MS积极支持OpenGL。M$终于在Win95的OSR2版本里集成了OpenGL,并为以前版本的Win95免费提供单独的OpenGL实现。(或许您还不了解这些人的影响力,不知道您听说过以生产Voodoo系统图形加速卡而著称于世的3dfx公司吗?当年Quake的开发者不肯用Voodoo的glide API对voodoo做优化版本,差点没把3dfx吓蒙,于是赶紧搞了一个针对游戏的OpenGL子集:MiniGL,让ID Software的人只要在制作OpenGL时只使用MiniGL API做过优化就成,这样Quake总算可以用上voodoo的硬件加速能力了。这样也造就了一个新名词:MCD--MiniGL Client Driver,用于Windows的MiniGL驱动程序,而标准的OpenGL则依靠ICD驱动)。
好了,家常就拉到这里,下回咱们就该正正经经看,在Delphi里使用OpenGL开发三维应用程序是咋回事了。
OpenGL的原理
可以把OpenGL看成一条生产流水线,原料是场景、物体的顶点、表面细节等信息,产品是看起来有三维感觉的平面位图。
在OpenGL中是以面边界(B-REP)模型来描述物体的,或者说是使用多边形造型系统。在OpenGL中每个物体都只是一组平面,这组平面记录了该物体的表面。显然这些平面越小画出不断的物体越逼真。
生成本图的程序源码(http://chinaaspdownload.xajh.net/delphiuser/zhuanlan/opengl_1/polymodalsrc.zip)[需要TGLPanel]而物体表面的每个平面都只需要边界和平面上的图案就足以表示。在OpenGL中需要用户提供围绕平面边缘的线段的顶点参数、平面内图案的位图两组信息,术语称为Vertex(顶点)、Texture(纹理)。
如果表示物体的平面小到一个像素那么得到图像将会是极为真实的,然而这意味着天文数字般的计算任务。所以OpenGL三维图形程序设计很大程度上是在质量与速度之间折中的艺术。
在计算机三维图形学上还有诸如实体几何、Voxel等其它的方法,有很多朋友问过我医学图象处理方面的问题,其实在该领域里使用得更多的是Voxel方法,该方法可以很好在像素级计算生成剖面等的图像,另外象DeltaForce这个游戏也使用了该方法。目前还没有见过支持Voxel加速的硬件,所以DeltaForce是需要全部使用CPU计算的,而支持OpenGL硬件加速的显卡满大街都是,而且适当使用纹理也可以取得极为逼真的效果。
总而言之,OpenGL吃进去的是顶点和纹理,挤出来的是看上去很三维的平面位图。不知道什么是位图?!就是那个啥你在屏幕上看见那个呀。^o^
OpenGL流水线工作的原理是咋样的呢?那可是一个复杂的过程,下面简单描述一下,详细的自己看三维图形学的书去吧。
客户端(即咱们写的图形应用程序)==命令和数据==$#@62;服务器(流水线)==$#@62;帧缓冲区
客户在程序中所发的命令和数据并不是立即传到流水线执行的,流水线在收到glFlush/glFinish/SwapBuffers之类的命令之后才会真正开始执行命令加工数据,这些命令都有说明某一阶段处理相关的指令数据改送已经结束请求获得所需结果的含义。这就是所谓的客户/服务器模式。
1.坐标变换,生成基本图元
2.裁剪,只留下视见范围内的部份
3.光栅化,生成图形片段
4.逐片段操作,生成素像
基于Delphi的图像漫游
在开发多媒体应用中,经常会遇到需要在有限区域内显示大图像的情况,有不少文章对此提出过解决方法,如通过调用Windows的API函数,直接读写内存等。这些方法有某些优点,但实现起来较为复杂,且易出错?收咴谑导?型ü?邢该??利用Delphi的强大的面向对象可视化开发环境开发了一种交互式图像漫游方法。
Delphi中,鼠标的消息响应是通过元件的OnMouseDown、OnMouseU p和OnMouseMove事件实现的,通过对此三个事件编程,可控制图像在有限区域内移动。考虑到所移动的图像的边界应总在该区域外,因此图像的左上角坐标应小于该区域对应坐标,图像右下角坐标应大于该区域对应坐标(除非图像大小比该区域小)。图1
具体方法是:
1、新建一工程Project1,在Form1中依次放入Panel1、Panel2和I mage1元件,注意Pa nel2和Image1分别在Panel1和Panel2上,再将一La bel1元件加入Panel2中,调整Panel1尺寸为适当大小,并修改各元件属性为:
元件 属性名 属性值
Panel1
BevelInner:bvRaised
BevelOuter: bvNone
BorderStyle: bsSingle
Panel2
Align:alClient
Image1
AutoSize:True
Picture:”Apple.bmp”
Label1
Align:alClient
Transparent : True
注意:此处Label1的作用不是显示字符,而是利用它响应鼠标消息 ,如果不用Label1而直接利用Image1的鼠标事件响应,则会由于其OnMo useDown事件的激活与Image1的自身坐标移动事件冲突而使图像发生闪烁甚至不能移动。
2、在implementation后加入变量声明:
origin:Tpoint;
image_left:integer;
image_top:integer;
visa1:Tpoint; (鼠标当前位置相对图像右下角的坐标)
visa2:Tpoint; (鼠标当前位置相对图像左上角的坐标)
canmove:boolean;
编写Label1鼠标响应事件:
procedure TForm1.Label1MouseDown(Sender: TObject; Button
: TMouseButton;S hift: TShiftState; X, Y: Integer);
begin
if Button=mbLeft then
begin
origin.x:=X;
origin.y:=Y;
image_left:=image1.left;
image_top:=image1.top;
visa1.x:=X-(image1.width-panel2.width+image1.left);
visa1.y:=Y-(image1.height-panel2.height+image1.top);
visa2.x:=X-image1.left;
visa2.y:=Y-image1.top;
canmove:=true;
end;
end;
procedure TForm1.Label1MouseMove(Sender: TObject; Shift:
TShiftState; X, Y: Integer);
begin
if canmove then
begin
if X< visa1.x then X:=visa1.x;
if X>visa2.x then X:=visa2.x;
if Y< visa1.y then Y:=visa1.y;
if Y>visa2.y then Y:=visa2.y;
image1.left:=image_left+(X-origin.x);
image1.top:=image_top+(Y-origin.y);
end;
end;
procedure TForm1.Label1MouseUp(Sender: TObject; Button:
TMouseButton;Shi ft: TShiftState; X, Y: Integer);
begin
canmove:=false;
end;
用Delphi进行OpenGL编程学习心得
在开发图形程序时,尤其是三维的图形程序,因为感觉OpenGL没有DirectX那么庞杂,所以选择了DelphiOpenGL,凭感觉而言,Delphi也没有C++那么繁杂而且更加人性化,于是选择Delphi+OpenGL进行工作。在这过程中,碰到(肯定会)一些问题,在此提出希望和朋友们能够进行交流。
首先是初始化。初始化时,有几项工作需要进行:①创建设备描述表(Device Context)。(注:关于DC,各种资料译文不尽相同如设备环境、设备描述表、设备上下文等,但好象都不太贴切。要是能有李善兰这样的翻译就好了。下文中的RC情形相同)②设置相应的象素格式(PIXELFORMAT DESCRIPTOR)。③创建着色描述表(Rendering Context)。 Delphi中有好几种获得或创建设备描述表的方法。最简单的就是直接获得画布对象(TCanvas)的句柄属性(Handle),如:
DC:HDC;
DC:=Canvas.Handle;
也可以用API函数GetDC获得设备描述表。如:
DC:=GetDC(Handle,DC);
也可以用函数CreateCompatibleDC或者BeginPaint..EndPaint(需要注意它们之间的区别)等来获得设备描述表。但是设备描述表用完之后要记得释放或删除它,以解放资源的占用。拥有设备描述表的使用权后,就可以设置相应的象素格式。象素格式是个记录类型,其中有些字段或域是没什么用处的(至少现在是)。象素格式描述完成后,调用ChoosePixelFormat和SetPixelFormat函数将之与设备描述表进行匹配和设置。如下面代码:
function SetupPixelFormat(var dc:HDC):Boolean;
var
ppfd
PIXELFORMATDESCRIPTOR;
npixelformat:Integer;
begin
New(ppfd);
ppfd^.nSize:=sizeof(PIXELFORMATDESCRIPTOR);
ppfd^.nVersion:=1;
ppfd^.dwFlags:=PFD_DRAW_TO_WINDOW
or PFD_SUPPORT_OPENGL or
PFD_DOUBLEBUFFER;
ppfd^.dwLayerMask:=PFD_MAIN_PLANE;
ppfd^.iPixelType:=PFD_TYPE_COLORINDEX;
ppfd^.cColorBits:=8;
ppfd^.cDepthBits:=16;
ppfd^.cAccumBits:=0;
ppfd^.cStencilBits:=0;
npixelformat:=ChoosePixelFormat(dc, ppfd);
if (nPixelformat=0) then
begin
MessageBox(NULL, ’choosePixelFormat failed’,
’Error’, MB_OK);
Result:=False;
Exit;
end;
if (SetPixelFormat(dc, npixelformat, ppfd)= FALSE) then
begin
MessageBox(NULL, ’SetPixelFormat failed’,
’Error’, MB_OK);
Result:=False;
Exit;
end;
Result:=True;
Dispose(ppfd);
end;
也可以向下面这样进行设置如:
var pfd: PixelFormatDescriptor;
nPixelFormat : Integer;
begin
FillChar(pfd,SizeOf(pfd),0);
with pfd do
begin
nSize:=sizeof(pfd);
nVersion:=1;
dwFlags:=PFD_SUPPORT_OPENGL
or PFD_DRAW_TO_BITMAP
or PFD_DOUBLEBUFFER;
iPixelType:=PFD_TYPE_RGBA;
cColorBits:=32;
cDepthBits:=32;
iLayerType:=Byte(PFD_MAIN_PLANE);
end;
nPixelFormat:=ChoosePixelFormat(DC,@pfd);
SetPixelFormat(DC,nPixelFormat,@pfd);
{ // 使用DescribePixelFormat检查象素格式是否设置正确
DescribePixelFormat(DC,nPixelFormat,SizeOf(pfd),@pfd);
if (pfd.dwFlags and PFD_NEED_PALETTE)
< > 0 then SetupPalette(DC,pfd);
//SetupPalette是自定义函数
}end;
上述工作完成以后,最好先运行一遍,并检查nPixelFormat的值。正常的话,该值应该是大于0的,否则就有问题。同样的代码,我在NT机器上能够得到正确的大于0的值而在PWIN97或98的机器上得不到正确值,但是编译时不会有问题,而且NT上编译后在PWIN97机器上也能够正确运行。现在可以创建着色描述表(RC)了。调用函数wglCreateContext、wglMakeCurrent,如下例示:
RC:HGLRC;
RC:=wglCreateContext(DC);
wglMakeCurrent(DC,RC);
在程序结束之前,要记得释放所占用的资源。
wglMakeCurrent(0,0);
if RC< >null then
wglDeleteContext(RC);
if ghDC< >null then
ReleaseDC(Handle,DC);
以下的代码是从C++Builder 4中OpenGL的例子改写过来的?嘁牒蟮某绦虼笮∥?00K左右,而在C++Builder 4下编译后程序的大小为384K。
< a href=”061403-05.zip ”>程序代码 Zip 3KB
程序中的OpenGL函数及象素格式在Delphi中的MSHelp中有比较详细的解释,本文不敢多做解释。