Windows 可以在单个控件上管理多个焦点吗?

发布于 12-24 04:02 字数 845 浏览 4 评论 0原文

我正在构建一个具有多个焦点的自定义控件。例如,在 1 个控件内,假设有 3 个区域(可以定义为画布上的矩形)能够获得焦点。根据焦点所在,我不希望周围有默认的 Windows 虚线,而是需要一些特殊处理。我什至不知道如何让 1 个自定义控件拥有自己的焦点。

最初的项目是一个单一的 TPanel,上面有一些 VCL 控件,当然每个控件都有自己的窗口,因此有自己的焦点。但现在我将它放入自己的自定义类中,这 3 个控件将不再存在(它们仅作为原型出现在版本 1 中),现在我需要以某种方式模仿这些不同区域的焦点。

我想类似于 TListBox 这样简单的东西,其中该控件中的某些项目获得焦点,而不是整个控件本身。

这是一张图片,可以帮助演示我正在制作的内容...

在此处输入图像描述

顶部的图片是原始图片与按钮。但底部的那个是我正在建造的新的,全部是定制绘制的。

详细地说,在我重新发明轮子之前,我想看看 Windows 是否已经对这种类型的场景进行了特殊处理。

我并不是在寻找“最简单”的方法来实现这一目标。而且我也不希望建议恢复到我之前的样子,因为有很多原因我不希望 1 个控件与多个其他控件一起使用。我只需要一个是或否,以及一个解释。

更多

我刚刚意识到主要关心的是tab键的使用。该控件必须首先获得焦点,开始将焦点集中在它应该关注的任何子项上,然后响应我的命令上的 tab 直到到达末尾,然后将 Tab 键传递到下一个控件。然后还需要shift+tab。我到底要如何实现这个选项卡?这就是我陷入困境的地方,但我突然意识到这是我问的主要原因。

I'm building a custom control which is to have multiple focus points. For example, within 1 control, let's say there's 3 regions (could be defined as a rect on the canvas) which are to be able to have focus. Depending on which one has focus, I don't want the default Windows dotted line around it, but some special handling. I know nothing about how to even give 1 custom control its own focus.

The original project was a single TPanel with a few VCL controls on it, each of course being its own window, thus having its own focus. But now I'm putting it into a custom class of its own, which these 3 controls will no longer exist (they were only there in version 1 as a prototype) and I need to now somehow mimic the focus in these different regions.

I guess similar to something as simple as a TListBox, where certain items within that control get the focus instead of the entire control its self.

Here's a picture to help demonstrate what I'm making...

enter image description here

The one on the top is the original with the buttons. But the one on the bottom is the new one I'm building which is all custom drawn.

To elaborate, I'd like to see if Windows already has special handling for this type of scenario before I go and re-invent the wheel.

I'm not looking for the "Easiest" way to accomplish this. And I also do not want recommendations to revert back to how I had it before, because there's many reasons I don't want 1 control with multiple other controls within. I just need a yes or no, with an explanation.

More

I just realized the main concern is the use of the tab key. The control has to first get the focus, start the focus on whichever sub-item it's supposed to, then respond to tab on my command until it reaches the end, then pass the tabbing over to the next control. Then it also needs shift+tab as well. How on earth would I implement this tabbing? That's where I got stuck, but it just struck me that this is the main reason I'm asking.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

身边2024-12-31 04:02:39

关于 TAB 键的处理 - 应该是这样的:您处理 WM_GETDLGCODE 消息 表示您要处理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;

About the handling of the TAB key - it should be something like this: you handle the WM_GETDLGCODE message to indicate that you want to proccess the TAB key, ie

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;

and the in the overriden KeyDown method you decide what to do in response of it, something like

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;
若相惜即相离2024-12-31 04:02:39

不,您无法让窗口识别同一窗口句柄内的多个键盘焦点点,因为带有窗口句柄的每个控件要么具有或不具有键盘焦点。多个控件之间的“内在焦点”由你来梳理。

正如您已经知道的,完成此操作的最简单方法是拥有多个带有自己的窗口句柄的子控件,这就是您所说的正在做的事情:

TMyThreeEditControls = class(TControl) //  parent has no window handle!!!!
    protected
        FEdit1:TEdit;
        FEdit2:TEdit;
        FEdit3:TEdit;
    ...
end

在上面的情况中,父控件是一个 TControl,它创建了几个子控件,在我上面的示例中,所有三个都有自己的窗口句柄,因此 Windows 可以在您点击 Tab 时显示键盘焦点,并将处理鼠标焦点作为 Windows 公共控件库功能的一部分。

简而言之,在主控件中包含子对象(其他控件)的“复合”方法(您试图摆脱这种方法)实际上是让 Windows 完成大部分工作的唯一方法。

另一方面,您可能正在寻找的不是一种让控件绘画本身的方法,而是一些使某些东西看起来像集中在您自己的自定义绘画例程中的代码,如果这就是您正在寻找的,您应该查看 VCL 源代码或 about.com 上的链接有关如何进行的示例告诉 Windows 绘制焦点矩形等。about.com 链接是一个模仿,不使用真正的 Windows 代码以 Windows 主题感知的方式绘制焦点。

更新:您可能也在寻找确定鼠标坐标是否在指定矩形内的方法(该矩形代表您的情况下的按钮),如果是,则为鼠标绘制“热状态”按钮。如果您想自己构建一个控件,还有更多的子任务需要完成,我建议您研究 VCL 源代码中的现有控件,例如 TStringGrid 和 TCategoryButtons,以查看您需要的 MouseMove、MouseDown 和 MouseUp 处理代码去做你想做的事情。特别是,StringGrid 源代码是查看如何在具有单个窗口句柄的单个控件中使用“tab 键”的方法,因为在该控件中可以使用 tab 键(如果打开了正确的选项)在字符串网格内的所有单元格之间导航,就好像每个单元格都是一个单独的控件,即使它们都是一个控件。

No you can't get windows to recognize multiple points of keyboard focus inside the same window handle, since each control with a window handle either has, or does not have, keyboard focus. The "inner focus" between multiple controls is up to you to sort out.

As you already knew, the most simple way to accomplish this is to have multiple sub-controls with their own window-handles, which is what you said you are doing:

TMyThreeEditControls = class(TControl) //  parent has no window handle!!!!
    protected
        FEdit1:TEdit;
        FEdit2:TEdit;
        FEdit3:TEdit;
    ...
end

In the situation above, the parent control is a TControl, it creates several sub controls, in my example above, all three have their own window handles, and thus Windows can display keyboard focus when you hit tab, and handle mouse focus as part of Windows's common controls library's functionality.

In short, the "composite" approach where you include sub-objects (other controls) in your main control, which you are trying to move away from is in fact, the only way to let Windows do most of the work.

On the other hand, what you might be looking for is not a way to have a control paint itself, but some code to make something look like it is focused, in your own custom painting routines, if that is what you are looking for, you should look into the VCL source code or this link on about.com for examples on how to tell Windows to draw a focus rectangle, etc. The about.com link is an imitation and does not use real windows code to draw focus in a Windows-theme aware way.

Update: it is possible that what you are also looking for is the way to determine if mouse co-ordinates are within a specified rectangle (the rectangle represents a button in your case) and if so, to draw a "hot state" for the button. There are more sub-tasks than this to accomplish if you wish to build a control yourself, I recommend you study existing controls such as TStringGrid and TCategoryButtons in the VCL source code, to see the MouseMove, MouseDown, and MouseUp handling code you will need to do the things you are trying to do. In particular, StringGrid source code is the way to see how the "tab key" can be used within a single control with a single window handle, because in that control the tab key can be used (if the right options are turned on) to navigate among all the cells inside the string grid, as if each one was a separate control, even though it is all one control.

愛放△進行李2024-12-31 04:02:39

实现此目的的另一种方法是使用一个编辑框,您可以为每个想要“聚焦”的区域重复使用该编辑框。这本质上就是 Delphi 网格的工作方式。

当用户单击该区域(或按 Tab 键进入控件)时,您将编辑控件文本设置为该区域中的数据,将编辑控件边界设置为该区域并使其可见。当用户退出控件(通过单击控件或按 Tab 键)时,您将隐藏编辑控件。如果你让你的控件接受 Tab 键,你可以让它在点击 Tab 时“编辑”下一个区域,并在它们位于最后一个区域时退出它。

然后,只需进行内务管理即可确保将输入的数据存储在组件中的正确位置。

Another way to achieve this is to use one edit box that you re-use for each region that you want to have "focused". This is essentially how Delphi's grids work.

When the user clicks in that area (or hits the tab key into your control) you set the edit controls text to the data in that area, set the edit controls bounds to the area and make it visible. When the user exits the control (by clicking out of it or tabbing) you hide the edit control. If you make your control accept the tab key, you can make it "edit" the next area when they hit tab and exit it when they are in the last area.

Then it's just house keeping to make sure you store the entered data in the right spot in your component.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文