QT5 自定义窗口的详细设计方案

本文档详细介绍了如何使用QT5在Windows系统下创建无边框窗口,包括实现难点、技术要点、界面示例和布局设计。通过使用Label作为边框,实现拖动窗口和改变窗口大小的功能。同时,文中还展示了如何制作可拖动的标题栏以及添加最大化、最小化系统按钮,提供了一种资源节省的解决方案。
摘要由CSDN通过智能技术生成

windows系统下,QT的Widget窗口,使用的是操作系统的窗口Style,很多老板不喜欢这个窗口的标题栏和系统按键,程序员自己无法更改这个窗口标题栏,而大伤脑筋。网上有很多介绍用QT实现无框架窗口的的案例都很好,但都是没有完整的案例可以使用。

今天,用ui拉控件的方式,实现了一个自定义窗口的框架,运行起来还算是稳定。分享出来让初学者学习研究。

一. 无边框窗口实现的难点

1、鼠标拖动标题栏,实现拖动窗口移动。

2、鼠标拖动窗口的边框、四角,实现窗口拖动改变窗口的大小。

二. 无边框窗口实现的技术要点

1、设置无边框

setWindowFlags(Qt::FramelessWindowHint);//无边框

2、调用 paintEvent 重绘窗口的边框

3、捕捉标题栏的鼠标拖动事件,实现拖动窗口移动。

4、过滤鼠标点击、移动、释放事件,拖动窗口边框,改变窗口大小。

三. 运行界面示例图

四. 运行界面组成

 

边框的设计结构如下图:

根据图的内容,很容易在UI中,通过 GridLayout 布局,对窗口的边框和窗口内容进行布局。

本例中,我使用了8个 Label 来作为窗口的边框,其中 4 个作为上下左右的边框,四个作为四个角的边框。 用了一个widget作为窗口内容的框架。总共9个元素形成一个窗口的整体框架,符合九宫布局格式,用 GridLayout进行布局。

上下边框Label设置固定高度 5pix, 左右边框label设置固定宽度5pix。 四个角设置固定5pix高,5pix宽。窗口内容widget根据布局自动拉伸宽高。

肯定有人问,我为什么用 Label作为边框,解释一下,

(1)节省资源:拉伸窗口时,必须捕捉鼠标的位置,如果整个窗口都开启鼠标跟踪,当鼠标在窗口上时,无论你是否想拉伸窗口,系统都在捕捉鼠标的位置,耗用资源太多。如果用label作为边框,只需要开启这九个Label的鼠标跟踪就可以了,只有鼠标在这9个Label上,系统才开始捕捉鼠标的位置,节省cpu资源。

(2)因为Label上可以用来显示图片,如果你不想画边框的话,在Label上贴图,可以做成好看的边框,比如圆角边框,或者带阴影的窗口。

  (3) 当然你可以不用Label, 一样可以完成这个功能,这不是本文讨论的内容。

五. 窗口布局设计方案

 1, 打开 QT Creator , 创建一个 widget 应用工程,选择 带上ui, 窗口的类型为 QMainWindow 或者 QDialog。工程的名字为 MainWindow, 当然你喜欢的话,工程名随你喜欢。

2, 打开 MainWindow ui,进行编辑。

3、删除MainWindow的菜单、工具栏、状态栏(根据需要是否保存状态栏)

4,拖进三个 Label 放在ui窗口的第一行,分别命名为:leftTopLabel, topLabel,rightTopLabel, 分别代表 左上角边框,顶部边框、右上角边框,清除 Label上的文字。

5、分别拖进去 一个 Label 一个 widget(frame也行)和一个 Label,放在第二行 命名为 :leftLabel, mainWidger, rightLabel.分别代表 左边框,主框架,右边框,清除Label上的文字。

6、拖进去三个Label,放在第三行,命名为:leftBottomLabel, bottomLabel,rightBottomLabel, 分别代表左下角边框,底部边框、右下角边框。清除Lael上的文字。

7、右键点击ui的mainWindow 空余地带,在菜单中选择布局,选择 Grid 布局, 9个元素平均分配大小。

8、 选择9个Label,在属性栏里, 开启鼠标跟踪。

9、选择顶部和底部两个Label, 在属性栏里,设置最大、最小高度为 5,选择鼠标样式为上下移动的鼠标样式。

10、 选择左右两个Label,在属性栏里,设置最大、最小宽度为5,选择鼠标样式为左右移动的鼠标样式。

11、选择左上、右下两个Label,在属性栏里,设置最大、最小宽度为5,最大最小高度为5, 设置鼠标样式为 左上右下的移动鼠标样式。

12、选择 右上、左下两个Label,在属性栏里,设置最大、最小宽度为5,最大最小高度为5,设置鼠标样式为右上左下的移动鼠标样式。

这样设置完后,整个窗口布局中, mainWidget就占据了基本全部的窗口区域,每个边框Label占据5pix的区域,基本上完成了整个窗口的布局设计。

13、 编辑 mainWindow.cpp , 在构造函数里,添加下面的代码:

// 设置无边框
  setWindowFlags(Qt::FramelessWindowHint);//无边框
 // 设置透明度
   setWindowOpacity(0.99);

14、运行程序,一个无边框的窗口就出现了,背景颜色是 QT默认的灰白色,设置透明度,可以设置窗口的透明效果。把鼠标分别放在窗口的上下左右边框上,看鼠标的样式是否是 左右、上下移动的鼠标样式,四个边角,是否是斜上、斜下移动的鼠标样式。

15、重写 paintEvent , 给没边框的窗口画一个边框,给窗口设定一个背景色。

void MainWindow::paintEvent(QPaintEvent* event)
 {
    // 绘图处理
    // 重绘窗口的背景颜色
    QPalette palette = this->palette();
    qDebug() << "palette color: " << palette.color(QPalette::Window);
    QColor color(100,100,100);   
    palette.setBrush(QPalette::Window, QBrush(color));
    this->setPalette(palette);
    // 重绘窗口的边框大小
    QPainter painter(this);
     QRect rect = this->rect();
     QPen pen;
     pen.setWidth(5);
     pen.setColor(Qt::black);
     painter.setPen(pen);
     painter.drawRect(rect);

    QMainWindow::paintEvent(event);
 }

 

重新运行程序,一个崭新的窗口就出来了。

六. 拖动窗口的边框,改变窗口的大小的实现。

1,  在mainWindow.cpp 的 MainWindow 构造函数中,给上面做好的边框Label添加事件过滤器,

//设置过滤器,8个Label作为边框,过滤的鼠标事件
    ui->leftTopLabel->installEventFilter(this);
    ui->topLabel->installEventFilter(this);
    ui->rightTopLabel->installEventFilter(this);
    ui->leftLabel->installEventFilter(this);
    ui->rightLabel->installEventFilter(this);
    ui->leftBottomLabel->installEventFilter(this);
    ui->bottomLabel->installEventFilter(this);
    ui->rightBottomLabel->installEventFilter(this);

 //设置拉伸边框改变大小的参数
    mWp = unKnown; //设置拉伸边框初始标志为 unKnow, 这是一个枚举型变量
    m_bPressed = false;  // 设置鼠标按下的状态,如果鼠标在边框Label上拖动,则改参数为false.
    mouseEvent = nullptr;  //设置鼠标事件的初始值,默认为null

2. 在 mainWindow.h 头文件中, 定义 mWp, m_bPressed,, mouseEvent ,pLast参数。

enum LabelBorderStatus {
       unKnown = 0,
       toTop = 1,
       toBottom = 2,
       toLeft = 3,
       toRight = 4,
       toLeftTop = 5,
       toRightTop = 6,
       toLeftBottom = 7,
       toRightBottom = 8
    };

 LabelBorderStatus mWp;
    QMouseEvent* mouseEvent;
    bool m_bPressed;
    QPoint pLast; 

(1)定义了一个枚举类型, 用来确定是哪一条边框被拖动,后者哪一个边角被拖动。默认为 unKnow。系统中的变量名为 mWp.

(2)定义了一个布尔型 m_bPressed. 当鼠标在边框Label上被按压时,设定标志位 true, 如果有鼠标被释放,则 false

(3)定义了一个位置 pLast, 每次拖动后,保存拖动后的坐标点,再次触发拖动后,新的位置与该变量的差值,就是窗口应该增加或减少的数量。

 

3、 实现拖动,重写事件过滤器。

// 过滤 8 个 Label 边框的点击、移动、改变窗口大小
 bool MainWindow::eventFilter(QObject *target, QEvent *event)
 {
    // 如果过滤事件是鼠标按下,设置改变窗口大小的标志为鼠标按下状态。
     if(event->type() == QEvent::MouseButtonPress)
     {
         //检测是哪条边框按下
         mWp = testLabelBorder(target->objectName());
        if(mWp == LabelBorderStatus::unKnown)
        {
           m_bPressed = false;
        }
        else {
             m_bPressed = true;
             mouseEvent = nullptr;
             mouseEvent = static_cast<QMouseEvent*>(event);
             if(mouseEvent )
             {
                 // 获取鼠标按下的定位。
                 pLast = mouseEvent->globalPos();
                 event->ignore();
             }
  • 14
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值