GUI 在低级别检测正在单击哪个元素的常见方法是什么?

What are common ways that GUIs detect which element is being clicked, in a low level?

我一直在努力寻找这个问题,但我发现的都是与高层次的事情有关,比如“如何知道哪个 HTML 被点击了”。那不是我要找的东西。我正在寻找更底层的细节。

假设有人正在尝试为给定系统编写 GUI 库。另外,假设这个程序员已经设法在屏幕上显示图形、文本、按钮等。现在他们想要实现用户与该界面交互的方式,更具体地说,使用鼠标点击(或者可能是触摸输入)。

他们运行 GUI 引擎的系统能够告诉他们点击何时发生,以及点击发生在屏幕上的哪个 (x, y) 点。要找到屏幕上的哪些元素被点击,一种简单的方法是循环遍历每个元素并测试它们中的每一个。但这是现有 GUI 中通常的做法吗?例如,这是浏览器在显示 HTML 页面时所做的吗?这是操作系统对其 GUI 和 windows 所做的吗?他们是否使用更复杂的数据结构,如 R-Trees?他们如何处理移动元素?

这个问题并不特定于任何软件,我只是想知道在 GUI 开发的上下文中通常如何解决这个问题。

有两种基本方法。一个你已经想通了:

  1. 测试“每个”对象与鼠标位置

    可以通过使用空间细分结构(类似于 2D 中的 BVH 和八叉树)来加快速度。然而,这种方法总是比较慢,并且会受到复杂性的限制,例如 O(log(n))O(n),其中 n 是 GUI 元素的数量。这里是天真的 O(n) 示例:

    • simple C++ Drag&Drop example

    但是一旦测试的物品数量增多或者形状过于复杂,这种方法就很麻烦了。

  2. 使用索引缓冲区

    这种方法是像素完美的,但复杂度 O(1),并且在大多数实现中也几乎是免费的。

    我们的想法是让索引缓冲区的分辨率与屏幕的分辨率相同,保存测试元素的 ID(索引)而不是颜色。因此,当您渲染 GUI 时,除了为元素的每个像素设置颜色之外,您还在索引缓冲区中的相同位置设置渲染项目索引或 ID。

    此后检测只是获取鼠标位置的索引缓冲区值。这里有几个例子:

    • VCL/GDI index buffer based mouse select

    此方法也可用于 2D 和投影 3D->2D 或更高维度。