目录
效果
拖拽
移动编辑
实现
DragResizeWgt类.h文件
DragResizeWgt类.cpp文件
使用
testwidget窗口.ui文件
testwidget窗口.h文件
testwidget窗口.cpp文件
参考
效果
想要的效果就是类似于QT IDE中的效果,可以拖动边缘改变大小,用户自身可以调整一些窗口的布局,方便使用,如下所示:
demo完成后,经测试达到的效果,如下所示:
拖拽
移动
如果你想要的是这样的效果,无需多言,上代码。
实现
这是一个自定义的窗口类,需要重写窗口的一些函数,如下所示:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
DragResizeWgt类.h文件
#ifndef DRAGRESIZEWGT_H
#define DRAGRESIZEWGT_H
#include <QWidget>
#include <QMouseEvent>
#include <QPoint>
#include <QScreen>
#include <QPainter>
#include <QResizeEvent>
#include <QEvent>
namespace Ui {
class DragResizeWgt;
}
class DragResizeWgt : public QWidget
{
Q_OBJECT
enum DIRECTION{
nodir,
top = 0x01,
bottom = 0x02,
left = 0x04,
right = 0x08,
topLeft = 0x01 | 0x04,
topRight = 0x01 | 0x08,
bottomLeft = 0x02 | 0x04,
bottomRight = 0x02 | 0x08};
public:
explicit DragResizeWgt(QWidget *parent = nullptr);
~DragResizeWgt();
signals:
void sizeChange();
public:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
bool eventFilter(QObject *watch, QEvent *event);
void setEdgeBeReSized(const bool& resizeableTop, const bool& resizeableBottom, const bool& resizeableRight, const bool& resizeableLeft);
void setIsRepositioning(const bool& reposition);
private:
void checkEdge();
private:
Ui::DragResizeWgt *ui;
QPoint m_startCursor;
int m_nLeftOff = 0;//鼠标开始拖拽时子窗口左边相对父窗口左边的距离
int m_nRightOff = 0;//鼠标开始拖拽时子窗口右边相对父窗口左边的距离
int m_nTopOff = 0;//鼠标开始拖拽时子窗口上边相对父窗口上边的距离
int m_nBottomOff = 0;//鼠标开始拖拽时子窗口下边相对父窗口上边的距离
QPoint dragPosition; //鼠标拖动的位置
int edgeMargin = 4; //鼠标检测的边缘距离
DIRECTION resizeDir; //更改尺寸的方向
bool m_resizing;
bool m_repositioning;
//帮助判断是否需要激活边框可变化大小
bool m_resizeableTop;
bool m_resizeableBottom;
bool m_resizeableRight;
bool m_resizeableLeft;
};
#endif // DRAGRESIZEWGT_H
DragResizeWgt类.cpp文件
#include "DragResizeWgt.h"
#include "ui_DragResizeWgt.h"
#include <QDebug>
#include "Windows.h"
#include <QMouseEvent>
#include <QObject>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#define min(a,b) ((a)<(b)? (a) :(b))
#define max(a,b) ((a)>(b)? (a) :(b))
DragResizeWgt::DragResizeWgt(QWidget *parent) :
QWidget(parent),ui(new Ui::DragResizeWgt),
resizeDir(nodir), m_resizing(false),m_repositioning(false),
m_resizeableTop(true), m_resizeableBottom(true),
m_resizeableRight(true), m_resizeableLeft(true)
{
ui->setupUi(this);
this->setObjectName("DragResizeWgt");
//注意:一定要设置一个最小的宽高奥,要不会被拖到看不见,默认最小(0,0)
setMinimumSize(100, 100);
//一定一定要有这句话奥,这是能捕捉到这个窗口鼠标事件的关键,还有一点需要特别注意,如果这个窗口上会叠加其他的widget或者控件,对应的子UI也需要调用setMouseTracking这个函数
this->setMouseTracking(true);
//鼠标事件过滤器,来处理父窗口与子窗口的事件关系,不能互相干扰,后续会十分用得到
setAttribute(Qt::WA_NoMousePropagation);
installEventFilter(this);
// QVBoxLayout *layout = new QVBoxLayout(this);
// QLabel *label = new QLabel("Resizable and Draggable Widget", this);
// layout->addWidget(label);
edgeMargin = 4; //设置检测边缘为4
resizeDir = nodir; //初始化检测方向为无
setEdgeBeReSized(false,true,true,false);
// setEdgeBeReSized(true,true,true,true);
setLayout(new QHBoxLayout);
}
DragResizeWgt::~DragResizeWgt() = default;
void DragResizeWgt::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) //每当按下鼠标左键就记录一下位置
{
dragPosition = event->globalPos() - frameGeometry().topLeft(); //获得鼠标按键位置相对窗口左上面的位置
m_startCursor = event->globalPos();
m_nLeftOff = frameGeometry().left();
m_nRightOff = frameGeometry().right() + 1;
m_nTopOff = frameGeometry().top();
m_nBottomOff = frameGeometry().bottom() + 1;
qDebug() << "mousePressEvent" << dragPosition << m_startCursor << m_nLeftOff << m_nRightOff << m_nTopOff << m_nBottomOff;
}
}
void DragResizeWgt::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)//如果左键是按下的
{
if(resizeDir == nodir)//鼠标未放置在边缘处,进行窗口整体拖动处理
{
if(m_repositioning)
{
move(event->globalPos() - dragPosition);
}
}
else//拖拽边缘,根据拖拽方向进行大小调整
{
int ptop,pbottom,pleft,pright;
ptop = m_nTopOff;
pbottom = m_nBottomOff;
pleft = m_nLeftOff;
pright = m_nRightOff;
//这里获取父窗口的大小,如果没有则获取全局可用的屏幕大小
QRect parentRect = parentWidget() ? parentWidget()->rect() : QApplication::primaryScreen()->availableGeometry();
if(resizeDir & top)//拖拽顶部上下变化
{
//计算根据当前鼠标位置与拖拽偏移量计算当前top的位置
ptop = m_nTopOff-(m_startCursor.ry()- event->globalY());
qDebug() << "#########top position" << ptop << m_nTopOff << m_startCursor.ry() << event->globalY();
if(ptop < 0)
{
ptop = parentRect.height() - this->maximumHeight();
}
else{
if(this->height() <= minimumHeight())//进行极端高度最小的处理
{
ptop = min(m_nBottomOff-minimumHeight(),ptop);
qDebug() << "this->height() >= minimumHeight()" << ptop << m_nBottomOff << minimumHeight();
}
else if(this->height() >= maximumHeight())//进行极端高度最大的处理
{
ptop = max(m_nBottomOff-maximumHeight(),ptop);
qDebug() << "this->height() >= maximumHeight()" << ptop << m_nBottomOff << maximumHeight();
}
}
}
else if(resizeDir & bottom)//拖拽底部上下变化
{
//计算根据当前鼠标位置与拖拽偏移量计算当前bottom的位置
pbottom = m_nBottomOff +(event->globalY()-m_startCursor.ry());
if(pbottom > parentRect.bottom())
{
pbottom = this->maximumHeight();
}else{
if(this->height()<minimumHeight())//进行极端高度最小的处理
{
pbottom = m_nTopOff+minimumHeight();
}
else if(this->height()>maximumHeight())//进行极端高度最大的处理
{
pbottom = m_nTopOff+maximumHeight();
}
}
}
if(resizeDir & left)//拖拽左侧左右变化
{
//计算根据当前鼠标位置与拖拽偏移量计算当前left的位置
pleft = m_nLeftOff-(m_startCursor.rx() - event->globalX());
if(pleft < 0)
{
pleft = 0;
}else{
if(this->width()<= minimumWidth())//进行极端宽度最小的处理
{
pleft = min(pleft,m_nRightOff- minimumWidth());
}
else if(this->width() >= maximumWidth())//进行极端宽度最大的处理
{
pleft = max(m_nRightOff- maximumWidth(),pleft);
}
}
}
else if(resizeDir & right)//拖拽右侧左右变化
{
//计算根据当前鼠标位置与拖拽偏移量计算当前right的位置
pright = m_nRightOff + (event->globalX()-m_startCursor.rx());
if(pright > parentRect.right())
{
pright = parentRect.right();
}
if(this->width()<minimumWidth())//进行极端宽度最小的处理
{
pright = m_nLeftOff+minimumWidth();
}
else if(this->width()> this->maximumWidth())//进行极端宽度最大的处理
{
pright = m_nLeftOff + this->maximumWidth();
}
}
setGeometry(pleft,ptop,pright-pleft,pbottom-ptop);
emit sizeChange();
}
}
else checkEdge();
}
void DragResizeWgt::mouseReleaseEvent(QMouseEvent * event)
{
// Q_UNUSED(event);
if(resizeDir != nodir)//还原鼠标样式
{
checkEdge();
emit sizeChange();
}
}
void DragResizeWgt::paintEvent(QPaintEvent *event)
{
// QPainter painter(this);
// painter.fillRect(rect(), Qt::white);
QWidget::paintEvent(event);
}
void DragResizeWgt::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
// emit sizeChange();
}
bool DragResizeWgt::eventFilter(QObject *watch, QEvent *event)
{
//一定要加这一句,不然父窗口的event事件也会出发窗口大小的改变信号
if(watch == parentWidget() && event->type() == QEvent::MouseButtonRelease)
{
event->ignore();
return true;
}
// if(watch == parentWidget() && event->type() == QEvent::Resize)
// {
// event->ignore();
// return true;
// }
return QWidget::eventFilter(watch, event);
}
void DragResizeWgt::setEdgeBeReSized(const bool &resizeableTop, const bool &resizeableBottom, const bool &resizeableRight, const bool &resizeableLeft)
{
m_resizeableTop = resizeableTop;
m_resizeableBottom = resizeableBottom;
m_resizeableRight = resizeableRight;
m_resizeableLeft = resizeableLeft;
}
void DragResizeWgt::setIsRepositioning(const bool &reposition)
{
m_repositioning = reposition;
}
void DragResizeWgt::checkEdge()
{
QPoint pos = this->mapFromGlobal(QCursor::pos());//开始拖拽时点击控件的什么位置
int diffLeft = pos.rx();
int diffRight = this->width() - diffLeft;
int diffTop = pos.ry();
int diffBottom = this->height() - diffTop;
QCursor tempCursor; //获得当前鼠标样式,注意:只能获得当前鼠标样式然后再重新设置鼠标样式
tempCursor = cursor(); //因为获得的不是鼠标指针,所以不能这样用:cursor().setXXXXX
// qDebug() << "diffLeft" << diffLeft << "diffRight" << diffRight << "diffTop" << diffTop << "diffBottom" << diffBottom ;
if(diffTop < edgeMargin && m_resizeableTop)
{ //根据 边缘距离 分类改变尺寸的方向
if(diffLeft < edgeMargin && m_resizeableTop && m_resizeableLeft)
{
resizeDir = topLeft;
tempCursor.setShape(Qt::SizeFDiagCursor);
}
else if(diffRight < edgeMargin && m_resizeableTop && m_resizeableRight)
{
resizeDir = topRight;
tempCursor.setShape(Qt::SizeBDiagCursor);
}
else
{
resizeDir = top;
tempCursor.setShape(Qt::SizeVerCursor);
}
}
else if(diffBottom < edgeMargin && m_resizeableBottom)
{
if(diffLeft < edgeMargin && m_resizeableBottom && m_resizeableLeft)
{
resizeDir = bottomLeft;
tempCursor.setShape(Qt::SizeBDiagCursor);
}
else if(diffRight < edgeMargin && m_resizeableBottom && m_resizeableRight)
{
resizeDir = bottomRight;
tempCursor.setShape(Qt::SizeFDiagCursor);
}
else
{
resizeDir = bottom;
tempCursor.setShape(Qt::SizeVerCursor);
}
}
else if(diffLeft < edgeMargin && m_resizeableLeft)
{
resizeDir = left;
tempCursor.setShape(Qt::SizeHorCursor);
}
else if(diffRight < edgeMargin && m_resizeableRight)
{
resizeDir = right;
tempCursor.setShape(Qt::SizeHorCursor);
}
else
{
resizeDir = nodir;
tempCursor.setShape(Qt::ArrowCursor);
}
setCursor(tempCursor);
}
使用
新建一个主界面窗口testwidget,用于创建主界面包含QWidget和DragResizeWgt共同存在的情况
其中widget_6为底部窗口,widget_5为顶部窗口
注意,我这里右边的窗口类中,我将widget_6和widget提升为了DragResizeWgt窗口类。
testwidget窗口.ui文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>testwidget</class>
<widget class="QWidget" name="testwidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>662</width>
<height>549</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget_8" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget_5" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>50</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_7" native="true">
<property name="styleSheet">
<string notr="true">background-color: rgb(170, 85, 255);</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="DragResizeWgt" name="widget" native="true">
<property name="styleSheet">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_4" native="true">
<property name="styleSheet">
<string notr="true">background-color: rgb(0, 0, 127);</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="DragResizeWgt" name="widget_6" native="true">
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 85, 127);</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>DragResizeWgt</class>
<extends>QWidget</extends>
<header>dragresizewgt.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
testwidget窗口.h文件
#ifndef TESTWIDGET_H
#define TESTWIDGET_H
#include <QWidget>
#include <QMouseEvent>
namespace Ui {
class testwidget;
}
class testwidget : public QWidget
{
Q_OBJECT
public:
explicit testwidget(QWidget *parent = nullptr);
~testwidget();
public:
void resizeEvent(QResizeEvent *event);
private:
Ui::testwidget *ui;
};
#endif // TESTWIDGET_H
testwidget窗口.cpp文件
#include "testwidget.h"
#include "qdebug.h"
#include "ui_testwidget.h"
#include "dragresizewgt.h"
#include <QPushButton>
testwidget::testwidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::testwidget)
{
ui->setupUi(this);
// DragResizeWgt *w = new DragResizeWgt(this);
// w->resize(400,400);
// w->setStyleSheet("background-color: rgb(255, 255, 0);");
// w->show();
// this->setMaximumSize(1920,1080);
this->setMouseTracking(true);
this->setMinimumSize(480,270);
ui->widget->setEdgeBeReSized(false,false,true,false);
// ui->widget->setWgtMaxmumSize(300,800);
ui->widget->setMinimumSize(100,0);
// ui->widget_4->setEdgeBeReSized(false,false,false,true);
ui->widget_6->setEdgeBeReSized(true,false,false,false);
ui->widget_6->setMinimumSize(0,100);
// ui->widget_6->setWgtMaxmumSize(1000,800);
// ui->widget->setStyleSheet("background-color: rgb(20, 20, 255);");
QWidget *childWidget3 = new QWidget;
childWidget3->setMouseTracking(true);
childWidget3->setStyleSheet("background-color: rgb(255, 12, 128);");
childWidget3->setMouseTracking(true);
ui->widget->layout()->addWidget(childWidget3);
ui->widget->layout()->setContentsMargins(0,0,0,0);
ui->widget->layout()->setSpacing(0);
connect(ui->widget, &DragResizeWgt::sizeChange, [=](){
qDebug() << "this->width()" << this->width() << "ui->widget->width()"<< ui->widget->width();
int remainingWidth = this->width() - ui->widget->width();
ui->widget_4->setFixedWidth(remainingWidth);
});
connect(ui->widget_6, &DragResizeWgt::sizeChange, [=](){
qDebug() << "this->width()" << this->height() << "ui->widget->height()"<< ui->widget_6->height();
int remainingHeight= this->height() - ui->widget_6->height();
ui->widget_8->setFixedHeight(remainingHeight);
ui->widget_4->setFixedHeight(remainingHeight);
});
QWidget *childWidget1 = new QWidget;
QVBoxLayout *layout = new QVBoxLayout(this);
QPushButton *label = new QPushButton("Resizable and Draggable Widget", childWidget1);
layout->addWidget(label);
childWidget1->setLayout(layout);
connect(label, &QPushButton::clicked, [](){
qDebug() << "pushbutton clicked";
});
childWidget1->setMouseTracking(true);
childWidget1->setStyleSheet("background-color: rgb(85, 85, 255);");
QWidget *childWidget2 = new QWidget;
childWidget2->setMouseTracking(true);
childWidget2->setStyleSheet("background-color: rgb(85, 20, 255);");
ui->widget_6->layout()->addWidget(childWidget1);
ui->widget_6->layout()->addWidget(childWidget2);
ui->widget_6->layout()->setContentsMargins(0,0,0,0);
ui->widget_6->layout()->setSpacing(0);
ui->widget->setIsRepositioning(true);
}
testwidget::~testwidget()
{
delete ui;
}
// void testwidget::mousePressEvent(QMouseEvent *event)
// {
// }
// void testwidget::mouseReleaseEvent(QMouseEvent *event)
// {
// }
void testwidget::resizeEvent(QResizeEvent *event)
{
qDebug() << "resizeEvent";
ui->widget_6->setMaximumSize(this->width(),this->height()*0.7);
ui->widget_8->setMinimumWidth(0);
ui->widget_8->setMaximumWidth(this->width());
ui->widget_8->setMinimumHeight(0);
ui->widget_8->setMaximumHeight(this->height() - ui->widget_6->height());
ui->widget_4->setMaximumWidth(this->width()*0.9);
ui->widget->setMaximumSize(this->width()*0.9,this->height() - ui->widget_5->height());
}
最后在main函数中show()
testwidget w;
w.show();
参考
源于对这篇文章的参考,调试与修改
https://blog.csdn.net/weixin_40425059/article/details/116495403
如有什么别的问题可以留言,谢谢。