Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

以使用QWK的窗口为父窗口弹出另一个使用QWK的子窗口,父窗口丢失QWK特性 #51

Closed
Ikok9c6s opened this issue Feb 28, 2024 · 14 comments

Comments

@Ikok9c6s
Copy link

如下图所示,在example代码中创建MainWindow w1,并创建以w1为父窗口的w2。
两个窗口显示后,即使w2使用的是show不是exec,w1仍不能移动,右键无法触发系统菜单,也丢失了SnapLayout的特性。关掉w2后也无法恢复正常。而当我设置MainWindow属性为Qt::WA_DeleteOnClose,关闭w2,发生了崩溃,这是不合理的。
在我的项目中,我打算完全引入QWK作为无边框窗口的解决方案,所以软件窗口打开的情况下,会频繁地弹出子对话框,这个问题是致命的,希望作者能关注下。
image

@SineStriker
Copy link
Contributor

  1. "而当我设置MainWindow属性为Qt::WA_DeleteOnClose,关闭w2,发生了崩溃,这是不合理的。"这是你自己的问题,因为你把w2创建在了栈上,程序退出会double free。
  2. 参考 the window can't be moved if call this->winId() in the widget #50 ,当使用了QWK的窗口使用了具有Qt::WA_NativeWindow属性的widget时,顶级窗口将会收不到WM_NCHITTEST消息,这个我研究了很久暂时没有找到解决办法。针对你的需求,我建议最外面套一层使用了QWK的widget作为顶级窗口。

@Ikok9c6s
Copy link
Author

1.发生崩溃并不是在程序退出时,在关闭w2时就会发生,所以我并不认为是双重析构的问题
2.你的意思是QMainWindow具有NativeWindow的属性才导致的这个后果吗?按你说的,是要在QWidget里套一个QMainWindow?

@SineStriker
Copy link
Contributor

SineStriker commented Feb 28, 2024

1.发生崩溃并不是在程序退出时,在关闭w2时就会发生,所以我并不认为是双重析构的问题 2.你的意思是QMainWindow具有NativeWindow的属性才导致的这个后果吗?按你说的,是要在QWidget里套一个QMainWindow?

我说错了,只要删除在栈上的东西就会引发异常,而不是double free的问题,不信你可以随便写个程序在栈上创建一个int然后delete它试试,开调试看看异常断在什么地方。第二点对的,在QWidget里套一个QMainWindow,确保要移动进无边框窗口的那个QWidget永远不是native window,因为顶级窗口永远是native window。

@Ikok9c6s
Copy link
Author

我刚尝试了一下,和 #43 类似,通过设置QApplication的Qt::AA_DontCreateNativeWidgetSiblings可以解决这个问题,暂时不清楚原因

@Ikok9c6s
Copy link
Author

这个属性我记得在FramelessHelper的初始化函数中被设置了,QWK出于什么原因取消了这个属性的设置呢

@SineStriker
Copy link
Contributor

我刚尝试了一下,和 #43 类似,通过设置QApplication的Qt::AA_DontCreateNativeWidgetSiblings可以解决这个问题,暂时不清楚原因

我试了一下似乎只能让标题栏特性回来,如果不启用系统边框的话下面的边角是resize不了的,另外画面会有严重错位,所以我还是建议套一层。这个设置可能是忘了迁移,但是现在貌似设了也没啥用...

@Ikok9c6s
Copy link
Author

关于2还是不太清楚究竟该怎么做,我的项目中软件界面使用的是QMainWindow,子对话框使用的是QDialog,我该将哪个窗口套上一层QWidget呢?套上之后,widgetWindowAgent->setup的是this(QWidget),还是被包含的QMainWindow,QDialog?

@SineStriker
Copy link
Contributor

关于2还是不太清楚究竟该怎么做,我的项目中软件界面使用的是QMainWindow,子对话框使用的是QDialog,我该将哪个窗口套上一层QWidget呢?套上之后,widgetWindowAgent->setup的是this(QWidget),还是被包含的QMainWindow,QDialog?

我没搞懂你想做什么,你就是想弹一个对话框然后对话框也是无边框吗?

@Ikok9c6s
Copy link
Author

是的,主界面和对话框都是用的QWK的无边框

@SineStriker
Copy link
Contributor

SineStriker commented Feb 29, 2024

我用以下代码试了,发现没有出现任何问题。

class FramelessDialog : public QDialog {
public:
    FramelessDialog(QWidget *parent = nullptr) : QDialog(parent) {
        auto agent = new QWK::WidgetWindowAgent(this);
        agent->setup(this);

        auto btn = new QPushButton("ok");
        connect(btn, &QPushButton::clicked, this, &QDialog::accept);

        auto layout = new QHBoxLayout();
        layout->addWidget(btn);
        setLayout(layout);
    }
};

// MainWindow function
FramelessDialog dlg(this);
dlg.exec();

注意不能是show。在dialog存在的时候主窗口仍然存在一个是本地窗口的child,因为exec的时候主窗口被阻塞就可以忽略主窗口特性丢失的问题,show的时候就不行。

@SineStriker
Copy link
Contributor

开启QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings)似乎可以解决这个问题,但是还是请注意不要把具有native句柄的widget作为内嵌在父窗口中的子控件,作为dialog倒确实看起来没什么问题。

@Ikok9c6s
Copy link
Author

我用以下代码试了,发现没有出现任何问题。

class FramelessDialog : public QDialog {
public:
    FramelessDialog(QWidget *parent = nullptr) : QDialog(parent) {
        auto agent = new QWK::WidgetWindowAgent(this);
        agent->setup(this);

        auto btn = new QPushButton("ok");
        connect(btn, &QPushButton::clicked, this, &QDialog::accept);

        auto layout = new QHBoxLayout();
        layout->addWidget(btn);
        setLayout(layout);
    }
};

// MainWindow function
FramelessDialog dlg(this);
dlg.exec();

注意不能是show。在dialog存在的时候主窗口仍然存在一个是本地窗口的child,因为exec的时候主窗口被阻塞就可以忽略主窗口特性丢失的问题,show的时候就不行。

使用如下代码测试还是丢失了QWK特性。
image
不指定w2的parent是w1就是正常的

@Ikok9c6s
Copy link
Author

开启QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings)似乎可以解决这个问题,但是还是请注意不要把具有native句柄的widget作为内嵌在父窗口中的子控件,作为dialog倒确实看起来没什么问题。

我是否可以理解为现在推荐的做法是:
1.设置QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings)
2.软件界面使用QMainWindow+QWK,对话框使用QDialog+QWK
3.布局中的控件不能有Qt::WA_NativeWindow的属性

@SineStriker
Copy link
Contributor

开启QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings)似乎可以解决这个问题,但是还是请注意不要把具有native句柄的widget作为内嵌在父窗口中的子控件,作为dialog倒确实看起来没什么问题。

我是否可以理解为现在推荐的做法是: 1.设置QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings) 2.软件界面使用QMainWindow+QWK,对话框使用QDialog+QWK 3.布局中的控件不能有Qt::WA_NativeWindow的属性

是的,你总结得非常正确,我觉得我要更新一下readme了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants