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是一套开源的殿堂级架构技术教程。
参考资料: