FLTK学习笔记3-随机点名器


前面学习了基本控件以及回调函数的创建,在这里我们利用之前的知识编写一个随机点名程序。

随机点名程序应当有一个显示文本的控件用来显示被点到的人,这里我们用Fl_Input控件;还应该有一个按钮,点击后开始随机显示人名,再点击一下停止更新人名,这里我们用Fl_Button控件。

所需知识

C++ 随机数

随机点名需要产生随机数来代表被点到的人。关于C++随机数可以参考这里。本文中用以下方式产生随机数:

std::mt19937_64 engine(2020);									/* 定义随机数引擎,种子为2020 */
std::uniform_int_distribution<> udist(min_number, max_number);	/* 创建均匀分布 */
int random_number = udist(engine);								/* 产生随机数 */

FLTK中自动重复执行指令

在FLTK中可以通过Fl::add_timeoutFl::repeat_timeout来实现自动重复执行指令。

Fl::add_timeout的作用是添加运行一次的回调函数,其函数原型如下,具体说明见官方文档

void Fl::add_timeout (double t, Fl_Timeout_Handler cb, void* argp=0); 	

这里的t代表每t秒触发一次,cb是要重复执行的回调函数。

Fl::repeat_timeout的作用是重复运行回调函数,其函数原型如下,具体说明见官方文档

void Fl::repeat_timeout (double t, Fl_Timeout_Handler cb, void* argp=0); 	

这里的tcb含义与上面一样。

因此,可以用如下代码实现自动重复执行指令:

void repeat_cb(Fl_Widget* pw, void* pv){
    
    
	/* some codes */
	Fl::repeat_timeout(repeat_cb);			/* 重复执行自身指令 */
}
int main(){
    
    
/* some codes */
Fl::add_timeout(1.0/5, repeat_cb);			/* 执行repeat_cb指令 */
/* some codes */
}

在不需要重复指令时可以通过Fl::remove_timeout来终止自动重复执行。

扫描二维码关注公众号,回复: 15091775 查看本文章
void Fl::remove_timeout (Fl_Timeout_Handlercb, void* argp=0);

随机点名器

首先,随机点名器中需要一些全局变量来储存状态:

std::mt19937_64 engine;			/* 存储随机数产生器 */
std::vector<std::string> vs;	/* 存储点名名单 */
Fl_Input* pText;				/* 存储文本控件的地址 */

然后需要读取点名名单与产生随机数:(这里的名单是一个.txt文件,每一行是一个人名)

/* 读取点名名单 */
void loadNames(const std::string& dest){
    
    
    std::fstream fs;
    std::string name;
    fs.open(dest, std::ios::in);
    if (!fs){
    
    
        return;
    }
    while (std::getline(fs, name)){
    
    
        vs.push_back(name);
    }
    fs.close();
}
int getRandom(int min_number, int max_number){
    
    
    std::uniform_int_distribution<> udist(min_number, max_number);
    return udist(engine);
}

之后是画我们的GUI界面。整个界面非常简单,仅由一个输入框和一个按钮组成:

Fl_Double_Window* window = new Fl_Double_Window(300, 200, "随机点名测试");
pText = new Fl_Input(40, 50, 150, 30);
Fl_Button* pButton = new Fl_Button(190, 50, 70, 30, "开始点名");
window->end();

最后是写回调函数。这里我们需要三个回调函数:start_cbstop_cbrollCall_cb

初始按钮上的文字是“开始点名”,当被点击时调用第一个回调函数start_cb,其作用是将按钮上的文字变为“停止点名”,并且将按钮的回调函数变为第二个回调函数stop_cb,同时将第三个用于随机点名的回调函数rollCall_cb设为重复执行。

void start_cb(Fl_Widget* pw, void* pv){
    
    
    Fl_Button* o1 = (Fl_Button*)pw;
    o1->label("停止点名");					/* 变更文字描述 */
    o1->callback(stop_cb, nullptr);			/* 改变按钮绑定的回调函数 */
    Fl::add_timeout(1.0/5, rollCall_cb);	/* 将点名回调函数设为重复执行 */
}

在开始点名后,按钮被点击时调用第二个回调函数stop_cb,其作用是将按钮上的文字变为“开始点名”,并且将按钮的回调函数改回第一个回调函数start_cb,同时结束第三个回调函数rollCall_cb的重复执行。

void stop_cb(Fl_Widget* pw, void* pv){
    
    
    Fl_Button* o1 = (Fl_Button*)pw;
    o1->label("开始点名");					/* 变更文字描述 */
    o1->callback(start_cb, nullptr);		/* 改变按钮绑定的回调函数 */
    Fl::remove_timeout(rollCall_cb);		/* 结束点名回调函数的重复执行 */
}

之后是随机点名回调函数:

void rollCall_cb(void*){
    
    
    int i = getRandom(0, vs.size()-1);      /* 产生代表某个人的随机数 */
    pText->value(vs[i].c_str());            /* 将对应人名显示到输入框内 */
    Fl::repeat_timeout(1.0/5, rollCall_cb); /* 重复执行自身指令 */
}

程序示例

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Button.H>

#include <fstream>
#include <random>
#include <string>
#include <vector>

std::mt19937_64 engine(2020);   /* 存储随机数产生器 */
std::vector<std::string> vs;    /* 存储点名名单 */
Fl_Input* pText;                /* 存储文本控件的地址 */

void loadNames(const std::string& dest){
    
    
    std::fstream fs;
    std::string name;
    fs.open(dest, std::ios::in);
    if (!fs){
    
    
        return;
    }
    while (std::getline(fs, name)){
    
    
        vs.push_back(name);
    }
    fs.close();
}
int getRandom(int min_number, int max_number){
    
    
    std::uniform_int_distribution<> udist(min_number, max_number);
    return udist(engine);
}

void start_cb(Fl_Widget* pw, void* pv);
void stop_cb(Fl_Widget* pw, void* pv);
void rollCall_cb(void*);

void start_cb(Fl_Widget* pw, void* pv){
    
    
    Fl_Button* o1 = (Fl_Button*)pw;
    o1->label("停止点名");                   /* 变更文字描述 */
    o1->callback(stop_cb, nullptr);         /* 改变按钮绑定的回调函数 */
    Fl::add_timeout(1.0/5, rollCall_cb);	/* 将点名回调函数设为重复执行 */
}
void stop_cb(Fl_Widget* pw, void* pv){
    
    
    Fl_Button* o1 = (Fl_Button*)pw;
    o1->label("开始点名");                   /* 变更文字描述 */
    o1->callback(start_cb, nullptr);        /* 改变按钮绑定的回调函数 */
    Fl::remove_timeout(rollCall_cb);        /* 结束点名回调函数的重复执行 */
}
void rollCall_cb(void*){
    
    
    int i = getRandom(0, vs.size()-1);      /* 产生代表某个人的随机数 */
    pText->value(vs[i].c_str());            /* 将对应人名显示到输入框内 */
    Fl::repeat_timeout(1.0/5, rollCall_cb); /* 重复执行自身指令 */
}

int main(){
    
    
    loadNames("Names.txt");

    Fl_Double_Window* window = new Fl_Double_Window(300, 200, "随机点名测试");
    pText = new Fl_Input(40, 50, 150, 30);
    Fl_Button* pButton = new Fl_Button(190, 50, 70, 30, "开始点名");
    pButton->callback(start_cb, pText);
    window->end();
    window->show();

    return Fl::run();
}

这里注意在编译的时候记得加上-lfltk命令(在MSYS2上还要加上-mwindows -DWIN32 -lole32 -luuid -lcomctl32)。
运行结果:
随机点名相关链接:
专栏:FLTK
FLTK学习笔记2-回调函数
FLTK学习笔记4-在FLTK中显示图片(上)

猜你喜欢

转载自blog.csdn.net/willian113/article/details/106743621
今日推荐