这是一个关于GUI如何绘制,以及是怎么绘制的问题。
什么是GUI?
图形用户界面,英文为Graphical User Interface,简写为GUI。
众说纷纭,有人列举了许多实现GUI界面的类库,例如C 的QT、MFC,Python的Tkinter等。但是这些类库是如何显示的呢?归根结底,它们都是在计算机屏幕上显示信息,那么计算机是如何绘制屏幕的呢?
计算机是如何绘制屏幕的?
计算机把内存中的内容输出到屏幕上,这个操作叫渲染。现代计算机有一个专门的关键部分,用于完成渲染工作,它就是GPU(Graphics Processing Unit)。
我们在屏幕上看到的动画或视频,是单一的一帧一帧画面重复绘制的结果。每一帧渲染主要分为六步:
- 顶点着色器(Vertex Shader):顶点着色器主要的目的是把 3D 坐标转为另一种 3D 坐标。
- 形状装配(Shape Assembly):将所有的点装配成指定图元的形状。
- 几何着色器(Geometry Shader):把图元形式的一系列顶点的集合作为输入,通过产生新顶点构造出新的图元来生成其他形状。
- 光栅化(Rasterization):该阶段会把图元映射为最终屏幕上相应的像素。
- 片段着色器(Fragment Shader):对输入片段进行裁切(Clipping)。裁切会丢弃超出视图以外的所有像素,用来提升渲染效率。
- 测试与混合(Tests and Blending):该阶段还会检查
alpha
值。
完全理解这六个步骤稍微有点困难。大概可以这么理解:CPU送给GPU需要渲染的画面数据,是立体的,就像重叠的窗口一样,是一个立体、有重叠和覆盖性质的内容;GPU收到这些数据以后,先建点连线,构建3D图形,然后在屏幕上投影,将3D图形转化为2D图形,最后裁掉屏幕以外的部分,将像素绘制出来。
GPU本质上绘制的是像素。屏幕上每个像素可以看作是一个带颜色控制的小灯泡,GPU频繁控制这些灯泡的明灭暗淡,以此完成复杂的画面渲染。
程序是如何调用GPU的?
既然屏幕绘制工作是GPU完成的,那么在系统里,软件是如何调用GPU的呢?
无论是什么系统,软件是不能直接控制GPU的。软件向系统发出控制请求,系统通过设备驱动控制特定的计算机设备。驱动全称是设备驱动程序,是添加到操作系统中的特殊程序。驱动中包含有关硬件设备信息,以及设备控制指令。厂商生产了硬件设备,只有厂商自己发布的设备驱动才知道如何控制设备。
计算机或其它程序软件没有办法直接控制某个驱动,只有设备驱动可以。驱动在计算机中的地位,就好比归附的山寨军队的山大王。要指挥山寨,必须通过山大王发号施令,直接安排是不好使的。
图源:snappygoat.com
Windows、Mac和Linux,是最常见的操作系统。这些系统的实现是有差异的,显卡之间也有差异,如何消减软件间接调用GPU的差异呢?为此程序员发明了OpenGL。
图源:www.kissclipart.com
OpenGL是Open Computer Graphics的简写,是图形学研究人员和程序员以图形学的渲染理论为基础,实现的底层图形算法库。OpenGL封装了不同操作和不同显式驱动之间的差异,让不同软件可以使用一套统一的接口控制屏幕绘制。用稍为正式语句表达,OpenGL是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API),由近350个不同的函数组成。这些函数并不是天生被支持的,OpenGL对显卡的支持是依赖于版本更新。OpenGL像一个适配的插头,处在软件和系统之间。
OpenGL作为一个开放图形库,并不是唯一的。微软的DirectX与它具有相似的功能。
编程语言如何绘制界面?
在屏幕上绘制图形和文本的原理是相同的,本质上计算机没有文本,文本也是一个个字符编码对应的字符图像。计算机绘制文本,是拿字符编码先在字体库中找到对应的矢量图形或位图图形,再将图形绘制到屏幕上。
编程语言在屏幕上完成绘制,很少有直接调用显卡驱动的,一般都是通过一个通用的图形类库,间接调用一个或几个图形驱动库(OpenGL或DirectX)完成的。不同语言有不同的图形类库。
1,C 语言
Filament:https://github.com/google/filament
Filament是谷歌推出的,开源的,一个实时的基于物理的渲染引擎,适用于Android, iOS, Linux, macOS, Windows和WebGL(浏览器)。它被设计得尽可能小,在Android上尽可能高效。Filament底层引用了OpenGL。
下面它的渲染效果:
图源:https://github.com/google/filament
CEF:https://github.com/chromiumembedded/cef
CEF是Chromium Embedded Framework的简写,它可以将一个浏览器内核嵌入到软件中。
2,C语言
Glfw:https://github.com/glfw/glfw
GLFW是一个开源的,跨平台GUI类库。它提供了简单的方法,用于创建窗口、读取输入、处理事件等。
3,Java语言
Gephi:https://github.com/gephi/gephi
Gephi是一个用于可视化和处理大型图形的开源平台,它可以在Windows、Mac OS X和Linux上运行。
图源:https://github.com/gephi/gephi
4,Go语言
G3N:https://github.com/g3n/engine
G3N是一个用Go语言编写的跨平台的OpenGL 3D游戏引擎。
但是这些类库太过庞大复杂,对于我们创建简单的UI界面没有实质性的帮助。我们需要使用UI组件库,帮助我们创建常见的UI,例如一个按钮,一个下拉框,一个窗体等。
有哪些UI组件库可以直接使用?
1,C语言
Nuklear ⭐️⭐️⭐️
https://github.com/vurtun/nuklear
2,Go语言
https://github.com/therecipe/qt:Go语言版本的QT类库。
3,Python语言
Tkinter: Tkinter 模块是 Python 的标准 Tk GUI 工具包的接口。Tkinter的窗体及按钮效果:
图源:https://www.runoob.com/
wxPython
wxPython 是一款开源软件,是 Python 语言的一套优秀的 GUI 图形库。
PySimpleGUI ⭐️⭐️⭐️
https://github.com/PySimpleGUI/PySimpleGUI
代码:
代码语言:javascript复制import PySimpleGUI as sg # Part 1 - The import
# Define the window's contents
layout = [ [sg.Text("What's your name?")], # Part 2 - The Layout
[sg.Input()],
[sg.Button('Ok')] ]
# Create the window
window = sg.Window('Window Title', layout) # Part 3 - Window Defintion
# Display and interact with the Window
event, values = window.read() # Part 4 - Event loop or Window.read call
# Do something with the information gathered
print('Hello', values[0], "! Thanks for trying PySimpleGUI")
# Finish up by removing from the screen
window.close() # Part 5 - Close the Window
效果:
4,.Net(C#、VB等)
https://dotnet.microsoft.com/apps/aspnet
微软自搞了一套同时支持窗体、HTML页面、终端应用开发的.Net框架。使用VS可以实现拖拉式UI编程。
5,C 语言
Elements C GUI library ⭐️⭐️⭐️
https://github.com/cycfi/elements
ImGui
https://github.com/ocornut/imgui
代码:
代码语言:javascript复制ImGui::Text("Hello, world %d", 123);
if (ImGui::Button("Save"))
MySaveFunction();
ImGui::InputText("string", buf, IM_ARRAYSIZE(buf));
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
效果:
6,JavaScript & Html & CSS3
浏览器在系统中是一类特殊的软件,因为它依赖于浏览器引擎,可以解析执行js & html代码。有三个主流的UI类库,可以帮助我们在浏览器宿主环境中开发界面:
- React:https://zh-hans.reactjs.org/
- Vue:https://cn.vuejs.org/v2/guide/
- Bootstrap:https://www.bootcss.com/
- ElementUI:http://element.eleme.io/
7,微信小程序⭐️⭐️⭐️
https://developers.weixin.qq.com/miniprogram/dev/component/
微信小程序本质是基于浏览器内核渲染的,它的WXML标签是微信团队自创的。在微信小程序中,主要使用js语言。官方文档上提供了完备的组件及API,实现常见UI功能都比较容易。
除了官方组件,微信团队还提供了一个WeUI扩展组件库。
结论
最后总结一下,在计算机中,CPU负责计算,渲染是通过GPU完成的,操作系统(Mac、Windows and Linux)通过OpenGL或DirectX底层图形库实现对GPU的控制。不同编程语言,通过对OpenGL等底层图形库的封装,都有一些具体的图形引擎库,一般这些引擎库也是游戏引擎库。与此同时,为了方便业务应用开发,不同编程语言也实现了不同的UI组件库,默认实现了像按钮、下拉框、窗体等控件,可以直接使用。
浏览器是一类特殊的系统软件,它可以解析执行js、html标签代码。通过html、css3、js可以快速开发出好看易用的页面。也有UI组件库可以帮助程序员更快地完成开发。微信小程序与之类似。
如果程序员想以代码的形式开发GUI界面,依据语言不同,有不同的选择:
- 如果是C语言,适合用Nuklear
- 如果是C 语言,适合用Elements C GUI library
- 如果是Go语言,适合用therecipe/qt
- 如果是Python,适合用Tkinter
- 如果是JS,用Vue Bootstrap ElementUI最为简单
- 如果是小程序,用官方组件 WeUI组件
- 如果是C#,直接用.Net Framework就可以了
但是,每个语言都有自己擅长做的事情,后端语言写UI一般都是不太合适的。像Python语言,适合做数据抓取、分析,UI并非其长项;像Go语言,适合开发高并发、高吞吐的后端数据应用,UI并非其长项;像C语言,当下适合做嵌入式、物联网开发,UI也并非其长项;像C 语言,传统类库丰富,适合维护旧系统老软件,直接写UI也并非其长项,C 写界面必须依据业务需求基于某个成熟的UI组件库完成。
当下写PC软件,一种流行的做法是基于Electron框架开发。Electron是一个浏览器框架,可以将浏览器嵌入到软件中,使用Html & CSS3 & JS这些成熟的页面技术开发UI界面,同时也可以调用系统资源,做一些js不能做的事情。
学习反馈要及时,初学者学习编程,以前最好的入门语言是AS3,现在最好的入门技术是微信小程序。微信小程序的主要编程语言是js,有完整的UI组件,和丰富的平台接口,入门门槛低,非常合适初学者入门学习。
但是js这门语言太过简单,单线程,不涉及线程问题、内存问题等复杂问题。在学习微信小程序开发的同时,最好同时学一门后端语言,Go语言是最好的选择。
开发GUI应用,最方便的是使用前端技术(Vue、React或微信小程序都可以)。依赖CSS3丰富的表现能力,加上热加载技术,UI修改及时呈现,特别方便程序员开发出漂亮的UI界面。
---
我讲明白没有,欢迎留言讨论。