效果如下:
头文件widget_manager.h如下:
#pragma once
#include<qwidget.h>
#include<qpropertyanimation.h>
#include<QResizeEvent>
class WidgetManager
:public QObject //尽量集成QObject类,因为如果继承QWidget类在多个窗口时会出现bug,
//原因是当前子窗口会被当成单独窗口处理
{
public:
WidgetManager(QWidget* parent=Q_NULLPTR);
~WidgetManager();
//其他界面调用此接口来添加子窗口以用来管理
//添加id及widget
void addWidget(QString id, QWidget* widget);
//根据id放大收缩对应窗口
void popupWidget(QString id, bool enable);
//事件过滤器,为了实现父窗口放大缩小时子窗口跟着变化
//让子窗口来处理父窗口的窗口大小变化事件
virtual bool eventFilter(QObject *watched, QEvent *event);
private:
QWidget* parent_;//需要继承父窗口,当前被管理类的子窗口的父窗口
std::map<QString, QWidget*> id_widget_map_;//用来记录多个子窗口
QString flag;//用来记录当前哪个窗口被打开
};
源文件widget_manager.cpp如下:
#include "widget_manager.h"
WidgetManager::WidgetManager(QWidget* parent)
:QObject(parent)
{
parent_ = parent;
}
WidgetManager::~WidgetManager()
{
}
void WidgetManager::addWidget(QString id, QWidget* widget)
{
if (parent_ == nullptr)
return;
id_widget_map_[id] = widget;
widget->setParent(parent_);
//刚添加时最好先隐藏而不设置位置
//因为在多个窗口加载时父窗口还会有变化,需要实时获取父窗口位置
widget->hide();
}
void WidgetManager::popupWidget(QString id, bool enable)
{
QWidget* widget = id_widget_map_[id];
if (widget == nullptr)
return;
if (enable){
flag = id;
widget->show();
widget->raise();
//添加动画
//两个参数:添加动画的对象,属性。
QPropertyAnimation *animation = new QPropertyAnimation(widget, "pos");
int x = parent_->width();
animation->setStartValue(QPoint(x, 0));
animation->setEndValue(QPoint(x - widget->width(), 0));
animation->setEasingCurve(QEasingCurve::Linear);
animation->start();
}
else{
flag = " ";
QPropertyAnimation *animation = new QPropertyAnimation(widget, "pos");
int x = parent_->width();
int y = parent_->y();
animation->setStartValue(QPoint(x - widget->width(), 0));
animation->setEndValue(QPoint(x, 0));
animation->setEasingCurve(QEasingCurve::Linear);
animation->start();
}
}
bool WidgetManager::eventFilter(QObject *watched, QEvent *event)
{
//这部分位置移动有很多坑,需要自己多调试注意,可灵活修改。
if (event->type() == QEvent::Resize){
QResizeEvent* resize_event = (QResizeEvent*)event;
QSize cursize = resize_event->size();
for (auto a : id_widget_map_){
if (a.first == flag){
a.second->move(cursize.width() - a.second->width(), a.second->y());
}
else{
a.second->move(cursize.width(), a.second->y());
}
}
return true;
}
return QObject::eventFilter(watched, event);
}
用来测试的头文件managerightscalablecontrols.h如下:
#pragma once
#include <QtWidgets/QWidget>
#include "widget_manager.h"
#include "GeneratedFiles/ui_managerightscalablecontrols.h"
class ManageRightScalableControls : public QWidget
{
Q_OBJECT
public:
ManageRightScalableControls(QWidget *parent = Q_NULLPTR);
//调用管理类指针
WidgetManager* widget;
//用来测试添加的子窗口
QWidget* test1;
public Q_SLOTS:
//弹出子窗口信号
void popup();
//收缩子窗口信号
void close();
private:
//最大的父窗口,创建qtguiclass最开始自带的窗口。
Ui::ManageRightScalableControlsClass ui;
};
用来测试的源文件managerightscalablecontrols.cpp如下:
#include "managerightscalablecontrols.h"
#include <qpushbutton.h>
ManageRightScalableControls::ManageRightScalableControls(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//实例化
widget = new WidgetManager(this);
test1 = new QWidget;
//用来弹出的按钮
QPushButton *pushButton = new QPushButton("OPEN", this);
//用来关闭的按钮
QPushButton *x1 = new QPushButton("X", test1);
//设置测试子窗口最小大小
test1->setMinimumSize(300, 300);
//设置测试子窗口背景颜色为红色
test1->setStyleSheet("background-color:red");
//调用事件过滤器,具体实现在管理类
this->installEventFilter(widget);
//向管理类添加widget
widget->addWidget("A", test1);
//弹出按钮信号槽
connect(pushButton, SIGNAL(clicked()), this, SLOT(popup()));
//缩小按钮信号槽
connect(x1, SIGNAL(clicked()), this, SLOT(close()));
}
void ManageRightScalableControls::popup()
{
widget->popupWidget("A", true);
}
void ManageRightScalableControls::close()
{
widget->popupWidget("A", false);
}
主函数main.cpp
#include "managerightscalablecontrols.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ManageRightScalableControls w;
w.show();
return a.exec();
}