在软件开发过程中,与用户的交互是不可或缺的一部分。无论是直接的图形用户界面(GUI)还是间接的命令行界面(CLI),都需要程序员投入大量的时间和精力去实现。本文介绍一种通过抽象类简化用户界面编程的方法,这种方法不仅可以减少程序员的工作量,还可以提供多种用户界面实现方式,包括文本基础和图形用户界面等。
几乎每个程序都需要某种方式与用户进行通信。那些不需要与用户通信的程序(如驱动程序、系统进程等)仍然可以从与开发人员通信中受益,这使得调试过程变得更加容易。实现这些功能通常需要程序员特别注意,从而导致繁琐且耗时的工作。
但是,这种工作量可以大大减少。毕竟,用户所做的唯一事情就是改变变量和调用函数。因此,一个最优的解决方案就是告诉机器哪些变量和函数需要对用户公开(发布)。然后,与用户的通信可以导出到其他标准一次性实现的代码中,从而节省了程序员的工作。换句话说,程序员只需要坚持使用基础设施定义的(非常少的)函数,而不必担心用户界面的实现。
这种方法还允许用户界面的不同实现,提供了极大的灵活性。这些实现不仅可以在基于文本和图形之间变化,还可以在用户提示、配置文件、命令行开关、网络协议等之间变化。
本文介绍的基础设施基于一个名为ui_export
的抽象类。任何想要向用户发布一些成员变量的类都需要继承这个类。通过这样做,它需要实现addoptions
函数。addoptions
的实现应该只包含对postoption
函数的调用,该函数也是从ui_export
继承的。
每个要发布的选项都需要在addoptions
中调用postoption
函数。它有14种不同的实现,允许发布不同类型的数据和函数。
以下示例说明了上述函数的调用方式:
class car : public ui_export {
...
class engine eng;
void start() {};
int weight;
bool _lights;
bool getlights() {
return (_lights);
}
void setlights(bool par) {_lights=par; repaint();}
...
void addoptions() {
postoption("eng", "manipulate the engine object", ŋ);
postoption("start", "start the car", this, &car::start);
postoption("weight", "weight of the car in kg", &weight);
postoption("lights", "headlights of the car", this, &car::getlights, &car::setlights);
}
};
完成这些后,类就可以被用户界面使用了。
随代码提供的这个用户界面是基于文本的。它只使用C++标准库,这使得它与平台无关。由于基础设施的面向类方法,它具有菜单驱动的感觉。
用户界面的基础是一个名为user_interface
的类。要使用它,需要创建该类的实例。作为ui_export
的子类,user_interface
实现了所有的postoption
函数。这些函数用于初始化用户界面。operator()
函数启动用户界面。
user_interface ui;
ui.postoption("o", "manipulate obj", &obj);
ui.postoption(...);
...
ui();
就是这样。
以下是'Demo1YourApp.cpp'的简化版本。它展示了使用用户界面的简单程序的样子:
#include "UI.hpp"
class yourClass : public ui_export {
public:
bool b;
int i;
void addoptions() {
postoption("b", "mess with a boolean", &b);
postoption("i", "mess with an integer", &i);
}
};
int main(int argc, char* argv) {
yourClass c;
user_interface ui;
ui.postoption("yourClass", "mess around with yourClass", &c);
ui();
}
用户界面有一个简单的“保存状态”机制。它可以用于初始化应用程序,但不适合实际保存复杂应用程序的状态(启动需要很长时间)。当用户界面退出时,它会询问用户是(Q)退出(不保存)还是(S)保存(并退出)。
它的工作原理是简单地记住所有用户输入并将其保存在文件中。在启动时,用户界面打开文件(默认文件名为'input')并执行之前保存的所有输入。可以通过用户界面对象访问加载和保存文件的文件名:
ui.loadfilename = "init";
ui.savefilename = "save";
保存文件的名称也可以在用户界面执行期间更改。这是通过默认发布的SaveFile
选项完成的。
还可以手动编辑包含已保存输入的保存文件。
与基础设施概念相关的另一个真正的好处是,像C++标准库这样的通用库可以预先发布为UI-capable。这再次减少了程序员的工作量,并确保了不同程序的统一行为,这对用户来说是很好的。
已经开始了。文件stdUI.hpp
旨在构建UI-capable类,这些类沿着C++标准库类在命名空间stdUI
中。以下类已经可用:
非基本版本也是可用的。
优点: