前言

  1. Qt原本的窗口虽然可以通过QSS样式进行美化,但是只是对客户区有用,对于客户区是无效的。所以想做出一个比较好看的程序,还得自己重写实现无边框窗口。
  2. Qt实现无边框其实一句代码就可以,但是窗口自带的缩放,移动功和关闭功能都会没有,需要自己重写。
    setWindowFlags(Qt::FramelessWindowHint);
  3. 无边框窗口 java 无边框窗口模式_Qt


重写无边框窗口

1.效果如下

无边框窗口 java 无边框窗口模式_无边框窗口 java_02


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

无边框窗口 java 无边框窗口模式_无边框_03


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进行一些设置,同时也要给父类设置,要不然会有问题的.

无边框窗口 java 无边框窗口模式_Qt_04


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

一些问题

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

完整项目代码