JUCE复合控件之ThreadWithProgressWindow

ThreadWithProgressWindow为使用后台线程并模态显示的进度条窗口(带有进度条的消息窗),可带有【取消】按钮。该类是一个抽象基类,并没有继承自Component类,而是继承自Thread和Timer这两个类,虽实现了Timer类的纯虚函数timeCallback(),但没有实现Thread类的纯虚函数run()。因此,使用本类完成进度条窗口功能时,必须派生子类。

ThreadWithProgressWindow类的构造函数(后3个参数有默认值):

ThreadWithProgressWindow (1参窗口标题, 2参是否显示进度条, 3参是否显示【取消按钮】, 4参退出线程的超时时间, 5参【取消】按钮的文本, 6参出现在哪个组件的中心)

本类的重要成员函数
 runThread () 启动线程,模态运行,默认优先级为5
 setProgress () 设置进度条的进度值(百分比),该函数应由run()循环调用
 setStatusMessage () 设置对话框中显示的文本消息
 getAlertWindow () 返回所使用的AlertWindow,可利用该对象添加更多的控件

使用流程

1、自定义进度窗类,继承自ThreadWithProgressWindow。初始化基类,实现run()函数。要执行的功能性处理和刷新进度条状态等代码均在run()函数中完成,这是本类的核心与重点。

class DemoBackgroundThread : public ThreadWithProgressWindow 
{
public:
    // 构造函数。初始化基类
    DemoBackgroundThread() : ThreadWithProgressWindow (L"标题", 
                             true, true, 5000, L"取消") 
{ 
    // 设置对话框初始状态下所显示的文本消息
    setStatusMessage (L"初始文本...");
}  

// 实现基类的基类Thread的纯虚函数
void run() 
{
    /* 循环开始前,设置进度条的状态,通常设置为“系统忙”. setProgress的double型参数为进度条的百分比位置,有效范围:0.0~1.0. 有效范围之外的值将不显示进度条,只显示一个旋转的“纺轴”(系统忙) */
    setProgress (-1.0); 

    // 设置对话框中显示的文本消息
    setStatusMessage (L"准备中...");

    /* 等待2秒钟。此处使用等待语句,纯属演示。实际编程时,在此执行一些前提处理,做好各项准备,优化数据结构与算法,以便干脆利落、准确无误地进入下面的循环 */
    wait (2000);

    /* 定义一个const整型变量thingsToDo,确定循环次数。本例初始化为100纯属演示。实际编程时,循环的次数由功能性代码需循环执行的次数而定。比如:操作一个结构很复杂、数据量很大的记录集合,如需逐条记录进行处理,那么需要循环的次数就是集合中的记录数  */
    const int thingsToDo = 100;

    /* 通常,可以循环执行且比较耗时的处理才适合使用进度条技术。不适于用循环算法来实现的处理,最好别多此一举。原因:没有多次循环,就很难不间断的刷新进度条的前进位置,硬性使用进度条,反而画蛇添足 */

   // 开始循环。重复执行thingsToDo次
    for (int i = 0; i < thingsToDo; ++i) 
    {
        /* 为及时响应用户点击【取消】按钮或按下ESC键,每次循环期间均需判断处理一下。这是必须的。threadShouldExit()方法的返回值作为判断条件,true即用户强行退出。 */
        if (threadShouldExit())     
            return;     // 直接退出本函数

        /* 每次循环,均设置进度条的位置,百分比的值为:i / 循环次数. 注意:此处两个计数值均是int,要强转为double,否则结果永远为0进度条无法前进 */
        setProgress (i / (double) thingsToDo);

        // 每次循环,可更新文本消息,比如:当前还剩多少多少之类
        setStatusMessage (L"还有" + String (thingsToDo - i) + 
                          L"个批次即大功告成...");

        // 此句纯属演示。实际编程时,此处为需要循环执行的功能性代码
        wait (100); 
    }
  
    setProgress (-1.0); // 循环结束后,再次将进度条的状态设置为“系统忙”。
    setStatusMessage (L"请稍候...");  // 设置此时对话框中显示的文本消息
    wait (3000);     // 故意等待3秒钟,纯属演示。实际编程时,在此善后处理。
    }
};

2、内容组件类的有关函数中创建进度窗对象,该对象调用runThread()函数。runThread()方法在启动进度窗之后,还将返回一个bool值,如果为true,则说明进度窗的run()方法顺利执行完毕;如果为false,则表示未成功执行完毕,比如用户点击【取消】按钮或按下ESC强行终止了处理。可根据此返回值做针对性的编码,给出提示消息等等。注意:runThread()内部调用进度窗的run()函数,这个步骤无需显式编码。

DemoBackgroundThread  demoThread; // 临时创建进度窗栈对象demoThread

#if JUCE_MODAL_LOOPS_PERMITTED	  // 使用模态宏包裹
    if (demoThread.runThread()) // 模态运行并根据返回值执行某些代码
       // 正常结束时返回true,可执行某些代码,比如弹出消息窗,给出提示信息...
#endif

ThreadWithProgressWindow属于JUCE的“重量级”进度窗。如需轻量的进度指示,可使用控件式的ProgressBar,详情请点此参阅