QT实现窗口置顶、置顶状态切换、多窗口置顶优先关系

本文介绍了在Qt界面开发中如何实现窗口置顶,并探讨了动态切换置顶状态、多个置顶窗口的优先级问题以及解决闪烁和置顶失效的策略。通过Qt::WindowFlags设置窗口属性,利用setWindowFlags函数可以轻松实现窗口置顶和取消置顶。当遇到置顶失效或被其他窗口覆盖的情况,可以尝试使用Windows API的SetWindowPos函数来强制置顶,并通过定时器确保窗口始终保持在最上方。
摘要由CSDN通过智能技术生成

我们使用QT进行界面开发时,可能会遇到需要将窗口置顶的情况。最常见的就是,需要制作一个悬浮工具栏,悬浮菜单,甚至是悬浮的画板。这就意味这我们需要将这个窗口置顶于“系统”以及我们自己“软件”的窗口之上。
其实实现的方法很简单,就是在创建这个窗口类的时候,在构造函数中的加一个Qt::WindowFlags
枚举标识

Widget::Widget(QWidget *parent)
    : QWidget(parent,Qt::Widget | Qt::WindowStaysOnTopHint)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Qt::WindowStaysOnTopHint的意思就是窗口置顶的意思,设置了之后就能一直悬浮在桌面上面了。
有关其他的枚举标识,可以参考这个。Qt::WindowFlags枚举类型解析 像取消顶部工具条、无边框、弹窗化什么的,都可以实现。

现在有一种情况是,我们需要灵活切换窗口的置顶状态,那就可以直接调用相关的设置接口来实现。setWindowFlags();
具体的话是这样:

void Widget::on_pushButton_clicked()
{
    if(!istop)
    {
        Qt::WindowFlags m_flags = windowFlags();
        setWindowFlags(m_flags | Qt::WindowStaysOnTopHint);
        show();
        qDebug()<<"always top";
    }else{
        //Qt::WindowFlags m_flags = windowFlags();
        //setWindowFlags(Qt::Widget);
        setWindowFlags(NULL);
        show();
        qDebug()<<"no always top";
    }
    istop=!istop;
}

setWindowFlags(Qt::Widget);和setWindowFlags(NULL);都可以取消置顶状态,只要重新设置就可以了。但这样设置之后,窗口是默认不显示的,所以需要show一下。但show的时候,窗口会有明显的闪烁。这个还没能很好的解决。

另外还要一个问题,两个置顶窗口之间的优先级无法设置和判定,也就是说用同样的方法设置两个置顶窗口,他们之间的拖动,是可以覆盖住对方的,取决于当前焦点点击再哪个窗口里面。
这个问题,在某些场合里面是互斥违和的。
目前有一种方法是,把a对象设置成b对象的父类,那么b对象就始终置顶与a对象

Widget::Widget(QWidget *parent)
    : QWidget(parent,Qt::Widget | Qt::WindowStaysOnTopHint)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    son_widget_1 = new QWidget(this);
    son_widget_2 = new QWidget(son_widget_1);

    son_widget_1->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);
    son_widget_2->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);
    son_widget_1->setWindowTitle("son_widget_1");
    son_widget_2->setWindowTitle("son_widget_2");

    son_widget_1->show();
    son_widget_2->show();
}

在这里插入图片描述
这三个置顶窗口是互相叠加的,跟父子关系有关。(son_widget_1/2设置了Qt::Dialog,如果是Qt::Widget,在设置了父类的情况下,是父类的子部件)。

2022.5.25补充
感谢评论区的朋友提供更好的解决方式,解决了切换置顶时必须show所导致的闪烁问题,以下是验证过可行的代码:

void Widget::on_pushButton_clicked()
{
    if(!istop)
    {
//        Qt::WindowFlags m_flags = windowFlags();
//        setWindowFlags(m_flags | Qt::WindowStaysOnTopHint);
//        show();
        qDebug()<<"always top";

        QWindow* pWin = this->windowHandle();
        pWin->setFlags(Qt::Widget | Qt::WindowStaysOnTopHint);
    }else{
        //Qt::WindowFlags m_flags = windowFlags();
//        setWindowFlags(Qt::Widget);
//        //setWindowFlags(NULL);
//        show();

        QWindow* pWin = this->windowHandle();
        pWin->setFlags(Qt::Widget);
        qDebug()<<"no always top";
    }
    istop=!istop;
}

2024.5.20补充
最近遇到一个很奇怪的问题,在某几台客户电脑中,窗口的置顶效果会失效…其实也不是完全失效,对于系统窗口(文件夹这些)还是可以置顶的,可如果打开一个其他软件的页面,或者qt程序本身的其他页面,还是会覆盖住我们的置顶窗口。
这个问题原因不明,只体现在部分电脑中,非常奇怪,几年都这样写的置顶方法,突然碰到这样的问题。

下面说一下解决方法:
除了qt中的Qt::WindowStaysOnTopHint外,我们其实还可以用window api来实现置顶,也就是SetWindowPos(pro中添加LIBS += -lUser32,对应地方添加头文件#include “Windows.h”,#include “WinUser.h”)

SetWindowPos((HWND)this->winId(),HWND_TOPMOST,this->pos().x(),this->pos().y(),this->width(),this->height(),SWP_SHOWWINDOW);

HWND_TOPMOST是置顶最上层的意思,SWP_SHOWWINDOW就是显示窗口,当然也有其他含义的枚举量,这里不一一列举了。注意,SetWindowPos需要在窗口show过之后再设置,我尝试过在构造函数中设置,结果整个原本半透明的窗口,直接变成全黑,无法刷新了。

进行过SetWindowPos后,该窗口就是置顶效果了,跟Qt::WindowStaysOnTopHint其实是一样的。但很不幸,在那几台电脑中同样出现了其他窗口的覆盖问题,证明可能跟电脑的某些设置有关,跟代码层面无关。
幸运的是,在置顶窗口被覆盖后,如果重新SetWindowPos,窗口还是可以重新置顶的。给人的感觉就是,就算你是置顶窗口,但其他页面弹出来的那一刻,还是默认盖在你上面了。
无奈,最后使用了定时器触发SetWindowPos的方法,思路是当窗口显示的时候,每隔一秒钟就SetWindowPos一下,把窗口置顶显示出来。这样能重新将窗口置顶,不至于被盖住。
另外,我测试过,不用担心定时器触发SetWindowPos的时候,会把当前焦点吸引过去,所以就算你在拖动其他窗口,在主程序内的其他操作(下拉框选择,lineedit输入文件),都不会被打断动作。最后,只需要在析构窗口的时候,停止定时器即可。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值