JUCE复合控件之LassoComponent

实现套索功能,需3个类模板和1个抽象类:

  • LassoComponent 套索组件,继承自Component。通常声明为内容组件的栈对象。
  • LassoSource 独立的抽象基类。拖拽套索时选择的项目由该类获取并转存。内容组件需继承该类。
  • SelectedItemSet 项目容器,继承自ChangeBroadcaster。声明为内容组件的栈对象。
  • ChangeListener 可变捕获器,抽象基类,用于捕获项目容器所产生的消息。内容组件需继承该类。

具体流程有6:

1、内容组件类的类头:

class BaseComp : public Component, 
                 private ChangeListener, // 捕获并处理SelectedItemSet的消息
                 public LassoSource<Component*> // 继承抽象模板类LassoSource

2、类中声明栈对象,注意这几个都是模板类:

OwnedArray testComps;   // 被选择的子组件集合,类型为TestComp
LassoComponent<Component*> lasso;  // LassoComponent套索对象
SelectedItemSet<Component*> selectItems;    // 所选择的项目集合

3、内容组件类的构造函数中,创添显设子组件后,设置LassoComponent套索对象的颜色,SelectedItemSet对象绑定可变捕获器。注意,没有在此添加并显示套索对象。

// 套索设置其背景颜色为淡蓝色,边线颜色采用默认的黑色
lasso.setColour (LassoComponent<Component*>::lassoFillColourId, 
                 Colours::lightskyblue.withAlpha(0.2f));

selectItems.addChangeListener(this);

内容组件类的析构函数中:

removeChildComponent (&lasso);

4、实现基类LassoSource的两个纯虚函数,这两个函数的作用是:获取拖拽套索期间所选的项目,获取的数据添加到findLassoItemsInArea()的1参对象中。该对象即另一个纯虚函数getLassoSelection()函数中所设置的返回值:

// 将2参套索区域中的项目添加到1参数组中。该函数在鼠标拖拽套索期间,不停的自动回调
void BaseComp::findLassoItemsInArea (Array<Component*>& itemsFound, 
                                     const Rectangle& area )
{
    // 遍历当前所有可能被选择的TestComp类型的子组件,
    // 如果套索套住了它们,则将其添加到1参数组中
    for (int i = 0; i < testComps.size(); ++i)
    {
        /* getBounds()返回值为Rectangle对象,该矩形的4个坐标点均相对于父级组件,即本例的内容组件。intersects()是Rectangle类的成员函数,如果当前矩形与该函数的参数矩形(即本例的套索矩形)有重叠部分,则返回true。该if语句的作用是:如果套索圈到或碰到了本组件内的某个或某些TestComp类型的子组件,则这些 子组件(指针)添加到本函数的1参数组中。此处添加所选的项目后,内部自动更新getLassoSelection()所提供的SelectedItemSet对象  */
        if (testComps[i]->getBounds().intersects (area))
            itemsFound.add (testComps[i]);
    }
}
/* 给出用于保存所选项目的SelectedItemSet对象,findLassoItemsInArea()的1参将自动把数据添加到该对象中,无需任何显式编码。*/
SelectedItemSet<Component*>& BaseComp::getLassoSelection()
{
    return selectItems;
}

5、套索操作依赖于其父级组件的鼠标事件,因此,在内容组件类的3个mouse…()函数中:

void BaseComp::mouseDown(const MouseEvent& event)
{
    addChildComponent(&lasso);   // 内容组件在此添加套索对象
    lasso.beginLasso(event, this); // 开始拖拽套索
}

void BaseComp::mouseDrag(const MouseEvent& event)
{
    lasso.toFront(false);   // 套索置顶,不拥有焦点
    lasso.dragLasso(event); // 套索拖拽中
}

void BaseComp::mouseUp(const MouseEvent& event)
{
    lasso.endLasso();   // 套索结束拖拽
    removeChildComponent(&lasso); // 内容组件在此移除套索对象

    // 本组件内点击了鼠标,并且没有按下键盘功能键,则取消已有的所有选择
    if (event.mouseWasClicked() && !event.mods.isAnyModifierKeyDown())
        selectItems.deselectAll(); 
}

6、实现基类ChangeListener的纯虚函数。当SelectedItemSet对象新增或移除项目(选择/不选)时将产生可变消息,所产生的消息,由该函数捕获处理。此函数是实现具体功能的关键处和核心点,具体编程时,需仔细斟酌和思考。在鼠标拖拽套索选择项目时,该函数同样不停的被回调执行。

void BaseComp::changeListenerCallback(ChangeBroadcaster* source )
{
    if (source == &selectItems)
    {
        for (int i = 0; i < selectItems.getNumSelected(); ++i)
        {
            TestComp* test = dynamic_cast<TestComp*> (selectItems.getSelectedItem(i));

            // 此语句纯属演示,所套住的子组件重绘自身或执行功能
            if (test != nullptr)
                test->setIsSelect(true); 
        }
        // ...其他代码
    }    
}

LassoComponent 类模板的重要成员函数:
 beginLasso () 在父级组件的mouseDown()中调用此函数,初始化拖拽操作
 dragLasso () 在父级组件的mouseDrag()中调用此函数,实时更新套索的位置
 endLasso () 在父级组件的mouseUp()中调用此函数,结束拖拽操作

LassoSource 类模板的两个纯虚函数:
 findLassoItemsInArea () 将2参区域中的项目添加到1参数组中
 getLassoSelection () 提供一个SelectedItemSet对象用来保存所获取的项目

SelectedItemSet 类模板的介绍参见前文数据容器一节。