是的,你没看错,是在浏览器中嵌入窗口,其实你想一想可能没必要,确实也是,在本地窗口中中嵌入浏览器是再正常不过的了,但是如果你有一个需求,需要使用到本地窗口,例如一些绘制操作,这边博客的大神使用的是PPAPI+skia实现简单的涂鸦功能
(
PPAPI+Skia实现的涂鸦板_安晓辉生涯——聚焦程序员的职业规划与成长-CSDN博客
),PPAPI具体我也不是很了解,应该是谷歌提供的支持的一个web插件的api吧。大家可参考我上边所说的那位大神的博客。本来这位大神的博客里也有提供嵌入本地窗口的讲解,但是这个也分cef的版本,我使用的qt版本是不支持的。
而且我的项目中使用的是基于qt的涂鸦等等的操作,所以只能想的是如何将qt窗口嵌入到cef中,最终还是没能解决,但是转念一想我可以在cef中的特定位置做一个浮层,覆盖在这个窗口上就行。
比如我的ui文件的结构是:
MainWindow
CentralWidget
WebViewWidget
即在WebViewWIdget中加载浏览器,所以我可以在centralWIdget中new一个GraffitiWidget用来做涂鸦。
GraffitiWidget *widget = new GraffitiWidget(ui->centralWidget);
widget->setGeometry(0, 40, 400, 300);
widget->shwow();
这样就会显示在浏览器窗口上了,同时也可以跟随窗口移动而移动。
但是当我实现了出来的时候是这样的:其中白色是我的html,然后蓝色还有画笔什么的是我的qt窗口。
这是发生了什么,大家都知道对于一个widget来说,内部会维持一个栈,用来装基于本窗口作为父组件的子组件,最先创建的最先显示,后创建的后显示,即后创建的是显示在先创建的窗口上边,但是为什么会出现这个问题呢,查资料好像是,cef的界面渲染不是交给qt来处理的,好像是交给系统来绘制,所以我无论怎么尝试cef窗口都是在这个窗口的上边。
找了好久,看到了一个qtwinmigrate (https://qt.gitorious.org/qt-solutions/qt-solutions/source/qtwinmigrate 或者 https://github.com/sorcererq/qtwinmigrate),这个的本意是在windows本地窗口上绑定qt窗口并显示,想来这个是独立处理的东西,那我既然可以在windows的窗口前边显示,自然可以在cef窗口前边显示。摘自里边我修改后的qwinwidget代码:
// qwinwidget.h
#ifndef QWINWIDGET_H
#define QWINWIDGET_H
#include <QWidget>
class CWnd;
#if defined(Q_OS_WIN)
# if !defined(QT_QTWINMIGRATE_EXPORT) && !defined(QT_QTWINMIGRATE_IMPORT)
# define QT_QTWINMIGRATE_EXPORT
# elif defined(QT_QTWINMIGRATE_IMPORT)
# if defined(QT_QTWINMIGRATE_EXPORT)
# undef QT_QTWINMIGRATE_EXPORT
# endif
# define QT_QTWINMIGRATE_EXPORT __declspec(dllimport)
# elif defined(QT_QTWINMIGRATE_EXPORT)
# undef QT_QTWINMIGRATE_EXPORT
# define QT_QTWINMIGRATE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTWINMIGRATE_EXPORT
#endif
class QT_QTWINMIGRATE_EXPORT QWinWidget : public QWidget
Q_OBJECT
public:
QWinWidget( HWND hParentWnd, QObject *parent = 0, Qt::WindowFlags f = 0 );
#ifdef QTWINMIGRATE_WITHMFC
QWinWidget( CWnd *parnetWnd, QObject *parent = 0, Qt::WindowFlags f = 0 );
#endif
~QWinWidget();
void show();
void center();
void showCentered();
HWND parentWindow() const;
protected:
void childEvent( QChildEvent *e );
bool eventFilter( QObject *o, QEvent *e );
bool focusNextPrevChild(bool next);
void focusInEvent(QFocusEvent *e);
#if QT_VERSION >= 0x050000
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#else
bool winEvent(MSG *msg, long *result);
#endif
private:
void init();
void saveFocus();
void resetFocus();
HWND hParent;
HWND prevFocus;
bool reenable_parent;
#endif // QWINWIDGET_H
//qwinwidget.cpp
/****************************************************************************
** Contact: http://www.qt-project.org/legal
** This file is part of the Qt Solutions component.
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
****************************************************************************/
// Implementation of the QWinWidget classes
#ifdef QT3_SUPPORT
#undef QT3_SUPPORT
#endif
#ifdef UNICODE
#undef UNICODE
#endif
#ifdef QTWINMIGRATE_WITHMFC
#include <afxwin.h>
#endif
#include <qevent.h>
#include <QApplication>
#include "qwinwidget.h"
#include <qt_windows.h>
#if QT_VERSION >= 0x050000
#include <QWindow>
#include <qpa/qplatformnativeinterface.h>
#define QT_WA(unicode, ansi) unicode
#endif
\class QWinWidget qwinwidget.h
\brief The QWinWidget class is a Qt widget that can be child of a
native Win32 widget.
The QWinWidget class is the bridge between an existing application
user interface developed using native Win32 APIs or toolkits like
MFC, and Qt based GUI elements.
Using QWinWidget as the parent of QDialogs will ensure that
modality, placement and stacking works properly throughout the
entire application. If the child widget is a top level window that
uses the \c WDestructiveClose flag, QWinWidget will destroy itself
when the child window closes down.
Applications moving to Qt can use QWinWidget to add new
functionality, and gradually replace the existing interface.
Creates an instance of QWinWidget. \a hParentWnd is the handle to
the native Win32 parent. If a \a parent is provided the object is
owned by that QObject. \a f is passed on to the QWidget constructor.
QWinWidget::QWinWidget(HWND hParentWnd, QObject *parent, Qt::WindowFlags f)
: QWidget(0, f), hParent(hParentWnd), prevFocus(0), reenable_parent(false)
if (parent)
QObject::setParent(parent);
init();
#ifdef QTWINMIGRATE_WITHMFC
\overload
Creates an instance of QWinWidget. \a parentWnd is a pointer to an
MFC window object. If a \a parent is provided the object is owned
by that QObject. \a f is passed on to the QWidget constructor.
QWinWidget::QWinWidget(CWnd *parentWnd, QObject *parent, Qt::WindowFlags f)
: QWidget(0, f), hParent(parentWnd ? parentWnd->m_hWnd : 0), prevFocus(0), reenable_parent(false)
if (parent)
QObject::setParent(parent);
init();
#endif
void QWinWidget::init()
Q_ASSERT(hParent);
if (hParent) {
// make the widget window style be WS_CHILD so SetParent will work
QT_WA({
SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLongA((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
#if QT_VERSION >= 0x050000
QWindow *window = windowHandle();
window->setProperty("_q_embedded_native_parent_handle", (WId)hParent);
HWND h = static_cast<HWND>(QGuiApplication::platformNativeInterface()->
nativeResourceForWindow("handle", window));
SetParent(h, hParent);
window->setFlags(Qt::FramelessWindowHint);
#else
SetParent(winId(), hParent);
#endif
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(this, &e);
Destroys this object, freeing all allocated resources.
QWinWidget::~QWinWidget()
Returns the handle of the native Win32 parent window.
HWND QWinWidget::parentWindow() const
return hParent;
\reimp
void QWinWidget::childEvent(QChildEvent *e)
QObject *obj = e->child();
if (obj->isWidgetType()) {
if (e->added()) {
if (obj->isWidgetType()) {
obj->installEventFilter(this);
} else if (e->removed() && reenable_parent) {
reenable_parent = false;
EnableWindow(hParent, true);
obj->removeEventFilter(this);
QWidget::childEvent(e);
/*! \internal */
void QWinWidget::saveFocus()
if (!prevFocus)
prevFocus = ::GetFocus();
if (!prevFocus)
prevFocus = parentWindow();
Shows this widget. Overrides QWidget::show().
\sa showCentered()
void QWinWidget::show()
saveFocus();
QWidget::show();
Centers this widget over the native parent window. Use this
function to have Qt toplevel windows (i.e. dialogs) positioned
correctly over their native parent windows.
\code
QWinWidget qwin(hParent);
qwin.center();
QMessageBox::information(&qwin, "Caption", "Information Text");
\endcode
This will center the message box over the client area of hParent.
void QWinWidget::center()
const QWidget *child = findChild<QWidget*>();
if (child && !child->isWindow()) {
qWarning("QWinWidget::center: Call this function only for QWinWidgets with toplevel children");
RECT r;
GetWindowRect(hParent, &r);
setGeometry((r.right-r.left)/2+r.left, (r.bottom-r.top)/2+r.top,0,0);
\obsolete
Call center() instead.
void QWinWidget::showCentered()
center();
show();
Sets the focus to the window that had the focus before this widget
was shown, or if there was no previous window, sets the focus to
the parent window.
void QWinWidget::resetFocus()
if (prevFocus)
::SetFocus(prevFocus);
::SetFocus(parentWindow());
/*! \reimp
#if QT_VERSION >= 0x050000
bool QWinWidget::nativeEvent(const QByteArray &, void *message, long *)
#else
bool QWinWidget::winEvent(MSG *msg, long *)
#endif
#if QT_VERSION >= 0x050000
MSG *msg = (MSG *)message;
#endif
if (msg->message == WM_SETFOCUS) {
Qt::FocusReason reason;
if (::GetKeyState(VK_LBUTTON) < 0 || ::GetKeyState(VK_RBUTTON) < 0)
reason = Qt::MouseFocusReason;
else if (::GetKeyState(VK_SHIFT) < 0)
reason = Qt::BacktabFocusReason;
reason = Qt::TabFocusReason;
QFocusEvent e(QEvent::FocusIn, reason);
QApplication::sendEvent(this, &e);
return false;
\reimp
bool QWinWidget::eventFilter(QObject *o, QEvent *e)
QWidget *w = (QWidget*)o;
switch (e->type()) {
case QEvent::WindowDeactivate:
if (w->isModal() && w->isHidden())
BringWindowToTop(hParent);
break;
case QEvent::Hide:
if (reenable_parent) {
EnableWindow(hParent, true);
reenable_parent = false;
resetFocus();
if (w->testAttribute(Qt::WA_DeleteOnClose) && w->isWindow())
deleteLater();
break;
case QEvent::Show:
if (w->isWindow()) {
saveFocus();
hide();
if (w->isModal() && !reenable_parent) {
EnableWindow(hParent, false);
reenable_parent = true;
break;
case QEvent::Close:
::SetActiveWindow(hParent);
if (w->testAttribute(Qt::WA_DeleteOnClose))
deleteLater();
break;
default:
break;
return QWidget::eventFilter(o, e);
/*! \reimp
void QWinWidget::focusInEvent(QFocusEvent *e)
QWidget *candidate = this;
switch (e->reason()) {
case Qt::TabFocusReason:
case Qt::BacktabFocusReason:
while (!(candidate->focusPolicy() & Qt::TabFocus)) {
candidate = candidate->nextInFocusChain();
if (candidate == this) {
candidate = 0;
break;
if (candidate) {
candidate->setFocus(e->reason());
if (e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::TabFocusReason) {
candidate->setAttribute(Qt::WA_KeyboardFocusChange);
candidate->window()->setAttribute(Qt::WA_KeyboardFocusChange);
if (e->reason() == Qt::BacktabFocusReason)
QWidget::focusNextPrevChild(false);
break;
default:
break;
/*! \reimp
bool QWinWidget::focusNextPrevChild(bool next)
QWidget *curFocus = focusWidget();
if (!next) {
if (!curFocus->isWindow()) {
QWidget *nextFocus = curFocus->nextInFocusChain();
QWidget *prevFocus = 0;
QWidget *topLevel = 0;
while (nextFocus != curFocus) {
if (nextFocus->focusPolicy() & Qt::TabFocus) {
prevFocus = nextFocus;
topLevel = 0;
} else if (nextFocus->isWindow()) {
topLevel = nextFocus;
nextFocus = nextFocus->nextInFocusChain();
if (!topLevel) {
return QWidget::focusNextPrevChild(false);
} else {
QWidget *nextFocus = curFocus;
while (1) {
nextFocus = nextFocus->nextInFocusChain();
if (nextFocus->isWindow())
break;
if (nextFocus->focusPolicy() & Qt::TabFocus) {
return QWidget::focusNextPrevChild(true);
::SetFocus(hParent);
return true;
这样使用就方便了,大概里边是一些自己处理事件的操作。我是这样使用的:
m_WinWidget = new QWinWidget((HWND)ui->webViewWidget->winId());
QHBoxLayout *hbox = new QHBoxLayout(m_WinWidget);
m_GraffitiWidget->setParent(m_WinWidget);
m_GraffitiWidget->initPanelView(400, 300);
m_GraffitiWidget->setVisible(true);
hbox->addWidget(m_GraffitiWidget);
m_WinWidget->setGeometry(0, 40, 400, 300);
m_WinWidget->show();
正常显示,大功告成。
注意:外部窗口不要设置
this->setAttribute(Qt::WA_TranslucentBackground);会让新创建的窗口变成白色。
工程代码我就没有整理,大家要是有需要的我可以给大家说下我的东西。
是的,你没看错,是在浏览器中嵌入窗口,其实你想一想可能没必要,确实也是,在本地窗口中中嵌入浏览器是再正常不过的了,但是如果你有一个需求,需要使用到本地窗口,例如一些绘制操作,这边博客的大神使用的是PPAPI+skia实现简单的涂鸦功能(https://blog.csdn.net/foruok/article/details/50547737),PPAPI具体我也不是很了解,应该是谷歌...
6. QWebEngine vs QCefView + QWebChannel vs QCefView 对比
1. 为什么要用QCefView + QWebChannel开发?
基于Qt自带的QWebEn
QtWebkits在Qt5.6以上版本被淘汰了,不可用,需要使用QWebEngine;
安装Qt的时候需要勾选QWebEngine,这样才可以使用该模块;
QWebEngine目前不支持MinGW编译器(Project ERROR: Unknown module(s) in QT: webenginewidgets),只支持MSVC编译器;
二、使用说明
1、在.pro文件中添加模块
QT += webenginewidgets
文章目录需求实现1. 在主界面中添加一个`treeWidget`2. 响应树形控件点击事件, 添加右侧布局3. 效果4. 改进使用UI文件第一种非常简单, 添加新文件时, 选择`Qt设计师界面类`第二种方法是如果只有ui文件, 需要一个class关联
在主窗口中, 左边显示树形结构, 元素是不同类型的节点, 要求根据节点类型不同在主窗口右侧显示不同的控件内容
这个功能在MFC中实现不是...
要编译qcefview,您需要按照以下步骤进行操作:
1.首先,确保您的电脑上已经安装了编译qcefview所需的软件工具,包括C++编译器(如GCC或Visual Studio)和CMake构建工具。这些工具可以通过官方网站或其他途径下载和安装。
2.下载qcefview的源代码。您可以在qcefview的官方GitHub存储库中找到源代码的链接。将源代码解压缩到您选择的目录中。
3.打开命令行终端,进入源代码所在的目录。
4.创建一个新的目录用于构建输出。在命令行中输入以下命令:
mkdir build
cd build
5.使用CMake来生成构建脚本。在命令行中输入以下命令:
cmake ..
6.运行CMake生成的构建脚本来编译qcefview。在命令行中输入以下命令:
cmake --build .
7.等待编译过程完成。这可能需要一些时间,具体取决于您的计算机性能和工程规模。
8.编译完成后,在构建目录中将会生成可执行文件或库文件,您可以使用它们来运行或集成qcefview。
这些是编译qcefview的大致步骤。请注意,具体的步骤可能会因您的操作系统或特定的编译环境有所不同,所以请根据您的设置和需要进行相应的调整。此外,关闭防火墙或安全软件可能会有助于编译过程的顺利进行。
### 回答2:
qcefview 是一款用于嵌入式浏览器的开源软件库。编译 qcefview 的过程比较简单。首先,确保你的电脑已经安装了 Visual Studio 2019,并且正确配置了 CMake。
首先,下载 qcefview 的源代码。你可以在 GitHub 上找到该项目的代码仓库。将源代码解压到你选择的目录中。
接下来,创建一个新的目录作为编译输出目录。我们将在这个目录中生成构建文件和编译结果。
打开 Visual Studio 2019,选择“文件”菜单中的“打开”选项,并选择你解压的 qcefview 源代码目录。Visual Studio 会自动识别源代码,并生成一个 CMakeLists.txt 文件。
然后,点击“CMake”的工具栏按钮。在弹出的窗口中,选择你刚刚创建的编译输出目录,并点击“生成”按钮。Visual Studio 会开始生成构建文件。
生成过程可能需要一些时间,一旦完成,你将在编译输出目录看到生成的构建文件。
接下来,点击“本地 Windows 调试器”工具栏按钮,Visual Studio 将开始编译 qcefview 项目。这个过程可能需要一些时间,具体时间还取决于你的电脑性能和项目大小。
一旦编译完成,你将在编译输出目录中看到生成的可执行文件和相关的库文件。你可以将这些文件复制到你的工程中,并根据你的需求进行使用。
编译 qcefview 的过程可能会有一些问题,可能涉及到依赖项的安装和配置。如果你在编译过程中遇到任何问题,可以参考 qcefview 的官方文档或在相关的开发者社区中寻求帮助。
### 回答3:
qcefview 是一个用于嵌入和展示 Chromium 浏览器功能的工具,它可以在 Windows、Mac 和 Linux 系统上运行。编译 qcefview 需要以下步骤:
1. 首先,确认你已经安装了 CMake、Python 和 Git 工具,这些是编译 qcefview 的必要工具。
2. 在命令行中,使用 Git 克隆 qcefview 的源代码库。你可以在 GitHub 上找到 qcefview 的源代码库,复制库的 URL 并使用 `git clone` 命令进行克隆。
3. 进入克隆的 qcefview 目录,运行以下命令以初始化依赖项:
python ./dependencies/depot_tools/roll-dep third_party
这个命令将从第三方库中获取 qcefview 的依赖项,并将其放入正确的目录。
4. 然后,运行以下命令下载 Chromium 源码并进行初始配置:
python ./dependencies/depot_tools/bootstrap.py --no-nacl
这个命令将下载 Chromium 的源代码,并创建一个用于编译的工具链。
5. 接下来,使用以下命令生成编译文件:
python ./dependencies/depot_tools/gclient.py runhooks
6. 在命令行中,使用 CMake 工具为 qcefview 生成编译文件。你需要指定生成文件的目录。
cmake -B build -S . -D CMAKE_BUILD_TYPE=Release
这个命令将在 build 目录中生成 qcefview 的编译文件。
7. 最后,运行以下命令进行编译:
cmake --build build --config Release
这个命令将使用 Release 配置编译 qcefview。
一旦编译完成,你将在 build 目录中获得可执行文件。请注意,编译 qcefview 可能需要一些时间和计算资源。如果遇到编译错误,你可能需要检查系统环境和依赖项配置,以确保正确编译 qcefview。