Qt - 实现自定义窗口可自由拉伸(方法2)
文件结构目录:
guimainwindow.h
#ifndef GUIMAINWINDOW_H
#define GUIMAINWINDOW_H
#include <QDialog>
QT_BEGIN_NAMESPACE
namespace Ui { class GUIMainWindow; }
QT_END_NAMESPACE
class GUIMainWindow : public QDialog
{
Q_OBJECT
public:
GUIMainWindow(QDialog *parent = nullptr);
~GUIMainWindow();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
bool resizeWindow(QPoint pos);
void checkMouseState(const QPoint &mPos);
bool event(QEvent *e);
private:
Ui::GUIMainWindow *ui;
bool left, right, top, bottom;//是否在窗口的左、右、上、下区域
bool m_bResizing;//是否缩放窗口
bool isLeftPressed;//左键是否按下
};
#endif // GUIMAINWINDOW_H
guimainwindow.cpp
#include "guimainwindow.h"
#include "ui_guimainwindow.h"
#include <QMouseEvent>
#include <QDebug>
GUIMainWindow::GUIMainWindow(QDialog *parent)
: QDialog(parent)
, ui(new Ui::GUIMainWindow)
{
ui->setupUi(this);
m_bResizing = false;
isLeftPressed=false;
left = false;
right= false;
top= false;
bottom= false;
qDebug()<<"GUIMainWindow> m_bResizing = "<<m_bResizing;
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);//窗口去标题栏,并且会去掉窗口拖拽移动功能和窗口自由拉伸功能
this->setMouseTracking(true);//设置鼠标追踪
this->setAttribute(Qt::WA_Hover, true);//开启鼠标悬停和点击功能
this->setMinimumSize(800,600);
//1.加载事件过滤器
//this->installEventFilter(this);
}
GUIMainWindow::~GUIMainWindow()
{
delete ui;
}
//new rain add
bool GUIMainWindow::resizeWindow(QPoint pos)
{
qDebug()<<"resizeWindowz> m_bResizing = "<<m_bResizing;
if ( m_bResizing )
{
QPoint point = mapToGlobal(pos);
int x = point.x();
int y = point.y();
QRect g = geometry();
if (left )//左边区域按下左键
{
if (g.right()-x>minimumSize().width())
{
g.setLeft( x );//g.left() + dx
}
else
{
g.setLeft(g.right()-minimumSize().width());
}
}
if ( right )//右边区域按下左键
{
g.setRight( x );//g.right() + dx
}
if( top )//上边区域按下左键
{
g.setTop( y );
if (g.bottom()-y>minimumSize().height())
{
g.setTop( y );//g.left() + dx
}
else
{
g.setTop(g.bottom()-minimumSize().height());
}
}
if (bottom )//下边区域按下左键
{
g.setBottom( y);//g.bottom() + dy
}
setGeometry( g );
}
return m_bResizing;
}
void GUIMainWindow::checkMouseState(const QPoint &mPos)
{
int x = mPos.x();
int y = mPos.y();
// QWidget * w = QApplication::widgetAt(mapToGlobal(mPos));//在全局屏幕位置点返回小部件,如果没有Qt小部件,则返回nullptr。这个函数可能很慢。
// if(w!=this && w!=NULL)
// {
// left = false;
// right = false;
// bottom = false;
// top = false;
// m_bResizing=false;
// qDebug()<<"checkMouseState> m_bResizing = "<<m_bResizing;
// qDebug()<<"w!=this && w!=NULL";
// setCursor( Qt::ArrowCursor );
// }
// else
// {
// qDebug()<<"w = NULL";
// }
QRect r = rect();
left = qAbs( x - r.left() ) <= 3; //计算窗口左边区域
right = qAbs( x - r.right() ) <= 3; //计算窗口右边区域
bottom = qAbs( y - r.bottom() ) <= 3;//计算窗口下边区域
//bool noTop = qAbs( y - r.top() ) > m_titleBar->height();
top = qAbs( y - r.top() ) <= 2; //计算窗口上边区域
//left = left && noTop;
//right = right && noTop;
bool hor = left | right;
if (hor && bottom )
{
if ( left )//鼠标在窗口左下角区域
{
setCursor( Qt::SizeBDiagCursor );
qDebug()<<"左下角";
}
else//鼠标在窗口右下角区域
{
setCursor( Qt::SizeFDiagCursor );
qDebug()<<"右下角";
}
}
else if(hor && top)
{
if(left)//鼠标在窗口左上角区域
{
setCursor( Qt::SizeFDiagCursor );
qDebug()<<"左上角";
}
else//鼠标在窗口右上角区域
{
setCursor( Qt::SizeBDiagCursor );
qDebug()<<"右上角";
}
}
else if (left)//鼠标在窗口左边区域
{
setCursor( Qt::SizeHorCursor );
}
else if(right)//鼠标在窗口右边区域
{
setCursor( Qt::SizeHorCursor );
}
else if (top)//鼠标在窗口上边区域
{
setCursor( Qt::SizeVerCursor );//grabMouse
}
else if (bottom)//鼠标在窗口下边区域
{
setCursor( Qt::SizeVerCursor );//grabMouse
}
else//鼠标不在以上区域
{
setCursor(Qt::ArrowCursor);
}
}
void GUIMainWindow::mousePressEvent( QMouseEvent* e )
{
if ( e->button() == Qt::LeftButton )
{
isLeftPressed = true;
if(left || right || bottom || top)//如果鼠标在窗口左、右、上、下区域,则需要改变窗口
{
m_bResizing = true;
qDebug()<<"鼠标在窗口左、右、上、下区域按下 ";
}
}
//checkMouseState(e->pos());
QDialog::mousePressEvent( e );
}
void GUIMainWindow::mouseReleaseEvent( QMouseEvent* e )
{
if ( e->button() == Qt::LeftButton )
{
isLeftPressed = false;
m_bResizing = false;
}
left = false;
right= false;
bottom= false;
top= false;
qDebug()<<"mouseReleaseEvent> m_bResizing = "<<m_bResizing;
//releaseMouse();
QDialog::mouseReleaseEvent( e );
}
bool GUIMainWindow::event(QEvent *e)
{
if (e->type() == QEvent::HoverMove)//Qt的Widget默认是不会响应Hover类型的事件,如需要捕捉Hover类型事件,则需要对Widget执行:setAttribute(Qt::WA_Hover, true);
{
QHoverEvent* hoverEvent = static_cast<QHoverEvent*>(e);
//QPoint mousePos = hoverEvent->pos();
//m_ctrl->HoverEvent(this, mousePos);
qDebug()<<"QEvent::HoverMove";
if(!isLeftPressed)
{
checkMouseState(hoverEvent->pos());
//resizeWindow(hoverEvent->pos());
//qDebug()<<"鼠标左键没有按下";
}
else
{
resizeWindow(hoverEvent->pos());
qDebug()<<"鼠标左键按下22";
}
}
if(e->type() == QEvent::MouseButtonPress)
{
qDebug()<<"鼠标左键按下";
}
return QDialog::event(e);
}
main.cpp
#include "guimainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GUIMainWindow widget;
widget.show();
return a.exec();
}
知识补充:
MouseMove
Qt中的mouseMove事件,默认情况下是需要按住鼠标左键移动时,才会相应Qt::mouseMoveEvent;
如果希望在鼠标不按住的情况下捕捉该事件:
1.对于单个Widget,需要对该Widget执行:
setMouseTracking(true);
2.对于父子窗口,父窗口若想捕捉子窗口上方的mouseMoveEvent,则父子窗口都需要执行:
setMouseTracking(true);
并且子窗口(控件)并未对该事件进行处理,即没有accept或ignore该事件,若子窗口(控件)重写了虚函数: void mouseMoveEvent(QMouseEvent *event) ;则父窗口是捕捉不到子窗口(控件)的mouseMoveEvent
3.举例,QMainWindow若想捕捉客户区域的mouseMove事件,则QMainWindow和其中的centralWidget子部件都需要执行 setMouseTracking(true);
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->centralWidget()->setMouseTracking(true);
this->setMouseTracking(true);
}
若该MainWindow中有一个QPushButton和一个QLabel;鼠标在button和label上移动时,MainWindow都不能收到mouseMove事件,除非对button和label都执行setMouseTracking(true);
HoverMove
Qt的Widget默认是不会响应Hover类型的事件,如需要捕捉Hover类型事件,则需要对Widget执行:setAttribute(Qt::WA_Hover, true);
Qt的Hover事件包括:
1.QEvent::HoverEnter: 当鼠标进入widget的边界时,触发HoverEnter事件。这通常用于改变widget的视觉表现,例如突出显示对象以指示它是可操作的。
2.QEvent::HoverLeave: 当鼠标离开widget的边界时,触发HoverLeave事件。这通常用于恢复widget的原始视觉表现。
3.QEvent::HoverMove: 当鼠标在widget边界内移动时,触发HoverMove事件。这可能涉及到更具动态性的视觉反馈,例如改变光标形状,或将特定区域突出显示以响应鼠标位置。
对比
HoverMove相比于mouseMove,自带穿透的效果,继续以上QMainWindow的例子:
- mouseMove事件是不会穿透button和label的,若MainWindow想要捕捉到在子控件上的mouseMove事件,除非子控件调用setMouseTracking(true);
- hoverMove是会穿透子控件,给MainWindow(父控件)设置了setMouseTracking(true);后;即使鼠标在button或label上移动,父控件(窗口)依然能收到HoverMove事件
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程