在DELPHI中调用API函数
<p>一、概述</p><p> Delphi作为一种面向对象的可视化开发工具,以其开发程序的高速度和编译代码的高效率越来越受到广大编程人员的喜爱。Delphi本身提供了包括界面设计、数据库操作、报表打印和Internet等在内的数十个组件,开发者使用它们可以非常容易、快速地制作出所要的应用系统,同时所需要的编程量却非常地小。除此之外,delphi同时秉承了borland公司产品一贯的编译效率高,速度快特色。</p>
<p> Delphi2.0版本以上的产品完全支持32位应用程序的开发,完全支持windows95和WindowsNT提供的所有API函数。应用程序接口(API)是windows提供的任何Windows应</p>
<p>用可以访问的函数的集合。尽管Delphi已经提供了非常强大的开发组件(VCL),但灵活使用API函数一定可以使你的程序增色不少。</p>
<p> 二、状态键的检查</p>
<p> 当今不少流行软件的编辑窗口(包括Delphi的代码编辑窗口)的底部都有一个状态条用来显示一些状态信息,比如当前光标的位置、页码消息和状态键的状态。什么是状态键呢?我们知道键盘上大多数按键只有在按下时才能为系统所识别,而状态键的共同特点就是他们好似一个开关,每按一次就切换到相反状态直至下一次按键为止。通常键盘的状态键包括[NumLock],[ScrollLock],[CapsLock]和[Insert]这四个键,在编辑窗口中显示状</p>
<p>态键的状态可以使你的界面更友好,更有利于方便用户。</p>
<p> 使用delphi强大的开发功能和API提供的GetKeyboardState()函数,你可以轻松地在你的程序中实现状态键检测这一功能。</p>
<p> 也许有些读者要问:我可以使用delphi提供的OnKeyPress函数捕捉按键动作来完成这一功能,又有什么必要调用API函数呢?这就涉及到状态键的另一个特点:即它的状态与程序运行无关。比如说你在word中按下insert键后再切换到delphi中输入代码,这个键的状态仍然保持不</p>
<p>变。而如果只使用OnKeyPress函数,那么当你的程序在后台运行时就无法捕捉到在前台程序中发生的按键动作,所以当切换到你程序时也就无法正确反映状态键的状态。因此需要使用API的GetKeyboardState()函数来检查键盘状态。当调用GetKeyboardState()函数时,你需要在程序中开辟一个256字节的缓冲区用来存储键盘上各个键的状态(最简单的方法你可以声明一个TKeyboardState变量)你可以根据缓冲区中相应位置的值来判断键盘状态,下表显示了系统常量和其相应的按键。(你如果想查看所有的键值列表可以在help菜单选择WindowsAPI中输入关键字virtualkeycodes,然后按下Show键)</p>
<p> 常量按键名称</p>
<p> VK—INSERT[Insert]键</p>
<p> VK—NUMLOCK[NumLock]键</p>
<p> VK—CAPITAL[CapsLock]键</p>
<p> VK—SCROLL[ScrollLock]键</p>
<p> 键盘缓冲区每一位都有特定的格式,对于状态键来说,最低位是1时表示状态键处于ON状态,你可以使用delphi提供的Odd()函数来确定这一位的状态。为了使程序显示正确的状态键的状态,你需要定期调用GetKeyboardState()函数来不断的查询键盘状态,实现这一功能最简单的方法是使用Timer组件。</p>
<p> 下面举一个小例子来说明如何具体实现这一调用功能,在这个例子中我们将检查[NumLock]键的状态并把它显示在屏幕底部的状态栏。</p>
<p> 从Component模板Win95页中选择StatusBar组件,按如下所示设置它的属性 </p>
<p>AlignalBottom Height20</p>
<p> 从system页中的选择Timer组件并把它放入窗体,双击Timer组件弹出OnTimer事件的代码编辑窗口,按如下所示添加代码:</p>
<p> procedureTForm1.Timer1Timer(Sender:TObject);</p>
<p> varKeyStates:TKeyboardState;</p>
<p> begin</p>
<p> GetKeyboardState(KeyStates);</p>
<p> begin</p>
<p> if Odd(KeyStates[VK—NUMLOCK])then</p>
<p> StatusBar1.Panels.Items[0].Text:=′NUM′</p>
<p> else</p>
<p> StatusBar1.Panels.Items[0].Text:=″</p>
<p> end;</p>
<p> end;</p>
<p> 我们可以检验一下程序的运行结果。运行程序,可以看到状态条中正确显示了当前的状态,切换到另一个程序改变[numlock]键的状态再切换回运行程序,可以看到状态条的状态已经改变。一般说来,在程序中加入状态条显示相应信息对于用户来说是十分方便的。</p>
<p> 三、改变提示框(hint)的特性</p>
<p> 许多程序在特定的控件上都有提示框,当鼠标在这些控件上停一定时间以后就可以显示提示框。在Delphi中实现提示框是非常容易的,只要设定相应的属性即可,这里就不详细讨论了。但通常的提示框都是以黄色矩形框的形式显示在对应控件的左下角,以下这段代码说明了如何使用API改变delphi中提示属性的一些特性。有一点需要声明的是代码中使用到的GetIconInfo函数只适用win32(也就是说你只能在delphi2.0以上的版本中使用以下代码)</p>
<p>。</p>
<p> 把以下代码加入到主窗体的Oncreate事件中,加入代码后的主窗体的formcreate过程的代码如下所示:</p>
<p> procedureTMainForm.FormCreate(Sender:TObject);</p>
<p> begin</p>
<p> ...</p>
<p> Application.OnShowHint:=GetHintInfo;</p>
<p> end;</p>
<p> 然后把以下过程声明加入到主窗体的public段</p>
<p> procedureGetHintInfo(VarHintStr:sting;VarCanShow:boolean;varHintInfo:</p>
<p>THintInfo);</p>
<p> 最后,在主窗体的implementation部分加入过程的实现代码,加入完代码的过程如下所示:</p>
<p> procedureTMainForm.GetHintInfo(varHintStr:string;varCanShow:boolean;</p>
<p>varHintInfo:THintInfo);</p>
<p> var</p>
<p> II:TlconInfo;</p>
<p> Bmp:Windows.TBitmap;</p>
<p> begin</p>
<p> with HintInfo do</p>
<p> begin</p>
<p> //应该保证有控件使用定义了Hint属 性</p>
<p> if HintControl=NIL then exit;</p>
<p> HintPos:=HintControl.ClientToScreen(CursorPos);</p>
<p> //把光标坐标系由相对于提示改为相对于屏幕</p>
<p> GetIconInto(Screen.Cursors[HintControl.Cursor],II);</p>
<p> //获得有关提示控制使用的有关光标的信息</p>
<p> GetObject(II.hbmMask,SizeOf(Windows.TBitmap),&Bmp);</p>
<p> //获得有关光标的位图(bitmap)信息</p>
<p> if II.hbmColor=0 then</p>
<p> inc(HintPos.Y,Bmp.bmHeightdiv2)</p>
<p> //如果光标不包括彩色位图,增加Y方向</p>
<p> else</p>
<p> inc(HintPos.Y,Bmp.bmHeight);</p>
<p> dec(HintPos.Y,II.yHotSpot);</p>
<p> //减掉y方向的热点位置</p>
<p> DeleteObject(II.hbmMask);</p>
<p> DeleteObject(II.hbmColor);</p>
<p> //清除位置句柄</p>
<p> end;</p>
<p> end;</p>
<p> 通过改变HintPos.X和Y的值可以在任意位置显示提示框。Word7.0中滚动纵向滚动条时页码序号总是显示鼠标在左方,用以上代码实现这一功能可以说是易如反掌。</p>
<p>*******************************************************************</p>
<p>Delphi以其优良的可视化编程,灵活的Windows API接口,丰富的底层操作越来越受到编程爱好者的青睐。</p>
<p> 在Delphi中,通过调用Windows API,可以很方便地获取系统信息,这有助于我们编写出更好的Windows应用程序。以下程序在Delphi3.0 For Windows 9x下编译通过。</p>
<p> 一、 用GetDriveType函数获取磁盘信息</p>
<p> Lbl_DriveType:Tlabel;</p>
<p> DriveType:WORD; //定义驱动器类型变量</p>
<p> DriveType:=GetDriveType(RootPathName); //获得RootPathName所对应的磁盘驱动器信息</p>
<p> case DriveType of</p>
<p> DRIVE_REMOVABLE:Lbl_DriveType.Caption:= '软盘驱动器';</p>
<p> DRIVE_FIXED : Lbl_DriveType.Caption:= '硬盘驱动器';</p>
<p> DRIVE_REMOTE: Lbl_DriveType.Caption:= '网络驱动器';</p>
<p> DRIVE_CDROM: Lbl_DriveType.Caption:= '光盘驱动器';</p>
<p> DRIVE_RAMDISK: Lbl_DriveType.Caption:= '内存虚拟盘';</p>
<p> end; //将该磁盘信息显示在Lbl_DriveType中</p>
<p> 二、 用GlobalMemoryStatus函数获取内存使用信息</p>
<p> MemStatus: TMEMORYSTATUS; //定义内存结构变量</p>
<p> Lbl_Memory:Tlabel;</p>
<p> MemStatus.dwLength := size of(TMEMORYSTATU</p>
<p>S);</p>
<p> GlobalMemoryStatus(MemStatus); //返回内存使用信息</p>
<p> Lbl_Memory.Caption := format('共有内存: %d KB 可用内存: %dKB',);</p>
<p> //将内存信息显示在Lbl_Memory中</p>
<p> 三、 用GetSystemInfo函数获取CPU信息</p>
<p> SysInfo: TSYSTEMINFO;</p>
<p> Lbl_CPUName:Tlabel;</p>
<p> GetSystemInfo(SysInfo);//获得CPU信息</p>
<p> case SysInfo.dwProcessorType of</p>
<p> PROCESSOR_INTEL_386:Lbl_CPUName.Caption:=format('%d%s',);</p>
<p> PROCESSOR_INTEL_486:Lbl_CPUName.Caption:=format('%d%s',);</p>
<p> PROCESSOR_INTEL_PENTIUM:Lbl_CPUName.Caption:=format('%d%s',[SysInfo.dwNum</p>
<p>berOfProcessors, 'Intel Pentium']);</p>
<p> PROCESSOR_MIPS_R4000:Lbl_CPUName.Caption:=format('%d%s', );</p>
<p> PROCESSOR_ALPHA_21064:Lbl_CPUName.Caption:=format('%d%s', );</p>
<p> end;//把CPU信息显示在Lbl_CPUName中。</p>
<p>****************************************************************** 生成非矩形窗口</p>
<hr size="1" width="94%">
<p> </p>
<p>利用win32 API函数setwindowrgn可以将窗口定义为任何形状,以下是将窗口定义为园角矩形的例子:</p>
<p>procedure TPortForm.FormCreate(Sender: TObject);</p>
<p>var hr :thandle;</p>
<p>begin</p>
<p>hr:=createroundrectrgn(0,0,width,height,20,20);//定义园角矩形(win API函数)</p>
<p>setwindowrgn(handle,hr,true); //设置园角窗口</p>
<p>end;</p>
<p>为了使该窗口更好,应在onResize事件处理程序放相同的代码。</p>
<p>********************************************************************** 程序不出现在任务栏</p>
<hr size="1" width="94%">
<p> </p>
<p>一般Windows 95运行程序时都会在任务栏上出现按钮,如果你的程序是一个监视程序,那么出现按钮就不是明智之举了。要实现该功能就要在OnCreate事件里利用到API函数SetWindowLong</p>
<p>procedure TForm1.FormCreate(sender:TObject);</p>
<p>begin</p>
<p>SetWindowLong(Application,Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);</p>
<p>end;</p>
<p> </p>
<p> </p>
<hr size="1" width="94%">
<p> </p>
<p> 关闭Windows</p>
<hr size="1" width="94%">
<p> </p>
<p>控制WINDOWS的开关:如关闭WINDOWS,重新启动WINDOWS等, ExitWindowsEx(UINT uFlags,DWORD dwReserved);是实现这一功能的API函数</p>
<p>首先定义常数</p>
<p>const</p>
<p>EWX_FORCE=4; //关闭所有程序并以其他用户身份登录</p>
<p>EWX_LOGOFF=0; //重新启动计算机并切换到MS-DOS方式</p>
<p>EWX_REBOOT=2; //重新启动计算机</p>
<p>EWX_SHUTDOWN=1;//关闭计算机</p>
<p>运行时给How赋值,让他等于EWX_SHUTDOWN或其他,调用以下语句</p>
<p>ExitWindowsEx(How,0);</p>
<hr size="1" width="94%">
<p>隐藏桌面上的图标</p>
<hr size="1" width="94%">
<p> </p>
<p>使桌面上的图标消失,连桌面上的右键功能也不能使用如果不让初学者乱用“我的电脑”的话,那么把程序放到“启动”里,顺便把“Windows资源管理器”也去掉,再加上个多用户密码,那么想破坏电脑文件也无从下手了。该程序Delphi 4里通过</p>
<p>var</p>
<p>hDesktop : THandle;</p>
<p>begin</p>
<p>hDesktop := FindWindow('Progman', nil);</p>
<p>ShowWindow(hDesktop, SW_HIDE);</p>
<p>end;</p>
<hr size="1" width="94%">
<p>模拟按下某键</p>
<hr size="1" width="94%">
<p> </p>
<p>让 WIN95 模拟按了一个按键,就向某窗体发送按键一样,例如按下 ENTER 或者 TAB 键,或者按 7 键</p>
<p>PostMessage(Object.Handle, WM_KEYDOWN, VK_TAB, 0);</p>
<p>{Object表示窗体名,WM_KEYDOWN是按下,VK_TAB是发送的按键}</p>
<p>PostMessage(edit1.Handle, WM_KEYDOWN, 55, 0);</p>
<p>{向edit1发送一个7字}</p>
<hr size="1" width="94%">
<p>动态修改显示器分辨率</p>
<hr size="1" width="94%">
<p> </p>
<p>Windows提供给我们两个API函数,可以动态调整显示器的分辨率,他们是EnumDisplaySettings() 和ChangeDisplaySettings(),下面这个例子就是了</p>
<p>function DynamicResolution(X, Y: word): BOOL;</p>
<p>var</p>
<p>lpDevMode: TDeviceMode;</p>
<p>begin</p>
<p>Result := EnumDisplaySettings(nil, 0, lpDevMode);</p>
<p>if Result then</p>
<p>begin</p>
<p>lpDevMode.dmFields := DM_PELSWIDTH Or DM_PELSHEIGHT;</p>
<p>lpDevMode.dmPelsWidth := X;</p>
<p>lpDevMode.dmPelsHeight := Y;</p>
<p>Result := ChangeDisplaySettings(lpDevMode, 0) = DISP_CHANGE_SUCCESSFUL;</p>
<p>end</p>
<p>end;</p>
<p>procedure TForm1.Button1Click(Sender: TObject);</p>
<p>begin</p>
<p>if DynamicResolution(640, 480) then</p>
<p>ShowMessage('Now is 640*480');</p>
<p>end;</p>
<p>procedure TForm1.Button2Click(Sender: TObject);</p>
<p>begin</p>
<p>if DynamicResolution(800, 600) then</p>
<p>ShowMessage('Now is 800*600');</p>
<p>end;</p>
<hr size="1" width="94%">
<p>限制FORM的大小</p>
<hr size="1" width="94%">
<p> </p>
<p>使用过DELPHI的朋友都会注意到DELPHI本身最上面的窗口,当它极大时只占屏幕的一小部分,它是如何实现的呢,请看下面的说明:</p>
<p>1)在FORM私有声明部分加上如下一行:</p>
<p>procedure WMGetMinMaxInfo( var Message:TWMGetMinMaxInfo ); message WM_GETMINMAXINFO;</p>
<p>2)在声明部分加上如下几行:</p>
<p>procedure TForm1.WMGetMinMaxInfo( var Message :TWMGetMinMaxInfo );</p>
<p>begin</p>
<p>with Message.MinMaxInfo^ do</p>
<p>begin</p>
<p>ptMaxSize.X := 200; {最大化时宽度}</p>
<p>ptMaxSize.Y := 200; {最大化时高度}</p>
<p>ptMaxPosition.X := 99; {最大化时左上角横坐标}</p>
<p>ptMaxPosition.Y := 99; {最大化时左上角纵坐标}</p>
<p>end;</p>
<p>Message.Result := 0; {告诉Windows你改变了 minmaxinfo}</p>
<p>inherited;</p>
<p>end;</p>
<hr size="1" width="94%">
<p>控制窗体</p>
<hr size="1" width="94%">
<p> </p>
<p> 如何在 Delphi 中把 Form 控制成不能放大/缩小/移动/关闭?</p>
<p>1、把 Form 的 BorderIcons 下的几个子属性值全改为 False;</p>
<p>2、修改 Form 的 BorderStyle 的值为bsSingle ;</p>
<p>3、为了让窗口不能移动,可以自已拦下 WM_NCHITTEST 消息, 对该消息的处理为:一概回应鼠标点在窗口的 Client 区域, 相信这个视窗就呆呆的不会动了。</p>
<p> 详情可以查一下 Win32API Help 的 CreateWindow() 与 WM_NCHITTEST 的说明。</p>
<p>下面是一个例子, 请参考看看:</p>
<p>unit Unit1;</p>
<p>interface</p>
<p>uses</p>
<p>Windows, Messages, SysUtils, Classes, Graphics, Controls,Forms, Dialogs, StdCtrls;</p>
<p>type</p>
<p>TForm1 = class(TForm)</p>
<p>Button1: TButton;</p>
<p>procedure Button1Click(Sender: TObject);</p>
<p>private</p>
<p>{ Private declarations }</p>
<p>procedure WMNCHitTest(var Msg: TMessage); message WM_NCHITTEST;</p>
<p>public</p>
<p>{ Public declarations }</p>
<p>end;</p>
<p>var</p>
<p>Form1: TForm1;</p>
<p>implementation</p>
<p>{$R *.DFM}</p>
<p>procedure TForm1.Button1Click(Sender: TObject);</p>
<p>begin</p>
<p>Close; // 不可少, 因为已经没有其他方法能关闭此窗口了</p>
<p>end;</p>
<p>procedure TForm1.WMNCHitTest(var Msg: TMessage);</p>
<p>begin</p>
<p>inherited; // 这样,移动就不可能了...</p>
<p>Msg.Result := HTCLIENT;</p>
<p>end;</p>
<p>end.</p>
<p> </p>
<hr size="1" width="94%">
<p> </p>
<p> 快速将某一区域的颜色取反</p>
<hr size="1" width="94%">
<p> </p>
<p> 快速将某一区域的颜色取反,主要应用在制作表格时的选择区域.</p>
<p> API函数:PatBlt(MyHDC:HDC;X,Y,WIDTH,HEIGHT:INTEGER;MODE);</p>
<p> 例如:</p>
<p> var</p>
<p> MyDC:HDC;</p>
<p> Begin</p>
<p> MyDC:HDC;</p>
<p> MyDC:=GetDC(Form1.Handle);</p>
<p> if not PatBlt(MyDC,</p>
<p> 1,</p>
<p> 1,</p>
<p> 100,</p>
<p> 100,</p>
<p> DSTINVERT) then</p>
<p> ShowMessage('ERROR :~(');</p>
<p> End;</p>
<hr size="1" width="94%">
<p>得到WINDOWS的SYSTEM路径</p>
<hr size="1" width="94%">
<p> </p>
<p> 方法:</p>
<p> var</p>
<p> MySysPath : PCHAR ;</p>
<p> begin</p>
<p> GetMem(MySysPath,255);</p>
<p> GetSystemDirectory(MySysPath,255);</p>
<p> end;</p>
<p> 注:MySysPath为SYSTEM路径.。</p>
<hr size="1" width="94%">
<p>Delphi下编程实现中文输入法</p>
<hr size="1" width="94%">
<p> </p>
<p>江 苏 省 电 信 传 输 局</p>
<p>周晓</p>
<p>---- Borland Delphi 以 其 强 大 的 功 能 及 和 高 效 的 可 视 化 开 发 环 境为 广 大 程 序 设 计 员 所 青 睐 。 尤 其 是 它 封 装 了WINDOWS API 函数, 能 方 便 地 利 用WINDOWS 资 源, 大 大 加 快 了 程 序 开 发 速度。</p>
<p>---- 在 平 时 的 计 算 机 操 作 中, 中 文 输 入 是 不 可 避 免 的。 使用 者 可 能 喜 欢 不 同 的 中 文 输 入 法(inputmethod editor, 简 称IME), 这 就 不 得 不 经 常 点 击 任 务 栏 中 的 中 文 图 标 或 用CTRL+Space,CTRL+Shift 热 键 切 换, 初 学 者 用 起 来 很 不 方 便。 针 对 这 一 问 题, 可以 在 开 发 软 件 时, 在 程 序 中 设 置 用 户 喜 欢 的 中 文 输 入法, 方 便 用 户 的 使 用。Delphi 中 只 有 少 数 控 件 如TEdit 支 持IME, 而 且 该 功 能 不 强, 不 能 在 运 行 时 更 改 输 入 法。</p>
<p>---- 笔 者 通 过 实 践 和 摸 索, 查 找 了 相 关 的IME 资 料, 利 用 了WINDOWS API 函 数, 实 现 了IME 的 功 能。</p>
<p>---- 常 用 函 数 有:</p>
<p>API函数:BOOL ImmSimulateHotKey</p>
<p>(HWND hWnd,DWORD dwHotKeyID);//模拟热键</p>
<p>其中Hwnd为程序窗口的句柄,dwHotHKeyID</p>
<p>为模拟的热键,若成功则返回True</p>
<p>HKL GetKeyboardLayout(DWORD dwLayout);</p>
<p>//获得当前键盘状态</p>
<p>BOOL ImmIsIME(HKL hKL);</p>
<p>//判断当前是否处于中文输入状态,若是则返回True</p>
<p>自定义函数:</p>
<p>打开相应输入法:OpenIme(imename:string),</p>
<p>例OpenIme('全拼输入法');</p>
<p>关闭中文输入法:CloseIme;</p>
<p>以下是一个简单的例子,仅起参考作用。</p>
<p>使用时uses中加上imm</p>
<p>具体的实现方法及源代码如下:</p>
<p>unit Unit1;</p>
<p>interface</p>
<p>uses</p>
<p>Windows, Messages, SysUtils, Classes,</p>
<p>Graphics, Controls, Forms, Dialogs,</p>
<p>StdCtrls, Buttons,imm;</p>
<p>type</p>
<p>TForm1 = class(TForm)</p>
<p>ComboBox1: TComboBox;</p>
<p>BitBtn1: TBitBtn;</p>
<p>BitBtn2: TBitBtn;</p>
<p>BitBtn3: TBitBtn;</p>
<p>procedure FormShow(Sender: TObject);</p>
<p>procedure OpenIme(imename:string);</p>
<p>procedure closeIme;</p>
<p>procedure ComboBox1Change(Sender: TObject);</p>
<p>procedure BitBtn1Click(Sender: TObject);</p>
<p>procedure BitBtn2Click(Sender: TObject);</p>
<p>procedure BitBtn3Click(Sender: TObject);</p>
<p>private</p>
<p>{ Private declarations }</p>
<p>public</p>
<p>{ Public declarations }</p>
<p>end;</p>
<p>var</p>
<p>Form1: TForm1;</p>
<p>implementation</p>
<p>{$R *.DFM}</p>
<p>procedure TForm1.FormShow(Sender: TObject);</p>
<p>var</p>
<p>j:integer;</p>
<p>begin</p>
<p>for j:=0 to screen.imes.count-1 do</p>
<p>begin</p>
<p>ComBoBox1.Items.Add(screen.Imes.strings);</p>
<p>//获取系统中已安装的中文输入法</p>
<p>end;</p>
<p>end;</p>
<p>procedure Tform1.OpenIme(imename:string);</p>
<p>var</p>
<p>I:integer;</p>
<p>myhkl:hkl;</p>
<p>begin</p>
<p>if ImeName<>'' then</p>
<p>begin</p>
<p>if Screen.Imes.Count<>0 then</p>
<p>begin</p>
<p>I:=screen.Imes.indexof(imename);</p>
<p>if I>=0 then</p>
<p>myhkl:=hkl(screen.Imes.objects);</p>
<p>activatekeyboardlayout(myhkl,</p>
<p>KLF_ACTIVATE);//设置相应的输入法</p>
<p>end;</p>
<p>end;</p>
<p>end;</p>
<p>procedure TForm1.closeime;</p>
<p>var</p>
<p>myhkl:hkl;</p>
<p>begin</p>
<p>myhkl:=GetKeyBoardLayOut(0);</p>
<p>if ImmIsIME(myhkl) then</p>
<p>//判断是否在中文状态,若是则关闭它</p>
<p>immsimulateHotkey(handle,</p>
<p>IME_CHotKey_IME_NonIME_Toggle);</p>
<p>end;</p>
<p>procedure TForm1.ComboBox1Change(Sender: TObject);</p>
<p>begin</p>
<p>OpenIme(ComboBox1.Text);</p>
<p>end;</p>
<p>procedure TForm1.BitBtn1Click(Sender: TObject);</p>
<p>begin</p>
<p>immsimulateHotkey(handle,</p>
<p>IME_CHotKey_shape_Toggle);//切换半角和全角模式</p>
<p>end;</p>
<p>procedure TForm1.BitBtn2Click(Sender: TObject);</p>
<p>begin</p>
<p>immsimulateHotkey(handle,</p>
<p>IME_CHotKey_symbol_Toggle);</p>
<p>//切换中文标点模式和英文标点模式</p>
<p>end;</p>
<p> </p>
<p> </p>
<p>procedure TForm1.BitBtn3Click(Sender: TObject);</p>
<p>begin</p>
<p>closeime;</p>
<p>end;</p>
<p>end.</p>
<p> </p>
<hr size="1" width="94%">
<p>闪动标题栏</p>
<hr size="1" width="94%">
<p> </p>
<p>在你的应用程序中,你可能会希望将应用程序的标题栏进行闪动,以提醒用户进行某种操作,本文介绍了如何使一个窗口的标题栏进行闪动。</p>
<p> </p>
<p>闪动标题栏</p>
<p>闪动一个窗口的标题栏意味着改变它的标题栏的外观,例如它从活动变为不活动,或是从不活动变为活动等等。只要你能在Delphi 或者 C++ Builder 中得到窗口的句柄,你就可以使用Windows 应用程序编程接口(API)函数来使该窗口的标题栏进行闪动。函数FlashWindows可以被用使一个特定的窗口闪动一次。 </p>
<p>函数原形:</p>
<p> function FlashWindow(const hwnd:Integer;const bInvert:LongBool):LongBool;</p>
<p> </p>
<p>该函数需要2个参数,第一个参数是要闪动标题栏的窗口的句柄,第二个参数用于指定是设置窗口的闪动状态,还是恢复其原始状态。如果该bInvert参数为True,则表明窗口的标题栏被闪动,如果该参数为False,则表明窗口的标题栏被恢复为原始状态。</p>
<p>该函数所返回的值用于指定调用该函数前窗口的状态,如果该返回值True,则表明窗口在调用该函数之前是活动的,否则,如果返回值为False,则表明调用函数前窗口是非活动的。</p>
<p>当使用该FlashWindow函数时,一个较好的方法是将标题栏闪动的频率设置为同脱字符(也即闪动的光标)相同,脱字符的闪动频率可以通过调用函数GetCaretBlinkTime来获得。要使用该函数,需要将如下的声明语句包含在你的窗体的通用声明部分中:</p>
<p> function GetCaretBlinkTime:Integer;</p>
<p>该函数返回用毫秒值表示的时间。 例程: 建立新的Project,并新建一From(包括New Project建立的Form,共两个),在Form1中加入一Button和Timer,按下面的方法建立程序.</p>
<p>procedure TForm1.Button1Click(Sender: TObject);</p>
<p>begin</p>
<p> Form2.Show;</p>
<p> Form1.BringToFront;</p>
<p> Timer1.Interval:=GetCaretBlinkTime;</p>
<p> Timer1.Enabled:=Not Timer1.Enabled;</p>
<p>end;</p>
<p>procedure TForm1.Timer1Timer(Sender: TObject);</p>
<p>begin</p>
<p> FlashWindow(Form2.Handle,TRUE);</p>
<p>end;</p>
<hr size="1" width="94%">
<p>应用程序敏感键的实现</p>
<hr size="1" width="94%">
<p> </p>
<p>---- 在一个应用程序内部菜单、部件都可以设置敏感键。如在菜单中一般用Alt+F进入“文件”之类的子菜单。另外我们在桌面上设置的快捷方式里的快捷键,无论你任何时候按下你所设置的快捷键就会启动相应的应用程序。在多个正在运行的应用程序中如何利用一个按键动作迅速地回到你所需要的应用程序呢?这就需要利用敏感键(HOTKEY)的技术来实现。本文利用Delphi3.0开发工具来阐述该技术在应用程序的实现方法。</p>
<p>一、敏感键的设置</p>
<p>---- 在windows Api中有一个函数RegisterHotKey用于设置敏感键,它的调用方式如下:</p>
<p>BOOL RegisterHotKey(HWND hWnd, //响应该敏感键的窗口句柄Int id, //该敏感键的唯一标示符UINT fsModifiers, //该敏感键的辅助按键UINT vk //该敏感键的键值);</p>
<p> </p>
<p>---- 其中敏感键的唯一标示符在Window中规定应用程序的取值范围为0x0000到0xBFFF之间,动态链接库的取值范围为0xC000到0xFFFF之间。为了保证其唯一性建议使用GlobalAddAtom函数来设置敏感键的唯一标示符。需要注意的是GlobalAddAtom还回的值是在0xC000到0xFFFF范围之间,为满足RegisterHotKey的调用要求,如果是在应用程序中设置敏感键可以利用GlobalAddAtom还回值减去0xC000。</p>
<p>---- 敏感键的辅助按键包括Mod_Ctrl 、Mod_Alt、Mod_Shift,对于Windows兼容键盘还支持Windows键,即其键面上有Windows标志的那个键,其值为Mod_win。</p>
<p>---- 在Delphi中建立一个“New Application”,在Tform1中的Private段中加入如下代码</p>
<p>private{ Private declarations }hotkeyid :integer;procedure WMhotkeyhandle(var msg:Tmessage);message wm_hotkey; //响应敏感键按键消息在FormCreate事件中加入如下代码…hotkeyid:=GlobalAddAtom(pchar(“UserDefineHotKey”))-$C000;//减去$C000是为了保证取值范围的限制registerhotkey(handle,hotkeyid,MOD_CONTROL or mod_Altt,$41);//敏感键为ctrl+Alt+A…</p>
<p> </p>
<p>二、敏感键的响应</p>
<p>---- 一旦敏感键设置成功,在程序应用过程中如果有相应敏感键被按下,Windows系统都会给你的应用程序发送一个消息WM_HOTKEY,不管你的应用程序是否为当前活动的。其中WM_HOTKEY消息的格式为:</p>
<p>idHotKey = (int) wParam;// 该参数在设置系统级的敏感键有用,一般不予使用fuModifiers = (UINT) LOWORD(lParam);//敏感键的辅助按键uVirtKey = (UINT) HIWORD(lParam);//敏感键的键值</p>
<p> </p>
<p>---- 因为Windows系统只是把一个WM_HotKey的消息发送给应用程序,要完成具体的事情需要一个消息处理程序,也就是上面Private段里的procedure WMhotkeyhandle(var msg:Tmessage); message wm_hotkey; 过程, 它的代码如下(这里只是简单地把窗口最前面显示)</p>
<p>procedure TForm1.Wmhotkeyhandle(var msg:Tmessage);beginif (msg.LParamHi=$41) and(msg.lparamLo=MOD_CONTROL or mod_Alt) thenbeginmsg.Result:=1; //该消息已经处理application.BringToFront;//把窗口最前面显示end;end;</p>
<p> </p>
<p>三、敏感键的释放</p>
<p>---- 在应用程序退出来之前应当把你所设置的敏感键释放掉,以释放其所占有的系统资源,这里需要调用两个Windows API函数UNREGISTERHOTKEY,它的调用格式如下:</p>
<p>BOOL UNREGISTERHOTKEY(HWND HWND, //与敏感键关联的窗口句柄INT ID //敏感键的标示符);也就是说只要在FormClose事件中加入如下代码…unregisterhotkey(handle,hotkeyid);DeleteAtom(HotKeyID);…</p>
<p> </p>
<p>---- 到这里为止,你应当对敏感键技术有了全面的了解, 以上的例子相当简单同时也没有提供必要的调用成功检测,可以根据具体情况加以完善,希望对你的开发过程会有所帮助.</p>
<p> </p>
<hr size="1" width="94%">
<p>在Delphi中使用动态图标</p>
<hr size="1" width="94%">
<p> </p>
<p> 在应用程序的编写中,组合框(ComboBox)、列表框(ListBox)、等常见的部件,通常不仅要用于显示文字,而且还要显示其与文字相关的图标。在一般的Windows应用程序中,这些图标的显示都要随列出的显示文本的变化而变化,例如在组合框中列出当前目录下的所有文件时,在组合框左边就显示与文件名相关联的图标,这就是所谓的动态图标。在Delphi中使用动态图标的步骤如下:</p>
<p> 一、图标的获取</p>
<p> 要使用动态图标,首先要解决的是如何获得显示文本和与其相关联的图标句柄。该图标通过文件关联由系统注册表决定,并且在Windows编程中同一文件(或子目录,或文件夹)在桌面上也可能有两种显示结果,这就是DOS文件名与显示名(Display Name)。如果我们的应用程序不需要有像Windows资源浏览器那样的效果,则可以使用FindFirst()和FindNext()二个函数以及FindClose()过程来获得DOS文件名,否则我们就应当使用WindowsAPI来获得显示名。在获得文件名的同时可通过使用ShellAPI.pas中的SHGetFileInfo()函数来获得其图标句柄HICON,说明如下:</p>
<p> function SHGetFileInfo(pszPath: PAnsiChar; dwFileAttributes: DWORD;var psfi: TSHFileInfo; cbFileInfo,uFlags: UINT): DWORDl;</p>
<p> pszPath 参数:指定的文件名。当uFlags的取值中不包含 SHGFI_PIDL时,可直接指定;否则pszPath要通过计算获得,不能直接指定;</p>
<p> dwFileAttributes参数:文件属性,仅当uFlags的取值中包含SHGFI_USEFILEATTRIBUTES时有效,一般不用此参数;</p>
<p> psfi 参数:返回获得的文件信息,是一个记录类型,有以下字段:</p>
<p> hIcon: HICON; //文件的图标句柄</p>
<p> iIcon: Integer; //图标的系统索引号</p>
<p> dwAttributes: DWORD; //文件的属性值</p>
<p> szDisplayName: array of AnsiChar; //文件的显示名</p>
<p> szTypeName: array of AnsiChar; //文件的类型名</p>
<p> cbFileInfo 参数:psfi的比特值;</p>
<p> uFlags 参数:指明需要返回的文件信息标识符,常用的有以下常数:</p>
<p> SHGFI_ICON; //获得图标</p>
<p> SHGFI_DISPLAYNAME; //获得显示名</p>
<p> SHGFI_TYPENAME; //获得类型名</p>
<p> SHGFI_ATTRIBUTES;//获得属性</p>
<p> SHGFI_LARGEICON; //获得大图标</p>
<p> SHGFI_SMALLICON; //获得小图标</p>
<p> SHGFI_PIDL;// pszPath是一个标识符</p>
<p> 函数SHGetFileInfo()的返回值也随uFlags的取值变化而有所不同。通过调用SHGetFileInfo()可以由psfi参数得到文件的图标句柄,但要注意在uFlags参数中不使用SHGFI_PIDL时,SHGetFileInfo()不能获得"我的电脑"等虚似文件夹的信息。</p>
<p> 二、图标的加载</p>
<p> 使用Delphi提供的TImageList组件,通过调用CommCtrl .pas中的函数ImageList_AddIcon()来加载得到的图标,并要保证其索引号与显示文本相对应。说明如下:</p>
<p> function ImageList_AddIcon(ImageList: HIMAGELIST; //加载图标的ImageList句柄</p>
<p> Icon: Hicon //加载的图标句柄 ): Integer; //返回图标在ImageList中的索引号</p>
<p> 在需要指明图标索引号时可使用ImageList_AddIcon()的返回值。</p>
<p> 三、图标和文本的绘图式输出</p>
<p> 对于组合框、列表框等不能直接显示图标的组件,由于要求显示图标的同时又要同时显示文本,可通过设置其相应的Style属性达到目的,示例如下:</p>
<p> 组合框:ComboBox1.Style:=csOwnerDrawVariable根据实际使用经验最好不要在ObjectInspector窗体中直接设置,而应将代码添加在程序的适当位置,否则可能出现绘图区域高度不规则变化</p>
<p> 列表框:ListBox1.Style:=lbOwnerDrawVariable</p>
<p> 状态栏:StatusBar1.Panels.Style:= psOwnerDraw 不能使用简单状态栏,i是状态栏中要绘制图标的某一窗格索引号,图形输出可使用TImageList的ImageList1.Draw()方法,而文本输出则可使用TCanvas的TextOut()方法,它由组件的Canvas属性继承得到,显然没有Canvas属性的组件不能使用此方法显示图标。</p>
<p> 对于可直接显示图标的组件,直接指定其Images、StateImages等需要的图标属性为相应的TimageList组件名,并通过指定图标的索引号则可显示图标。需要注意的是:在使用大图标时,必须先调用TImageList的CreateSize()方法指定可加载图标的尺寸,并且在每次调用TImageList的Clear方法后都要重新调用CreateSize()。</p>
<p> 使用TImageList的ImageList1.Clear方法清除已加载的图标,常在需要刷新时使用</p>
</div>
<div id="MySignature" role="contentinfo">
好的代码像粥一样,都是用时间熬出来的<br><br>
来源:https://www.cnblogs.com/jijm123/p/15990373.html
頁:
[1]