Giter Site home page Giter Site logo

wangwenx190 / framelesshelper Goto Github PK

View Code? Open in Web Editor NEW
837.0 23.0 201.0 12.55 MB

Project moved to: https://github.com/stdware/qwindowkit Cross-platform window customization framework for Qt Widgets and Qt Quick. Supports Windows, Linux and macOS.

License: MIT License

C++ 87.01% CMake 5.47% Objective-C++ 2.56% C 4.06% QMake 0.68% Batchfile 0.23%
win32 windows qt frameless frameless-windows frame-shadow dwm frameless-helper

framelesshelper's People

Contributors

alexandreptj avatar altairwei avatar czyt1988 avatar julienmaille avatar kira-96 avatar mentalfl0w avatar micpub avatar ollie-dawes avatar sinestriker avatar trbogdanov avatar wangwenx190 avatar yeahitsjan avatar zachhannum avatar zhuzichu520 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

framelesshelper's Issues

[Windows] [Win10] The top frame is missing

case WM_NCCALCSIZE: {
    const auto mode = static_cast<BOOL>(msg->wParam);
    *result = mode ? WVR_REDRAW : 0;
    const auto clientRect = mode
                                ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0])
                                : reinterpret_cast<LPRECT>(msg->lParam);
    const UINT dpi = GetDpiForWindow(msg->hwnd);
    const int sizeFrameX = GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi);
    const int sizeFrameY = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi);
    const int paddedBorder = GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
    const int bw = sizeFrameX + paddedBorder;
    const int bh = sizeFrameY + paddedBorder;
    const RECT originalRect = *clientRect;
    const LRESULT ret = DefWindowProcW(msg->hwnd, WM_NCCALCSIZE, msg->wParam, msg->lParam);
    if (ret != 0) {
        *result = ret;
        return true;
    }
    *clientRect = originalRect;
    clientRect->top += 1;
    clientRect->bottom -= 0;
    clientRect->left += bw;
    clientRect->right -= bw;
    *result = 0;
    return true;
}

It's quite easy to preserve the left frame and right frame, so now let's talk about the top frame and bottom frame.

The bottom frame

  • clientRect->bottom -= 0; makes the bottom frame totally removed, including the resize area, but the bottom frame shadow is still there.
  • clientRect->bottom -= 1; preserves the bottom frame, the resize area is still there as well, but it's only 1px height now so it's very hard to grab. The bottom frame shadow is still there.
  • clientRect->bottom -= bh; preserves the full bottom frame, which means the resize area is 8px height (when DPI is 96), the same with standard windows. The bottom frame shadow is still there, of course.

The top frame

  • clientRect->top += 0; makes the top frame totally removed, including the system title bar (including the window icon, the title text and the 3 system buttons) and the resize area, but the top frame shadow is still there.
  • clientRect->top += 1; preserves the top frame, the resize area is still there as well, but it's only 1px height now so it's very hard to grab. The top frame shadow is still there.
  • clientRect->top += bh; preserves the full top frame, which means the resize area is 8px height (when DPI is 96), the same with standard windows, but sadly the system title bar comes back at the same time. The top frame shadow is still there, of course.

Conclusion

I tried to combine clientRect->top += 1; with clientRect->bottom -= bh; or clientRect->bottom -= 1; to preserve the full window frame, however, the title bar comes back.

The conclusion for now: we can only preserve the top frame or the bottom frame, it's not possible to preserve them both without extra work.

使用setResizable固定大小后多屏来回移动窗体变小最后消失

1、使用FramelessWindowsManager::setResizable(windowHandle(), false)固定程序大小时在双屏幕情况下,来回拖动,程序的窗体越变越小,最后消失。

备注:使用setFixedSize(size())没有这个问题。

2、固定窗体后,窗体边缘部分几个像素点鼠标选中后窗体无法移动。

show system menu when right click titlebar

What I mean is this menu:
menu

I use followng code to show this menu when left-click on titlebar icon

    QObject::connect(mainWindow,
                     &QMainWindow::windowIconChanged,
                     titleBarWidget.iconButton,
                     &QPushButton::setIcon);
    QObject::connect(titleBarWidget.iconButton,
    &QPushButton::clicked, mainWindow, [mainWindow] () {
#ifdef WIN32
        HWND hwnd = (HWND)QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("handle"), mainWindow->windowHandle());
        //mainWindow->winId()
        HMENU systemMenu = ::GetSystemMenu(hwnd, FALSE);
        if (systemMenu) {
            // Open system menu in the left top corner of window.
            double pos_x = static_cast<double>(mainWindow->pos().x()) * mainWindow->devicePixelRatioF();
            double pos_y = static_cast<double>(mainWindow->pos().y() + mainWindow->menuWidget()->height()) * mainWindow->devicePixelRatioF();
            TrackPopupMenu(systemMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
                           pos_x, pos_y, NULL,
                           hwnd, 0);
        }
#endif
    });

However I don't know how to show this when user right-click titlebar as well, any idea?

[Qt Quick] When top-level Window has transparency, white line appears on top of window

When transparency is enabled on the top-level QML Window, a white line appears at the top of the window frame.

Capture

Window {
    id: window
    visible: true
    width: 800
    height: 600
    title: qsTr("Hello, World!")
    color: "transparent"
    flags: Qt.Window


    FramelessHelper {
        id: framelessHelper
    }

        Row {
            anchors.top: parent.top
            anchors.right: parent.right

            MinimizeButton {
                id: minimizeButton
                onClicked: window.showMinimized()
                Component.onCompleted: framelessHelper.addIgnoreObject(
                                           minimizeButton)
            }

            MaximizeButton {
                id: maximizeButton
                maximized: window.visibility === Window.Maximized
                onClicked: {
                    if (maximized) {
                        window.showNormal()
                    } else {
                        window.showMaximized()
                    }
                }
                Component.onCompleted: framelessHelper.addIgnoreObject(
                                           maximizeButton)
            }

            CloseButton {
                id: closeButton
                onClicked: window.close()
                Component.onCompleted: framelessHelper.addIgnoreObject(
                                           closeButton)
            }
        }


    Component.onCompleted: {
        framelessHelper.setWindowFrameVisible(false)
        framelessHelper.removeWindowFrame(true)
        framelessHelper.setBlurEffectEnabled(true);
    }
}

With blur effect turned off, the issue still occurs. Only fixes I've found are setting flags = Qt.FramelessWindowHint which removes the window shadows and breaks Aero snapping, or using a Window color with no transparency at all.

[macOS] Frameless windows can't be minimized on macOS

运行的源码里面的例子. 无法最小化.
自己写了个程序调用showMinimized是能正常最小化的, 但是调用了removeWindowFrame就无反应了

qt版本 : 5.15.0 从brew上安装的
mac os版本 : 10.15.4

[Windows] Restore after maximizing, the window goes out of the screen


系统:Windows10
Qt:5.9.3、5.14、5.15都有这个问题
编译器:msvc2017
效果图:
image

复现步骤:
1、窗口最大化
2、鼠标向下拖拽标题栏,让窗口从最大化变成常规大小,此时不要放开鼠标,再往上拖到屏幕顶部,触发Win10的Aero效果,自动变成最大化。
3、按Restore按钮,还原到常规大小。
此时窗口会跑到屏幕顶部,标题栏会超出去,如果标题栏高度比较小,就点不到了。


OS: Windows 10
Qt Version: 5.9.3 , 5.14 , 5.15.0
Compiler: msvc2017
Demo Image:
image
Reproduce:
1、make Window Maximize
2、Mouse drag-down title, make window change to normal from maximize, then not release mouse and drag-up caption to the top of screen, window will be maximized by Windows 10 Aero effect
3、Press Restore Button, window restore to normal.
now Window goes out of screen. if the title Bar is too short, you can't use it

Missing top frame + context menu

I've 2 questions regarding the toolbar. Is it a known issue that the top frame is not drawn?
It happens on both examples
image image

Also I was wondering if there is a way to emulate the right click context menu we usually have with native Windows frames.
image

QScreen *QWidget::screen() const since 5.14

建议尽量使用低版本存在的API,比如这个screen()改成windowHandle()->screen(),或者如果是低版本,直接拷贝源码实现一份screen(),因为你写的windows依赖qt版本>=5.6

Compatibility with QMainWindow

Great work with this piece of code!
Can this be used with a QMainWindow? I'm wondering what trick can be used to insert the top widgets (label+buttons) on top of the mainwindow created by setupUi()

Thanks!

请问如何才能去掉白边?

系统:Windows10 2004
Qt:5.9.9
编译器:msvc2015

感谢作者贡献。
我测试时,窗口处于激活状态时,左下右三边一个像素的白边。请问如何才能去掉白边?

测试代码如下:

QWidget* p = new QWidget;
WinNativeEventFilter::addFramelessWindow(p);
p->setStyleSheet("border: 1px solid #444851;");
p->show();

Screenshot 2020-10-13 111437

Support for child windows?

Is there any support for non-top level windows? I specifically mean the widgets that show up in a separate window and QDockWidget titlebar when undocked.

So far the whole library is the best out of all frameless QT solutions on Github! Looking great, but would be nice to handle the children as well.

Screen Shot 2020-11-05 at 11 41 48 AM

跨屏幕移动,底部绘制出现异常

image

1、我尝试过网络上其他很多无边框的方案,都会有这个问题,他们底部和右边会出现这个绘制重复的问题,但是作者您的代码只有底部会出现这个绘制问题。我感觉您找到了解决办法。不知道是我个人的问题还是怎样。希望作者能够花时间在Windows10平台上进行多屏幕测试。感谢作者~

Frameless examples without acrylic

I know you are quite busy finding a solution for the acrylic background.
However I think the initial target of this repo was to get a working frameless mainwindow, and I'm kinda lost how to do this with latest code.
I had a working toy project using the code from around November 2020 I think. My problem at that time was that I couldn't draw the 1pixel frame around my QMainWindow.

So I decided to update to the latest code (and also tried some commit in between) but I end up with unmovable window, graphical glitches, and still no frame.

Do you plan to restore the QMainWindow example I had contributed to? Does it still work on your side?
Is QtAcrylicWidget in charge of drawing the coloured frame? Or is it a feature of FramelessWindowsManager?

[Windows] GetSystemMetrics returns the same value with GetSystemMetricsForDpi

According to Microsoft's documentation, GetSystemMetrics is not DPI aware and thus it should return a totally different value with GetSystemMetricsForDpi. However their return values are exactly the same currently. And it's leading us to a very bad situation: the system metric value returned by our own function getSystemMetric is now double scaled.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetricsfordpi

addIgnoreObject with an hidden button will cause unmovable

OS: Ubuntu 20.04 with Gnome 3.38
Qt: 5.15.1
gcc: 9.3.0

    QPushButton *maximizeButton = new QPushButton;
    maximizeButton->setText(QObject::tr("Maximize"));
    maximizeButton->setVisible(false);

    widget.createWinId(); // Qt's internal function, make sure it's a top level window.
    const QWindow *win = widget.windowHandle();
    FramelessWindowsManager::addWindow(win);
    FramelessWindowsManager::addIgnoreObject(win, maximizeButton);

Then, the whole window will be unmovable.

[Windows] Window resize border location is inside of the application border

Fist thing first, illustration:
screenshot2

In the above illustration, the yellow color shows the area where mouse cursor changes to show that the user now can resize the window.
In framelesshelper application the mouse cursor changes when the mouse cursor is inside of the application window but in any other normal Windows application the cursor changes when the mouse is on the application border or outside of the application border(in the window shadow area).
I think the resize border area is kept on border or outside of the border(in the window shadow area) to increase the client area so that the mouse could interact with the widgets inside of the application borders. So can this resize border be placed outside of the framelesshelper window border just like any other normal application window?

By the way, I noticed this when I got irritated by this unusual behavior as I missed clicking on the window border and mistakenly clicking on an other application running in the background.

Furthermore, I really like the way Mozilla does this(chrome way is not good, in my opinion). You can try to resize the Mozilla window by dragging the LEFT border and you won't see any flicker introduced in the minimize, maximize and close buttons but if you try the same with chrome then those buttons would flicker. While both Mozilla and Chrome provides custom window non-client area painting but retains the resizing border location.

I wish there was a stripped down just window part of the Mozilla browser so that the people like you ,me and others could benefit but that's another story. Mozilla is best in terms of GUI! But chrome is best in terms of other things.

Ignore algorithm doesn't ignore areas in the resizing borders region.

I tested the updated code and it works great but I found that resizing borders are not included in the ignore areas.
Suppose you place a button in the top-right corner just like a normal win32 app's close button, you would notice that resizing borders do not allow you to interact with a part of a button which is below the resizing borders area. A user may need such a button anywhere near the borders so, I think, the resizing borders should also be included in the ignore areas calculations.

Some bugs on Win7 with composition disabled

Great work! The best Qt frameless implementation I've seen.
I tested it on Win7 in a virtualbox vm, and found some problems:

  • The frame borders appear when switching with other apps.
  • Black flickers when maximize and minimize.
  • 拉动左边框和上边框,右边框和下边框会闪烁

Check the attachment for details.

frameless2

关闭弹窗后,主窗口无法拖动/拉伸

// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
#include "winnativeeventfilter.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

const auto hWnd_widget = reinterpret_cast<HWND>(this->winId());
WinNativeEventFilter::addFramelessWindow(hWnd_widget);

}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_pushButton_clicked(bool checked)
{
// 这里可以重现:关闭dlg后,主窗口无法拖动/拉伸
// TODO: bug - parent widget can not move and resize after close dlg
Dialog dlg(this);
dlg.exec();
}

//--------------------------------------------------
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"

#include "winnativeeventfilter.h"

Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);

const auto hWnd_widget = reinterpret_cast<HWND>(this->winId());
WinNativeEventFilter::addFramelessWindow(hWnd_widget);

this->setFixedSize(400, 300);

}

Dialog::~Dialog()
{
delete ui;
}

See through issue during maximizing and minimizing the window.

Related to master branch:
I noticed that as soon as I maximize or minimize the window by double clicking on the title bar, momentarily I can see through the window as if window becomes transparent. This problem doesn't occur in win10_only branch.

You can verify it by having some colorful background and then try to maximize and minimize the window.

win去除边框后无法固定窗口大小

调用WinNativeEventFilter::addFramelessWindow后再调用setFixedSize固定窗口大小, 还是能用鼠标改变窗口大小.
不调用WinNativeEventFilter::addFramelessWindow时正常, 窗口大小无法改变

qt版本 5.12.0

Application freezes upon left mouse button click and hold on title-bar

I have created a demo project in which I update a label with counter value which is incremented by QTimer every 30ms. I noticed that when I click and hold mouse left button on title bar then the application freezes for about a second.

Demo Application Files:

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QTimer>

namespace Ui {
class MainWidget;
}

class MainWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MainWidget(QWidget *parent = nullptr);
    ~MainWidget();

private:
    Ui::MainWidget *ui;
    QTimer timer;

private slots:
    void timerTimeout();
};

#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include "ui_mainwidget.h"

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWidget)
{
    ui->setupUi(this);

    connect(&timer, &QTimer::timeout, this, &MainWidget::timerTimeout);
    timer.setInterval(30);
    timer.start();
}

MainWidget::~MainWidget()
{
    timer.stop();
    delete ui;
}

void MainWidget::timerTimeout()
{
    static unsigned int counter = 0;
    ui->label->setText(QString::number(counter++));
}

mainwidget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWidget</class>
 <widget class="QWidget" name="MainWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>390</width>
    <height>154</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QLabel" name="label">
     <property name="font">
      <font>
       <family>Verdana</family>
       <pointsize>60</pointsize>
      </font>
     </property>
     <property name="text">
      <string>0</string>
     </property>
     <property name="alignment">
      <set>Qt::AlignCenter</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

main.cpp

#include "framelesshelper.h"

#include <QApplication>
#include <QWidget>

#include "mainwidget.h"

int main(int argc, char *argv[]) {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
#if 0
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
        Qt::HighDpiScaleFactorRoundingPolicy::Round);
#else
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
        Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#endif

    QApplication application(argc, argv);

    FramelessHelper helper;

//    QWidget widget;
//    helper.setFramelessWindows({&widget});
//    widget.show();

    MainWidget widget;
    helper.setFramelessWindows({&widget});
    widget.show();

    return QApplication::exec();
}

Qt版本过高,导致编译不过

win10+qt5.12.4
framelessquickhelper.h 中Q_DISABLE_COPY_MOVE不可用

建议在readme中写清mac的qt支持得版本

范例代码:data.titlebarHeight = 30;,拼写错误

顺便问下,qt5.15的无边框特性够完善吗?

[Windows] Frameless windows are flickering when resizing

Workaround:

//clientRect->top -= 1;

Make the client area a little smaller than it should be.

In this way, the flickering problem is gone indeed but it also causes many issues when we want to draw something manually by QPainter. Qt Quick is affected as well.

Another finding: most frameless windows have this issue. For example, Google Chrome, Mozilla Firefox, Microsoft Office and etc.

An example of ignoring areas (master branch)

Suppose a developer wants to place a widget somewhere in the title bar area or in an area overlapping border area then how framelesshelper API would help in this regard? Such an example/s alongside this repository would greatly help the community.

[Qt Quick][Windows] addIgnoreObject does not work on child windows

The addIgnoreObject function does not work for child windows created in QML. Controls within the title bar space are not able to be interacted with in child windows.

CustomWindow.qml:

Window {
    id: window
    visible: true
    width: 800
    height: 600
    title: qsTr("Hello, World!")
    color: "#803b3642"

    FramelessHelper {
        id: framelessHelper
    }

    Rectangle
    {
        anchors.fill: parent
        color: "transparent"
        border.width: .5
        border.color: "#3b3642"
    }

    Row {
        anchors.top: parent.top
        anchors.right: parent.right

        MinimizeButton {
            id: minimizeButton
            onClicked: window.showMinimized()
            Component.onCompleted: framelessHelper.addIgnoreObject(
                                       minimizeButton)
        }

        MaximizeButton {
            id: maximizeButton
            maximized: window.visibility === Window.Maximized
            onClicked: {
                if (maximized) {
                    window.showNormal()
                } else {
                    window.showMaximized()
                }
            }
            Component.onCompleted: framelessHelper.addIgnoreObject(
                                       maximizeButton)
        }

        CloseButton {
            id: closeButton
            onClicked: window.close()
            Component.onCompleted: framelessHelper.addIgnoreObject(
                                       closeButton)
        }
    }


    Component.onCompleted: {
        framelessHelper.setWindowFrameVisible(false)
        framelessHelper.removeWindowFrame(true)
        framelessHelper.setBlurEffectEnabled(true)//,true, "#803b3642")
    }


}

main.qml:

CustomWindow {

    Button
    {
        anchors.centerIn: parent
        onClicked: {childWindow.show();}
    }

    CustomWindow
    {
        id: childWindow
        visible: false
    }

}

Result:

2021-03-04.11-01-57.mp4

With QSplitter

当使用QSplitter作为一个界面最边缘侧组件时,
QSplitter 拖拽最小化,将无法再最大化。
考虑是不是因为边框调整大小的宽度遮住了QSplitter 的 handle 。
如下动图:
鼠标拖动QSplitter 到界面最边缘,鼠标松开后,界面的边框会遮挡QSplitter。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.