MiniGUI学习日记一----MiniGUI基础编程篇

一、什么是事件驱动编程:

        MinGUI是一个图形用户界面支持系统。通常的GUI编程概念均适用于MiniGUI编程。

二、焦点和光标:

        焦点和光标的概念用于管理输入设备和输入事件的传送。鼠标光标是一个绘制在屏幕上的小位图,指示当前的鼠标位置,应用程序可以绘制哪一个位图以及是否显示光标。应用程序还可以捕捉光标并获取光标事件。

三、MINIGUI的三种运行模式

        ① MiniGUI-Threads,运行在MiniGUI-Threads上的程序可以在不同的线程中建立多个窗口,但是所有窗口在一个进程或者地址空间中运行。

        ②MiniGUI-Process。MiniGUI-Process上的每个程序是独立的进程,每个进程也可以建立多个窗口,这种模式适用于具有完整UNIX特性的嵌入式操作系统。

        ③MiniGUI-Standalone。这种模式下,MiniGUI可以以独立进程的方式运行,不需要多线程,这种模式适合功能单一的场合

        MiniGUI-Standalone模式适应面最广,几乎支持所有操作系统。

四、MiniGUI-Lite

        Lite模式下,的MiniGui使用嵌入式的linux的进程机制,使得MiniGui更稳定,能充分利用类似地址控件保护的高级性能。我们可以在MiniGui-Lite模式下运行多个MiniGui客户进程,当其中一个进程不正常终止,其他进程将不受影响。

        MiniGui-Lite模式下,客户端创建的窗口不是一个全局对象。

五、helloworld程序

#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>

static LRESULT HelloWinProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    switch (message) {
        case MSG_PAINT:
            hdc = BeginPaint (hWnd);
            TextOut (hdc, 60, 60, "Hello, world!");
            EndPaint (hWnd, hdc);
            return 0;

        case MSG_CLOSE:
            DestroyMainWindow (hWnd);
            PostQuitMessage (hWnd);
            return 0;
    }

    return DefaultMainWinProc (hWnd, message, wParam, lParam);
}

int MiniGUIMain (int argc, const char* argv[])
{
    MSG Msg;
    HWND hMainWnd;
    MAINWINCREATE CreateInfo;

#ifdef _MGRM_PROCESSES
    JoinLayer (NAME_DEF_LAYER , "helloworld" , 0 , 0);
#endif

    CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION;
    CreateInfo.dwExStyle = WS_EX_NONE;
    CreateInfo.spCaption = "Hello, world!";
    CreateInfo.hMenu = 0;
    CreateInfo.hCursor = GetSystemCursor (0);
    CreateInfo.hIcon = 0;
    CreateInfo.MainWindowProc = HelloWinProc;
    CreateInfo.lx = 0;
    CreateInfo.ty = 0;
    CreateInfo.rx = 240;
    CreateInfo.by = 180;
    CreateInfo.iBkColor = COLOR_lightwhite;
    CreateInfo.dwAddData = 0;
    CreateInfo.hHosting = HWND_DESKTOP;

    hMainWnd = CreateMainWindow (&CreateInfo);

    if (hMainWnd == HWND_INVALID)
        return -1;

    ShowWindow (hMainWnd, SW_SHOWNORMAL);

    while (GetMessage (&Msg, hMainWnd)) {
        TranslateMessage (&Msg);
        DispatchMessage (&Msg);
    }

    MainWindowThreadCleanup (hMainWnd);

    return 0;
}

#ifndef _MGRM_PROCESSES
#include <minigui/dti.c>
#endif

        程序创建一个大小为 320x240 像素的应用程序窗口,并显示“Hello world!” 在窗口客户区的中心。

        所有MiniGUI都必须包含的四个头文件M<minigui/common.h>,<minigui/minigui.h>,<minigui/gdi.h>,和<minigui/window.h>、<control.h>

  • common.h: 包括 MiniGUI 中常用的宏和数据类型的定义。
  • minigui.h:包括全局和通用接口函数和一些杂项函数的定义。
  • gdi.h:包括MiniGUI图形功能的接口定义。
  • window.h: 包括宏、数据类型、数据结构的定义,这些都与窗口和函数接口的声明有关。

使用预定义控件的 MiniGUI 应用程序必须包含另一个头文件 -- minigui/control.h

  • control.h:包括minigui库中所有内置控件的接口定义。

        C 程序的入口是主程序,而 MiniGUI 程序的入口是MiniGUIMain,程序原型如下:

int  MiniGUIMain ( int argc, const  char * argv[]);

        该函数是mainANSI C 的(入口函数)封装的宏。所以每个MiniGUI 应用程序(无论是服务器功能mginit还是客户端应用程序)的入口 都是该MiniGUIMain函数。和的参数 argc与C程序中函数的argv含义相同main,分别是命令行参数的个数和指向参数的字符串数组指针。

        在 MiniGUI-Processes 中加入一个层

# ifdef _MGRM_PROCESSES
     JoinLayer (NAME_DEF_LAYER, " helloworld " , 0 , 0 ); 
#ENDIF

JoinLayer是 MiniGUI-Processes 的一个特殊功能,因此包含在_MGRM_PROCESSES. 在 MiniGUI-Processes 运行模式下,每个 MiniGUI 客户端程序在调用其他 MiniGUI 函数之前,必须先调用该函数加入一个层(或创建一个新层)。

如果程序是 MiniGUI-Processes 的服务器,你应该调用 ServerStartup

if (!ServerStartup ( 0 , 0 , 0 )) {
     fprintf (stderr, "无法启动 MiniGUI-Processes 的服务器: mginit. \n " );
    返回 1 ; 
}

注意MiniGUI 为三种运行模式定义了不同的宏:

  • MiniGUI 线程:_MGRM_THREADS;
  • MiniGUI-Processes:_MGRM_PROCESSES_LITE_VERSION;
  • MiniGUI-Standalone: _MGRM_STANDALONE_LITE_VERSION, 和_STAND_ALONE.

创建和显示主窗口

    hMainWnd = CreateMainWindow (&CreateInfo);

每个 MiniGUI 应用程序的初始用户界面通常是一个主窗口;您可以通过调用CreateMainWindow函数创建一个主窗口。CreateMainWindow函数的参数是一个指向MAINWINCREATE 结构体的指针,CreatInfo在这个例子中就是这个结构体,返回值是创建的主窗口的句柄。MAINWINCREAT结构体描述了主窗口的属性,在CreatInfo创建主窗口之前需要设置其属性。

    CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION;

上面的语句设置了主窗口的样式,这里的窗口设置为初始可见,并有边框和标题栏。

    CreateInfo.dwExStyle = WS_EX_NONE;

以上语句设置了主窗口的扩展样式,窗口没有扩展样式。

    CreateInfo.spCaption = "Hello, world!" ;

该语句将主窗口的标题设置为“Hello, world!”。

  CreateInfo.hMenu = 0 ;
该语句设置主窗口的主菜单,窗口没有主菜单。
    CreateInfo.hCursor = GetSystemCursor ( 0 );

该语句设置主窗口的光标,该窗口的光标是默认的系统光标。

    CreateInfo.hIcon = 0 ;

该语句设置主窗口的图标,窗口没有图标。

    CreateInfo.MainWindowProc = HelloWinProc;

该语句将主窗口的窗口过程函数设置为 HelloWinProc,所有发送到该窗口的消息都由该函数处理。

   创建信息.lx = 0 ; 
   创建信息.ty = 0 ; 
   创建信息.rx = 320 ; 
   CreateInfo.by = 240 ;

以上语句设置了主窗口在屏幕上的位置和大小,左上角和右下角分别位于(0, 0)和(320, 240)。

   CreateInfo.iBkColor = PIXEL_lightwhite;

该语句将主窗口的背景色设置为白色,PIXEL_lightwhite是 MiniGUI 预定义的像素值。

   CreateInfo.dwAddData = 0 ;

该语句设置主窗口的附加数据,窗口没有附加数据。

   CreateInfo.hHosting = HWND_DESKTOP;

此语句将主窗口的托管窗口设置为桌面窗口。

   ShowWindow (hMainWnd, SW_SHOWNORMAL);

ShowWindow创建主窗口后,需要调用函数将创建的窗口显示在屏幕上。

的第一个参数hMainWnd是要显示的窗口的句柄,

第二个参数指定显示窗口的动作(显示或隐藏)。SW_SHOWNORMAL表示显示主窗口并将其设置为最顶部的窗口。

进入消息循环

ShowWindow函数被调用时,主窗口将显示在屏幕上。和其他 GUI 一样,是时候进入消息循环了。MiniGUI 为每个 MiniGUI 程序维护一个消息队列。事件发生后,MiniGUI 将事件转化为消息,并将消息放入目标窗口的消息队列中。那么应用程序的任务就是执行下面的消息循环代码,不断地从消息队列中获取消息并进行处理。

    while (GetMessage (&Msg, hMainWnd)) {
         TranslateMessage (&Msg);
        DispatchMessage (&Msg); 
    }

Msg变量类型为 MSG 结构体,定义 minigui/window.h如下:

/**
 * 消息结构。
* \sa GetMessage, PostMessage, msgs 
 */
typedef struct _MSG
{
    /** 接收此消息的窗口句柄。*/
    HWND hwnd;    
    UINT  message;         /** 消息标识符 */
    WPARAM wParam;         /** 消息的第一个参数(具有指针精度的无符号整数)。 */
    LPARAM lParam;         /** 消息的第二个参数(具有指针精度的无符号整数) */
    DWORD time;            /**时间*/

#ifdef _MGRM_THREADS
    
    void*  pAdd;          /** 附加数据*/
#endif
} MSG;
typedef MSG* PMSG;

GetMessage 函数从应用程序的消息队列中获取一条消息。

     GetMessage (&Msg, hMainWnd);

此函数的第二个参数是主窗口的句柄,第一个参数是指向 MSG 结构的指针。GetMessage函数用从消息队列中得到的消息填充 MSG 结构的字段,其中包括:

  • hwnd: 消息发送到的窗口句柄。该值是相同hMainWndhelloworld.c程序。
  • message: 消息标识符。这是用于标识消息的整数。每条消息都有一个对应的预定义标识符,这些标识符定义在minigui/window.h并带有MSG_ 前缀。
  • wParam:第一个消息参数,不同的消息含义和取值不同。
  • lParam: 第二个消息参数,其含义和取值取决于消息。
  • time:消息放入消息队列的时间(tick count)。

只要从消息队列中得到的消息不是MSG_QUIT, GetMessage则返回一个非0值,消息循环将继续。MSG_QUITmessage 消息使GetMessage返回为零,并导致消息循环终止。

      TranslateMessage (&Msg);

TranslateMessage函数将击键消息转换为MSG_CHAR 消息,然后将消息发送给窗口过程函数。

      DispatchMessage (&Msg);

DispatchMessage函数最终将消息发送到目标窗口的窗口过程,并让它处理消息。

在这个例子中,窗口过程是HelloWinProc。也就是说,MiniGUI 在函数中调用主窗口的窗口过程函数(回调函数)DispatchMessage来处理发送到这个主窗口的消息。处理完消息后,应用程序的窗口过程函数返回DispatchMessage函数中,而DispatchMessage function最终返回应用程序代码,应用程序通过调用下一个GetMessage 函数开始新的消息循环。

窗口过程函数

        窗口过程函数是 MiniGUI 程序的主体。一个应用程序的大部分工作实际上发生在窗口过程函数中,因为GUI程序的主要任务是接收和处理窗口接收到的各种消息。

        在helloworld.c 程序中,窗口过程是名为HelloWinProc的函数,窗口过程函数可以由程序员任意命名,CreateMainWindow函数根据MAINWINCREATE结构中指定的窗口过程创建主窗口。

        窗口过程函数定义如下:

static LRESULT HelloWinProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        窗口过程函数的四个参数与 MSG 结构的前四个域相同,第一个参数hWnd是接收消息的窗口句柄,与CreateMainWindow函数的返回值相同, 表示接收消息的具体窗口。第二个参数与MSG结构的message字段相同,是一个整数值,表示接收到的消息。最后两个参数都是消息参数(两个具有指针精度的整数),提供与消息相关的特殊信息。

        窗口过程函数通常不是由程序直接调用,而是由MiniGUI 调用,即回调函数。

        窗口过程函数不予处理的消息应该传给DefaultMainWinProc函数进行缺省处理,从DefaultMainWinProc返回的值必须由窗口过程返回。

屏幕输出

        程序在响应MSG_PAINT 消息时执行屏幕输出。应用程序首先通过调用BeginPaint函数获取设备上下文句柄 ,并使用它来调用GDI函数来执行绘图操作。这里,程序使用TextOut文本输出函数来显示“Hello, world!” 字符串。绘制完成后,应用程序调用EndPaint函数释放设备上下文句柄。

我们将在本指南的第三部分详细介绍 MiniGUI 图形设备接口。

退出程序

        当用户单击窗口右上角的关闭按钮时,窗口过程函数将收到一条MSG_CLOSE消息。helloworld程序在收到MSG_CLOSE消息时调用DestroyMainWindow函数销毁主窗口,并且调用PostQuitMessage 函数将MSG_QUIT投入到到消息队列中。GetMessage 函数在接收到MSG_QUIT消息时会返回0 ,最终导致程序退出消息循环。

        程序最后调用MainWindowThreadCleanup清理主窗口使用的消息队列等系统资源,并最终由MiniGUIMain finally返回。

编译、链接和运行

可以在命令行中输入以下命令进行编译 helloworld.c,并链接生成执行文件helloworld

$ gcc -o helloworld helloworld.c -lpthread -lminigui_ths -ljpeg -lpng -lz

如果将 MiniGUI 配置为 MiniGUI-Processes,则需要以下编译选项:

$ gcc -o helloworld helloworld.c -lminigui_procs -ljpeg -lpng -lz

 -o告诉 编译器 ( gcc) 要生成的目标文件名,这里是helloworld-l选项 指定生成helloworld时需要链接的一个库,这里连接的是minigui库和pthread 库,如果 MiniGUI 配置为 MiniGUI-Threads时。还需要链接pthread库。 pthread 是提供 POSIX 兼容线程支持的函数库,编译 MiniGUI-Threads 程序时必须链接这个函数库。我们所编译的程序只使用MiniGUI核心库minigui中的函数,没有使用MiniGUI其他库提供的组件(如libmgext或libvcongui),因此只需要链接minigui库或链其他要链接的函数库如jpeg、png、z 等都是MiniGUI 内部依赖的函数库(这里假设您在配置MiniGUI 时已经开启了JPEG 和PNG 图像支持)。

        如果将 MiniGUI 配置为 MiniGUI-Processes,则在运行helloworld程序之前,必须先确保已经启动了MiniGUI的服务器端程序mginit。例如,你可以在 启动MED的mginit程序,然后进入helloworld文件所在目录,在命令行中输入./helloworld即可启动helloworld程序。

$ ./helloworld

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值