找回密码
 注册
Simdroid-非首页
查看: 96|回复: 0

[08.其他] 单窗口多视口实现思路

[复制链接]
发表于 2019-2-19 16:14:52 | 显示全部楼层 |阅读模式 来自 江苏南京
本帖最后由 天洑软件 于 2019-3-27 17:57 编辑

在众多工程应用软件中,一个模型中查看的数据会多种多样,比如:三维模型视图,受力图表等。然后,在查看过程中,用户可能还需要同时对各种数据进行对比查看等。在以前的软件中,多视口的实现通过多选项卡(多窗口)模式来实现的,如下图,这在软件操作过程中给用户带来了极大的不变,对于多模型来说,更是痛苦至极。



目前多视口的界面大体如下:



其中,左上为工程的整体三维视图,右上为计算域三维网格,左下为切片、矢量图等后处理结果,右下为部分边界网格。
这仅是列举的一小部分,这对于用户来说,查看不同的数据,对比分析也更加直观。而却各个视口独立于其他视口,只与当前的工程有关。用户可以在不同的视口中做不同的操作,不影响其他视口。
实现思路:
多视口中,每个视口都“贴”在一个父窗口上。当视口被分割成两个视口时,首先创建一个父窗口,用来“装”原视口和新创建出来的视口,然后再将创建的父窗口“贴”于原视口的位置。流程如下表示:



实现流程:
通过上述流程,不难发现,这与数据结构中的二叉树的数据结构类似,因此,采用动态数组来描述多视口数据。父窗口采用Qt中的QSplitter类,视口为相应的窗口类。
1. 定义数据元素类型:
struct ViewCell
    {
        Direction direction;    // 方向
        double splitFraction;   // 分割比例
        QWidget* view;
        ViewCell() : direction(NONE), splitFraction(0.5), view(0)  {}
};
其中,direction和splitFraction当为父窗口时有效。
2. 定义数据结构
QVector<ViewCell> m_Cells;
3. 分割算法:
由于二叉树的特性,每分割一次,数组的变为 (2*location)+2+1个,原视口变为 2*location+1,其中,location为当前窗口的序号(序号按照二叉树的前序序号排列)。然后将location位置的元素类型更改为父窗口内容,将2*location+1位置的元素类型更改为原视口内容,伪代码如下:
int split(int location, Direction direction, double fraction)
{
ViewCell cell = m_Cells[location];
cell.direction = direction;
cell.splitFraction = fraction;
    m_Cells.resize(2 * location + 2 + 1);
int child_location = (2 * location + 1);
ViewCell& child = m_Cells[child_location];
   child.view = cell.view;
cell.view = NULL;// 默认为空,在创建窗口函数中自动创建
    m_Cells[location] = cell;
return child_location;
}
4. 创建窗口:
当二叉树的数据完成后,接下来就需要创建窗口,刷新等操作了。可以按照二叉树的前序遍历进行迭代了。伪代码如下:
QWidget* createWidget(int index, QWidget* parentWdg)
{
    Direction direction = m_Cells[index].direction;
    QWidget* widget = m_Cells[index].view;
    switch (direction)
    {
    case NONE:
    {
        if (!widget)
        {
            widget = new QWidget(this);
        }
        frame->setParent(parentWdg);
        m_Cells[index].view = widget;
        return widget;
    }
    case VERTICAL:
    case HORIZONTAL:
    {
        QSplitter* splitter = qobject_cast<QSplitter*>(widget);
        if (!splitter)
        {
            splitter = new QSplitter(parentWdg);
        }
        m_Cells[index].view = splitter;
        splitter->setParent(parentWdg);
        splitter->setOrientation(direction);
// 采用前序遍历,迭代
        splitter->insertWidget(0, createWidget(2 * index + 1, splitter));
        splitter->insertWidget(1, createWidget(2 * index + 2, splitter));
        return splitter;
    }
    }
    return NULL;
}
到此,多视口的大体实现已经完成。


关注公众号“天洑CAE技术源”了解更多相关资讯


您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-4-24 19:55 , Processed in 0.045336 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表