我正在构建一个具有多个焦点的自定义控件。例如,在1个控件中,假设有3个区域(可以在画布上定义为rect),它们可以有焦点。根据哪一个有焦点,我不希望它周围有默认的Windows虚线,而是一些特殊处理。我对如何给自己的焦点提供一个自定义控件一无所知。
原始项目是一个单独的TPanel,上面有几个VCL控件,每个都是自己的窗口,因此有自己的焦点。但是现在我将它放入自己的自定义类中,这三个控件将不再存在(它们仅在版本1中作为原型)并且我现在需要以某种方式模仿这些不同区域中的焦点。 / p>
我想类似于像TListBox这样简单的东西,其中该控件中的某些项目获得焦点而不是整个控件本身。
这是一张帮助展示我正在制作的图片......
顶部的那个是带按钮的原件。但是底部的那个是我正在建造的新的,它是全部定制的。
详细说明一下,在我去重新发明轮子之前,我想看看Windows是否已经对这种类型的场景进行了特殊处理。
我不是在寻找“最简单”的方法来实现这一目标。而且我也不希望建议恢复到我之前的状态,因为有很多原因我不希望1控制其中有多个其他控件。我只需要一个是或否,并附上解释。
更多
我刚刚意识到主要关注的是使用tab
密钥。控件必须首先获得焦点,开始关注它应该的任何子项,然后在我的命令上响应tab
直到它到达结束,然后将标签传递给下一个控件。然后它也需要shift + tab。我该如何实现这个标签?这就是我被困住的地方,但这让我感到震惊,这是我要问的主要原因。
答案 0 :(得分:4)
关于 TAB 键的处理 - 它应该是这样的:你处理WM_GETDLGCODE message表示你想要处理 TAB 键,即
TMyControl = ...
protected
procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
...
procedure TMyControl.WMGetDlgCode(var Msg: TMessage);
begin
inherited;
Msg.Result:= Msg.Result or DLGC_WANTTAB;
end;
并且在重写KeyDown
方法中你决定做什么来回应它,比如
procedure TMyControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
if(Key = VK_TAB)then begin
if(ssShift in Shift)then begin
if(first subcontrol is focused) set focus to previous control on parent
else set focus to previous child area
end else begin
if(last subcontrol is focused) set focus to next control on parent
else set focus to next child area
end;
end else inherited;
end;
答案 1 :(得分:3)
不,你不能让窗户在同一个窗口句柄内识别多个键盘焦点,因为每个带窗口句柄的控件都有或没有键盘焦点。多个控件之间的“内部焦点”由您来解决。
正如您已经知道的,实现此目的的最简单方法是使用自己的窗口句柄来设置多个子控件,这就是您所说的:
TMyThreeEditControls = class(TControl) // parent has no window handle!!!!
protected
FEdit1:TEdit;
FEdit2:TEdit;
FEdit3:TEdit;
...
end
在上面的情况中,父控件是一个TControl,它创建了几个子控件,在我上面的例子中,所有三个都有自己的窗口句柄,因此当你点击tab时Windows可以显示键盘焦点,并处理鼠标焦点作为Windows常用控件库功能的一部分。
简而言之,您在主控件中包含子对象(其他控件)的“复合”方法实际上是让Windows完成大部分工作的唯一方法。
另一方面,你可能正在寻找的不是一种控制绘画本身的方法,而是在你自己的自定义绘画例程中,有些代码可以让它看起来像是重点,如果这就是你的意思在寻找时,你应该查看关于如何告诉Windows绘制焦点矩形等的VCL源代码或此link上的例子.ase.com链接是模仿的,不使用真实的Windows代码以Windows主题感知方式绘制焦点。
更新:您可能正在寻找的是确定鼠标坐标是否在指定矩形内的方式(矩形代表您的情况下的按钮),如果是,则绘制“热状态” “按钮。如果你想自己构建一个控件,有更多的子任务要完成,我建议你研究VCL源代码中的现有控件,如TStringGrid和TCategoryButtons,看看你需要的MouseMove,MouseDown和MouseUp处理代码做你想做的事情。特别是,StringGrid源代码是查看如何在具有单个窗口句柄的单个控件中使用“tab键”的方法,因为在该控件中可以使用tab键(如果打开了正确的选项)在字符串网格内的所有单元格之间导航,就好像每个单元格都是一个单独的控件一样,即使它只是一个控件。
答案 2 :(得分:1)
实现此目的的另一种方法是使用一个编辑框,您可以为要“聚焦”的每个区域重复使用该编辑框。这实质上就是德尔福网格的工作原理。
当用户单击该区域(或将Tab键按到控件中)时,将编辑控件文本设置为该区域中的数据,将编辑控件边界设置为该区域并使其可见。当用户退出控件(通过单击它或标签)时,您隐藏编辑控件。如果你让你的控件接受tab键,你可以在它们点击tab时“编辑”下一个区域,当它们位于最后一个区域时退出它。
然后,只需保管,确保将输入的数据存储在组件的正确位置。