English 中文(简体)
参考:如何使用无窗口控制?
原标题:Delphi: How to use windowless controls?

我知道无窗口控件并非神器。无窗口控件可以获得输入焦点(如Internet Explorer)。输入焦点只不过是绘制以下内容之一:

当用户开始按键时,会适当做出反应。您知道这些按键是针对那个被聚焦的控件的,因为该控件具有聚焦状态。

在我的(Windows®)窗口的情况下,我需要知道我的无窗口子控件(让我们假装它是TGraphicControl的后代)获得键盘事件。因此,在我表单的 OnKeyDownOnCharOnKeyUp期间,我需要假装它们是要去我的无窗口子控件。

我可以做,但它很痛苦。

但用户可能会想要使用Tab导航,然后我将不得不以某种方式拦截Delphi的正常Tab控件顺序处理,并钩入自己以指出这个东西是下一个(和上一个)在Tab顺序中的项目。

我可以做,但它很痛苦。

然后就有了ActiveControl,它只理解TWinControl。因此,如果Delphi尝试找出谁拥有焦点,它将变得疯狂。所以我需要有一个替代的ActiveControl实现。

我可以做,但它很痛苦。

换句话说:这是不是太麻烦了? 为了让几十个无窗口控件可通过键盘输入进行操作,我正在与Delphi的一切战斗。Delphi的设计师从未考虑过使用交互式无窗口控件,如果我现在尝试工作,我将陷入困境,就像拆弹部队一样。

Delphi 给了我乐意帮助我的机会,但我选择了痛苦的道路。


Some further explanation of windowless controls is needed.

并非你们相互交往的每一种控制都必须是窗户控制。 很可能把重点放在而不是视窗的控制权上,并将主要投入到这种控制上。

例如,几乎在Internet Explorer浏览器窗口中看到的每个控件都是无窗口控件。在以下屏幕截图中,您可以看到一个编辑控件,您可以在其中输入,以及一个按钮,该按钮(在此屏幕截图中)具有焦点:

alt text

您可以看到虚点聚焦矩形,而按钮是蓝色的(在Windows上表示它具有焦点)。

如果我在焦点在Google搜索按钮的情况下按下空格键,它将按下按钮。之所以可以这样做,是因为微软编写了一个完整的小部件控件库。这些控件看起来和感觉(几乎)与常规公共控件完全相同 - 它们非常接近于Windows公共控件的精确克隆,包括应用主题。

Mozilla Firefox 和 Google Chrome 也使用了一套控件窗口的小部件库。它们不使用 Microsoft 内置的窗口控件,而是使用了一个图形化、交互式、无窗口的小部件库。

如果你有适当的开发环境,那么无窗口小部件就像“普通”的窗口控件一样工作。GTK+ 是一个小部件库,而Glade是一个可以在该小部件库中布局控件的IDE。

我不知道 Firefox、Chrome 或 Blender 是在哪种开发环境中创建的,但它们的小部件支持无窗口控件。


现在转向我的问题。

除非我错了,我觉得尽管Delphi支持一个基本的TControl(它有宽度、高度,可以自我绘制),但它不能接收键盘焦点。在我看来,Borland从未将Delphi的VCL设计为通用的小部件库。我为支持这一点唯一的证据是一个表单的ActiveControl是一个TWinControl:

property ActiveControl: TWinControl;

这并不意味着 Delphi 只能被限制在窗口控件上。 VCL 小部件库可以扩展以支持针对无窗口控件进行聚焦。

但也许Delphi已经支持无窗口控件,只是我没有意识到? Delphi中是否已经建立了一种机制来支持将焦点集中于TControl?但我是一个相当聪明的人,我非常确定Delphi的VCL无法做到其他小部件库所能做的事情。

这就引出了另一个问题:子类化表格和类似的支持需要多少工作?也许还有其他人,也许是TeamB的某个比我聪明得多的人已经尝试过,并得出结论,认为它是不可能的吗?

我现在前面就问了,如果尝试添加无窗口控件支持几乎不可能(即徒劳无功),因此我不想白费几周时间。我试图借助Delphi开发者社区的知识。

i m 提问。

最佳回答

在Delphi的VCL框架中构建无窗口控件并将其适配是徒劳的。

你举了Internet Explorer作为例子。但在这种情况下,它完全负责其上的一切。它有自己的内部概念,关于活动控件是什么,但从外部看,你会发现它只是一个巨大的控件。当你询问操作系统哪个控件有焦点时,单个浏览器控件拥有它,无论浏览器的子控件看起来有焦点的是哪一个。

当您按下Tab键时,操作系统会认为浏览器仅仅是消耗了一个制表符,就像编辑控件一样。编辑控件将光标移到几个空格上,并将制表符添加到其内部缓冲区中;浏览器控件将光标移到显示的另一个区域。

你正在考虑在Delphi TForm上完成所有这些工作。Delphi表单已经有了管理活动控件和处理按键的框架,你必须与其作斗争。如果你想要无窗口控件,可以采用Internet Explorer路径,构建自己的容器控件来容纳它们,以便你可以控制容器内发生的一切。

你的容器可以是一个VCL控件,但你放在上面的东西可能不行——它们仍然希望使用VCL的焦点和键盘处理规则。注意,你也不能在Internet Explorer中放置普通的Windows控件。任何你放进去的东西都需要通过特定的ActiveX接口。也许你也需要接口,也许你只需要创建一组从你设计用于与你的容器配合工作的特殊祖先类派生出来的控件类。不要从TGraphicControl开始;它在VCL中过于根深蒂固,不能用作你的分支控件库的基础。

这将是很多的工作,但是同样,互联网浏览器也是一样的。

问题回答

Yes, it is futile.
And it s not Delphi s fault, you re just fighting Windows itself.
If you need a control that behaves like a windowed control, use a windowed one.
And you re right, trying to recreate the whole API stack of windowed controls from scratch is a pain.

Y年,你大概略了。 利用无窗户控制意味着你失去一切窗户,能够帮助你。 在一个单一的实际窗口上有一个以上的夫妇是痛苦的。

大多数这些程序很可能最初没有使用RAD类型的工具开发,因此别无选择,只能重新发明轮子。Delphi最大的优势之一是深入的VCL和第三方组件支持,以提供您想要的外观。

我曾经用一种非常成功的技术来减少复杂的(税务准备)基于表单的应用程序中使用的窗口句柄数量,即在画布上绘制文本,并将单个TCustomEdit子类移动到用户正在编辑的位置。 捕获TAB / Up / Down键并将编辑器移动到适当的位置非常容易。 我们遇到的挑战在于在鼠标悬停字段周围绘制热矩形。 我们最终是使用TObject的网格数组,其中数组元素可能为nil(没有字段),一个TLIst(网格包含多个字段)或包含我们字段描述符的类。 这减少了我们必须执行的范围检查的数量,因为盒子很可能仅包含单个字段,或者最多包含4个字段。

fpGUI 工具包是您需要的示例。源代码存储库中的最新 fpGUI 代码基于多窗口设计。简单地说,这意味着每个小部件 / 组件都有一个窗口句柄,但 Windows 或 Linux 仅处理基本通知消息(mouseenter,mouseexit 等),fpGUI 仍然可以完全控制每个组件的位置、焦点控制、外观等。fpGUI 中的某些小部件 / 组件也是非窗口化的,例如:TfpgScrollbar、TfpgMainMenu、组合框中的按钮等。

如果您想要一个真正的非窗口化版本,这意味着只有一个顶级窗口具有窗口句柄,所有其他窗口小部件/组件都实际上不存在于操作系统中(它们没有窗口句柄),那么fpGUI也可以提供帮助。fpGUI Toolkit的初始设计基于这样的设计。再次查看源代码存储库的v0.4代码分支。在这种设计中,fpGUI必须处理所有东西,创建鼠标进入/离开事件,为容器组件翻译坐标系,处理(虚假的)组件焦点状态等等...是的,最初的设计需要很多工作,但然后您就有一个非常便携的框架,可以轻松应用于其他操作系统中。

是的,fpGUI是完全使用Object Pascal语言实现的,使用Free Pascal编译器为我提供跨平台支持。目前,fpGUI可在Windows,Linux(32位和64位),Windows Mobile和嵌入式Linux(ARM)设备上运行。

我不清楚你的问题到底是什么,但我觉得这个小故事可能有关联……

我们有一个应用程序,可以填写十几个表格。用户可以填写额外的表格,并且还可以更改应用程序自身填写的值。

现在,在我们的第一个执行过程中,我们利用了每个单一投入领域的窗口部件,以便这些领域能够得到重点和投入。 这确实是一个大问题,因为所有这些窗口都花费了大量资源。

我们现在为每个输入字段提供无窗口控件。这意味着我们最终得到的是表单及其输入字段的组合图纸。当用户单击图纸内部或使用某些按键移动/设置焦点时,我们为所单击的字段创建一个新的有窗口控件。当用户移动到下一个输入字段时,我们销毁第一个窗口并创建一个新窗口。这样我们只有一个有窗口的控件,又为我们带来了良好的速度提升。

再次 - 我不知道你真正想要管理什么。TWinControl 之所以是 TWinControl,是有原因的,但是不管你想要什么,可能会有一个解决方案...

我认为fgGUI可能会对你有所帮助。

请先查看它的维基百科

我认为你可以在Delphi应用程序中使用这个框架,因为它完全是用Pascal编写的。事实上它是基于FreePascal的 ;)

HTH: 希望能帮助到你 (Xi wang neng bang zhu dao ni)





相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签