当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]为了满足嵌入式系统的界面设计需求,给出了一种图形用户界面系统SKY-GUI 的设计思路和其在嵌入式Linux 环境下的实现方法。SKY-GUI 有四大组成部分:输入抽象层、显示抽象层、事件系统和窗口系统。

为了满足嵌入式系统的界面设计需求,给出了一种图形用户界面系统SKY-GUI的设计思路和其在嵌入式Linux环境下的实现方法。SKY-GUI有四大组成部分:输入抽象层、显示抽象层、事件系统和窗口系统。其特点是界面美观、占用资源少、运行效率高,现已应用于嵌入式视频监控项目。实验证明其设计思路可行,性能优良,适用于典型的嵌入式系统项目。

嵌入式图形用户界面(GUI, Graphic UserInterface)系统作为嵌入式系统中的一大关键技术,为用户提供设备的控制接口,其性能的好坏,界面的美观程度,影响着用户对产品的购买意愿和使用感受。

当前嵌入式系统中GUI的实现方式主要有两种:一是采用现有的GUI库;第二种是开发商基于嵌入式操作系统设计特有的GUI系统。采用第1种方式一般要对通用GUI库进行剪裁和个性化定制,也往往要支出额外的成本来获得软件授权。相对而言,第2种方法实现的GUI占用资源较小、容易满足嵌入式系统的实时性和个性化需求。

本文采用第2种方式,在嵌入式Linux下使用C语言实现了一个界面美观、轻量级、占用资源少、执行效率高的图形用户界面系统SKY-GUI.本文的结构如下:第1部分介绍SKY-GUI的基本结构;第2部分给出具体的模块设计;第3部分给出其实验和测试结果;最后总结。

1 SKY-GUI基本结构

SKY-GUI系统的功能主要有以下四点:

(1)接收各种输入设备的输入。

(2)建立消息循环,将设备的输入翻译为抽象的事件。

(3)建立窗口和控件对象系统,组织好各个抽象模块的关系,处理各种GUI事件。

(4)将GUI对象通过具体形状显示在屏幕上,通过动画将系统的状态变化呈现给用户。

基于这样的设计目标,SKY-GUI结构如图1所示。


图1 SKY-GUI的整体架构

它主要由输入抽象层、显示抽象层、事件系统和窗口系统四大部分组成。输入抽象层管理所有的输入设备,将用户的操作转化成消息送入事件系统。

显示抽象层操作显示设备,提供给窗口系统绘画、贴图、显示字体接口。事件系统为窗口系统提供消息获取、存储和处理的机制。窗口系统是SKY-GUI的核心,定义了各种控件和窗口,描述它们之间的逻辑关系和消息循环关系。下面将分别对这四大组成部分的设计进行介绍。

2 SKY-GUI模块设计

2. 1输入抽象层

输入抽象层为各种输入设备对事件系统的输入接口,它是一个单独的线程,其流程如图2所示。


图2输入抽象层流程。

输入抽象层首先对GUI所需的各种输入设备初始化,而后等待各个设备的输入。当接到设备输入,就把用户对设备的操作翻译成消息,送至事件系统最底层消息队列(在异2. 3. 2详细讨论)中。

设备输入的翻译过程根据具体的输入设备而定。对于键盘,只要将其键值和该键的状态封成消息。对于鼠标,除了要记录其按键状态,还要根据鼠标当前的位置和屏幕的大小将输入的位移分量转化成鼠标的新位置封入消息。

2. 2显示抽象层

显示抽象层的作用是为窗口系统提供显示接口函数,包括基本图形接口(画点、画线、填充矩形、区域拷贝、Alpha混合等)、贴图接口和字体接口三大功能,其结构如图3所示。


图3显示抽象层的结构。

显示抽象层在嵌入式Linux下的基础设备为帧缓冲,对其按坐标写入或读出颜色值即可实现基本的图形接口的功能。

简单的贴图功能用基本图形接口加bmp格式的文件(图片不经过压缩,其颜色分量按坐标顺序存储)就可以实现。为了让界面更加美观,SKY-GUI移植了开源的jpeg库和png库来解压相应格式的压缩图片文件,实现了对这两种图片格式的支持。

对字体的支持当然必不可少。点阵字体把字体的位图按12伊12、16伊16等格式存入二进制文件,可以比较容易地实现字体接口,但字体不能随意放大缩小,且放大后字体有明显的锯齿。矢量字体用数学方程加字形上的关键点来描述字体,可以进行无级缩放,为界面的绘制带来极大的灵活性。SKY-GUI移植了开源的Freetype库,用其寻址矢量字体文件并生成字体位图,实现了对矢量字体的支持。

2. 3事件系统

事件系统为SKY-GUI的其他三大部分提供消息发送、存储、获取和处理的功能。其核心为消息、消息队列和消息处理函数。

2. 3. 1消息定义

SKY-GUI的消息定义为:

typedef STruct __MSG {

HWND hWnd;摇/ /窗口指针

int event;摇/ /事件编号

void* wParam;摇/ /事件附加参数1

void* lParam;摇/ /事件附加参数2

} MSG;

hWnd为指向窗口的指针,表明此消息需要发给哪个窗口。event为事件编号,用不同的整数代表不同的事件。wParam和lParam为事件的附加参数,它们的含义根据事件类型的不同而定,例如,在鼠标消息中这两个参数就代表光标在屏幕上的坐标位置。

2. 3. 2消息队列

消息队列是事件系统中的消息的暂存处,它由一个环形先入先出结构的消息数组和一个消息链表组成。消息数组的空间是固定的,一旦被写满,后来的消息只好被丢弃;而消息链表则可以动态扩充大小。在SKY-GUI中,消息数组主要用来存放底层输入设备的事件(如鼠标、键盘、时钟等等),而消息链表主要用来存放优先级更高且不可丢弃的上层事件(窗口事件和显示事件)。

2. 3. 3消息操作接口

SKY-GUI定义了三类消息操作接口:消息发送函数、消息获取函数和事件处理函数。

消息发送函数为输入抽象层和窗口系统提供消息发送接口,包括Post_Msg函数和Send_Msg函数,其作用都是向消息队列发送消息,不同之处在于Post_Msg发送的消息存入消息队列的数组之中,而Send_Msg发送的消息则存入链表之中。

消息获取函数为Get_Msg函数,它为窗口提供取得消息的接口。拥有独立线程的窗口(异2. 4会描述其结构)调用它从消息队列中取得一个消息,其中存在链表中的消息更为重要,优先取出。

事件处理函数是窗口处理消息事件的函数接口,在SKY-GUI中,拥有独立线程的窗口调用Dispatch_Msg函数来实现对自己消息处理函数的调用。

2. 3. 4消息处理函数

Dispatch_Msg只是事件处理的调用接口,窗口收到消息后所采取的具体措施是由消息处理函数决定的,其定义为:

int WndProc(HWND hwnd, int event, void *wParam,void* lParam);

每一个窗口都有一个函数指针指向自己的消息处理函数,其功能根据不同的窗口有所不同,但总体结构是一样的,如图4所示。


图4消息处理函数的结构

其本质上是一个消息处理的分类列表。当窗口调用消息处理函数时,其根据消息类型的不同分别调用底层输入消息、控件消息或显示消息的处理函数,而后再根据具体的消息事件调用相应的处理函数,实现对各种事件的响应。

2. 4窗口系统

窗口系统为SKY-GUI系统的核心,它维护了一个完整的窗口列表,定义了窗口系统和事件系统之间的关系,并制定了窗口之间的消息传递机制。

2. 4. 1窗口的定义

SKY-GUI中,窗口既包含桌面、对话框这种狭义的窗口,也包含窗口控件(如按钮、下拉菜单、编辑框等等)这样的广义窗口,其定义为:

typedef struct __WINDOW {

STR32 caption; / /窗口的名称

RECT rect; / /窗口的大小、位置

int style; / /窗口的类型

MsgQueue* pMsgQ; / /附属于窗口的消息队列

struct __WINDOW*pFocus; / /活动窗口指针

struct __WINDOW*pParent; / /父窗口指针

struct __WINDOW*pChldHead; / /子窗口列表

struct __WINDOW*pNext; / /兄弟窗口或控件指针

struct __WINDOW*pCtrlHead; / /控件列表

WNDPROC WndProc; / /消息处理函数指针

void* data1; / /窗口私有数据

void* data2; / /窗口私有数据

void* data3; / /窗口私有数据

int msg1; / /窗口状态变化消息

} WINDOW;

caption为窗口的名称;rect为保存窗口位置和大小的矩形;style为窗口的类型;pMsgQ为窗口的消息队列的指针;pFocus指向当前窗口的活动子窗口或控件;pParent指向当前窗口的父窗口;pNext指向当前窗口的兄弟窗口;pChldHead用来保存当前窗口的子窗口列表;pCtrlHead保存当前窗口的控件列表。WndProc指向当前窗口的消息处理函数;data1、data2、data3为窗口的私有数据,msg1为窗口状态变化时需要发出的控件消息,它们的意义根据窗口的类型而定。

从窗口的定义可以看出,本文要实现的是一种树形的窗口关系,整个系统可以拥有一个或多个主窗口,每个主窗口拥有自己的控件和子窗口,而子窗口又可以拥有各自的子窗口和控件,依此类推。

2. 4. 2窗口与消息队列的关系

窗口定义中含有指向消息队列的指针,但并不是所有的窗口都有自己的消息队列。主窗口(如桌面)需要随时呈现在用户的面前,可以拥有自己的消息队列;其他的子窗口、控件则没有必要拥有自己的消息队列。这两类窗口用不同的方式使用事件系统。

拥有消息队列的主窗口必须拥有自己独立的线程,其消息发送和处理的流程如图5所示。


图5拥有消息队列的窗口的消息发送和处理流程。

当其他窗口或输入抽象层需要操作主窗口时,就调用事件系统中的Post_Msg或Send_Msg函数向该窗口的消息队列发送一个消息。而主窗口得知有消息输入,就调用事件系统中的Get_Msg函数取出消息,并使用Dispatch_Msg调用自己的消息处理函数,找到相应的事件处理方法处理事务。这种消息传递的特点是消息的发送和处理分别在不同的窗口线程中完成,一般用于两个主窗口之间或者输入抽象层和主窗口之间的消息通信。

没有消息队列的子窗口或控件处理消息的流程如图6所示。


图6没有消息队列的窗口的消息处理流程

主窗口调用事件系统中的Post_Msg或Send_Msg函数向子窗口或控件发送消息,由于该窗口没有自己的消息队列,事件系统不会将该消息保存,而是直接调用该窗口的消息处理函数找到具体的事件处理方式完成这次窗口操作。这种消息传递方式中,发送消息和处理消息都在主窗口的线程中完成,向一个窗口发送消息相当于要求该窗口立刻对事件进行处理。

SKY-GUI只设置了一个主窗口,即桌面。其他所有的窗口或对话框都作为桌面的子窗口而存在。

这样系统中只有一个窗口线程和一个消息队列,第一种消息处理方式只存在于输入抽象层和桌面之间,而窗口之间的消息处理都采用第二种方式,这样系统的线程开销和消息循环开销会大大减少,从而提高其运行效率。

2. 4. 3窗口之间的消息传递

窗口之间的消息传递根据消息类型的不同有两种不同方式。

主窗口从消息队列中取得的消息在SKY-GUI中称为底层消息。这类消息是由主窗口处理,还是交给子窗口或是控件处理,是根据窗口定义中的pFocus变量而定的。当一个窗口的pFocus不为空时,表示该窗口上方有子窗口被用户使用,消息应该交给它指向的子窗口处理,而这个子窗口也检查自己的pFocus变量,依此类推;只有当一个窗口的pFocus为空,表示该窗口位于屏幕的最上方,得到的底层消息由窗口自身处理(如图7左边流程)。

而当控件的状态变化产生控件消息时,其消息处理的过程正好跟上面的流程相反。控件产生的消息首先由自己处理,有必要时再送给pParent指针指向的父窗口处理,而后还有必要的话再送给父窗口的父窗口处理,最后也可以由主窗口送入消息队列(如图7右边流程)。


图7从消息队列读出的消息处理流程(左)和控件产生的消息处理流程(右)。

pFocus变量和pParent变量加上这样树形的窗口系统实质上是实现了很多GUI系统中的窗口的Z序[6](窗口的上下顺序)功能。该功能是建立在子窗口显示在其父窗口之上,且控件显示在其所属窗口之上的思想上的。由于底层消息一般代表用户对输入设备的操作,所以应该送给位于屏幕最上方的用户正在使用的窗口处理,而控件消息一般代表着GUI界面自上而下的图形和数据变化过程,所以应该从上到下逐层处理。

3实验和测试

SKY-GUI现已嵌入已有的视频监控系统项目中予以使用,它有下拉菜单、输入框、密码框、按钮、软键盘等十几种控件,提供视频监控的操控界面和配置界面。其中的一个典型的界面如图8所示。


图8 SKY-GUI在视频监控系统中的典型界面。

为了测试其的性能,本文利用SKY-GUI和开源的Qt界面库分别为视频监控系统制作了一套用户界面,其参数对比如表1所示。

表1 SKY-GUI与Qt在视频监控系统中的性能比较。


很显然,Qt在嵌入式监控系统中占用资源过多,导致其运行速度缓慢并影响到系统的正常编解码。

而SKY-GUI加上其所需的开源图片和字体库大小也不超过1 M,运行时只占用4 M左右的内存,这在典型的嵌入式Linux系统中完全可以接受,也不会影响到监控系统本身的性能。可以看出,Qt要运用在该监控系统中还需进行更深层次的剪裁和性能优化,而SKY-GUI则可满足其对界面的功能和性能需求。

4总结

本文描述了一种嵌入式Linux平台下GUI的设计方案。实验证明此设计方案可行,可以满足一般嵌入式平台上的图形界面要求。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为了满足日益增长的数据处理需求,铁威马NAS推出了全新的性能巅峰2024年旗舰之作F4-424 Pro,并搭载了最新的操作系统--TOS 6。这款高效办公神器的问世,无疑将为企业和专业人士带来前所未有的便捷与效率。

关键字: 存储 Linux 服务器

在嵌入式系统开发、调试和测试过程中,J-Link作为一种高效的调试工具,为开发者提供了极大的便利。然而,要想充分发挥J-Link的功能,首先需要正确安装其驱动程序。本文将详细介绍J-Link驱动的安装过程,并深入解析其中...

关键字: jlink 嵌入式系统 嵌入式开发

与谷歌的合作使 Nordic 能够在 nRF Connect SDK 中嵌入开发人员软件,以构建与安卓移动设备兼容的谷歌Find My Device和未知跟踪器警报服务

关键字: 谷歌 SoC 嵌入式开发

嵌入式开发作为当今电子工程和信息技术领域的核心分支,涵盖了广泛的软硬件技术和系统集成方法,用于构建高性能、低成本、低功耗、体积小巧且功能专一的嵌入式系统。这些系统无处不在,从微型传感器节点到复杂的工业控制设备,从日常使用...

关键字: 嵌入式开发 Python

嵌入式开发是当今信息技术领域不可或缺的一部分,它融合了硬件设计、软件开发和系统集成等多个学科,专门用于创建那些被嵌入到特定设备或系统中的专用计算机系统。嵌入式开发的主要过程包括利用分立元件或集成器件进行电路设计、结构设计...

关键字: 嵌入式开发 硬件设计 软件开发

嵌入式开发作为一种专业且技术密集型的领域,涵盖了从硬件底层驱动、中间件到应用层软件开发等多个层面的工作,其所需的工具种类繁多,各有针对性,旨在提升开发效率、保证代码质量以及简化调试过程。

关键字: 嵌入式开发 keil

嵌入式开发作为信息技术领域的重要分支,其涉及的语言种类繁多,各具特色。这些语言的选择取决于目标平台的特性、性能需求、开发者的熟练程度以及项目的具体要求。本文将详细介绍几种常见的嵌入式开发语言,包括C语言、C++、汇编语言...

关键字: 嵌入式开发 C语言

嵌入式开发是一项综合了硬件设计、软件编程以及系统整合的技术活动,其目的是为了创造出能够在特定环境中高效、稳定运行的嵌入式系统。这一流程涵盖了多个紧密关联且不可或缺的阶段,从最初的客户需求分析到最终的产品测试和交付,每个环...

关键字: 嵌入式开发 硬件设计

嵌入式开发作为一个融合了计算机软硬件和系统工程的综合性领域,其成功与否往往取决于三个核心要素的有效整合与协调。这三个要素分别是:硬件平台的选择与设计、软件开发及其优化、以及系统级的设计与集成。深入理解并熟练掌握这三个方面...

关键字: 嵌入式开发 ARM

嵌入式开发作为信息技术的关键支柱,在全球数字化转型浪潮中扮演着无可替代的角色。从传统的嵌入式微控制器到如今先进的片上系统(SoC),再到与云计算、人工智能深度融合的智能终端,嵌入式系统的演进与发展始终紧跟时代脉搏。本文将...

关键字: 嵌入式开发 智能应用
关闭
关闭