You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
11 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "FITKMdiArea.h"
#include "FITKMdiSubWindow.h"
#include <QResizeEvent>
#include <QMutexLocker>
#include <QTabBar>
#include <cmath>
namespace Comp
{
//互斥锁初始化
QMutex FITKMdiArea::_mutex;
FITKMdiArea::FITKMdiArea(QWidget * parent) :
QMdiArea(parent)
{
//设置在tab模式下bar中包含关闭按钮
this->setTabsClosable(true);
//设置tab页bar为矩形
this->setTabShape(QTabWidget::TabShape::Rounded);
}
FITKMdiArea::~FITKMdiArea()
{
_widgetHash.clear();
}
int FITKMdiArea::addSubWidget(QWidget* widgwt, QString title)
{
//互斥锁添加
QMutexLocker locker(&_mutex);
FITKMdiSubWindow* subWin = new FITKMdiSubWindow;
subWin->setWidget(widgwt);
subWin->setParent(this);
this->addSubWindow(subWin);
_objectID++;
//初始化界面的布局方式
setLayoutType(_layoutType);
_widgetHash.insert(_objectID, subWin);
//QMdiArea中添加widget后需要调用一下show不然可能无法显示
subWin->setWindowTitle(title);
subWin->show();
//返回ID
return _objectID;
}
void FITKMdiArea::setLayoutType(FITKVportsLayoutType type)
{
_layoutType = type;
switch (_layoutType){
//当前视口最大化
case Comp::FITKVportsLayoutType::CurrentMax:this->setViewMode(QMdiArea::ViewMode::SubWindowView); break;
//层叠
case Comp::FITKVportsLayoutType::Cascade:this->setViewMode(QMdiArea::ViewMode::SubWindowView); break;
//水平平铺
case Comp::FITKVportsLayoutType::TileHorizontally:this->setViewMode(QMdiArea::ViewMode::SubWindowView); break;
//垂直平铺
case Comp::FITKVportsLayoutType::TileVertically:this->setViewMode(QMdiArea::ViewMode::SubWindowView); break;
//Tab页
case Comp::FITKVportsLayoutType::Tab: this->setViewMode(QMdiArea::ViewMode::TabbedView); break;
}
//更新布局
updateLayout();
}
void FITKMdiArea::setTabPos(FITKVportsTabPos pos)
{
//设置tab下toolbar的位置
if (_layoutType != Comp::FITKVportsLayoutType::Tab)return;
_tabPos = pos;
switch (_tabPos) {
//顶部
case Comp::FITKVportsTabPos::Top:this->setTabPosition(QTabWidget::TabPosition::North); break;
//底部
case Comp::FITKVportsTabPos::Bottom:this->setTabPosition(QTabWidget::TabPosition::South); break;
//左侧
case Comp::FITKVportsTabPos::Left:this->setTabPosition(QTabWidget::TabPosition::West); break;
//右侧
case Comp::FITKVportsTabPos::Right:this->setTabPosition(QTabWidget::TabPosition::East); break;
}
}
QMdiSubWindow * FITKMdiArea::getSubWidget(int objectID)
{
return _widgetHash.value(objectID);
}
QWidget* FITKMdiArea::getWidget(int id)
{
QMdiSubWindow* subWidget = _widgetHash.value(id);
if (subWidget == nullptr)return nullptr;
return subWidget->widget();
}
void FITKMdiArea::removeWidget(int id)
{
//互斥锁
QMutexLocker locker(&_mutex);
QMdiSubWindow* widget = _widgetHash.value(id);
if (widget == nullptr)return;
this->removeSubWindow(widget);
_widgetHash.remove(id);
//更新布局
updateLayout();
}
QWidget* FITKMdiArea::getWidget(QMdiSubWindow* subWidget)
{
if (subWidget == nullptr)return nullptr;
QList<QMdiSubWindow*> subWidgets = _widgetHash.values();
if(!subWidgets.contains(subWidget))return nullptr;
return subWidget->widget();
}
QMdiSubWindow * FITKMdiArea::getSubWidget(QWidget* widget)
{
if (widget == nullptr)return nullptr;
QList<QMdiSubWindow*> subWidgets = _widgetHash.values();
for (QMdiSubWindow* subWidget : subWidgets) {
if (subWidget == nullptr)continue;
if (subWidget->widget() == widget)return subWidget;
}
return nullptr;
}
QWidget* FITKMdiArea::getCurrentWidget()
{
FITKMdiSubWindow* subMainwin = dynamic_cast<FITKMdiSubWindow*>(this->currentSubWindow());
if (subMainwin == nullptr)return nullptr;
return subMainwin->widget();
}
QMdiSubWindow * FITKMdiArea::getCurrentSubWidget()
{
return this->currentSubWindow();
}
void FITKMdiArea::removeCurrentWidget()
{
QMutexLocker locker(&_mutex);
QMdiSubWindow* subMainwin = this->currentSubWindow();
if (subMainwin == nullptr)return;
int id = _widgetHash.key(subMainwin);
removeWidget(id);
}
void FITKMdiArea::updateLayout()
{
switch (_layoutType){
//当前视图最大化
case Comp::FITKVportsLayoutType::CurrentMax:currentMaxViewports(); break;
//叠层布局
case Comp::FITKVportsLayoutType::Cascade:cascadeViewports(); break;
//水平平铺
case Comp::FITKVportsLayoutType::TileHorizontally:tileHorizontallyViewports(); break;
//垂直平铺
case Comp::FITKVportsLayoutType::TileVertically:tileVerticallyViewports(); break;
}
}
void FITKMdiArea::setTabBarExpanding(bool ex /*= true */)
{
if (_layoutType != FITKVportsLayoutType::Tab) return;
QTabBar* bar = this->findChild<QTabBar*>();
if (bar) bar->setExpanding(ex);
}
void FITKMdiArea::resizeEvent(QResizeEvent * event)
{
QMdiArea::resizeEvent(event);
//大小发生变化时重新计算窗口位置
updateLayout();
}
bool FITKMdiArea::eventFilter(QObject * object, QEvent * event)
{
QMdiArea::eventFilter(object, event);
QList<QMdiSubWindow*> subWidgets = _widgetHash.values();
for (QMdiSubWindow* subWidget : subWidgets) {
if (object == subWidget) {
if (event->type() == QEvent::Close) {
slotWidgetClose(subWidget);
}
}
}
return false;
}
void FITKMdiArea::slotWidgetClose(QMdiSubWindow* subWidget)
{
if (subWidget == nullptr)return;
QList<QMdiSubWindow*> subWidgets = _widgetHash.values();
if (!subWidgets.contains(subWidget))return;
_widgetHash.remove(_widgetHash.key(subWidget));
this->removeSubWindow(subWidget);
}
void FITKMdiArea::currentMaxViewports()
{
//最大化当前窗口
QMdiSubWindow* currentSubWin = this->currentSubWindow();
if (currentSubWin == nullptr)return;
currentSubWin->showMaximized();
}
void FITKMdiArea::cascadeViewports()
{
QPoint position(0, 0);
// 分别设置每个视口大小为总尺寸的75%
auto viewportWidth = width() * 0.75;
auto viewportHeight = height() * 0.75;
QList<QMdiSubWindow*> widgetList = this->subWindowList(QMdiArea::CreationOrder);
for (QMdiSubWindow* widget : widgetList)
{
// 宽度超出最大值,则从左上角从新开始排列
if (position.x() + viewportWidth > width()) {
position.setX(0);
position.setY(0);
}
// 高度超出最大值,则从新开始一列
if (position.y() + viewportHeight > height()) {
position.setY(0);
}
// 分别设置每个视口的位置、大小
widget->setWindowState(Qt::WindowState::WindowNoState);
QRect rect(0, 0, viewportWidth, viewportHeight);
widget->setGeometry(rect);
widget->move(position);
position.setX(position.x() + 30);
position.setY(position.y() + 30);
}
}
void FITKMdiArea::tileHorizontallyViewports()
{
//已创建的顺序获取列表
QList<QMdiSubWindow*> widgetList = this->subWindowList(QMdiArea::CreationOrder);
// 最大可用长度和宽度
int availableWidth = width();
int availableHeight = height();
// 计算行数和列数
int count = widgetList.size();
int column = floor(sqrt((double)count));
if (column == 0) return;
int row = ceil((double)count / (double)column);
if (row == 0) return;
// 计算每个视口的显示宽度和高度
int viewportWidth = availableWidth / column;
int viewportHeight = availableHeight / row;
// 当前行索引与列索引
int rowIndex = 0, columnIndex = 0;
// 分别计算每个视口的长度,分别设置显示位置和大小
QPoint position(0, 0);
int i = 0;
for (auto widget : widgetList)
{
if (widget == nullptr) continue;
// 计算索引为i的视口的行索引和列索引
rowIndex = floor(i / column);
columnIndex = i % column;
// 设置视口的显示状态
widget->setWindowState(Qt::WindowState::WindowNoState);
// 设置视口大小
QRect rect(0, 0, viewportWidth, viewportHeight);
widget->setGeometry(rect);
// 计算视口的位置
position.setX(columnIndex * viewportWidth);
position.setY(rowIndex * viewportHeight);
// 移动到指定位置
widget->move(position);
i++;
}
}
void FITKMdiArea::tileVerticallyViewports()
{
QList<QMdiSubWindow*> widgetList = this->subWindowList(QMdiArea::CreationOrder);
// 最大可用长度和宽度
int availableWidth = width();
int availableHeight = height();
// 计算行数和列数
auto count = widgetList.size();
int row = floor(sqrt((double)count));
if (row == 0) return;
int column = ceil((double)count / (double)row);
if (column == 0) return;
// 计算每个视口的显示宽度和高度
int viewportWidth = availableWidth / column;
int viewportHeight = availableHeight / row;
// 当前行索引与列索引
int rowIndex = 0, columnIndex = 0;
// 分别计算每个视口的长度,分别设置显示位置和大小
QPoint position(0, 0);
int i = 0;
for (QMdiSubWindow* widget : widgetList)
{
if (widget == nullptr) continue;
// 计算索引为i的视口的行索引和列索引
rowIndex = floor(i / column);
columnIndex = i % column;
// 设置视口的显示状态
widget->setWindowState(Qt::WindowState::WindowNoState);
// 设置视口大小
QRect rect(0, 0, viewportWidth, viewportHeight);
widget->setGeometry(rect);
// 计算视口的位置
position.setX(columnIndex * viewportWidth);
position.setY(rowIndex * viewportHeight);
// 移动到指定位置
widget->move(position);
i++;
}
}
}