之前介绍了如何miniblink集成到qt,采用wkeCreateWebWindow来创建一个浏览器窗口,wkeCreateWebWindow有三种方式
typedef enum _wkeWindowType { WKE_WINDOW_TYPE_POPUP, WKE_WINDOW_TYPE_TRANSPARENT, WKE_WINDOW_TYPE_CONTROL } wkeWindowType;
WKE_WINDOW_TYPE_POPUP 创建一个弹出式窗体,模态窗体。
WKE_WINDOW_TYPE_TRANSPARENT 透明父窗口窗体
WKE_WINDOW_TYPE_CONTROL 创建一个弹出式窗体,非模态窗体。
因为要实现成一个qtwidget的子窗体,所以用了WKE_WINDOW_TYPE_TRANSPARENT来创建浏览器窗口,qt两种方式其实应用场景很有限。
这个属性创建的窗体在win7,surface系统表现异常,出现渲染布出来问题, 只有win10 表现还过得去。最后发现是因为我同时使用了两种浏览器QtWebengineView和miniblink浏览器,这两种窗体在不同系统中兼容性存在问题。
如果只是放到qtwidget上面没有啥问题。
尝试了如下方法:
1.使用WKE_WINDOW_TYPE_POPUP/WKE_WINDOW_TYPE_CONTROL表现正常,但是跟其他窗体存在层级问题
2.使用WKE_WINDOW_TYPE_TRANSPARENT创建,将窗体独立,跟上面的基本一样,不止存在层级问题,win10多桌面显示也存在问题。
所以wkeCreateWebWindow无法满足需求。
看了一下接口文件发现一个wkeCreateWebView,该函数只是创建一个对象,并不会真正绘制,绘制需要自己处理。
1.创建对象
_hWebView = wkeCreateWebView();
wkeSetTransparent(_hWebView, false);
wkeOnPaintUpdated(_hWebView, onPaintUpdatedCallback, this);
wkeOnLoadUrlBegin(_hWebView, onLoadUrlBegin, (void *)this);
wkeOnLoadUrlEnd(_hWebView, onLoadUrlEnd, (void *)this);
wkeOnLoadUrlFail(_hWebView, onLoadUrlFailed, (void *)this);
wkeOnLoadingFinish(_hWebView, onLoadingFinish, (void *)this);
最重要的回调函数是onPaintUpdatedCallback,因为要自己绘制,改接口在需要绘制时会回调回来。原型为:
static void onPaintUpdatedCallback(wkeWebView webView, void* param, const HDC hdc, int x, int y, int cx, int cy);
返回的是HDC,所以我们需要一个绘制窗口
2.创建一个windows 窗口对象
注册窗口类:
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_DBLCLKS;// CS_HREDRAW | CS_VREDRAW; //
wcex.lpfnWndProc = webViewWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = wkeWebViewClassName;
wcex.hIconSm = 0;
return !!RegisterClassEx(&wcex);
创建窗口:
_hWnd = CreateWindow(wkeWebViewClassName, 0,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, nWeight, nHeight,
hParent,
0,
0, 0);
3. 使用GDI绘制
将miniblink dc的内同绘制到我们创建窗体之上
HDC hScreenDC = ::GetDC(m_hView);
::BitBlt(m_hDC, x, y, m_width, m_height, hBlinkDC, x, y, SRCCOPY);
::BitBlt(hScreenDC, x, y, m_width, m_height, m_hDC, x, y, SRCCOPY);
::ReleaseDC(m_hView, hScreenDC);
4.事件处理
这种方式需要我们自己处理键盘事件,鼠标事件 如下:
LRESULT QtMiniblinkWebView::webViewClassWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SETCURSOR:
return onSetCursor(wParam, lParam);
case WM_COMMAND:
return onCommand(wParam, lParam);
case WM_SIZE:
return onSize(wParam, lParam);
case WM_PAINT:
return onPaint(wParam, lParam);
case WM_KEYDOWN:
return onKeyDown(wParam, lParam);
case WM_KEYUP:
return onKeyUp(wParam, lParam);
case WM_CHAR:
return onChar(wParam, lParam);
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
return onMouseEvent(uMsg, wParam, lParam);
case WM_MOUSEWHEEL:
return onMouseWheel(wParam, lParam);
case WM_SETFOCUS:
return onSetFocus(wParam, lParam);
case WM_KILLFOCUS:
return onKillFocus(wParam, lParam);
case WM_IME_STARTCOMPOSITION:
return onIMEStartComposition(wParam, lParam);
case WM_GETDLGCODE:
return DLGC_WANTARROWS | DLGC_WANTALLKEYS | DLGC_WANTCHARS;
default:
return DefWindowProc(_hWnd, uMsg, wParam, lParam);
}
return 0;
}
其实就是将windows定义的消息转化为miniblink定义的对应消息,通过函数调用过去,如鼠标
LRESULT QtMiniblinkWebView::onMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_cursorInfoType = wkeGetCursorInfoType(_hWebView);
if (uMsg == WM_LBUTTONDOWN || uMsg == WM_MBUTTONDOWN || uMsg == WM_RBUTTONDOWN) {
SetFocus(_hWnd);
SetCapture(_hWnd);
} else if (uMsg == WM_LBUTTONUP || uMsg == WM_MBUTTONUP || uMsg == WM_RBUTTONUP) {
ReleaseCapture();
}
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
unsigned int flags = 0;
if (wParam & MK_CONTROL)
flags |= WKE_CONTROL;
if (wParam & MK_SHIFT)
flags |= WKE_SHIFT;
if (wParam & MK_LBUTTON)
flags |= WKE_LBUTTON;
if (wParam & MK_MBUTTON)
flags |= WKE_MBUTTON;
if (wParam & MK_RBUTTON)
flags |= WKE_RBUTTON;
//flags = wParam;
wkeFireMouseEvent(_hWebView, uMsg, x, y, flags);
return 0;
}
其他消息类似
5.win7最小化恢复未渲染
//win7最小化问题
connect(qApp, &QApplication::applicationStateChanged, this, [=](Qt::ApplicationState state)
{
if (Qt::ApplicationActive == state)
{
RECT rc;
::GetClientRect(_hWnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
//repaint
resize(0, 0, width-1, height-1);
resize(0, 0, width, height);
}
}
);
6.创建接口
BOOL QtMiniblinkWebView::create(int x, int y, int nWeight, int nHeight, HWND hParent)
{
if(!_isInit)
initialize();
_hWebView = wkeCreateWebView();
wkeSetTransparent(_hWebView, false);
wkeOnPaintUpdated(_hWebView, onPaintUpdatedCallback, this);
wkeOnLoadUrlBegin(_hWebView, onLoadUrlBegin, (void *)this);
wkeOnLoadUrlEnd(_hWebView, onLoadUrlEnd, (void *)this);
wkeOnLoadUrlFail(_hWebView, onLoadUrlFailed, (void *)this);
wkeOnLoadingFinish(_hWebView, onLoadingFinish, (void *)this);
if (!_hWebView)
{
return FALSE;
}
if (!registerControlerClass())
{
return FALSE;
}
_hWnd = CreateWindow(wkeWebViewClassName, 0,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, nWeight, nHeight,
hParent,
0,
0, 0);
if (INVALID_HANDLE_VALUE == _hWnd)
{
return FALSE;
}
_hParent = hParent;
wkeSetHandle(_hWebView, _hWnd);
resize(x, y, nWeight, nHeight);
SetWindowLong(_hWnd, GWL_USERDATA, (LONG)this);
SetWindowSubclass(_hParent, subClassProc, 0, (DWORD_PTR)this);
return _pRender->init(_hWnd);
}
从创建接口可以看到我们可以传递父窗口,通过qt winId就可以拿到,这样就实现这种方法的集成。经测试这种方法表现良好。
如果需要完整源码可以留言