本文翻译自OGRE 1.12.0 Trays GUI System
你曾经也想要使用简单GUI控件来控制你的样例吗?不想从头写一个,但CEGUI又有点太多了?创建托盘系统是为了解决这个问题。它是一个基于OGRE Overlays系统的简单GUI 系统,专为样例而设计。因为它很简单,你无法为它设置外观或构建非常独特的界面,但你也会发现它更容易使用。
Trays
为什么要使用托盘?托盘的概念是系统的核心,因为它不需要GUI设计者(您)来计算或指定任何类型的位置坐标。想想典型GUI中的窗口小部件位置。它们几乎总是位于四个角中的任何一个角中,沿着四个边中的任何一个,或者在极少数情况下,位于屏幕的中心。在托盘中,有九个“托盘”,前面提到的每个位置都有一个托盘。创建窗口小部件时,您可以指定这九个位置中的一个,窗口小部件将添加到该位置的托盘中。您的小部件将直接添加到该托盘中的最后一个小部件下方。将小部件添加到托盘时,托盘的大小会增加。沿着屏幕顶部的托盘向下生长,沿着底部的托盘向上添加,并且中间排的托盘在两个方向上垂直添加。在视觉上,托盘是适合它们包含的小部件的半透明的面板。只有非空托盘是可见的。如果这很难想象,请不要担心,这里有一张照片可以帮到你。
TrayManager
要使用托盘,必须创建TrayManager。这是一个类,你可以通过它来创建和管理所有小部件,操作光标,更改背景图像,调整托盘属性,弹出对话框,显示/隐藏加载栏等。你可以在一个应用程序中拥有多个托盘管理器。例如,OGRE Sample Browser使用自己的托盘管理器并在样本运行时隐藏它,并且SDK样本也有自己的托盘管理器,当浏览器暂停样本时,这些托盘管理器将被隐藏。
Note
TrayManager需要Trays.zip
,因此你只能在加载该资源后创建它。此外,请确保你已正确初始化Overlays Component,因为Trays Framework依赖于它。
像这样创建托盘管理器:
OgreBites::TrayManager* mTrayMgr = new OgreBites::TrayManager("InterfaceName", mWindow);
你必须为你的界面和Ogre :: RenderWindow传递一个名称。如果你希望在按下按钮时收到通知,可以选择传递OgreBites::TrayListener作为
第三个参数。你可以将示例或示例上下文扩展为托盘侦听器。记得像这样销毁你的托盘管理器:
delete mTrayMgr;
获得托盘管理器后,请确保将输入事件转发给它。
addInputListener(mTrayMgr);
Note
如果你还想自己处理事件:如果事件与托盘管理器相关,则TrayManager上的侦听器方法返回true,不应再由您处理。例如,如果你单击场景交互部分上的按钮,则需要按下按钮,但不希望发生场景交互。因此,侦听器方法可以兼作鼠标事件的过滤器。
你现在可以自由创建小部件!尝试在左上方托盘中添加一个按钮:
Button* b = mTrayMgr->createButton(TL_TOPLEFT, "MyButton", "Click Me!");
TrayManager是一个庞大的类,你可以用它做很多事情。有关示例,请参阅下面的“The Things to Try”部分。
The cursor
光标在Trays系统中有三个部分:在Overlay中移动的层,定位光标的容器(OverlayContainer)和光标图像,它是容器的子项(OverlayElement)。隐藏/显示光标时,整个光标层都被隐藏/显示。光标容器的左上角用作光标的热点。通过相对于光标容器定位光标图像,你基本上可以确定光标图像的哪个部分是“点击部分”。对于默认的箭头光标,图像只是与容器对齐,这意味着左上角是热点。但是,对于像十字光标这样的东西,你可以移动光标图像,使其中心位于光标容器的左上角。要显示光标,请使用OgreBites::TrayManager::showCursor
,它为光标图像提供可选的材质名称。如果未指定,则不更改光标图像。要隐藏光标,请使用OgreBites::TrayManager::hideCursor
。你可以使用getCursorLayer,getCursorContainer和getCursorImage获取光标的不同部分。请注意,如果隐藏了光标,则禁用与窗口小部件的所有交互。
The Backdrop
如果要显示背景,请使用OgreBites::TrayManager::showBackdrop
,该背景采用可选材质名称作为背景。如果未指定,则不更改背景图像。要隐藏它,请使用OgreBites::TrayManager::hideBackdrop
。
Widgets
有10个基本的小部件。每个小部件只是OverlayElement模板的一个实例,所有小部件都使用{LEX()}像素{LEX}指标。您可以通过OgreBites::Widget::getOverlayElement
访问任何小部件的底层OverlayElement 。不要手动实例化和删除小部件。使用TrayManager创建并销毁它们。任何一个TrayManager的小部件创建方法的第一个参数是您希望小部件所在的托盘的位置。这是枚举类型TrayLocation。第二个参数是窗口小部件的名称(这不是窗口小部件的标题,而是窗口小部件的唯一字符串标识符)。其余参数特定于窗口小部件的类型。
Button
这是最基本的小部件。要创建按钮,请使用OgreBites::TrayManager::createButton
。除了托盘位置和名称外,还必须为按钮指定标题和可选宽度。如果未指定宽度,则按钮将自动调整大小以适合其标题。没有按钮状态。只有按下按钮才会收到通知。要了解如何响应按钮推送事件,请参阅下面的TrayListener部分。
TextBox
此小部件由粗体标题栏和可以垂直滚动的文本区域组成。除了托盘位置和名称外,还OgreBites::TrayManager::createTextBox
需要标题,宽度和高度。你可以设置/获取标题,文本区域内容,文本填充,文本对齐,手动更改滚动条位置等。
SelectMenu
要创建一个基本的下拉菜单,请使用OgreBites::TrayManager::createLongSelectMenu
或OgreBites::TrayManager::createThickSelectMenu
。这两个方法都返回一个SelectMenu对象,但它们为窗口小部件提供了两种不同的视觉样式之一。一个更厚,但更短,因为它将标题放在项目框上。这种菜单适合放入侧托盘。另一个更长,但更薄,因为它将项目框放在标题旁边。这种菜单适合放入顶部或底部托盘。createThickSelectMenu采用托盘位置,名称,标题,整个窗口小部件的宽度,展开时可见项目的最大数量以及项目的可选字符串向量。createLongSelectMenu函数
除了需要显示当前所选项的文本框的宽度之外,它采用几乎相同的参数。此外,对于长菜单,可以选择指定总宽度,因为它会自动调整大小以适合项目框和标题。您可以设置/获取标题,并以多种不同方式设置/获取项目。您也可以手动更改选择,并选择不触发事件。要了解如何响应菜单项选择事件,请参阅下面的TrayListener部分。
Label
标签大,半透明且平纹。此小部件使用与其他小部件不同的字体,并且适用于章节标题等。除了托盘位置和名称,OgreBites::TrayManager::createLabel
还有一个标题和一个可选的宽度。如果未指定宽度,标签会自动调整其宽度以填充其当前所在的托盘,因此它与托盘的其他内容相匹配。也可以点击标签。要了解如何响应标签点击事件,请参阅下面的TrayListener部分。
Separator
分隔器看起来像是被蚀刻到托盘中的水平线。适合将其他小部件分成多个部分,而不占用标签所需的空间。TrayManager::createSeparator
设置托盘位置,名称和可选宽度。如果未指定宽度,则行为与Label的行为相同。
Slider
滑块由一个容器框,一个显示值的小文本框和一个轨道+句柄组成。滑块与类型无关。使用三个参数 - 最小值,最大值和“捕捉点”的数量,你可以为滑块提供任何类型的离散比例 - 整数,浮点或甚至标称。捕捉点基本上是滑块轨道上的“步骤”。通过指定它们中有多少,你实际上指定整个值从最小值一直到最大值的范围。假设你有最小值0,最大值1和6个捕捉点。在曲面下方,每个滑块都存储浮点值,因此在这种情况下,你将能够显示6个浮点值:{0,0.2,0.4,0.6,0.8,1}。滑块将以最简洁的方式显示您的值(使用Ogre::StringConverter::toString
)。这意味着如果所有值都发生在整数上,那么它们将显示为不带小数的整数。你还可以使用滑块的整数值作为字符串值数组的索引来利用此功能,并手动将滑块的值设置为新的字符串值。基本上,你可以使滑块显示低,中,高,1 / 3,4 / 4, $4.00,N / A等等。这需要您响应滑块移动事件。有关详细信息,请参阅下面的TrayListener部分。然后你的喜欢选择菜单,滑块也有厚和长两种。粗体样式将标题和值框放置在轨道上方,而长样式将标题,轨道和值框按顺序并排放置。OgreBites::TrayManager::createThickSlider
获取托盘位置,名称,标题,总宽度,值框宽度,最小值,最大值和捕捉点数。OgreBites::TrayManager::createLongSlider
采用可选的总宽度,轨道宽度,值框宽度,最小值,最大值和捕捉点数。如果未指定总宽度,滑块将自动缩放以适合轨道,值框和标题文本。你可以获取/设置滑块的标题,显示的值,实际值和值范围。更改范围时,该值将重置为最小值。更改值时,你还可以选择不触发事件。要响应滑块移动事件,请参阅下面的TrayListener部分。
ParamsPanel
此面板显示任意数量的参数及其值。这可能是你想要的任何东西。例如,SDK示例中的统计信息面板显示平均帧速率,最佳帧速率,批次计数等.SDK示例中的详细信息面板显示纹理过滤技术,多边形模式以及摄像机位置和方向。要创建ParamsPanel,请使用OgreBites::TrayManager::createParamsPanel,它设置
托盘位置,名称,宽度,还有参数名称的字符串向量或用来留出空间参数(行)的数量。参数名称将左对齐,并且它们的值将在同一行上右对齐。你可以随时使用字符串向量同时设置/获取参数名称和值,也可以同时设置/获取参数名称和值。
CheckBox
不言自明。OgreBites::TrayManager::createCheckBox
获取托盘位置,名称,标题和可选宽度。未指定的宽度表示自动适合标题。你可以设置/获取复选框的状态,并选择不触发事件。要响应复选框状态更改事件,请参阅下面的TrayListener部分。
DecorWidget
此小部件采用任何OverlayElement模板,并从中创建一个小部件。如果要将自己的图片,图标或其他静态对象放入托盘,请从中制作OverlayElement模板,然后将其转换为DecorWidget。OgreBites::TrayManager::createDecorWidget
获取托盘位置,名称和OverlayElement模板名称。这些基本上与你通常用于从模板创建OverlayElement的内容相同。SDK示例中的OGRE徽标是一个DecorWidget。
ProgressBar
进度条带有标题,注释/详细信息框和填写的表。OgreBites::TrayManager::createProgressBar
设置托盘位置,名称,标题,总宽度和注释框宽度。你可以使用进度条显示您想要的任何类型的进度,但对于最常见的类型(加载资源),可以使用TrayManager创建的ProgressBar的特殊实例。请参阅下面的加载栏。
The Null Tray
除了可以放置小部件的九个托盘外,还有一个“空托盘”。这是一个虚构的托盘,其位置由TL_NONE
指定。这个托盘是虚拟的,不可见的,并且不会在其中排列小部件。基本上,如果你将小部件放在此托盘中,它将变为“自由浮动”,并且你可以手动将其放置在屏幕上的任何位置。只要小部件存在,必须始终位于托盘中,因此当从托盘中移除小部件时,它将自动放置在空托盘中。
Special Widget
有些小部件很常见,却值得特别对待。
Frame States
这不仅仅是一个窗口小部件,而且是显示当前FPS的Label组合和显示高级帧统计信息的ParamsPanel(例如平均FPS和批量计数)。使用OgreBites::TrayManager::showFrameStats
和OgreBites::TrayManager::hideFrameStats
显示/隐藏此特殊小部件。你可以选择放置它的位置。当用户单击FPS标签时,它会切换高级帧统计信息的可见性,因此当不被需要时它们会消失。您还可以使用OgreBites::TrayManager::toggleAdvancedFrameStats
手动切换高级帧统计信息的可见性。
Logo
这只是OGRE标志的装饰部件。使用OgreBites::TrayManager::showLogo
和OgreBites::TrayManager::hideLogo
显示/隐藏徽标。你可以选择放置它的位置。
Loading Bar
这是一个进度条,显示当前资源加载作业的进度。注释框将显示正在加载的当前资源。在开始加载任务之前使用OgreBites::TrayManager::showLoadingBar
。指定要初始化的资源组的数量,要加载的组的数量,以及你认为将初始化的时间比例(默认估计值为70%)(如果需要)。你无法决定放置此加载栏的位置。屏幕将变暗,加载栏将显示在中心。任何其他对话框或加载栏将被关闭。完成装载作业后,调用OgreBites::TrayManager::hideLoadingBar
。
Information Dialog
这是一个对话框,告诉用户一些东西并显示一个OK按钮。它是TextBox和Button的组合。使用OgreBites::TrayManager::showOkDialog
来显示一个信息对话框。指定TextBox的标题以及要在其中显示的消息。任何其他对话框或加载栏将被关闭。屏幕将变暗,对话框将显示在中间。在关闭对话框之前,将禁用所有其他窗口小部件交互。你可以使用手动关闭对话框OgreBites::TrayManager::closeDialog
。要响应信息对话框关闭事件,请参阅下面的TrayListenersection。
Question Dialog
除了它询问用户的内容并显示“是”按钮和“否”按钮,其余都与信息对话框相同。使用OgreBites::TrayManager::showYesNoDialog
显示询问对话框。指定TextBox的标题以及要在其中显示的问题。要回答问题对话框关闭事件,请参阅下面的TrayListener部分。
TrayListener
这个类包含小部件可以触发的所有不同事件的处理程序。TrayManager类本身是一个TrayListener,因为它响应来自其特殊小部件的事件。如果要处理窗口小部件事件,则应从TrayListener以及Sample扩展样本类。如果您正在使用SdkSample,那么您已完成设置,因为它已经是TrayListener。某些小部件为您提供了在更改状态时不触发事件的选项。这有助于初始化或重置窗口小部件,在这种情况下,不应该有任何类型的响应。例如,如果在场景设置之前初始化滑块,并且滑块用于控制场景的某些部分,则触发事件会导致错误。以下是不同处理程序的列表。所有处理程序都有返回类型void。
- buttonHit:给你一个指向被点击的Button的指针。
- itemSelected:为你提供指向选择项目的SelectMenu的指针。然后,你可以使用SelectMenu查看选择了哪个项目。
- labelHit:为你提供指向所单击的Label的指针。
- sliderMoved:为你提供指向其值已更改的Slider的指针。然后,你可以使用Slider查看其新值。此外,你可以将此值转换为更合适的形式,并使用Slider :: setDisplayedValue显示它。
- checkBoxToggled:给你一个指向状态已更改的CheckBox的指针。然后,你可以使用CheckBox查看是否已选中或未选中。
- okDialogClosed:给你关闭的OK对话框的消息。
- yesNoDialogClosed:给出关闭的Yes-No对话框的问题,以及指示是否按下Yes按钮的布尔值。
Things to Try
访问小部件
Button* b;
b = (Button*)mTrayMgr->getWidget("MyButton"); // by name
b = (Button*)mTrayMgr->getWidget(TL_LEFT, 0); // by tray and position
b = (Button*)mTrayMgr->getWidget(TL_LEFT, "MyButton"); // by tray and name
b = (Button*)mTrayMgr->getWidgets(TL_LEFT).front(); // by tray
计数小部件
unsigned int n = mTrayMgr->getNumWidgets(); // total
unsigned int n = mTrayMgr->getNumWidgets(TL_LEFT); // by tray
将小部件移动到其他托盘:
mTrayMgr->moveWidgetToTray(b, TL_TOP);
mTrayMgr->moveWidgetToTray(b, TL_BOTTOM, 1);
mTrayMgr->moveWidgetToTray(TL_BOTTOM, 1, TL_RIGHT, 3);
mTrayMgr->moveWidgetToTray(TL_RIGHT, 3, TL_BOTTOM);
mTrayMgr->moveWidgetToTray("MyButton", TL_TOP);
mTrayMgr->moveWidgetToTray(TL_TOP, "MyButton", TL_LEFT);
从托盘中删除小部件:
mTrayMgr->removeWidgetFromTray(b);
mTrayMgr->removeWidgetFromTray("MyButton");
mTrayMgr->removeWidgetFromTray(TL_LEFT, 0);
mTrayMgr->moveWidgetToTray(b, TL_NONE);
mTrayMgr->clearTray(TL_LEFT);
mTrayMgr->clearAllTrays();
销毁小部件:
mTrayMgr->destroyWidget(b);
mTrayMgr->destroyWidget("MyButton");
mTrayMgr->destroyWidget(TL_LEFT, 0);
mTrayMgr->destroyAllWidgetsInTray(TL_LEFT);
mTrayMgr->destroyAllWidgets();
在托盘中查找小部件的位置:
unsigned int pos = mTrayMgr->locateWidgetInTray(b);
Finding the tray a widget is in:
TrayLocation trayLoc = b->getTrayLocation();
更改托盘侦听器对象:
mTrayMgr->setListener(newListener);
Toggling system visibility:
mTrayMgr->showAll();
mTrayMgr->hideAll();
在一个托盘中更改水平小部件对齐:
mTrayMgr->setTrayWidgetAlignment(TL_LEFT, GHA_RIGHT);
更改间距和填充:
mTrayMgr->setWidgetSpacing(5);
mTrayMgr->setWidgetPadding(3);
mTrayMgr->setTrayPadding(12);
从光标向场景投影3D光线:
Ray r = mTrayMgr->getCursorRay(mCamera);
将3D光线从任何2D屏幕坐标投射到场景中
Ray r = OgreBites::TrayManager::screenToScene(mCamera, Vector2(320, 240));
将3D场景坐标转换为2D屏幕坐标:
Vector2 p = OgreBites::TrayManager::sceneToScreen(mCamera, Vector3::ZERO);