【问题标题】:How does a GUI Framework work?GUI 框架如何工作?
【发布时间】:2010-05-24 05:33:44
【问题描述】:

我一直在网上寻找答案,我的问题是: GUI 框架是如何工作的?例如 Qt 是如何工作的,是否有任何关于从头开始编写 GUI 框架的书籍或网站?框架是否必须调用操作系统 GUI 框架中的方法?

-- 感谢任何花时间尝试回答这个问题的人,如果我拼写错误,请原谅我。

【问题讨论】:

  • 这是一个很好的问题,有没有人知道一本涵盖 3 种或更多设计方法来构建和实际 GUI 框架的教科书,而不仅仅是作为 api 用户?
  • @GrantRostig 你有没有找到这样的教科书?
  • @SujalSingh,甚至没有课程笔记或幻灯片。

标签: user-interface graphics frameworks


【解决方案1】:

在过去,我们从头开始进行大量 GUI 编程。这并不像看起来那么难,但需要几周的时间才能得出结果。

首先你需要一个好的绘图库。这个库的最小功能是绘制剪裁矩形(使用图案)、线条、位图和字体。您可以通过将字体创建为位图来作弊,而裁剪的矩形只是一堆水平线。

现在您至少需要鼠标、键盘和计时器驱动程序(如果操作系统尚未提供)。通常,您将需要检测键、符号键(如 shift 等)、鼠标移动和鼠标点击。基本计时器功能将允许您检测双击。

然后你需要创建一个窗口数据结构。这个数据结构需要有坐标,即一个矩形,链接到父窗口(如果不是顶部窗口),以及窗口函数,即当这个窗口应该处理一些事件时将调用的函数。

一旦您可以在屏幕上绘图,您就需要一些矩形代数函数。您至少需要一个好的函数来计算矩形的交集,以及相对于绝对坐标的快速分辨率。例如 - 如果您的子窗口有父窗口,那么它的 x 和 y 应该递归地添加到父 x 和 y 直到您到达顶部窗口。

此时,您拥有: - 原始图形功能, - 窗口结构, - 鼠标驱动程序、键盘驱动程序和计时器, - 矩形算术。

现在您可以编写您的主事件收集函数。此功能将一直运行。其目的是检测事件并将消息发送到正确的窗口。什么是事件?好吧,当您启动程序时,存储鼠标 x 和 y 坐标。然后循环检查它们是否发生了变化。如果它们已更改,请在该位置找到窗口...并向其发送 WM_MOUSEMOVE 事件。您的收割功能应处理: - 鼠标移动 - 鼠标点击 - 鼠标双击(记住最后一次单击和位置,测量时间并确定是否是双击) - 定时器事件 - 键盘缓冲区更改 ...

现在您应该可以向窗口发送事件了。但是你真的需要一个机制。它是消息队列和窗口过程的组合。它通常是这样工作的:每个窗口都有一个窗口过程,它通常接受四个参数:消息 id(即是否是鼠标移动,是否绘制消息)、窗口句柄、参数 1 和参数 2。您可以使用直接调用此窗口过程类似于 send_message 函数的东西。或者您可以通过 post_message 函数向该窗口发送消息。这会将消息放入队列,窗口将一一处理消息,最终接收到这一消息。那么,为什么要直接调用一条消息并将其他消息放入队列中呢?因为优先。您会看到,键盘单击可能会等待一段时间才能被处理。但是窗口重绘必须立即完成,以防止屏幕上出现闪烁和错误数据。

因此,您的 Harvest_events 函数使用 post_message 和 send_message 将消息发送到窗口。您的窗口消息泵使用典型的消息泵来获取它们,如下所示:

while (pmsg = get_message() != NULL) send_message(pmsg->id, pmsg->hwnd, pmsg->p1, pmsg->p2);

get_message 只是从队列中获取消息,然后调用 send message。很简单吧?好吧,并非如此。这样你就只会接收到windows的驱动消息,但你还需要一些函数来重绘窗口移动它们等。当你创建move_window函数时,resize_window、show_window , 和 hide_window 函数,你的窗口坐标会改变。其他窗口的部分将被覆盖(如果顶部窗口被移动或关闭)。您需要计算哪些窗口受到坐标变化的影响并将绘制消息发送到这些窗口(仅重新绘制未覆盖的部分 - 请记住,您有剪裁绘图功能,所以这将起作用)。

这些函数引入了消息msg_paint、msg_move、msg_resize、msg_hide...

最后,您需要维护窗口的层次结构。您的顶部窗口应该是桌面。它应该有子窗口(应用程序顶部窗口)。这些窗口可能还有更多的子窗口(按钮、编辑框等)。保存这些窗口的明显结构是窗口树。当您检测到鼠标点击时,您必须遍历窗口树并以一种聪明的方式(找出谁有焦点、谁是模态等等)来将消息发送到正确的窗口。当你画画时,你还必须遍历所有的孩子,看看谁没有被发现,谁没有。最后但同样重要的是,您需要将鼠标矩形作为顶部窗口处理,以防止在重新绘制窗口或(使用计时器和 msg_paint 事件)动画时鼠标闪烁。

大概就是这样。

【讨论】:

  • 要将这样的 gui 映射到现代面向对象的语言,您通常创建窗口类,记住窗口句柄,在静态成员中维护窗口列表,并使用现代 c++ 信号将来自静态窗口函数的事件重新连接到正确的类和插槽或类似技术。 GUI 的初始实现通常是程序性的。但是因为是事件驱动,所以很容易被OO语言封装。我不认为有这方面的书。这是古老的开源库,例如文本DFLAT库或图形GEM gui库,可以获得的古老智慧。
  • IMO,这个答案和评论应该是公认的答案。
  • 有谁知道一本涵盖 3 种或更多设计方法来构建和实际 GUI 框架的教科书,而不仅仅是作为 api 用户?
【解决方案2】:

像 Qt 这样的 GUI 框架通常通过采用现有操作系统的原始对象(窗口、字体、位图等),将它们包装在更独立于平台和不那么笨重的类/结构/句柄中,并为您提供您所需要的功能。将需要操纵它们。是的,这几乎总是涉及使用操作系统自己的功能,但它不必——例如,如果你正在设计一个 API 来绘制一个 OpenGL UI,那么大多数底层操作系统的 GUI 东西甚至都不会工作,而且您几乎可以自己做所有事情。

无论如何,这都不适合胆小的人。如果你不得不问一个 GUI 框架是如何工作的,那么你甚至还没有准备好设计一个。你最好坚持使用现有的框架并扩展它来做它还没有做的漂亮的事情。

【讨论】:

  • 谢谢您的回复,事情开始变得更有意义了。我不得不同意你的观点,我可能还没有准备好开发一个,但希望有一天我会达到那种理解水平。但是感谢您的回答,这很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多