单窗口多视口实现思路

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

单窗口多视口实现思路的图1

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

单窗口多视口实现思路的图2

其中,左上为工程的整体三维视图,右上为计算域三维网格,左下为切片、矢量图等后处理结果,右下为部分边界网格。

这仅是列举的一小部分,这对于用户来说,查看不同的数据,对比分析也更加直观。而却各个视口独立于其他视口,只与当前的工程有关。用户可以在不同的视口中做不同的操作,不影响其他视口。

 

实现思路:

多视口中,每个视口都“贴”在一个父窗口上。当视口被分割成两个视口时,首先创建一个父窗口,用来“装”原视口和新创建出来的视口,然后再将创建的父窗口“贴”于原视口的位置。流程如下表示:

单窗口多视口实现思路的图3

实现流程:

通过上述流程,不难发现,这与数据结构中的二叉树的数据结构类似,因此,采用动态数组来描述多视口数据。父窗口采用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;

}

 

到此,多视口的大体实现已经完成。

默认 最新
当前暂无评论,小编等你评论哦!
点赞 评论 收藏
关注