近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅。

网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo,写了一个小时,问题太多了,扔一边先不管了。

今天需要改进UI界面,没办法了,重新整理了下思路,没想到做出来了。下面来分享下实现的过程,也许是菜鸟专栏,高手勿喷~

1.首先大家要了解各九宫格的概念

一个窗体可以被划分为上、下、左、右、左上、左下、右上、右下、中间,除了中间部分,其他都需要写程序处理。

在程序中定义Padding 为2,并同时定义枚举类型。

#define PADDING 2
enum Direction { UP=0, DOWN=1, LEFT, RIGHT, LEFTTOP, LEFTBOTTOM, RIGHTBOTTOM, RIGHTTOP, NONE };

2.定义一个方法,参数为鼠标目前的全局位置。

void Dialog::region(const QPoint &cursorGlobalPoint)
{
  // 获取窗体在屏幕上的位置区域,tl为topleft点,rb为rightbottom点
QRect rect = this->rect();
QPoint tl = mapToGlobal(rect.topLeft());
QPoint rb = mapToGlobal(rect.bottomRight());
int x = cursorGlobalPoint.x();
int y = cursorGlobalPoint.y(); if(tl.x() + PADDING >= x && tl.x() <= x && tl.y() + PADDING >= y && tl.y() <= y) {
// 左上角
dir = LEFTTOP;
this->setCursor(QCursor(Qt::SizeFDiagCursor)); // 设置鼠标形状
} else if(x >= rb.x() - PADDING && x <= rb.x() && y >= rb.y() - PADDING && y <= rb.y()) {
// 右下角
dir = RIGHTBOTTOM;
this->setCursor(QCursor(Qt::SizeFDiagCursor));
} else if(x <= tl.x() + PADDING && x >= tl.x() && y >= rb.y() - PADDING && y <= rb.y()) {
//左下角
dir = LEFTBOTTOM;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
} else if(x <= rb.x() && x >= rb.x() - PADDING && y >= tl.y() && y <= tl.y() + PADDING) {
// 右上角
dir = RIGHTTOP;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
} else if(x <= tl.x() + PADDING && x >= tl.x()) {
// 左边
dir = LEFT;
this->setCursor(QCursor(Qt::SizeHorCursor));
} else if( x <= rb.x() && x >= rb.x() - PADDING) {
// 右边
dir = RIGHT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}else if(y >= tl.y() && y <= tl.y() + PADDING){
// 上边
dir = UP;
this->setCursor(QCursor(Qt::SizeVerCursor));
} else if(y <= rb.y() && y >= rb.y() - PADDING) {
// 下边
dir = DOWN;
this->setCursor(QCursor(Qt::SizeVerCursor));
}else {
// 默认
dir = NONE;
this->setCursor(QCursor(Qt::ArrowCursor));
}
}

3.在对话框类中定义几个私有成员变量

bool isLeftPressDown;  // 判断左键是否按下
QPoint dragPosition; // 窗口移动拖动时需要记住的点
Direction dir; //
窗口大小改变时,记录改变方向

编写对话框构造函数,初始化几个变量并做一些其他工作。

isLeftPressDown = false;
this->dir = NONE;
this->setMinimumHeight(100);
this->setMinimumWidth(150);
this->setWindowFlags(Qt::FramelessWindowHint|Qt::WindowSystemMenuHint); // 设置成无边框对话框
this->setMouseTracking(true);                    // 追踪鼠标
this->setStyleSheet("QDialog{background:url(:/bg_main.png)}"); // 设置样式背景色,可有可无

4.接着就要实现几个重要的重载事件了

void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);

实现过程如下:

void Dialog::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton) {
isLeftPressDown = false;
if(dir != NONE) {
this->releaseMouse();
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
} void Dialog::mousePressEvent(QMouseEvent *event)
{
switch(event->button()) {
case Qt::LeftButton:
isLeftPressDown = true;
if(dir != NONE) {
this->mouseGrabber();
} else {
dragPosition = event->globalPos() - this->frameGeometry().topLeft();
}
break;
case Qt::RightButton:
this->close();
break;
default:
QDialog::mousePressEvent(event);
} } void Dialog::mouseMoveEvent(QMouseEvent *event)
{
QPoint gloPoint = event->globalPos();
QRect rect = this->rect();
QPoint tl = mapToGlobal(rect.topLeft());
QPoint rb = mapToGlobal(rect.bottomRight()); if(!isLeftPressDown) {
this->region(gloPoint);
} else { if(dir != NONE) {
QRect rMove(tl, rb); switch(dir) {
case LEFT:
if(rb.x() - gloPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(gloPoint.x());
break;
case RIGHT:
rMove.setWidth(gloPoint.x() - tl.x());
break;
case UP:
if(rb.y() - gloPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(gloPoint.y());
break;
case DOWN:
rMove.setHeight(gloPoint.y() - tl.y());
break;
case LEFTTOP:
if(rb.x() - gloPoint.x() <= this->minimumWidth())
rMove.setX(tl.x());
else
rMove.setX(gloPoint.x());
if(rb.y() - gloPoint.y() <= this->minimumHeight())
rMove.setY(tl.y());
else
rMove.setY(gloPoint.y());
break;
case RIGHTTOP:
rMove.setWidth(gloPoint.x() - tl.x());
rMove.setY(gloPoint.y());
break;
case LEFTBOTTOM:
rMove.setX(gloPoint.x());
rMove.setHeight(gloPoint.y() - tl.y());
break;
case RIGHTBOTTOM:
rMove.setWidth(gloPoint.x() - tl.x());
rMove.setHeight(gloPoint.y() - tl.y());
break;
default:
break;
}
this->setGeometry(rMove);
} else {
move(event->globalPos() - dragPosition);
event->accept();
}
}
QDialog::mouseMoveEvent(event);
}

到此为止,一个无边框窗体拖动并且改变大小的功能就实现了,Run and debug it。

总结起来,这个算法其实并不复杂,就看有几个点能不能想到:

1)窗体矩形区域要转换成在屏幕上的区域,我采取的方式就是取TopLeft和RightBottom两个点来确定这个区域。

2)鼠标移动要去全局的坐标。

3)region函数中判断坐标区间,然后改变鼠标形状,这块很容易出错,如果你一下子就写出来,那我真的很佩服。

这个纠结的网上都没有现成代码的问题,终于在今天圆满解决了。如需运行,请下载实例代码:SizableNoFrame.rar

转载请注明出处哦:http://www.cnblogs.com/xufeiyang/p/3313104.html

http://download.csdn.net/detail/qq_33266987/9497160

Qt 无边框窗体改变大小 完美实现(全部自己实现)的更多相关文章

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

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

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

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

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

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

  4. WinForm 无边框窗体改变尺寸及移动窗体

    #region 无边框窗体移动改变大小 [DllImport("user32.dll")] public static extern bool ReleaseCapture(); ...

  5. winform无边框窗体更改大小

    实现方式一: const int HTLEFT = 10; const int HTRIGHT = 11; const int HTTOP = 12; const int HTTOPLEFT = 13 ...

  6. C# WinForm 拖动无边框窗体 改变无边框窗体尺寸

    经常遇到这种情况.窗体的边框去掉了.然后种种问题就出来了:不能拖动.不能改变窗体大小.不能......当然.肯定有解决方案滴*^_^*今天的目标就是:可以直接拖动没有边框的窗体.可以直接拉拽窗体改变其 ...

  7. C# 改变无边框窗体尺寸大小的方法

    ; ; ; ; ; ; const int HTBOTTOMLEFT = 0x10; ; protected override void WndProc(ref Message m) { switch ...

  8. 【C#】使用DWM实现无边框窗体阴影或全透窗体

    1.无边框窗体阴影,win7(需要开启Aero效果)及以上系统 public class LdwmForm : Form { public LdwmForm() { Initialize(); } / ...

  9. Winform拖拽改变无边框窗体大小

    大家在进行Winform开发过程中,很容易就可以完成一个窗口的布局工作,但现在的软件界面美化效果一个比一个好,很多软件都是无边框的,于是乎,你是不是也感叹:winform的带边框的窗体如此丑陋,我一定 ...

随机推荐

  1. Xamarin Android长度单位区别

    Xamarin Android长度单位区别 Android中长度单位有6种:px.in.mm.pt.dp/dip.sp.其中,px表示显示设备的一个像素:in表示显示设备的1英寸:mm表示显示设备的1 ...

  2. Quartz.net misfire实践

      1.问题描述 在使用Quartz.net定时运行作业时,存在一种情况:作业错过了某次执行,当作业恢复的时候应该怎么处理?如:job1在3:50的时候应该执行的,但此刻job1处于暂停状态,而到3: ...

  3. EntityFramework 6.0< Code First > 连接 Mysql数据库

    网上有很多关于用EntityFrame来连接Mysql数据库的教程,可是很多并不靠谱,转载的太多了.找了很久,总算是配置好了,现在分享一下. 一,安装:     1.开发环境: VS2013与EF6 ...

  4. POJ3694 Network(边双连通分量+缩点+LCA)

    题目大概是给一张图,动态加边动态求割边数. 本想着求出边双连通分量后缩点,然后构成的树用树链剖分+线段树去维护路径上的边数和..好像好难写.. 看了别人的解法,这题有更简单的算法: 在任意两点添边,那 ...

  5. JavaScript判断用户是通过电脑端还是移动端访问

    每个浏览器对应的useragent不同,JavaScript通过判断useragent的类型,便可以判断出用户所使用的浏览器类型,包括 IE.Firefox.chrome等.还可以判断用户是否通过移动 ...

  6. c/c++ 笔试面试题

    #include <iostream> using namespace std; class A { public: void sayHi(){ cout<<"hel ...

  7. JAVA7遍历文件夹

    在JAVA7中提供了新的遍历文件的方法,比原有File类的递归遍历效率要好大约30%左右. 测试结果: 测试用的File类的递归,是经过对比测试几种方法,找出相对效率较好的来和JAVA7进行测试. 1 ...

  8. MySQL修改root密码的各种方法整理

    方法一: 1.首先cmd中输入  net stop mysql   //停止Mysql服务 2.然后在my.ini文件中的[mysqld]下面一行添加 skip_grant_tables 3.在cmd ...

  9. CentoS 下安装gitlab

    curl https://raw.github.com/mattias-ohlsson/gitlab-installer/master/gitlab-install-el6.sh | bash 报错 ...

  10. org.apache.hadoop.hdfs.server.namenode.SafeModeException: Cannot create directory /user/hive/warehouse/page_view. Name node is in safe mode

    FAILED: Error in metadata: MetaException(message:Got exception: org.apache.hadoop.ipc.RemoteExceptio ...