Qt没有真正完美的无边框解决方案吗?

尝试过很多种方案,都无法真正完美的实现无边框方案, 尤其是用 nativeEvent方法的时候,在WM_GETMINMAXINFO里,一定要写成这样c…
关注者
355
被浏览
247,339

18 个回答

谢... 忘记 哪个大佬一年前邀请我了,看了半天大家都实现的Windows上跟Mac上的无边框的解决方案。

这里我就抛砖引玉,上个Linux的无边框的解决方案吧。

估计Qt写Linux无边框的博客我这是全网第一份。



众所周知,Linux是基于X协议的,所以这里要写x函数,本次使用xlib来实现。你也可以用xcb的函数。

是的我又犯懒了,本来想自己写xlib的函数的,发现deepin的dktwidget里已经有对应的实现了,这里我们把他偷过来

github.com/linuxdeepin/

先上实现,这里上关键代码,重写这三个函数就可以达到效果

void FLWidget_Linux::mouseMoveEvent(QMouseEvent *event)
#ifdef Q_OS_LINUX
    const int x = event->x();
    const int y = event->y();
    if (resizingCornerEdge == XUtils::CornerEdge::kInvalid)
        XUtils::UpdateCursorShape(this, x, y, this->layout()->contentsMargins(), ResizeHandleWidth);
#endif
    return QWidget::mouseMoveEvent(event);
void FLWidget_Linux::mousePressEvent(QMouseEvent *event)
#ifdef Q_OS_LINUX
    const int x = event->x();
    const int y = event->y();
    if (event->button() == Qt::LeftButton)
        const XUtils::CornerEdge ce = XUtils::GetCornerEdge(this, x, y, this->layout()->contentsMargins(), ResizeHandleWidth);
        if (ce != XUtils::CornerEdge::kInvalid)
            resizingCornerEdge = ce;
            //send x11 move event dont send mouserrelease event
            XUtils::SendButtonRelease(this, event->pos(), event->globalPos());
            XUtils::StartResizing(this, QCursor::pos(), ce);
#endif
    return QWidget::mousePressEvent(event);
void FLWidget_Linux::resizeEvent(QResizeEvent *e)
#ifdef Q_OS_LINUX
    int resizeHandleWidth = ResizeHandleWidth;
    XUtils::SetWindowExtents(this, this->layout()->contentsMargins(), resizeHandleWidth);
#endif
    return QWidget::resizeEvent(e);
void FLWidget_Linux::mouseReleaseEvent(QMouseEvent *event)
#ifdef Q_OS_LINUX
    resizingCornerEdge = XUtils::CornerEdge::kInvalid;
#endif
    return QWidget::mouseReleaseEvent(event);

这里有个小坑,使用xlib的move之后,Qt会收不到鼠标抬起的事件,所以这里我又在deepin的代码里加了个新的函数

//XUtils::SendButtonRelease(this, event->pos(), event->globalPos());
void SendButtonRelease(const QWidget *widget,
                                     const QPoint &pos, const QPoint &globalPos)
    const auto display = QX11Info::display();
    const auto screen = QX11Info::appScreen();
    XEvent xevent;
    memset(&xevent, 0, sizeof(XEvent));
    xevent.type = ButtonRelease;
    xevent.xbutton.button = Button1;
    xevent.xbutton.window = widget->effectiveWinId();
    xevent.xbutton.x = pos.x();
    xevent.xbutton.y = pos.y();
    xevent.xbutton.x_root = globalPos.x();
    xevent.xbutton.y_root = globalPos.y();
    xevent.xbutton.display = display;
    XSendEvent(display, widget->effectiveWinId(), False, ButtonReleaseMask,




    
 &xevent);
    XFlush(display);

来手动发送下这个事件


效果

Linux下Qt无边框的解决方案 https://www.zhihu.com/video/1223701344076697600

Ubuntu

ubuntu的无边框很有意思,你只需要把Qt的flag设置成 Qt::FramelessWindowHint ,不用重写x消息就能够自己无边框可移动。

Qt5.15

据说Qt5.15的QWindow类自带了无边框可移动的flag,可以等等这个feature。

未实现的

至于最大化,最小化,全屏之类的,deepin的代码里都封装好了对应的x函数。我又犯懒了,不想再加上自定义的标题栏,这个就算是抛砖引玉吧

上github代码链接 github.com/CryFeiFei/FL

也顺便实现了下windows的无边框的实现,欢迎star。

也欢迎关注我的公众号:张小飞那些事儿

上个链接