欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt自定义标题栏-移动窗口

程序员文章站 2022-03-07 16:01:49
...

前情提要

众所周知,一个最简单的窗口也是有标题栏的

Widnows默认提供的标题栏上有:

图标-窗口标题-Min-Max-Close按钮

但是,这未免太过局限

高*度的自定义是极客(Geek)精神不可或缺的一部分

如果你想在标题栏上增加/减少控件,或改变布局、颜色、Size

就必须抛弃Windows提供的嗟来之食

蹴尔而与之,乞人不屑也

じゃあ、どうする

使用无边框窗口即可

setWindowFlags(Qt::FramelessWindowHint);//Qt

这样就可以去除默认的标题栏,取而代之的便是光秃秃的客户区

你问我接下来怎么办?

那自然是自己写一个标题栏,当然这不是重点

只是你很快就会发现:根本没法移动窗口

それは決まってんだろう(那可不废话)

衣来伸手饭来张口,吃久了五斗米都不知道怎么下地了

正题

前摇巨长,现在进入正题,重点讲讲如何移动窗口

有两种方式:

  • 监测鼠标动作
  • 响应Windows消息,伪造标题栏

手动模拟

第一种最直观,平时移动窗口的方式不就是:

在鼠标在标题栏按下左键并移动 就可以带着窗口一起飞嘛

那只要手动检测鼠标状态 并移动窗口即可

void Widget::mousePressEvent(QMouseEvent* event)//鼠标按下
{
    curPos = event->screenPos().toPoint();
}

void Widget::mouseMoveEvent(QMouseEvent* event)//鼠标按着并移动
{
    if (!(event->buttons() & Qt::LeftButton)) return;//左键按下
    QPoint mousePos = event->screenPos().toPoint();
    QPoint newPos = this->pos() + mousePos - curPos;
    curPos = mousePos;
    move(newPos);
}

每次鼠标移动都会触发Move消息,只要计算与上次移动的差值并同步移动窗口,即可

这里要注意几个细节:

  • 最好用函数自带的参数event,因为QCursor::pos()更新相对滞后

  • 最好用鼠标的全局坐标event->screenPos(),而不是相对窗口坐标event->pos(),因为后者在鼠标快速移动的情况下可能越界导致Bomb爆炸,窗口鬼畜

伪造消息

第二种,欺骗Windows,假装自定义标题栏就是原来的标题栏

响应Windows消息即可

bool Widget::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
    Q_UNUSED(eventType);
    MSG* msg = (MSG*)message;
    switch (msg->message) {
    case WM_NCHITTEST://鼠标移动消息
        int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x();//解析鼠标相对坐标
        int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y();
        if (ui->label_title->geometry().contains(xPos, yPos)) //标题栏(伪)
            *result = HTCAPTION;//POINT重点语句,通过result指针返回--------------------------------<-
        else //其他部分不做处理,返回false,留给其他事件处理器处理
            return false;
        return true;
    }
    return false; //此处返回false,留给其他事件处理器处理
}

通过result指针,将结果返回给Windows,假装是标题栏(CAPTION)

Peace

相关标签: Qt qt windows