3

Qt--无边框窗口完美(FrameLess)实现,包含缩放和移动功能重写。 - 对愁眠

 1 year ago
source link: https://www.cnblogs.com/duichoumian/p/16855107.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
  1. Qt原本的窗口虽然可以通过QSS样式进行美化,但是只是对客户区有用,对于客户区是无效的。所以想做出一个比较好看的程序,还得自己重写实现无边框窗口。
  2. Qt实现无边框其实一句代码就可以,但是窗口自带的缩放,移动功和关闭功能都会没有,需要自己重写。
    setWindowFlags(Qt::FramelessWindowHint);
    1330717-20221103161333619-794888005.png

重写无边框窗口

1.效果如下

1330717-20221103170255084-1940089231.gif

2.由于无边框窗口没有了标题栏和最小化,最大化,关闭的按钮,所以需要自己布局相对应的控件,并重写事件。我的布局如下
1330717-20221104095019889-760633711.png
3.事件对应代码

展开

//窗口关闭事件
void MainWindow::windowClose()
{
    qApp->exit();
}

//窗口最小化
void MainWindow::windowMin()
{
    this->showMinimized();
}
//窗口最大化
void MainWindow::windowMax()
{
    isMaxWin=!isMaxWin; 
    if(isMaxWin)    //根据是否最大化窗口,改变对应的图标
    {
        ui->btnMax->setIcon(QIcon(":/icons/normal.png"));
        this->showMaximized();
    }
    else
    {
        ui->btnMax->setIcon(QIcon(":/icons/maxsize.png"));
        this->showNormal();
    }
}

4.窗口移动事件,需要重写鼠标的点击事件和移动事件

展开

void MainWindow::mousePressEvent(QMouseEvent*event)
{
    if(event->button()==Qt::LeftButton) //如果鼠标左键按下
    {
        isPressed=true;         
        curPos=event->pos();    //记录当前的点击坐标
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent*event)
{
    if(isPressed) //如果鼠标左键按下           
    {
        this->move(event->pos()-curPos+this->pos());    //窗口移动
    }
}

//鼠标释放
void MainWindow::mouseReleaseEvent(QMouseEvent*event)
{
    isPressed=false;    
}

3.窗口的缩放功能比较麻烦,需要用到windows的消息机制.代码如下

展开

//需要包含头文件
/*
    #include <qt_windows.h>
    #include <Windowsx.h>
*/
//消息处理
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
    int m_nBorder = 5;  //边界宽度
    Q_UNUSED(eventType)
    MSG *param = static_cast<MSG *>(message);

    switch (param->message)
    {
    case WM_NCHITTEST:
    {
        int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();
        int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();


        *result = HTCAPTION;

        //判断鼠标位置是否位于窗口边界
        if ((nX > 0) && (nX < m_nBorder))
            *result = HTLEFT;

        if ((nX > this->width() - m_nBorder) && (nX < this->width()))
            *result = HTRIGHT;

        if ((nY > 0) && (nY < m_nBorder))
            *result = HTTOP;

        if ((nY > this->height() - m_nBorder) && (nY < this->height()))
            *result = HTBOTTOM;

        if ((nX > 0) && (nX < m_nBorder) && (nY > 0)
                && (nY < m_nBorder))
            *result = HTTOPLEFT;

        if ((nX > this->width() - m_nBorder) && (nX < this->width())
                && (nY > 0) && (nY < m_nBorder))
            *result = HTTOPRIGHT;

        if ((nX > 0) && (nX < m_nBorder)
                && (nY > this->height() - m_nBorder) && (nY < this->height()))
            *result = HTBOTTOMLEFT;

        if ((nX > this->width() - m_nBorder) && (nX < this->width())
                && (nY > this->height() - m_nBorder) && (nY < this->height()))
            *result = HTBOTTOMRIGHT;

        if (*result == HTCAPTION)
        {
            return false;
        }
        return true;
    }
    }
    return QMainWindow::nativeEvent(eventType, message, result);
}

4.要实现窗口的正常功能,还需要对窗口的Flags进行一些设置,同时也要给父类设置,要不然会有问题的.

1330717-20221104102014521-1248945713.png

其中 Qt::FramelessWindowHint设置窗口为无边框,Qt::Window表示widegt为窗口,Qt::WindowMinimizeButtonHint 程序在任务栏被点击时能够显示/隐藏.

1.把以上那些功能实现了,无边框窗口基本可以用了,至于如何用Qss美化,界面如何布局,那就看每个人了,反正可以自己进行定制
2.由于用到了windows下的消息机制,所以该实现只适用于Windows系统.虽然我在GitHub上找到不少可以跨平台的无边框窗口实现,但是都不是很完美,有兴趣的自己可以去GitHub上去看看.
3.目前的实现方法都会有一些问题,没有原本的好,但基本不影响使用,如果有需要自己也可以进行优化,所以问题不大.

完整项目代码

github: QtFrameLess

星期五女孩

1330717-20221104111152572-1993388121.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK