《C++程序设计原理与实践》笔记 第12章 一个显示模型

news2024/11/18 8:30:45

本章介绍了一个显示模型(display model)(GUI的输出部分),并给出了使用示例和基本概念,例如屏幕坐标、线和颜色等。

12.1 为什么需要图形?

我们为什么用四章的篇幅介绍图形以及一章介绍GUI?

  • 图形很有用。例如,科学计算、数据分析需要数据图形化。
  • 图形很有趣。一段代码的效果能够立刻呈现出来。
  • 图形提供了许多有趣的代码来阅读。学习编程的一部分是阅读大量代码,寻找好代码的感觉。
  • 图形的设计实例非常丰富。图形领域有非常丰富的设计决策和设计技术的具体、实际的例子。
  • 图形有利于解释面向对象程序设计(object-oriented programming)的概念和语言特性。图形提供了一些非常易于理解的面向对象设计实例。
  • 一些关键的图形学概念并不是简单直白的。

12.2 一个显示模型

iostream库是面向字符的输入/输出流。本章和之后的四章介绍另外一种技术:图形(graphics)和图形用户界面(graphical user interface, GUI),可以直接显示在计算机屏幕上。图形包括点、线、矩形、圆等形状(shape),GUI包括窗口、按钮、输入框等构件(widget)。

基本模型如下:我们利用图形库提供的基本图形(例如线)组合出更复杂的图形(例如多边形);之后将这些图形对象附加(attach)到一个表示物理屏幕的窗口对象;最后,显示引擎(图形库/GUI库)在屏幕上绘制这些图形。

显示模型

12.3 第一个例子

下面的程序在屏幕上绘制一个三角形:

绘制三角形

运行结果如下:

draw_triangle

下面逐行分析这个程序。首先包含(作者提供的)图形库头文件:

#include "Graph.h"          // get access to our graphics library facilities
#include "Simple_window.h"  // get access to our window library

接着,告诉编译器图形相关的类在命名空间Graph_lib中:

using namespace Graph_lib;  // our graphics facilities are in Graph_lib

然后,在main()中创建一个窗口win

Point tl(100, 100);             // to become top left corner of window
Simple_window win(tl, 600, 400, "Canvas");  // make a simple window

其中,tl表示窗口左上角在屏幕上的坐标,宽度和高度分别为600和400像素,字符串 “Canvas” 将显示在窗口左上角的标题栏。

接下来,创建一个多边形对象poly,并添加三个点,从而得到一个三角形:

Graph_lib::Polygon poly;        // make a shape (a polygon)

poly.add(Point(300, 200));      // add a point
poly.add(Point(350, 100));      // add another point
poly.add(Point(400, 200));      // add a third point

这里的点表示的是窗口内的坐标。

之后将三角形的边设置为红色(纯粹是为了展示):

poly.set_color(Color::red);     // adjust properties of poly

最后,将poly附加到窗口win

win.attach(poly);               // connect poly to the window

只有这样图形才会被绘制出来。程序的最后一行

win.wait_for_button();          // give control to the display engine

wait_for_button()将控制权交给GUI系统,并告诉GUI系统将窗口显示出来(同时绘制附加到该窗口的图形)。之后,将会等待用户点击(Simple_window自带的) “Next” 按钮。当点击该按钮后,程序将终止并关闭窗口。

操作系统会为每个窗口添加标题栏/窗口框(frame),因此你“免费”得到了右上角的三个按钮。

12.4 使用GUI库

要编写GUI程序,必须使用GUI库(用于调用操作系统的底层接口来绘制窗口和图形)。然而,C++并没有提供标准GUI库,因此作者从很多可用的C++ GUI库中选择了一个。

本书使用的GUI库叫做FLTK(Fast Light Toolkit,读作 “fulltick”),可以从fltk.org下载。我们的代码可以移植到任何使用FLTK的平台(Windows、Linux、macOS等)。

书中的代码不是直接使用FLTK,而是使用了作者提供的GUI库。这个GUI库是在FLTK的基础上又封装了一层,提供了形状和GUI构件的接口类(如无特殊说明,后面提到“GUI库”就是指作者提供的这个GUI库)。

源代码可以从作者网站上下载:https://www.stroustrup.com/Programming/code.tar

注:代码中存在几处编译错误,需要如下需要修改

  • Window.h:开头增加两个#include和两个using声明:
#include <string>
#include <vector>
// ...

using std::string;
using std::vector;
// ...
  • Simple_window.h:struct Simple_window : Window改为struct Simple_window : Graph_lib::Window
  • Graph.h:Vector_ref(const Vector<T>&);Vector_ref& operator=(const Vector<T>&);中的Vector改为Vector_ref

该GUI库由5个头文件和4个源文件组成:

  • 头文件
    • Point.h
    • Window.h
    • Simple_window.h
    • Graph.h
    • GUI.h
  • 源文件
    • Window.cpp
    • Simple_window.cpp
    • Graph.cpp
    • GUI.cpp

GUI库头文件

其中,Window.h、Simple_window.h和GUI.h提供了WindowSimple_windowButton等GUI构件:

GUI库窗口和构件类

Graph.h提供了形状类Shape以及LineRectangleCircle等子类:

GUI库图形类

12.8 让程序运行起来

注:和第6章一样,本章中作者又是到最后一节才讲如何让程序运行起来(正文中也没有详细讲,只提到了附录D,附录中也只介绍了使用Visual Studio一种方法)。实际上对于初学者来说这是最困难的部分。在不同操作系统上、使用不同构建工具的构建方式也各不相同,但基本上包括以下步骤:

  • 编译FLTK源代码,生成库文件
  • 编译GUI库源代码,生成库文件
  • 编译我们自己的源代码,并链接到GUI库和FLTK库,生成可执行文件

下面详细介绍使用Make和CMake两种构建方法。

12.8.1 使用Make

12.8.1.1 安装FLTK

本节在Ubuntu系统上使用Make命令编译FLTK库。

首先从 https://www.fltk.org/software.php 下载FLTK源代码(例如fltk-1.3.8-source.tar.gz),解压后执行以下命令:

cd fltk-1.3.8/
./configure --prefix=/usr/local
make
sudo make install
sudo ldconfig

其中,configure命令用于生成构建配置文件,--prefix选项指定安装路径,头文件将被拷贝到$prefix/include目录,库文件将被拷贝到$prefix/lib目录。如果报错 “Configure could not find required X11 libraries, aborting” 则需要先安装X11:

sudo apt-get install libx11-dev

make命令将源代码编译为库文件,生成在fltk-1.3.8/lib目录;make install命令将头文件、库文件、fltk-config可执行文件等拷贝到--prefix选项指定的目录下(这里是/usr/local):

$ cd /usr/local
$ ls bin/
fltk-config  fluid  ...

$ ls include/
FL  ...

$ ls lib/
lib/libfltk.a        lib/libfltk_images.a  lib/libfltk_png.a
lib/libfltk_forms.a  lib/libfltk_jpeg.a    lib/libfltk_z.a
...

其中,fltk-config是一个辅助程序,可以自动生成编译和链接选项,从而不必手动编写复杂的命令:

$ fltk-config --cxx
g++

$ fltk-config --cxxflags
-I/usr/local/include -I/usr/local/include/FL/images -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_THREAD_SAFE -D_REENTRANT

$ fltk-config --ldflags
-L/usr/local/lib -lfltk -lpthread -ldl -lm -lX11

例如,下面是FLTK官方文档Writing Your First FLTK Program中的Hello World程序:

#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Window.H>

int main(int argc, char* argv[]) {
    Fl_Window* window = new Fl_Window(340, 180);
    Fl_Box* box = new Fl_Box(20, 40, 300, 100, "Hello, World!");
    box->box(FL_UP_BOX);
    box->labelfont(FL_BOLD_ITALIC);
    box->labelsize(36);
    box->labeltype(FL_SHADOW_LABEL);
    window->end();
    window->show(argc, argv);
    return Fl::run();
}

可以使用以下命令编译该程序:

g++ `fltk-config --cxxflags` -o hello_fltk hello_fltk.cpp `fltk-config --ldflags`

该命令等价于

g++ -I/usr/local/include -I/usr/local/include/FL/images -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_THREAD_SAFE -D_REENTRANT -o hello_fltk hello_fltk.cpp -L/usr/local/lib -lfltk -lpthread -ldl -lm -lX11

运行结果如下:

hello_fltk

另外,fltk-config还提供了一个更简便的命令:

fltk-config --compile hello_fltk.cpp

该命令自动将编译选项和链接选项组合成一个编译命令并执行,和上面的编译命令也是等价的。

注:由于/usr/local/include和/usr/local/lib在默认的头文件和库文件搜索路径列表中,因此可以省略编译命令中的-I-L选项,从而简化为

g++ -o hello_fltk hello_fltk.cpp -lfltk -lpthread -ldl -lm -lX11

要卸载FLTK,在fltk-1.3.8目录下执行

sudo make uninstall

参考:

  • FLTK官方文档 Building and Installing FLTK Under UNIX and Apple OS X

12.8.1.2 编译GUI库

安装好FLTK后,下面将作者提供的GUI库源代码编译为库文件。

首先下载源代码code.tar,解压出GUI目录。由于作者提供的源代码中已经包含了Makefile,因此直接在GUI目录下执行make命令,即可构建出库文件libbookgui.a,与源代码在同一个目录下。

12.8.1.3 编译自己的程序代码

假设12.3节中的程序保存在ch12/draw_triangle.cpp,目录ch12与GUI在同级目录下:

PPP-code/
    GUI/
        Window.h
        Graph.h
        ...
        libbookgui.a
    ch12/
        draw_triangle.cpp

则在ch12目录中执行以下命令:

g++ -I../GUI -o draw_triangle draw_triangle.cpp -L../GUI -lbookgui `fltk-config --ldflags --use-images`

即可得到可执行文件draw_triangle。其中,-I../GUI选项告诉编译器GUI头文件的搜索路径,从而#include "Graph.h"能够找到GUI目录下的Graph.h;-L../GUI选项告诉链接器GUI库文件的搜索路径,从而-lbookgui能够找到GUI目录下的libbookgui.a;fltk-config --ldflags --use-images将自动生成需要链接的FLTK库。

运行结果如下:

draw_triangle

12.8.2 使用CMake

CMake是一个开源的、跨平台的C++构建工具,新版本的FLTK已经支持CMake构建。与Make相比,使用CMake构建具有以下优点:

  • 简单,不需要手动编写复杂的编译命令
  • 不需要手动安装FLTK,使用CMake的FetchContent模块可以自动下载并构建FLTK库
  • CMake是跨平台的,因此在Windows、Linux和macOS系统上都适用
  • 不仅可以在命令行使用,任何支持CMake的IDE(例如CLion、Visual Studio等)都适用

CMake使用名为CMakeLists.txt的文件声明构建目标。在项目根目录、GUI目录和ch12目录下分别创建一个CMakeLists.txt文件:

PPP-code/
    CMakeLists.txt
    GUI/
        CMakeLists.txt
        Window.h
        Graph.h
        ...
    ch12/
        CMakeLists.txt
        draw_triangle.cpp

根目录下的CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.20)
project(PPP_code)

set(CMAKE_CXX_STANDARD 14)

include(FetchContent)
set(FLTK_BUILD_TEST OFF CACHE BOOL " " FORCE)
FetchContent_Declare(
  fltk
  GIT_REPOSITORY https://github.com/fltk/fltk.git
  GIT_TAG release-1.3.8
)
FetchContent_MakeAvailable(fltk)

add_subdirectory(GUI)
add_subdirectory(ch12)

其中,FetchContent_Declare()命令声明了fltk库及其Git仓库地址,FetchContent_MakeAvailable()将自动下载fltk库的源代码。

GUI/CMakeLists.txt内容如下:

file(GLOB SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
add_library(GUI ${SOURCES})
target_link_libraries(GUI fltk fltk_images)
target_include_directories(GUI PUBLIC ${fltk_SOURCE_DIR} ${fltk_BINARY_DIR})
target_include_directories(GUI INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

这里声明了一个库文件GUI,并链接到fltk和fltk_images库。

ch12/CMakeLists.txt内容如下:

add_executable(draw_triangle draw_triangle.cpp)
target_link_libraries(draw_triangle GUI)

这里声明了一个可执行文件draw_triangle,并链接到GUI库(CMake会自动处理传递依赖,并将其链接到fltk库)。

在项目根目录下执行以下命令:

cmake -G "Unix Makefiles" -B cmake-build
cmake --build cmake-build --target draw_triangle

初次构建时CMake将自动下载并构建FLTK库,构建完成后即可得到可执行文件cmake-build/ch12/draw_triangle,运行可得到与上面同样的效果。

注:这里给出的方法就是我自己的代码仓库PPP-code使用的方法。

参考:

  • README.CMake.txt
  • Using CMake to build an FLTK application
  • Provide easier instructions for modern CMake

12.8.3 使用Visual Studio

参考:

  • FLTK官方文档 Building FLTK Under Microsoft Windows
  • Install FLTK for use with Visual C++

12.5 坐标系

计算机屏幕是由像素(pixel)组成的矩形区域。像素是一个可以设置为某种颜色的点。在程序中最常见的建模屏幕的方式是由像素组成的矩形,每个像素由x(水平)坐标和y(垂直)坐标确定,屏幕左上角是坐标原点,如下图所示。

屏幕坐标系

与数学上的坐标系不同的是,y坐标是向下增长的。

在GUI程序中,窗口(window)是从屏幕中划分出的由程序控制的矩形区域。可以将窗口看作一个小屏幕(窗口内的坐标系建模方式屏幕相同)。例如:

Simple_window win(tl, 600, 400, "Canvas");

创建了一个宽600像素、高400像素的窗口(不包括标题栏),从而窗口内的x坐标从左到右为0~599,y坐标从上到下为0~399。能够进行绘制的窗口区域通常称为画布(canvas)。

12.6 形状

GUI库的头文件Graph.h定义了一组形状类,见12.4节。

12.7 使用形状类

本节介绍GUI库的一些基本特性:Simple_window, Window, Shape, Text, Polygon, Line, Lines, Rectangle, Color, Line_style, Point, Axis,目的是让你对这些特性有一个全面的了解,而不是详细理解某个类。下一章将会介绍每个类的设计。

12.7.1 图形头文件和main函数

首先需要包含GUI库的头文件:

#include "Graph.h"
#include "Window.h"

或者

#include "Graph.h"
#include "Simple_window.h"

Window.h包含于窗口有关的特性,Graph.h包含在窗口上绘制形状(包括文本)有关的特性。这些特性都定义在Graph_lib命名空间中。为了简单起见,使用using指令使得程序可以直接使用Graph_lib中的名字:

using namespace Graph_lib;

12.7.2 一个几乎空白的窗口

12.7.3 坐标轴

12.7.4 绘制函数图像

12.7.5 多边形

12.7.6 矩形

12.7.7 填充

12.7.8 文本

12.7.9 图片

12.7.10 还有很多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/192111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通信原理笔记—基带信号的波形设计与编码

目录 引言&#xff1a; 基带传输系统的基本模型&#xff1a; 基带信号的波形设计与编码&#xff1a; 数字信号的波形设计原则&#xff1a; 基带信号的基本波形&#xff1a; 常用的二进制码型&#xff1a; 单极性不归零码&#xff1a; 双极性不归零码&#xff1a; ​编辑…

RTI Connext DDS代码生成器

0 简介RTI代码生成器Code Generator,创建用RTI ConnextDDS定义define和注册register用户数据类型所需的代码。在以下情况下&#xff0c;使用代码生成器是可选的&#xff1a;您正在使用动态类型&#xff08;请参阅RTI Connext DDS核心库用户手册[RTI ConnextDDS Core Libraries …

新来一个卷王,天天加班到12点,太让人崩溃......

在程序员职场上&#xff0c;什么样的人最让人反感呢&#xff1f; 是技术不好的人吗&#xff1f;并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗&#xff1f;也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反…

2023全网汇总PMP备考攻略(附答题技巧资料)

一&#xff0c;多复习和学习新版考纲 01《PMBOK》看三遍 这边建议看三遍《PMBOK》&#xff0c;更有利于我们巩固知识&#xff0c;查缺补漏。 第一遍 第一遍是老师带着我们去看。这个时候一定要非常专心&#xff0c;千万不要上课走神或者玩手机。因为这一遍老师会告诉我们&a…

结构型设计模式 Structural Patterns :适配器 Adapter(C++ 实现)

文章大纲 适配器简介对象适配器类适配器C++ 实现代码参考文献与学习路径Structural PatternsAdapterMatch interfaces of different classesBridgeSeparates an object’s interface from its implementationCompositeA tree structure of simple and composite objectsDecorat…

C#中的那些警告如何去除?完全去除C#警告

一般在c中没有使用的变量会有警告&#xff0c;C#中也有&#xff0c;在QT中我们利用Q_UNSED可以直接消除这些警告&#xff0c;那么我们在C#中该如何做才能消除这些不必要的警告呢&#xff1f;经过查询微软官方网站发现&#xff0c;有的找到了解决方法&#xff0c;有的仍然一筹莫…

学习bootstrap怎么样?

想必学习前端的都知道这个响应式框架&#xff0c;之前我接触这个框架的时候是在学习前段页面设计的进阶教程是接触的&#xff0c;那个时候要做那种登陆注册界面&#xff0c;里面的输入框很让人头疼有时候电脑的宽度不一样或者是写了一个精美的网页然后放到手机上的时候就变了模…

【C++】继承(基类和派生类的关系、菱形虚拟继承、继承和组合)

文章目录1、继承的概念和定义2、基类和派生类的赋值转换3、继承中的作用域4、派生类的默认成员函数5、继承与友元和静态成员6、复杂的菱形继承及菱形虚拟继承7、继承和组合1、继承的概念和定义 继承是面向对象程序设计上程序复用的重要手段&#xff0c;以往接触的复用都是函数复…

程序员的自律之路

世界的精彩不是单纯的美丽&#xff0c;毕竟丑恶也是美丽的食粮&#xff0c;黑暗也是光明的救世主 很久没有写博客了&#xff0c;最近半年不太稳定&#xff0c;也经历了一些自我成长的东西。 事后我进行深度反省&#xff0c;思考一个人或者说是一个程序员的失控原因到底是什么&a…

推荐几款好用的企业级文档管理软件

知识库&#xff0c;又称为智能数据库或人工智能数据库。知识库的概念来自两个不同的领域&#xff0c;一个是人工智能及其分支-知识工程领域&#xff0c;另一个是传统的数据库领域。由人工智能&#xff08;AI&#xff09;和数据库&#xff08;DB&#xff09;两项计算机技术的有机…

Java字符串查找(3种方法)

在给定的字符串中查找字符或字符串是比较常见的操作。字符串查找分为两种形式&#xff1a;一种是在字符串中获取匹配字符&#xff08;串&#xff09;的索引值&#xff0c;另一种是在字符串中获取指定索引位置的字符。根据字符查找String 类的 indexOf() 方法和 lastlndexOf() 方…

金融公司在 2022 年扩大了对下一代技术的投资

根据 Broadridge Financial Solutions, Inc. 的一份新报告&#xff0c;大多数金融服务公司现在认为数字化转型对其业务至关重要&#xff0c;并且已经在寻求下一波技术来帮助取得成功。 在对 500 名最高管理层高管及其在全球买方和卖方的直接下属进行的 2023 年数字化转型和下…

代码随想录算法训练营第五十七天_第九章_动态规划 | 1143.最长公共子序列、1035.不相交的线、53. 最大子数组和 动态规划

LeetCode 1143.最长公共子序列 视频讲解https://www.bilibili.com/video/BV1ye4y1L7CQ文章讲解https://programmercarl.com/1143.%E6%9C%80%E9%95%BF%E5%85%AC%E5%85%B1%E5%AD%90%E5%BA%8F%E5%88%97.html 思路&#xff1a;代码&#xff1a;LeetCode 1035.不相交的线 视频讲解h…

技术开发119

技术开发119 业务内容&#xff1a; 汽车零部件的制造产业用机械零部件的设计、制造、组装电机零部件的制造 公司简介&#xff1a; 董事长&#xff1a;管原胜安 资本金&#xff1a;3200万日元 员工数&#xff1a;36名 成立时间&#xff1a;1972年7月 资格认证&#xff1a…

【学习笔记】coursera | Computational Neuroscience | Week 1

Course Introduction 1.1 Course Introduction 三种模型 Descriptive models of the brain&#xff08;描述型, what&#xff09;&#xff1a;神经元如何对外部刺激做出反应&#xff1f;用神经元编码模型如何量化描述&#xff1f;如何从神经元中获取信息&#xff08;解码&am…

Linux 中 su 命令的使用

目录 &#x1f34d;①普通用户切换 root 用户 &#x1f349;②root 用户切换普通用户 su 命令的作用是在 Linux 中切换用户&#xff0c;是英文单词&#xff1a;Switch&#xff08;切换&#xff09; User&#xff08;用户&#xff09; 的缩写。 语法&#xff1a; su [-] 用户…

三维引擎大盘点

近年&#xff0c;智慧城市、数字孪生大热&#xff0c;三维引擎就成为了绕不过去的一个词&#xff0c;但是目前市场的的三维引擎多的让人头晕目眩&#xff0c;他们各自都有哪些优缺点呢&#xff0c;今天我们就来盘点下主流的三维引擎。 常见的三维引擎按平台可分为客户端三维引擎…

1613_PC汇编语言_位操作

全部学习汇总&#xff1a; GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 这一次看一下位操作的章节。 如果是逻辑位操作其实不需要考虑大小端。 1. 移位操作在快速乘除法中经常用到。 2. 这里提到了一个算是移位&#xff0c;其实跟前面的…

Hive(4):场景案例:Apache Hive初体验

1 体验1&#xff1a;Hive使用起来和Mysql差不多吗&#xff1f; 1.1 背景 对于初次接触Apache Hive的人来说&#xff0c;最大的疑惑就是&#xff1a;Hive从数据模型看起来和关系型数据库mysql等好像。包括Hive SQL也是一种类SQL语言。那么实际使用起来如何&#xff1f; 1.2 过…

激光投影仪哪款好?坚果N1 Pro和海信Vidda C1和当贝X3测评

当贝x3、坚果N1Pro和海信Vidda C1都是近期比较热门的激光投影仪,作为消费者来说选择哪一款比较好呢?看看实测对比和参数对比就知道它们的区别了。(一)三款激光投影仪的实测对比1)外观对比:坚果N1 Pro枪灰加深灰的色彩组合,自带了一个云台,能够支持任意角度调整,但比普通的投影…