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

摘要:
无};rect();=x和=tl.x()&=rb.y()-衬垫&=rb.x()-衬垫&=tl.x()+衬垫elseif(x<=rb.x()&=tl.y()&&setCursor(QCursor(Qt;}elseif(y<=rb.y()&&

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

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

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

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

Qt 无边框窗体改变大小 完美实现(全部自己实现)第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 无边框窗体改变大小 完美实现(全部自己实现)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于UGUI的Image,Text (转雨凇momo)Web开发学习之路--Eclipse+Tomcat+mysql之初体验下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

eclipse导入maven项目有红叉及pom.xml出错的问题的解决

导入我们的项目的时候总会出现很多红叉,看着很难受,其实可以解决的(本人使用方法一解决)解决方法:1、先build project,然后右键项目->maven->update projectpom还是有问题就到这个目录,打开命令行,mvn clean->mvn eclipse:clean->mvn eclipse:eclipse 基本...

meter标签

meter meter元素标签用来表示范围已知且可度量的等级标量或分数值,如磁盘使用量比例、关键词匹配程度等。需要注意的是,meter不可以用来表示那些没有已知范围的任意值,例如重量、高度,除非已经设定了它们值的范围。meter元素共有6个属性: Value:表示当前标量的实际值;如果不做指定,那么meter标签中的第一个数字就会被认为是其当前实际值,例如...

VMware共享文件夹

如何能将文件在虚拟机和Win7(在这里以Win7为例,WinXP操作一样)下实现互传。方法有很多种。今天,我们就介绍其中一种方法,通过VMware的共享文件夹来实现虚拟机Ubuntu与Win7的文件传输。 第一步:启动Ubuntu 12.04(其他版本的Ubuntu操作差不多)         1. 在VMware虚拟机界面,点VM->Install...

Springboot的开发环境(dev)、测试环境(beta)和生产环境(product)打包部署

1、在项目开发过程中需要考虑不同的运行环境:开发环境(dev)、测试环境(beta)和生产环境(product)。在以往的开发过程中通常使用Maven构建工具进行控制,但却需要进行大量的配置。SpringBoot考虑到此类问题,专门设计了profile支持。   备注:尤其是项目开发完毕,在正式环境部署的时候出现问题,进行本地调试的时候就头疼了,因为正式环...

CSS样式表定义让文字自动适应Table宽度

以下的例子是用样式实现,文字自动适应Table的宽度,并且超出的宽度的文字自动隐藏。IE下面还可以自动出现...的省略符号.关键样式:table-layout:fixed 固定布局的算法,则表格被呈递的默认宽度为 100% (For IE,Mozilla)text-overflow:ellipsis 当对象内文本溢出时显示省略标记(...) (For IE...

Cesium 拾取 API 完全总结

先讲怎么用,再讲大致原理。 1 拾取坐标 > 仅拾取椭球体表面坐标 使用 Camera.prototype.pickEllipsoid 方法,接受一个必选的屏幕坐标,返回一个三维世界坐标 Cartesian3。 > 拾取带地形高度的地表坐标 使用 Globe.prototype.pick 方法。需要事先使用 Camera.prototype.g...