Qt 无边框拖拽实现

头文件定义:

class TDragProxy:public QObject
{
Q_OBJECT public:
TDragProxy(QWidget* parent);
~TDragProxy(); protected:
enum WidgetRegion
{
Top = ,
TopRight,
Right,
RightBottom,
Bottom,
LeftBottom,
Left,
LeftTop,
Inner,
Unknown
}; public:
void SetBorderWidth(int top, int right, int bottom, int left);//设置四周边框宽度
void SetDragEnable(bool bEnable); //最大化无拖拽效果 protected:
virtual bool eventFilter(QObject* obj, QEvent* event); void MakeRegions();
WidgetRegion HitTest(const QPoint& pos);
void UpdateGeometry(int x, int y, int w, int h); //鼠标从边框快速移到窗体内子控件上,可能会造成鼠标样式未改变,这里使用计时器监控
void StartCursorTimer();
void StopCursorTimer(); private:
QWidget* m_proxyWidget; //代理的窗体
int m_top,m_right,m_bottom,m_left; //四周宽度
QRect m_regions[]; //九宫格,对应9个区域 QPoint m_originPosGlobal; //拖拽前鼠标位置
QRect m_originGeo; //拖拽前窗体位置和大小 bool m_mousePressed; //鼠标是否按下
WidgetRegion m_regionPressed; //记录鼠标按下时所点击的区域 int m_cursorTimerId; bool m_bDragEnable;
bool m_bBorderMini; //边框为1时,处理四对角位置
};

CPP文件实现:

TDragProxy::TDragProxy(QWidget *parent)
:QObject((QObject*)parent)
, m_bDragEnable(true)
, m_bBorderMini(false)
{
m_proxyWidget = parent;
m_top = m_right = m_bottom = m_left = ; m_proxyWidget->setMouseTracking(true);
m_proxyWidget->installEventFilter(this); // 代理窗体事件 m_mousePressed = false;
m_regionPressed = Unknown; m_cursorTimerId = ;
} TDragProxy::~TDragProxy()
{
} void TDragProxy::SetBorderWidth(int top, int right, int bottom, int left)
{
m_top = top;
m_right = right;
m_bottom = bottom;
m_left = left; if (m_top == && m_right == && m_bottom == && m_left==)
{
m_bBorderMini = true;
} MakeRegions();
} void TDragProxy::UpdateGeometry(int x, int y, int w, int h)
{
int minWidth = m_proxyWidget->minimumWidth();
int minHeight = m_proxyWidget->minimumHeight();
int maxWidth = m_proxyWidget->maximumWidth();
int maxHeight = m_proxyWidget->maximumHeight(); if (w < minWidth || w > maxWidth || h < minHeight || h > maxHeight)
{
return;
} m_proxyWidget->setGeometry(x, y, w, h);
} bool TDragProxy::eventFilter(QObject* obj, QEvent* event)
{
if (!m_bDragEnable)
{
return QObject::eventFilter(obj, event);
} QEvent::Type eventType = event->type();
if (eventType == QEvent::MouseMove)
{
QMouseEvent* mouseEvent = (QMouseEvent*)event;
QPoint curPosLocal = mouseEvent->pos();
TDragProxy::WidgetRegion regionType = HitTest(curPosLocal);
QPoint curPosGlobal = m_proxyWidget->mapToGlobal(curPosLocal); if (!m_mousePressed) // 鼠标未按下
{
switch (regionType)
{
case Top:
case Bottom:
m_proxyWidget->setCursor(Qt::SizeVerCursor);
break;
case TopRight:
case LeftBottom:
m_proxyWidget->setCursor(Qt::SizeBDiagCursor);
break;
case Right:
case Left:
m_proxyWidget->setCursor(Qt::SizeHorCursor);
break;
case RightBottom:
case LeftTop:
m_proxyWidget->setCursor(Qt::SizeFDiagCursor);
break;
default:
m_proxyWidget->setCursor(Qt::ArrowCursor);
break;
} StartCursorTimer();
}
else // 鼠标已按下
{
QRect geo = m_proxyWidget->geometry(); if (m_regionPressed == Inner)
{
m_proxyWidget->move(m_originGeo.topLeft() + curPosGlobal - m_originPosGlobal);
}
else if (m_regionPressed == Top)
{
int dY = curPosGlobal.y() - m_originPosGlobal.y();
UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dY, m_originGeo.width(), m_originGeo.height() - dY);
}
else if (m_regionPressed == TopRight)
{
QPoint dXY = curPosGlobal - m_originPosGlobal;
UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() - dXY.y());
}
else if (m_regionPressed == Right)
{
int dX = curPosGlobal.x() - m_originPosGlobal.x();
UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dX, m_originGeo.height());
}
else if (m_regionPressed == RightBottom)
{
QPoint dXY = curPosGlobal - m_originPosGlobal;
UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() + dXY.y());
}
else if (m_regionPressed == Bottom)
{
int dY = curPosGlobal.y() - m_originPosGlobal.y();
UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width(), m_originGeo.height() + dY);
}
else if (m_regionPressed == LeftBottom)
{
QPoint dXY = curPosGlobal - m_originPosGlobal;
UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() + dXY.y());
}
else if (m_regionPressed == Left)
{
int dX = curPosGlobal.x() - m_originPosGlobal.x();
UpdateGeometry(m_originGeo.x() + dX, m_originGeo.y(), m_originGeo.width() - dX, m_originGeo.height());
}
else if (m_regionPressed == LeftTop)
{
QPoint dXY = curPosGlobal - m_originPosGlobal;
UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() - dXY.y());
}
}
}
else if (eventType == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = (QMouseEvent*)event;
if (mouseEvent->button() == Qt::LeftButton)
{
m_mousePressed = true; QPoint curPos = mouseEvent->pos();
m_regionPressed = HitTest(curPos); m_originPosGlobal = m_proxyWidget->mapToGlobal(curPos);
m_originGeo = m_proxyWidget->geometry(); StopCursorTimer();
}
}
else if (eventType == QEvent::MouseButtonRelease)
{
m_mousePressed = false;
m_regionPressed = Unknown; m_proxyWidget->setCursor(Qt::ArrowCursor);
}
else if (eventType == QEvent::Resize)
{
MakeRegions();
}
else if (eventType == QEvent::Leave)
{
m_proxyWidget->setCursor(Qt::ArrowCursor);
StopCursorTimer();
}
else if (eventType == QEvent::Timer)
{
QTimerEvent* timerEvent = (QTimerEvent*)event;
if (timerEvent->timerId() == m_cursorTimerId)
{
if (m_regions[Inner].contains(m_proxyWidget->mapFromGlobal(QCursor::pos())))
{
m_proxyWidget->setCursor(Qt::ArrowCursor);
StopCursorTimer();
}
}
}
return QObject::eventFilter(obj, event);
} void TDragProxy::StartCursorTimer()
{
StopCursorTimer();
m_cursorTimerId = m_proxyWidget->startTimer();
} void TDragProxy::StopCursorTimer()
{
if (m_cursorTimerId != )
{
m_proxyWidget->killTimer(m_cursorTimerId);
m_cursorTimerId = ;
}
} void TDragProxy::MakeRegions()
{
int width = m_proxyWidget->width();
int height = m_proxyWidget->height(); if (m_bBorderMini)
{
m_regions[Top] = QRect(, , width - , );
m_regions[TopRight] = QRect(width - , , , );
m_regions[Right] = QRect(width - , , , height - );
m_regions[RightBottom] = QRect(width - , height - , , );
m_regions[Bottom] = QRect(, height - , width - , );
m_regions[LeftBottom] = QRect(, height - , , );
m_regions[Left] = QRect(, , , height - );
m_regions[LeftTop] = QRect(, , , );
m_regions[Inner] = QRect(, , width - , height - );
}
else
{
m_regions[Top] = QRect(m_left, , width - m_left - m_right, m_top);
m_regions[TopRight] = QRect(width - m_right, , m_right, m_top);
m_regions[Right] = QRect(width - m_right, m_top, m_right, height - m_top - m_bottom);
m_regions[RightBottom] = QRect(width - m_right, height - m_bottom, m_right, m_bottom);
m_regions[Bottom] = QRect(m_left, height - m_bottom, width - m_left - m_right, m_bottom);
m_regions[LeftBottom] = QRect(, height - m_bottom, m_left, m_bottom);
m_regions[Left] = QRect(, m_top, m_left, height - m_top - m_bottom);
m_regions[LeftTop] = QRect(, , m_left, m_top);
m_regions[Inner] = QRect(m_left, m_top, width - m_left - m_right, height - m_top - m_bottom);
}
} TDragProxy::WidgetRegion TDragProxy::HitTest(const QPoint& pos)
{
for (int i = ; i < ; i++)
{
const QRect rect = m_regions[i];
if (rect.contains(pos))
{
return TDragProxy::WidgetRegion(i);
}
}
return Unknown;
} void TDragProxy::SetDragEnable(bool bEnable)
{
m_bDragEnable = bEnable;
}

接口调用例子:

setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
setMinimumSize(MWS_MIN_WIDTH, MWS_MIN_HEIGHT); mpDragProxy = new TDragProxy(this);
mpDragProxy->SetBorderWidth(MWS_BORD_WIDTH, MWS_BORD_WIDTH, MWS_BORD_WIDTH, MWS_BORD_WIDTH);

Qt 无边框拖拽实现的更多相关文章

  1. Qt无边框窗体-最大化时支持拖拽还原

    目录 一.概述 二.效果展示 三.demo制作 1.设计窗体 2.双击放大 四.拖拽 五.相关文章 原文链接:Markdown模板 一.概述 用Qt进行开发界面时,既想要实现友好的用户交互又想界面漂亮 ...

  2. Qt无边框窗体-模拟模态窗体抖动效果

    目录 一.概述 二.效果展示 三.功能实现 四.相关文章 原文链接:Qt无边框窗体-模拟模态窗体抖动效果 一.概述 用Qt开发windows客户端界面确实是一大利器,兼顾性能的同时,速度相对来说也不错 ...

  3. HTML5 CSS3 经典案例:无插件拖拽上传图片 (支持预览与批量) (二)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/31513065 上一篇已经实现了这个项目的整体的HTML和CSS: HTML5 C ...

  4. qt中的拖拽及其使用技巧

    关于qt中的拖放操作,首先可以看这篇官方文档:http://doc.qt.io/qt-5.5/dnd.html 一.QDrag 首先是创建QDrag,可以在mousePressEvent或者mouse ...

  5. Qt 无边框窗体改变大小 完美实现(全部自己实现)

    近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅. 网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo, ...

  6. Qt之窗体拖拽、自适应分辨率、自适应大小 good

    Qt之自定义界面(实现无边框.可移动) Qt之自定义界面(窗体缩放-跨平台终极版) Qt之自定义界面(窗体缩放) http://blog.csdn.net/liang19890820/article/ ...

  7. Qt 无边框窗体改变大小 完美实现

    近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅. 网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo, ...

  8. Qt之窗体拖拽、自适应分辨率、自适应大小

    简述 在自定义无边框.标题栏的界面中,需要自己实现最小化.最大化.关闭.窗体背景等功能.最小化.最大化.关闭等按钮设计及功能比较简单,这里就不多做介绍.今天主要介绍一下绘制背景的问题,主要实现自适应屏 ...

  9. QT之——QTableWidget拖拽单元格并替换内容(进阶)

    所需待重写函数: [virtual] bool QObject::eventFilter(QObject *watched, QEvent *event); /* * Filters events i ...

随机推荐

  1. CSS3学习系列之布局样式(二)

    使用盒布局 在CSS3中,通过box属性来使用盒布局,例子如下: <!DOCTYPE html> <html lang="en"> <head> ...

  2. My sql添加远程用户root密码为password

    添加远程用户root密码为password grant all privileges on *.* to root@localhost identified by '123321' with gran ...

  3. Phpcms 前台页面实现分页

    phpcms开发就是模仿里面原有的方法进行扩展,前台要实现分页,就去找后台页面的分页实现. 如后台 扩展->后台操作日志,就有分页展示. 1.先去添加自己的分页方法(千万不要在原来的方法上修改, ...

  4. sqlserver提高篇续集

    七.数据完整性 1.概念:数据一致性和准确性. 分类:域完整性.实体完整性.引用完整性. 解析:域完整性也叫列完整性是指一个数据集对某个列是否有效和确定是否允许为空值.实体完整性也叫行完整性 要求所有 ...

  5. Hibernate 实体关联关系映射----总结

    在我看来,Hibernate提供这些映射关系,常用就是一对一和多对一,并且在能不用连接表的时候尽量不要用连接表.多对多会用到,如果用到了,应该首先考虑底层数据库设计是否合理.   在实际开发中,在Hi ...

  6. JavaScript系统学习小结——Object类型、Array类型

    今天学习JavaSript中引用变量中的Object类型和Array类型: 1. Js中大多数引用类型值都是Object类型的实例,Object类型在应用程序中存储和传输数据时,是非常理想的选择: 创 ...

  7. Django中ORM模型总结(一)[概述,查询语句]

    理解ORM框架 概述 O:(objects)->类和对象. R:(Relation)->关系,关系数据库中的表格. M:(Mapping)->映射. 作用: 可以通过类和类对象就可以 ...

  8. Swift 细节

    1.swift ?和 !的区别 1.1 Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化.如果在使 ...

  9. 基于脚本的modelsim自动化仿真笔记

    这里记录一下基于脚本的modelsim自动化仿真的一些知识和模板,以后忘记了可以到这里查找.转载请标明出处:http://www.cnblogs.com/IClearner/ . 一.基本介绍 这里介 ...

  10. JVM学习笔记三:垃圾收集器及内存管理策略

    垃圾收集器 上文说到了垃圾收集算法,这次我们聊一下HotSpot的具体垃圾收集器的实现,以JDK1.7为例,其包含的可选垃圾收集器如下图: 不同收集器之间的连线,代表它们可以搭配使用,收集器所属的区域 ...