CEF 网页中内嵌qt窗口

     是的,你没看错,是在浏览器中嵌入窗口,其实你想一想可能没必要,确实也是,在本地窗口中中嵌入浏览器是再正常不过的了,但是如果你有一个需求,需要使用到本地窗口,例如一些绘制操作,这边博客的大神使用的是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窗口。

CEF 网页中内嵌qt窗口_第1张图片

这是发生了什么,大家都知道对于一个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 

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

/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** 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 
#endif

#include 
#include 

#include "qwinwidget.h"

#include 

#if QT_VERSION >= 0x050000
#include 
#include 
#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(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();
    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);
    else
	::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;
        else
            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);会让新创建的窗口变成白色。

工程代码我就没有整理,大家要是有需要的我可以给大家说下我的东西。

你可能感兴趣的:(cef,cef,qt)