870920 Menu

JUCE类库附带示例的源码分析·11

 如果某个组件中需添加并管理多个同类型或不同类型的子组件,完全不必在该组件类中声明一到多个子组件数组,因为组件本身就是子组件容器,可专门写一个添加子组件的函数,该函数中直接addAndMakeVisible(new ChildComponent())即可。哪怕仅有一个子组件,也可以这么做。但不要忘记在析构函数中deleteAllChildren()。

 全局数据没那么可怕,不是洪水猛兽,相反,运用得当,反而会减轻编码量,提高性能。但是,尽量不要在h头文件中声明全局数据,可写在cpp源文件中。cpp中定义的本编译单元(本文件)所用的全局性变量、对象、数组,尽管具有外部链接属性,但外部并不可见(如无需外部链接属性,则将其声明为static静态类型,这种类型仅具有内部链接属性),因此,小心使用的前提下,并不违反C++信息隐藏的原则。为防止多个编译单元内的全局数据同名冲突的问题,可将这些全局数据置入一个匿名名称空间中。
 GenericAudioProcessorEditor类继承自AudioProcessorEditor插件界面类,代表某个插件的参数编辑界面,其构造函数为AudioProcessor*,可用node节点对象初始化该类的对象:
AudioProcessorEditor* ui =
new GenericAudioProcessorEditor (node->getProcessor());
 如果创建该插件的UI交互式界面组件,语句则是:
ui = node->getProcessor()->createEditorIfNeeded();
// 基于node节点创建并初始化插件实例对象
AudioPluginInstance* const plugin =
dynamic_cast <AudioPluginInstance*> (node->getProcessor());
// 基于插件实例,设置ui的组件名称
if (plugin != nullptr)
ui->setName (plugin->getName());
 Component类的getComponentAt()可基于给出的坐标返回内容组件中的某个子组件。在查找并获取内容组件中的某个子组件时,此函数比较有用(配合dynamic_cast强转和非空判断):
PinComponent* const pin
= dynamic_cast <PinComponent*> (fc->getComponentAt (x, y);
if (pin != nullptr)
return pin;
 组件的鼠标事件处理函数中,偶尔需获取鼠标点击时所位于的组件(配合dynamic_cast强转):
ConnectorComponent* draggingConnector
= dynamic_cast<ConnectorComponent*> (e.originalComponent);
 可将另外组件中的鼠标坐标转换为本组件内的坐标:
// 调用getEventRelativeTo()后,返回的鼠标坐标将相对于新组件的原点
// e为另外组件中的MouseEvent&对象
const MouseEvent e2 (e.getEventRelativeTo (this));
 直接获取当前鼠标所位于的组件:
// Desktop::getInstance()返回本程序当前的桌面对象
// Desktop对象. getMainMouseSource()返回MouseInputSource&主输入设备(鼠标)
// MouseInputSource&对象调用其getComponentUnderMouse()
// 返回主输入设备(鼠标)所位于的Component
Component* const underMouse = Desktop::getInstance().
getMainMouseSource().getComponentUnderMouse();
 本组件内是否按下了鼠标键,可使用该函数:isMouseButtonDown()
 PluginListComponent类可显示插件列表,并可对插件进行扫描、添加、排序,是一个非常实用和必不可少的可视化功能类。
 音频插件的列表显示、扫描、添加、排序等可由一个类来完成:PluginListComponent。可将该组件封装在一个自定义的DocumentWindow中。详情可参阅本项目的PluginListWindow类。该类是MainHostWindow类中前向声明的嵌套类,其定义和实现写在了一起,所在的文件:
MainHostWindow.cpp
 外围类中前向声明的嵌套类,默认为外围类的友元类。即:该嵌套类中的外围类对象可直接调用其私有成员。
 组件类的addKeyListener()用于添加按键捕获器,该捕获器处理本组件所收到的键盘事件。
/* 本组件添加KeyListener按键捕获器,即:本组件所接收的键盘事件将由参数对象捕获处理。 本例,命令管理器对象调用getKeyMappings()函数,返回值的类型为KeyPressMappingSet,而该类恰继承自KeyListener,这就意味着:本组件接收的按键事件由KeyPressMappingSet对象来捕获处理 */
addKeyListener (commandManager->getKeyMappings());
 音频类程序,通常在主窗口类的构造函数中设置较高的进程优先级:
Process::setPriority (Process::HighPriority);
 选项作用域指针OptionalScopedPointer<Component>专用于组件类的堆对象,当它指向某个组件的堆对象时,不使用重载的运算符=,而是这两个函数:setNonOwned()和setOwned(),前者在本指针离开作用域时不自动销毁所指的组件堆对象,后者的作用等同于ScopedPointer。
 关闭插件窗之后,插件内部有可能还在进行消息循环,为防止此时点击主界面或按下键盘后产生的事件发送给插件内部,可临时创建一个组件,使之模态显示,拦截并阻断鼠标及键盘消息,而后,使该模态组件进入50毫秒的消息循环(显示50毫秒后自动消失)。
Component dummyModalComp;
dummyModalComp.enterModalState();
MessageManager::getInstance()->runDispatchLoopUntil (50);
 可将两个各自描述形状的Path对象合而为一,以构成复合式的复杂形状(Path对象描述形状通常在组件类的resized()中进行):
// linePath和arrow分别为两个Path对象
arrow.addTriangle (x1, y1, x2, y2, x3, y3);
// 将箭头arrow添加到linePath中,二者视为一个整体
linePath.addPath (arrow);
linePath.setUsingNonZeroWinding (true);