⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 delphi3.html

📁 对于学习很有帮助
💻 HTML
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>Delphi实用技巧(三)</title>
</head>

<body background="../../images/background.gif" bgcolor="#628394" text="#FFFFFF"
link="#FFFF00" vlink="#FFFF00">

<p><a name="topofpage"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td><strong><em><font face="楷体_GB2312" size="6">Delphi实用技巧(三)</font></em></strong></td>
  </tr>
</table>
</center></div>

<p align="center"><a href="../programming.html"><font face="楷体_GB2312" size="4">返回“编程交流”</font></a></p>

<p><img src="delphilogo.gif" alt="Delphi" align="right" border="0" WIDTH="93" HEIGHT="128"> 

<ul type="square">
  <li><a href="#noobject"><font face="楷体_GB2312" size="4">用最原始的方法编制Windows应用程序</font></a></li>
  <li><a href="#initmenu"><font face="楷体_GB2312" size="4">“用户选取菜单”事件</font></a></li>
  <li><a href="#iunknown"><font face="楷体_GB2312" size="4">IUnknown类的局部变量由谁负责Release</font></a></li>
  <li><a href="#whichwnd"><font face="楷体_GB2312" size="4">为全屏幕方式的DirectDraw对象指定窗口Handle</font></a></li>
  <li><a href="#hint"><font face="楷体_GB2312" size="4">建立自己的Hint窗口</font></a></li>
</ul>

<hr width="80%">

<p><a name="noobject"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td><strong><em><font face="楷体_GB2312" size="5">用最原始的方法编制程序</font></em></strong></td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  Delphi将几乎所有我们要用到的东西进行了封装,让程序员以面向对象的方法来快速高效地完成任务。正如使用MFC编写程序,其生成的最终可执行文件要比使用纯C语言编制的程序大得多,Delphi生成的最终程序往往很大。<br>
  其实Delphi本质上仍是一种编程语言,只不过它的可视化特性太过强大,使得程序员往往忘了这一点。使用纯C语言编制Windows应用程序的朋友都知道,常规的方法是为Windows提供一个回调函数,在这个回调函数中处理各种消息,而程序的入口是一个名为WinMain的函数。<br>
  如果将Delphi看成一个单纯的PASCAL语言,就可以按上述的常规方法编制程序,下面就是这样一个例子,最终生成的可执行程序十分小,只有不到10KB。使用C语言编程的朋友可得会觉得下面的代码很眼熟。</font></p>
<div align="center"><center>

<table border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><pre><font face="Courier New" color="#000000">program MyApp;

uses Windows, Messages;

// </font><font
color="#000000">回调函数
</font><font face="Courier New" color="#000000">function AppWindowProc(
    hWnd:HWND; uMsg:UINT;
    wParam:WPARAM; lParam:LPARAM):LRESULT; stdcall;
begin
  Result := 0;
  case uMsg of
    WM_DESTROY:begin
      PostQuitMessage(0);
      Exit;
    end;
  end;
  Result :=
    DefWindowProc(hWnd, uMsg, wParam, lParam);
end;

var
  wc: TWndClass;
  hWnd: Integer;
  MSG: TMsg;
begin
  // </font><font
color="#000000">程序从这里开始执行
  </font><font face="Courier New" color="#000000">wc.style := CS_VREDRAW or CS_HREDRAW;
  wc.lpfnWndProc := @AppWindowProc;
  wc.cbClsExtra := 0;
  wc.cbWndExtra := 0;
  wc.hInstance := HInstance;
  wc.hIcon := LoadIcon(0, IDI_APPLICATION);
  wc.hCursor := LoadCursor(0, IDC_ARROW);
  wc.hbrBackground := (COLOR_BTNFACE+1);
  wc.lpszMenuName := nil;
  wc.lpszClassName := 'My App';
  if RegisterClass(wc)=0 then Exit;
  hWnd := CreateWindow(
    wc.lpszClassName, 'TEST',
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    0, 0, HInstance, nil);
  if hWnd=0 then Exit;
  ShowWindow(hWnd, SW_SHOWNORMAL);
  while GetMessage(MSG, 0, 0, 0) do begin
    TranslateMessage(MSG);
    DispatchMessage(MSG);
  end;
  Halt(MSG.wParam);
end.</font></pre>
    </td>
  </tr>
</table>
</center></div>

<p align="center"><a href="#topofpage">回到页首</a></p>

<hr width="80%">

<p><a name="initmenu"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td><strong><em><font face="楷体_GB2312" size="5">“用户选取菜单”事件</font></em></strong></td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  Delphi的TMainMenu构件没有提供很丰富的事件处理,这给程序设计带来了一些不便。例如,在一个文本编辑器程序中,可能需要随时侦测系统的剪帖板是否有数据,如果有则将主菜单的Paste条目设为Enabled,反之设为Disabled。检测剪帖板是否有内容的代码应该在用户选取菜单时立即执行,可惜Delphi并未提供相应的事件。<br>
  当用户选取菜单时,Windows会向程序发送WM_INITMENU消息,因此可在MainForm中加入处理WM_INITMENU消息的过程,示例如下:</font> 

<ul type="circle">
  <li><font face="楷体_GB2312" size="4">首先在MainForm声明的private段中加入如下声明</font><br>
    <font face="Courier New" color="#000000">procedure WMInitMenu(var msg: TMessage); message 
    WM_INITMENU;</font></li>
  <li><font face="楷体_GB2312" size="4">WMInitMenu消息处理过程的代码如下:</font><div
    align="center"><center><table border="0" cellpadding="2">
      <tr>
        <td><pre><font face="Courier New" color="#000000">procedure TMainForm.WMInitMenu(var msg: TMessage);
begin
  if msg.WParam=GetMenu(Handle) then begin
    EditPasteItem.Enabled := Clipboard.HasFormat(CF_OEMTEXT);
  end else inherited;
end;</font></pre>
        </td>
      </tr>
    </table>
    </center></div></li>
</ul>

<p><font face="楷体_GB2312" size="4">  在上例中,当用户选取菜单时,WMInitMenu立刻获得控制权,并根据剪帖板中是否有文本内容来决定Paste菜单条目的Enabled属性值。注意,无论是在MDI程序还是在非MDI程序中,处理WM_INITMENU消息的过程都应该放在MainForm中。</font></p>

<p align="center"><a href="#topofpage">回到页首</a></p>

<hr width="80%">

<p><a name="iunknown"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><font face="楷体_GB2312" size="5" color="#FFFFFF"><strong><em>IUnknown类型的局部变量由谁负责Release</em></strong></font></td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  在C++中,IUnknown是一个抽象类,它拥有三个方法:QueryInterface、AddRef和Release,而在Delphi中,这三个方法分别是QueryInterface、_AddRef和_Release,注意方法名前页的下划线。<br>
  编制使用IUnknown类局部变量的程序时应注意,Delphi在一个模块结束之前将会自动调用_Release方法来释放所有的IUnknown局部变量,而这些代码对于程序员来说是不可见的。看下面的代码:</font></p>
<div align="center"><center>

<table border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><pre><font color="#000000">function TestProc: HRESULT;
var
  lpDD : IDirectDraw;
begin
  Result := DirectDrawCreate(nil, lpDD, nil);
  if Result&lt;&gt;0 then raise Exception.Create('Failed create!');
  Result := lpDD.QueryInterface(IID_IDirectDraw2, MyDirectDraw);
  lpDD._Release; // 这一行代码是多余的,将导致出错
end;</font></pre>
    </td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  上面的一段函数建立一个IDirectDraw2类(MyDirectDraw是一个IDirectDraw2类型的全局变量),其中最后一行的lpDD._Release是错误的,在C++中需要这么做,但在Delphi里因为有一段不可见的代码自动完成对lpDD的Release工作,所以会引起一个异常。这段不可见代码是我反汇编后观察汇编源码才得知的。</font></p>

<p align="center"><a href="#topofpage">回到页首</a></p>

<hr width="80%">

<p><a name="whichwnd"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><font face="楷体_GB2312" size="5" color="#FFFFFF"><strong><em>为全屏幕方式的DirectDraw对象指定窗口Handle</em></strong></font></td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  在DirectX编程中,IDirectDraw2对象有一个方法名为SetCooperativeLevel,功能是指定该对象的性能级别。调用该方法需要指定一个窗口Handle,在C++中可简单地指定为主程序的窗口Handle,而在Delphi中,如果设定的级别为全屏幕独占方式,则这个Handle一定要是Application.Handle而不是MainForm.Handle,这一点在我所见到的所有关于DirectDraw的封装、构件中均未得见。<br>
  在设定为全屏幕独占方式时,还要先使Application.Handle所代表的窗口显示在最前方,否则下一步调用CreateSurface方法就会失败。这一点也是我几经尝试才总结出来的。请见示例代码:</font></p>
<div align="center"><center>

<table border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><pre><font face="Courier New" color="#000000">function CreateFullScreen(out DDrawObj:IDirectDraw2): HRESULT
var
  lpDD : IDirectDraw;
begin
  Result := DirectDrawCreate(nil, lpDD, nil);
  if Result&lt;&gt;DD_OK then
    raise Exception.Create('Failed Create!');
  Result := lpDD.QueryInterface(IID_IDirectDraw2, DDrawObj):
  if Result&lt;&gt;DD_OK then
    raise Exception.Create('Failed QueryInterface!');
  ShowWindow(Application.Handle, SW_SHOWMAXIMIZED);
  Result := DDrawObj.SetCooperativeLevel(
    Application.Handle, {</font><font
color="#000000">很重要,一定要是</font><font face="Courier New" color="#000000">Application</font><font
color="#000000">窗口</font><font face="Courier New" color="#000000">}
    DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE);
  if Result&lt;&gt;DD_OK then
    raise Exception.Create('Failed SetCooperativeLevel');
  Result := DDrawObj.SetDisplayMode(640,480,8,0,0);
end;</font></pre>
    </td>
  </tr>
</table>
</center></div>

<p align="center"><a href="#topofpage">回到页首</a></p>

<hr width="80%">

<p><a name="hint"></a></p>
<div align="center"><center>

<table border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td width="100%"><font face="楷体_GB2312" size="5" color="#FFFFFF"><strong><em>建立自己的Hint窗口</em></strong></font></td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  当鼠标停留在某个控件上时,如果该控件的ShowHint特性为真则会显示出一个黄色的小窗口,这就是Hint窗口。如果从THintWindow派生一个类,并且将新类型赋值给全局变量HintWindowClass,则Delphi的Hint窗口将使用你所建立的新风格。<br>
  新类可以重载THintWindow的Paint方法来自己绘制Hint信息,例如下面这段代码将用红色填充整个Hint窗口,然后以黄色来显示Hint信息:</font></p>
<div align="center"><center>

<table border="0" cellpadding="0" cellspacing="0" width="80%">
  <tr>
    <td width="100%"><pre><font face="Courier New" color="#000000">procedure TNewHintWindow.Paint;
var
  R: TRect;
begin
  with Canvas do begin
    Brush.Color := clRed;
    Brush.Style := csClear;
    Rectangle(0,0,Width,Height);
  end;
  R := ClentRect;
  Inc(R.Top, 3);
  Inc(R.Left, 2);
  SetBKMode(Canvas.Handle, TRANSPARENT);
  Canvas.Font.Color := clYellow;
  DrawText(Canvas.Handle, PChar(Caption),
           -1, R, DT_LEFT);
end;</font></pre>
    </td>
  </tr>
</table>
</center></div>

<p><font face="楷体_GB2312" size="4">  如果希望Hint窗口是透明的,则可以在新类中加入一个消息捕获过程,使Hint窗口不执行重绘背景的操作:</font></p>
<div align="center"><center>

<table border="0" cellpadding="0" cellspacing="0" width="80%">
  <tr>
    <td width="100%"><pre><font face="Courier New" color="#000000">type
  TNewHintWindow = class(THintWindow);
  private
    procedure WMEraseBKGND(var Message:TMessage); message WM_ERASEBKGND;
    .
    .
    .
  end;

procedure TNewHintWindow.WMEraseBKGND(var Message:TMessage);
begin
  Message.Result := 0;
end;</font></pre>
    </td>
  </tr>
</table>
</center></div>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -