GUI程序原理分析

1 命令行应用程序

命令行应用程序的特点(Command Line Interface):

  • 是一种基于顺序执行结构的可执行程序。
  • 程序执行过程中不需要与用户产生交互。
  • 程序执行后会给出最终的运行结果。

比如:gcc a.c b.c c.c,编译过程中不产生用户交互,编译结束后或者生成可执行程序或者给出错误信息。

命令行应用程序的运行模式:
在这里插入图片描述

命令行应用程序适用于:

  • 单任务场合。
  • 无交互或简单交互场合。
  • 服务器应用场合。

在这里插入图片描述
命令行应用程序是早期计算机系统中的主要程序类型。


2 图形界面应用程序

图形界面应用程序的诞生:

  • 随着计算机技术的发展,计算机走进日常生活。
  • 计算机程序开始需要处理各个领域中的问题。
  • 计算机用户已经不再是专业的计算机工作者。

问题:如何让计算机程序更好的适应普通用户并走进日常生活?

图形界面应用程序的特点(Graphic User Interface):

  • 是一种基于消息驱动模型的可执行程序。
  • 程序的执行依赖于用户的交互过程。
  • 程序执行过程中实时响应用户操作。
  • 一般情况下程序执行后不会主动退出。

图形界面应用程序的运行模式:
在这里插入图片描述
图形界面应用程序的消息处理模型:
在这里插入图片描述
图形界面应用程序适用于:

  • 多任务场合。
  • 强用户交互的场合。
  • 非专业计算机用户。

在这里插入图片描述
图形界面应用程序是当代计算机系统中的主要程序类型。

当代大型软件产品架构模型:
在这里插入图片描述
命令行应用程序和图形界面应用程序的对比:
在这里插入图片描述


3 GUI程序实例分析

3.1 GUI程序开发概述

现代操作系统支持GUI界面:

  • 现代操作系统提供原生SDK支持GUI程序开发。
  • GUI程序开发是现代操作系统上的主流技术。
  • 不同操作系统上的GUI开发原理相同。
  • 不同操作系统上的GUI SDK不同。

GUI程序开发原理分析:

  • GUI程序在运行时会创建一个消息队列。
  • 系统内核将用户操作翻译成对应的程序消息。
  • 程序在运行过程中需要实时处理队列中的消息。
  • 当队列中没有消息时,程序处于停滞状态。

在这里插入图片描述
不同操作系统支持相同的GUI开发原理:
在这里插入图片描述

GUI程序开发:

  • 在代码中用程序创建窗口及窗口元素
  • 在消息处理函数中根据程序消息做出不同响应。

在这里插入图片描述

3.2 基于面向过程的GUI程序开发实例

多数操作系统以C函数的方式提供GUI SDK,以Windows操作系统为例:
在这里插入图片描述
使用win32进行GUI初体验:
运行效果:生成主窗口,主窗口上添加一个按钮,点击后弹出对话框。

在这里插入图片描述

#include <windows.h>

#define STYLE_NAME    L"MainForm"
#define BUTTON_ID     919

/* 主窗口定义函数 */
BOOL DefineMainWindow(HINSTANCE hInstance);
/* 主窗口创建函数 */
HWND CreateMainWindow(HINSTANCE hInstance, wchar_t* title);
/* 主窗口内部元素创建函数 */
HWND CreateButton(HWND parent, int id, wchar_t* text);
/* 主窗口显示函数 */
HWND DisplayMainWindow(HWND hWnd, int nCmdShow);
/* 主窗口消息处理函数 */
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

static HWND MainWindow = NULL; // 主窗口句柄标

void App_Exit()
{
    PostQuitMessage(0);
}

void Button_Handler(int id, int e)
{
    if ((id = BUTTON_ID) && (e == BN_CLICKED))
    {
        MessageBox(MainWindow, L"Button is clicked!", L"Clicked event", 0);
    }
}

BOOL WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG Msg = {0};

    /* 1.自定义主窗口样式 */
    if( !DefineMainWindow(hInstance) )
    {
        return FALSE;
    }

    /* 2.创建主窗口 */
    MainWindow = CreateMainWindow(hInstance, STYLE_NAME);

    if( MainWindow )
    {
        /* 3.创建主窗口中的控件元素 */
        CreateButton(MainWindow, BUTTON_ID, L"My Button");

        /* 4.在屏幕上显示主窗口 */
        DisplayMainWindow(MainWindow, nCmdShow);
    }
    else
    {
        return FALSE;
    }

    /* 5.进入消息循环 */
    while( GetMessage(&Msg, NULL, NULL, NULL) )
    {
        /* 6.翻译并转换系统消息 */
        TranslateMessage(&Msg);
        /* 7.分发消息到对应的消息处理函数 */
        DispatchMessage(&Msg);
    }

    return TRUE;
}

BOOL DefineMainWindow(HINSTANCE hInstance)
{
    static WNDCLASS WndClass = {0}; // 系统结构体类型
                                    // 用于描述窗口样式
    WndClass.style         = 0;
    WndClass.cbClsExtra    = 0;
    WndClass.cbClsExtra    = 0;
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);          // 定义窗口背景色
    WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);     // 定义鼠标样式
    WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION); // 定义窗口左上角图标
    WndClass.hInstance     = hInstance;                       // 定义窗口式样属于当前应用程序
    WndClass.lpfnWndProc   = WndProc;                         // 窗口消息处理函数
    WndClass.lpszClassName = STYLE_NAME;                      // 窗口样式名
    WndClass.lpszMenuName  = NULL;

    /* 将定义好的窗口式样注册到系统 */
    return RegisterClass(&WndClass);
}

HWND CreateMainWindow(HINSTANCE hInstance, wchar_t* title)
{
    HWND hwnd = NULL;

    hwnd = CreateWindow(STYLE_NAME,            // 通过定义好的窗口式样创建主窗口
                        title,                 // 主窗口标题
                        WS_OVERLAPPEDWINDOW,   // 创建后主窗口的显示风格
                        CW_USEDEFAULT,         // 主窗口左上角 x 坐标
                        CW_USEDEFAULT,         // 主窗口左上角 y 坐标
                        CW_USEDEFAULT,         // 主窗口宽度
                        CW_USEDEFAULT,         // 主窗口高度
                        NULL,                  // 父窗口
                        NULL,                  // 窗口菜单栏
                        hInstance,             // 主窗口属于当前应用程序
                        NULL);                 // 窗口参数

    return hwnd;

}

HWND DisplayMainWindow(HWND hWnd, int nCmdShow)
{
    ShowWindow(hWnd,nCmdShow); // 显示窗口
    UpdateWindow(hWnd);        // 刷新窗口

    return hWnd;
}

HWND CreateButton(HWND parent, int id, wchar_t* text)
{
    HINSTANCE hInstance = (HINSTANCE)GetWindowLong(parent, GWL_HINSTANCE);
    HWND hwnd = NULL;

    hwnd = CreateWindow(L"button",                               // 通过系统预定义式样创建窗口元素
                        text,                                    // 窗口元素标题
                        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // 窗口元素的显示风格
                        50,                                      // 窗口元素在窗口中的左上角 x 坐标
                        50,                                      // 窗口元素在窗口中的左上角 y 坐标
                        200,                                     // 窗口元素的宽度
                        60,                                      // 窗口元素的高度
                        parent,                                  // 窗口元素所在的父窗口
                        (HMENU)id,                               // 窗口元素 ID 值
                        hInstance,                               // 窗口元素属于当前应用程序
                        NULL);                                   // 窗口元素参数

	return hwnd;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_DESTROY)
    {
        App_Exit();
    }

    if (message == WM_COMMAND)
    {
        Button_Handler(LOWORD(wParam), HIWORD(wParam));
    }

    /* 调用系统提供的默认消息处理函数 */
    return DefWindowProc(hWnd, message, wParam, lParam);
}

3.3 基于面向对象的GUI程序开发实例

GUI用户界面是由固定的窗口元素所构成的:
在这里插入图片描述
对于操作系统来说:

  • 操作系统系统了创建用户界面元素所需要的函数。
  • 各种功能不同的函数依次调用,从而创建出界面元素。
  • 操作系统提供的原生函数无法直接映射到界面元素。

我们如何直观的将界面元素的概念直接映射到程序中呢?

面向对象的GUI程序设计:

  • GUI应用程序是为了解决非科学计算问题而诞生的。
  • GUI应用程序适用于非专业的日常生活领域。
  • 面向过程程序设计方法学不适合GUI程序设计。
  • 面向对象程序设计方法学更适合GUI程序设计。

我们用另一种眼界看GUI开发:

  • 用面向对象方法学看待GUI界面元素。
  • 所有的界面元素都可以看作实际的对象。
  • GUI用户界面是由各不相同的对象组成的。

比如:

  • 主窗口对象
    • 菜单对象
    • 按钮对象
    • 文本框对象

用面向对象的思想开发GUI应用程序,我们只需要考虑如下几个问题:

  • 主界面上有哪些界面元素?
  • 这些类都已经支持了吗?还是需要另外开发?
  • 需要的界面元素都对应哪些类?
  • 程序中需要几个对话框?

GUI开发非常适合采用面向对象方法学:

  • 将界面元素定义为对应的类。
  • 通过抽象和封装可以隐藏界面元素的细节。
  • 程序的创建过程就是组合不同界面元素对象的过程。
    在这里插入图片描述

接下来我们将上面基于面向过程的GUI程序修改为基于面向对象的GUI程序,但是未实现控件的消息映射部分。先看一下代码的组织结构:
在这里插入图片描述
Application:

// Application.h
 
#pragma once

#include <windows.h>

class Application
{
public:
    Application(HINSTANCE hInstance, LPSTR lpCmdLine);
    bool exec();
};

// Application.cpp

#include "Application.h"

Application::Application(HINSTANCE hInstance, LPSTR lpCmdLine)
{

}

bool Application::exec()
{
    MSG Msg = {0};

    /* 进入消息循环 */
    while( GetMessage(&Msg, NULL, NULL, NULL) )
    {
        /* 翻译并转换系统消息 */
        TranslateMessage(&Msg);
        /* 分发消息到对应的消息处理函数 */
        DispatchMessage(&Msg);
    }

    return TRUE;
}

Widget:

// Widget.h
#pragma once

#include <windows.h>

class Widget
{
protected:
    Widget* m_parent;
    HWND m_hwnd;
public:
    Widget();
    Widget(Widget* parent);
    HWND hwnd();
    Widget* parent();
};

// Widget.cpp

MainWindow:

// MainWindow.h:

#pragma once

#include "Widget.h"

class MainWindow : public Widget
{
protected:
    static const wchar_t STYLE_NAME[];

    /* 主窗口定义函数 */
    BOOL defineMainWindow(HINSTANCE hInstance);
    /* 主窗口创建函数 */
    void createMainWindow(HINSTANCE hInstance, const wchar_t* title);
    /* 主窗口消息处理函数 */
    static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
public:
    MainWindow(HINSTANCE hInstance, const wchar_t* title);
    void show();
};


// MainWindow.cpp:

#include "MainWindow.h"

const wchar_t MainWindow::STYLE_NAME[] = L"MainForm";

MainWindow::MainWindow(HINSTANCE hInstance, const wchar_t* title) : Widget(NULL)
{
    defineMainWindow(hInstance);

    createMainWindow(hInstance, title);
}

void MainWindow::show()
{
    ShowWindow(m_hwnd, SW_SHOWNORMAL); // 显示窗口
    UpdateWindow(m_hwnd);              // 刷新窗口
}

BOOL MainWindow::defineMainWindow(HINSTANCE hInstance)
{
    static WNDCLASS WndClass = {0}; // 系统结构体类型
                                    // 用于描述窗口样式
    WndClass.style         = 0;
    WndClass.cbClsExtra    = 0;
    WndClass.cbClsExtra    = 0;
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);          // 定义窗口背景色
    WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);     // 定义鼠标样式
    WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION); // 定义窗口左上角图标
    WndClass.hInstance     = hInstance;                       // 定义窗口式样属于当前应用程序
    WndClass.lpfnWndProc   = WndProc;                         // 窗口消息处理函数
    WndClass.lpszClassName = STYLE_NAME;                      // 窗口样式名
    WndClass.lpszMenuName  = NULL;

    /* 将定义好的窗口式样注册到系统 */
    return RegisterClass(&WndClass);
}

void MainWindow::createMainWindow(HINSTANCE hInstance, const wchar_t* title)
{
    m_hwnd = CreateWindow(STYLE_NAME,            // 通过定义好的窗口式样创建主窗口
                          title,                 // 主窗口标题
                          WS_OVERLAPPEDWINDOW,   // 创建后主窗口的显示风格
                          CW_USEDEFAULT,         // 主窗口左上角 x 坐标
                          CW_USEDEFAULT,         // 主窗口左上角 y 坐标
                          CW_USEDEFAULT,         // 主窗口宽度
                          CW_USEDEFAULT,         // 主窗口高度
                          NULL,                  // 父窗口
                          NULL,                  // 窗口菜单栏
                          hInstance,             // 主窗口属于当前应用程序
                          NULL);                 // 窗口参数
}

LRESULT CALLBACK MainWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    /* 调用系统提供的默认消息处理函数 */
    return DefWindowProc(hwnd, message, wParam, lParam);
}


PushButton:

// PushButt.h
#pragma once

#include "Widget.h"

class PushButton : public Widget
{
public:
    PushButton(Widget* win, const wchar_t* text);
};

// PushButt.cpp

#include "PushButton.h"

PushButton::PushButton(Widget* win, const wchar_t* text)
{
    HINSTANCE hInstance = (HINSTANCE)GetWindowLong(win->hwnd(), GWL_HINSTANCE);

    m_hwnd = CreateWindow(L"button",                               // 通过系统预定义式样创建窗口元素
                          text,                                    // 窗口元素标题
                          WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // 窗口元素的显示风格
                          50,                                      // 窗口元素在窗口中的左上角 x 坐标
                          50,                                      // 窗口元素在窗口中的左上角 y 坐标
                          200,                                     // 窗口元素的宽度
                          60,                                      // 窗口元素的高度
                          win->hwnd(),                             // 窗口元素所在的父窗口
                          (HMENU)this,                             // 窗口元素 ID 值
                          hInstance,                               // 窗口元素属于当前应用程序
                          NULL);                                   // 窗口元素参数
}

main

// main.cpp
#include <windows.h>
#include "Application.h"
#include "MainWindow.h"
#include "PushButton.h"

BOOL WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    Application a(hInstance, lpCmdLine);

    MainWindow w(hInstance, L"Main Window");

    PushButton b(&w, L"My Button");

    w.show();

    return a.exec();
}

3.4 QT的本质

对于QT:

  • QT是利用面向对象方法学开发的一套GUI组件库。
  • QT将不同操作系统的GUI细节封装于类的内部,具有跨平台的特性。
  • QT提供一套跨平台的类用于开发GUI程序。
  • QT遵循经典的GUI应用程序开发模式。
  • QT是一套跨平台的GUI开发库。
  • QT是一套C++集成开发环境。
  • QT是一套开源的殿堂级架构技术教程。

参考资料:

  1. QT实验分析教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值