Skip to content
This repository has been archived by the owner on May 25, 2022. It is now read-only.

将QCEF嵌入具有 WA_TranslucentBackground 背景透明的 Widget 后,QCefView 不显示 #21

Closed
BillHoo opened this issue Sep 14, 2017 · 21 comments
Labels

Comments

@BillHoo
Copy link

BillHoo commented Sep 14, 2017

你好,我遇到一个问题,
将 QCefView 嵌入一个父窗体,父窗体具备背景透明的属性,此时 QCefView 就不显示了,
这个问题可以在你的 DEMO 中复现,将 DEMO 的父窗体设置为背景透明,然后浏览器就不显示了。

截图:
1

2

@zhulingbiezhi
Copy link

我也遇到了,没解决,哈哈,你尝试设置qcefview的父窗体为window,并且父窗体的父亲为null

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

这样不行,我这边是基于 QWidget的APP,所有窗体都是继承自一个顶级 QWidget,该 Widget 用来显示阴影和自定义 Titlebar,顶级 Widget 设置了背景透明选项。

具体的技术原因QT官方没有明确的解释,但是好多论坛都说了,反正就是“不能”将一个QWindow或者QQuick2的窗体嵌入进背景透明的 QWidget 中。

如果这两者就是不能兼容,我实在是找不到解决方案了。

@zhulingbiezhi
Copy link

这是qt的bug吧,我只做了cef的api,嵌入到客户端程序中也发现这个问题,我直接注释了

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

估计是,我在QT Jira 中搜Bug,倒是有很多相关问题,但是没有一个给出了官方解答,基本都被直接关闭了。

你说的“直接注释了”是什么意思呢?注释掉QCEF中的哪句话能解决这个问题?

@zhulingbiezhi
Copy link

我之前做项目也是用你这样的方案去实现边缘透明效果,后来发现在xp不兼容出现黑边,所以后面改为采用windows API实现边缘毛玻璃效果

@zhulingbiezhi
Copy link

我把透明函数注释了

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

哦。。。。。透明函数注释了那我这边整个方案就洗白了。我这里不需要支持XP系统了。我赶项目进度,这种透明 Widget 方案是最快的。不知道你说的 windows api 是哪一个,能给我个MSDN链接么 我去参考下。

@zhulingbiezhi
Copy link

我代码都找不到,刚辞职了,你可以百度下windows毛玻璃

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

好的 我去搜一下,多谢你提供的信息。

@tishion
Copy link
Owner

tishion commented Sep 14, 2017 via email

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

链接Qt的Bug以便跟踪这个问题:
https://bugreports.qt.io/browse/QTBUG-63199

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

@tishion 你好,我主要需求是窗口的自定义阴影效果。Qt里面顶级窗口没办法在窗体之外绘制内容,因此我把所有contents绘制到了一个widget中,并把阴影绘制到这个widget的边上,调整widget到主窗体的边距用来显示这个阴影。主窗体的作用只是显示阴影和这个widget。所以主窗体需要背景透明。

@tishion
Copy link
Owner

tishion commented Sep 14, 2017 via email

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

好的,我去看看

@tishion
Copy link
Owner

tishion commented Sep 14, 2017

给你一点提示吧,Shadow做一个单独的窗口,属性设置为:

	setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
	setAttribute(Qt::WA_DeleteOnClose, TRUE);
	setAttribute(Qt::WA_TranslucentBackground);

真正的窗口我这里叫ContentWindow,是浮在这个ShadowWindow之上的一个Qwidget,ContentWindow和ShadowWindow并不具有父子关系,ShadowWindow接收到所有的size和pos相关的event的时候都要对ContentWindow处理适应新的size和pos。

@tishion
Copy link
Owner

tishion commented Sep 14, 2017

当然生命周期也要控制好。其实我的代码都写的很通用,一个类文件给你就可以直接用了,但是你还是自己搞搞吧。

@BillHoo
Copy link
Author

BillHoo commented Sep 14, 2017

好的多谢,代码是你的知识结晶我也无意索取,感谢你提供的思路,我去尝试一下也是对我自己的提高。多谢。

@zouyikang
Copy link

@BillHoo 请问你的这个问题完全解决没 我现在遇到当ContentWindow active的时候 ShadowWindow 无法raisze起来,有些操作能使ShadowWindow窗口的Z序发送变化。

@BillHoo
Copy link
Author

BillHoo commented Dec 23, 2017

@tishion 这几个月忙起来忘了回复你了,感谢你之前给我的思路指点。我这边也实现了阴影的效果和其他正常操作。具体方案感觉和你的不一样,不过核心思路是一样的,阴影是一个 Qt::Tool,再次感谢。

@zouyikang 我是借鉴了tishion的思路,但是我实现得更加繁琐和另类了,仅供参考:

阴影是一个独立的通用类,属性就是 tishion 之前提供的。之所以要具备 Qt::Tool 类型我觉得大致是因为这个类型的窗体或者Widget不会在任务栏上出现一个小方框,不然的话阴影也会被当作一个独立的窗口显示在任务栏上。

我的阴影 S 是一个完全独立的Widget,属性设置了:

    this->setAttribute(Qt::WA_DeleteOnClose); // from tishion
    this->setAttribute(Qt::WA_TranslucentBackground); // from tishion
    this->setAttribute(Qt::WA_TransparentForMouseEvents);
    this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); // from tishion
    this->setStyleSheet("background-color: grey; border: none;");

C 是我需要添加阴影效果的内容窗体或Widget。Widget C 是 S 的 parent(我现在记不得为什么要有这个parent了,估计是 Qt::Tool 属性的原因),但是仅仅只是 QObject 层面的 parent,S 可以独立于 C 进行任何显示、隐藏、改变大小等操作,S 不能放进 C 的任何一个布局继承体系中(从而避免了我这个问题之初遇到的情况,就是布局继承体系中使用了 Qt::WA_TranslucentBackground 这个属性的话,QCEF 渲染时就不显示了)。

C 类包含 S 类的成员变量,针对 C 的每一个窗体操作(移动、大小变更等)都对 S 人为地做同样的设置和处理。假设我要阴影宽度为20px,C 的大小现在变更为 40px * 40px,则 S 的大小我们要设置成 60px * 60px,且移动 S 使之中心点与 C 的中心点对其。这样才能从视觉上看出 C 的阴影是 S。

tishion 的方案是 C 是浮动于 S 之上的,也就是说阴影 S 始终位于底部。但是我的却完全相反,由于 Qt::Tool 或是别的什么原因(我不记得了 Orz...),S 只要一显示出来就始终覆盖于 C 之上,位于 Z 轴的 top 层,相当于 C 始终位于底部了,导致比 C 还大的 S 整个把 C 挡住了。像这样:

1

因此想办法在 S 中间挖了个洞,使用了 QT 的 setMask API,在 S 正中间挖了一个大小为 C 的(包括 C 的圆角形状)的洞,使得 C 可以透过这个洞显示出来。然后添加了 Qt::WA_TransparentForMouseEvents 属性给 S,使得在最上层的 S 始终不挡住任何鼠标操作,直接把鼠标操作传递给位于底层的 C。

我这里的整个逻辑就是这样。但是总感觉处理的过于复杂,tishion之前说的步骤要少很多。还有很多细节处理的具体问题会遇到。你说的 active 相关问题我没有遇到过,所有窗体 activate、modal 等都正常,大致说一下我对大小和窗体状态变更的一些处理供你参考:

C 窗体移动:

void BasicDialog::moveEvent(QMoveEvent *ev) {
    _basic_shadow->SetShadowPos(ev->pos()); // 同时移动阴影 S,使之中心与 C 对齐
}

C 窗体 Resize

void BasicDialog::resizeEvent(QResizeEvent *e) {
    setRoundedCornerMask(); // 这是我绘制圆角的逻辑

    _basic_shadow->SetShadowBodyFixedSize(e->size()); // 同时设置阴影大小,函数实现中设置的阴影大小始终比这个 size() 大一圈儿,从而实现 C 周围的阴影效果。

    // ...
}

C 窗体 Show

void BasicDialog::showEvent(QShowEvent *e) {
    setRoundedCornerMask();

    _basic_shadow->show(); // 由于 S 与 C 不具备任何布局继承关系,因此 S show 出来后,默认位于屏幕左上角,与 C 无关。
    _basic_shadow->SetShadowPos(this->pos()); // 移动 S 使之与 C 中心重合
}

C 窗体 Hide

void BasicDialog::hideEvent(QHideEvent *e) {
    _basic_shadow->hide();
}

@zouyikang
Copy link

@BillHoo 谢谢你的回复,很详细,解决了我的问题。

@bairutai
Copy link

bairutai commented Sep 2, 2020

给你一点提示吧,Shadow做一个单独的窗口,属性设置为:

	setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
	setAttribute(Qt::WA_DeleteOnClose, TRUE);
	setAttribute(Qt::WA_TranslucentBackground);

真正的窗口我这里叫ContentWindow,是浮在这个ShadowWindow之上的一个Qwidget,ContentWindow和ShadowWindow并不具有父子关系,ShadowWindow接收到所有的size和pos相关的event的时候都要对ContentWindow处理适应新的size和pos。

可以开源么,抱歉做伸手党,按照@BillHoo 的思路做了一遍,遇到白屏的问题,层级关系处理不好

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

No branches or pull requests

5 participants