Qt 有兩種方法能夠顯示flash.html
1. 經過QAxWidget 調用com形式顯示flash, 須要本機安裝IE flash插件linux
2. 直接經過qwebview顯示flash, 須要下載webkit 的flash插件 NPSWF32.dllweb
1. 經過IE顯示flash 是一般作法. QAxWidget提供很方便的嵌入, 只是IE對頁面的支持可能不是很好json
可是QAxWidget有個最大的問題, 不支持透明的flashwindows
若是直接設置frameless 和tranparent background的話, qaxwidget會整個窗口直接透明的. 瀏覽器
//flash->setWindowFlags(Qt::FramelessWindowHint); app
//flash->setAttribute(Qt::WA_TranslucentBackground);less
摸索了好久, 最開始的解決方案爲使用IWebBrowser2模擬出一個瀏覽器, 代碼複雜的很, 繼承一堆com 的東西. 估計有點像簡潔版的mfc html控件ide
概要以下:ui
class CBrowserEventBridge :public IDispatch { public: CBrowserEventBridge(); virtual ~CBrowserEventBridge(); public: STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHODIMP QueryInterface(REFIID riid, void** ppv); STDMETHODIMP GetTypeInfoCount(UINT* pCountTypeInfo); STDMETHODIMP GetTypeInfo(UINT iTypeInfo, LCID lcid, ITypeInfo** ppITypeInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); STDMETHODIMP Advise(IUnknown* pUnkCP, const IID& iid); STDMETHODIMP Unadvise(IUnknown* pUnkCP, const IID& iid); STDMETHODIMP Advise(CFlashPlayer *pPlayer, IWebBrowser2* pIE); STDMETHODIMP Unadvise(); STDMETHODIMP Invoke(DISPID dispidMember,REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS* dispParams,VARIANT* pvarResult,EXCEPINFO* pExcepInfo,UINT* puArgErr); private: IWebBrowser2* m_webBrowser; DWORD m_dwCookie; CFlashPlayer *m_pPlayer; }; class CFlashPlayer : public IOleClientSite , public IOleInPlaceSite , public IDocHostUIHandler , public IOleInPlaceFrame { public: class IFlashPlayerDelegate { public: //播放完畢回調 virtual HRESULT OnFlashPlayEnd() = 0; }; CFlashPlayer(IFlashPlayerDelegate *pDelegate); ~CFlashPlayer(); //imp IUnknown ULONG STDMETHODCALLTYPE AddRef( void); ULONG STDMETHODCALLTYPE Release( void); HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid,__RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject); //imp IOleClientSite HRESULT STDMETHODCALLTYPE SaveObject( void); HRESULT STDMETHODCALLTYPE GetMoniker( DWORD dwAssign,DWORD dwWhichMoniker,__RPC__deref_out_opt IMoniker **ppmk); HRESULT STDMETHODCALLTYPE GetContainer(__RPC__deref_out_opt IOleContainer **ppContainer); HRESULT STDMETHODCALLTYPE ShowObject( void); HRESULT STDMETHODCALLTYPE OnShowWindow( BOOL fShow); HRESULT STDMETHODCALLTYPE RequestNewObjectLayout( void); //imp IOleInPlaceSite HRESULT STDMETHODCALLTYPE CanInPlaceActivate( void); HRESULT STDMETHODCALLTYPE OnInPlaceActivate( void); HRESULT STDMETHODCALLTYPE OnUIActivate( void); HRESULT STDMETHODCALLTYPE GetWindowContext( __RPC__deref_out_opt IOleInPlaceFrame **ppFrame, __RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc, __RPC__out LPRECT lprcPosRect, __RPC__out LPRECT lprcClipRect, __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo); HRESULT STDMETHODCALLTYPE Scroll( SIZE scrollExtant); HRESULT STDMETHODCALLTYPE OnUIDeactivate( BOOL fUndoable); HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate( void); HRESULT STDMETHODCALLTYPE DiscardUndoState( void); HRESULT STDMETHODCALLTYPE DeactivateAndUndo( void); HRESULT STDMETHODCALLTYPE OnPosRectChange( __RPC__in LPCRECT lprcPosRect); //imp IOleInPlaceFrame HRESULT STDMETHODCALLTYPE InsertMenus( __RPC__in HMENU hmenuShared, __RPC__inout LPOLEMENUGROUPWIDTHS lpMenuWidths); HRESULT STDMETHODCALLTYPE SetMenu( __RPC__in HMENU hmenuShared,__RPC__in HOLEMENU holemenu,__RPC__in HWND hwndActiveObject); HRESULT STDMETHODCALLTYPE RemoveMenus( __RPC__in HMENU hmenuShared); HRESULT STDMETHODCALLTYPE SetStatusText( __RPC__in_opt LPCOLESTR pszStatusText); HRESULT STDMETHODCALLTYPE TranslateAccelerator( __RPC__in LPMSG lpmsg, WORD wID); //imp IOleInPlaceUIWindow HRESULT STDMETHODCALLTYPE GetBorder( __RPC__out LPRECT lprectBorder); HRESULT STDMETHODCALLTYPE RequestBorderSpace( __RPC__in_opt LPCBORDERWIDTHS pborderwidths); HRESULT STDMETHODCALLTYPE SetBorderSpace( __RPC__in_opt LPCBORDERWIDTHS pborderwidths); HRESULT STDMETHODCALLTYPE SetActiveObject( __RPC__in_opt IOleInPlaceActiveObject *pActiveObject, __RPC__in_opt_string LPCOLESTR pszObjName); //imp IOleWindow HRESULT STDMETHODCALLTYPE GetWindow( __RPC__deref_out_opt HWND *phwnd); HRESULT STDMETHODCALLTYPE ContextSensitiveHelp( BOOL fEnterMode); //imp IDocHostUIHandler HRESULT STDMETHODCALLTYPE ShowContextMenu( DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved,IDispatch *pdispReserved); HRESULT STDMETHODCALLTYPE GetHostInfo( DOCHOSTUIINFO *pInfo); HRESULT STDMETHODCALLTYPE ShowUI( DWORD dwID, IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame,IOleInPlaceUIWindow *pDoc); HRESULT STDMETHODCALLTYPE HideUI( void); HRESULT STDMETHODCALLTYPE UpdateUI( void); HRESULT STDMETHODCALLTYPE EnableModeless( BOOL fEnable); HRESULT STDMETHODCALLTYPE OnDocWindowActivate( BOOL fActivate); HRESULT STDMETHODCALLTYPE OnFrameWindowActivate( BOOL fActivate); HRESULT STDMETHODCALLTYPE ResizeBorder( LPCRECT prcBorder,IOleInPlaceUIWindow *pUIWindow,BOOL fRameWindow); HRESULT STDMETHODCALLTYPE TranslateAccelerator( LPMSG lpMsg, const GUID *pguidCmdGroup,DWORD nCmdID); HRESULT STDMETHODCALLTYPE GetOptionKeyPath( __out LPOLESTR *pchKey,DWORD dw); HRESULT STDMETHODCALLTYPE GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget); HRESULT STDMETHODCALLTYPE GetExternal( IDispatch **ppDispatch); HRESULT STDMETHODCALLTYPE TranslateUrl( DWORD dwTranslate,__in __nullterminated OLECHAR *pchURLIn,__out OLECHAR **ppchURLOut); HRESULT STDMETHODCALLTYPE FilterDataObject( IDataObject *pDO,IDataObject **ppDORet); public: void Resize(int width, int height); HRESULT BeforeNavigate2(std::wstring strUrl, DISPPARAMS* dispParams); static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); private: void _initialize(HINSTANCE hInstApp ); bool _makeTransparent(); bool _registWndClass(HINSTANCE hInstApp ); void _createWindow(HINSTANCE hInstApp); bool _embedBrowser(); void _unenbedBrowser(); void _openWebPage(std::wstring strUrl); private: HWND m_hWnd; IWebBrowser2* m_pWeb; IOleObject *m_pOleObj; IFlashPlayerDelegate *m_pDelegate; CBrowserEventBridge *m_pEvtBridge; };
再後來, 又發現了一個比較好的解決方法:
代碼以下, 直接經過handle控制qaxwidget的窗口屬性.
HWND hWnd = (HWND)flash->winId(); LONG lStyle = ::GetWindowLong(hWnd, GWL_STYLE); lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); ::SetWindowLong(hWnd, GWL_STYLE, lStyle); LONG lExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); ::SetWindowLong(hWnd, GWL_EXSTYLE, lExStyle|WS_EX_LAYERED|WS_EX_TOPMOST|WS_EX_TRANSPARENT); typedef int (WINAPI* LPFUNC)(HWND, COLORREF , BYTE, DWORD); HINSTANCE hins = ::LoadLibraryW(L"User32.DLL"); if(!hins) return ; LPFUNC func2 = (LPFUNC)GetProcAddress(hins,"SetLayeredWindowAttributes"); if(!func2) return ; COLORREF clrMask = RGB(255,255,255); func2(hWnd, clrMask, 0, LWA_COLORKEY); FreeLibrary(hins); flash->setControl(QString::fromUtf8("{d27cdb6e-ae6d-11cf-96b8-444553540000}")); //connect(flash,SIGNAL(FSCommand(QString,QString)),this,SLOT(flashAction(QString,QString))); //用於處理FLASH傳來的字符串 flash->dynamicCall("LoadMovie(long,string)", 0, "d:/9023.swf"); //調用方法 flash->dynamicCall("WMode", "transparent");
就這幾行代碼, 被搞了很久. 幸虧, 完美解決透明問題
2. 經過webview直接顯示flash
下載 NPSWF32_13_0_0_182.dll
放置在exe目錄下的plugins, 不然可能沒法加載flash 插件
目錄結構:
test.exe
plugins
└────NPSWF32_13_0_0_182.dll
顯示本地flash 須要加file:/// , 如 file:///d:/myswf.swf
npswf.dll 在本人寫文章時, 最新版是13, 大小15M.
估計大部分可能沒法接受這個大小
因此, 若是你沒有用到很高級的flash特性的話, 建議找版本老一點的npswf.
好比本人用的就是9.x版的npswf.dll, 大小僅爲2.6M
還有另一種方法, 爲QWebView編寫插件, 手動解析flash
這個方法是有很嚴重的bug, 這裏只是說下思路, 而且該方法也能夠用於解析pdf等等
1). 寫一個webkit的插件
WebKitPluginInterface.h #pragma once #include <QWebPluginFactory> #include <QtPlugin> class WebKitPluginInterface { public: WebKitPluginInterface(){}; virtual ~WebKitPluginInterface(){}; virtual QList<QWebPluginFactory::Plugin> plugins()const =0; virtual QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const =0; }; QT_BEGIN_NAMESPACE //聲明WebKitPluginInterface爲一個接口 Q_DECLARE_INTERFACE(WebKitPluginInterface, "org.Qt-Plugin.WebkitPluginFlash") QT_END_NAMESPACE
bluefish.h #include "WebKitPluginInterface.h" class bluefish: public QObject, public WebKitPluginInterface { Q_OBJECT //Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.WebkitPluginFlash" FILE "bluefish.json") Q_INTERFACES(WebKitPluginInterface) //聲明WebKitPluginInterface是一個接口 public: bluefish(); ~bluefish(); QList<QWebPluginFactory::Plugin> plugins()const ; QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const ; protected: };
#include "bluefish.h" #include <QUrl> #include <QDebug> #include <QAxWidget> bluefish::bluefish(): WebKitPluginInterface(){ }; bluefish::~bluefish(){}; QList<QWebPluginFactory::Plugin> bluefish::plugins()const { qDebug()<<"bluefish::plugins"; QWebPluginFactory::MimeType mimeType; mimeType.name="application/x-shockwave-flash"; mimeType.description=QObject::tr("flash"); mimeType.fileExtensions.append(".flv"); mimeType.fileExtensions.append(".f4v"); mimeType.fileExtensions.append(".swf"); QList<QWebPluginFactory::MimeType> mimeTypes; mimeTypes.append(mimeType); QWebPluginFactory::Plugin plugin; plugin.name = QObject::tr("ldh flash plugin"); plugin.description=QObject::tr("ldh flash plugin description"); plugin.mimeTypes=mimeTypes; QList<QWebPluginFactory::Plugin> plugins ; plugins.append(plugin); return plugins; } QObject *bluefish::create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const { qDebug()<<"bluefish::create"; QString strUrl = url.toString(); // QAxWidget *flash = new QAxWidget(0, 0); flash->setControl(QString::fromUtf8("{d27cdb6e-ae6d-11cf-96b8-444553540000}")); //connect(flash,SIGNAL(FSCommand(QString,QString)),this,SLOT(flashAction(QString,QString))); //用於處理FLASH傳來的字符串 flash->dynamicCall("LoadMovie(long,string)", 0, strUrl.toLocal8Bit().data()); //調用方法 //flash->setControl("{ca8a9780-280d-11cf-a24d-444553540000}"); //flash->dynamicCall("LoadFile( const string& )", "d:/bcomps.1.pdf"); //for(int i = 0; i < argumentNames.length(); i++) //{ // flash->dynamicCall(argumentNames[i].toLocal8Bit().data(), argumentValues[i].toLocal8Bit().data()); //} Q_UNUSED(argumentNames); Q_UNUSED(argumentValues); return flash; }
bluefish是能夠做爲dll 動態載入的. 這裏我爲了方便, 就去掉了導出接口的部分.
怎麼編寫一個Qt插件, 能夠參考Qt exsample中的樣例代碼
把QAxWidget對象返回, webkit會自動顯示.
同理, 也能夠在webkit中嵌入QtextEdit等等widget
ps:
//flash->setControl("{ca8a9780-280d-11cf-a24d-444553540000}");
這行代碼就是顯示pdf.
而後繼承QWebPluginFactory載入咱們編寫的插件
qt_modules.h #include <QWebPluginFactory> #include <QUrl> #include "WebKitPluginInterface.h" class WebkitPluginFactory : public QWebPluginFactory { Q_OBJECT public: WebkitPluginFactory(); QObject *create ( const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues ) const; QList<QWebPluginFactory::Plugin> plugins () const; private: mutable QList<QList<QWebPluginFactory::Plugin> > pluginslist; // 插件列表 mutable QList<WebKitPluginInterface *> interfaces; //插件接口,這個接口是咱們自定義的插件的贊成接口。 };
qt_modules.cpp #include "qt_modules.h" #include <QtNetwork\QNetworkProxyFactory> #include <Qdir> #include <QPluginLoader> #include <QLibrary> #include <QDebug> #include <QDir> #include "bluefish.h" WebkitPluginFactory::WebkitPluginFactory() : QWebPluginFactory() { qDebug()<<"=== ldh === WebkitPluginFactory::WebkitPluginFactory"; } QList<QWebPluginFactory::Plugin> WebkitPluginFactory::plugins () const { qDebug()<<"=== ldh === WebkitPluginFactory::create"; static bool isFirst=true; static QList<QWebPluginFactory::Plugin> plugins; if(!isFirst) { return plugins; } isFirst=false; plugins.clear(); bluefish *obj = new bluefish; WebKitPluginInterface * interface= qobject_cast<WebKitPluginInterface*> (obj);//載入自定義的接口,支持動態插件建立 plugins.append(interface->plugins()); pluginslist.append(interface->plugins()); interfaces.append(interface); if(plugins.isEmpty()){ qDebug()<<"no plugins is loaded!"; } //QDir dir(QCoreApplication::applicationDirPath()); //QStringList filters; //QString abspath=dir.absolutePath(); //qDebug()<<"the webkit plugin dir is:"<< abspath; ////獲取指定目錄下的全部插件,linux下是插件庫的後綴爲so,windows下則是dll //filters<<"*.dll"; //QStringList files=dir.entryList(filters); //foreach(QString file,files) //{ // file=dir.filePath(file);//dir.filePath(file); //file.absoluteFilePath(); // qDebug()<<"the webkit plugin path is: "<<file; // QPluginLoader loader(file); // QObject * obj= loader.instance(); // if(!obj) // { // qDebug()<<"error: "<<loader.errorString(); // continue ; // } // WebKitPluginInterface * interface= qobject_cast<WebKitPluginInterface*> (obj);//載入自定義的接口,支持動態插件建立 // qDebug() << "loading plugins is: " << interface->plugins().at(0).name; // plugins.append(interface->plugins()); // pluginslist.append(interface->plugins()); // interfaces.append(interface); //} //if(plugins.isEmpty()){ // qDebug()<<"no plugins is loaded!"; //} return plugins; } QObject * WebkitPluginFactory::create ( const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues ) const { qDebug()<<"=== ldh === WebkitPluginFactory::create"; for(int i=0;i<pluginslist.size();i++) { for( int j=0;j< pluginslist[i].size();j++) { foreach(QWebPluginFactory::MimeType mt, pluginslist[i][j].mimeTypes) { if(mt.name == mimeType) //根據MIME類型,建立相應的插件實例 { return interfaces[i]->create( mimeType, url, argumentNames, argumentValues); } } } } return NULL; //若是沒有,直接返回NULL,webkit會進行處理的 }
註釋部分是動態載入. 但其實不是必須的. 若是有多個插件的話, 能夠這樣作
//初始化flash插件 QNetworkProxyFactory::setUseSystemConfiguration (true); pWebView->settings()->setAttribute(QWebSettings::PluginsEnabled, true); pWebView->settings()->setAttribute(QWebSettings::JavascriptEnabled, true); pWebView->page()->setPluginFactory(new WebkitPluginFactory());
最後對QWebView 設置下就能夠了
這個方法有個很嚴重的bug, 不能動態增長axwidget. 而對於普通QWidget對象, 則沒有問題
即: 若是html在載入時必須肯定全部的object(flash, pdf等). 不能動態增長
好比在html中用js增長html代碼
這會致使webkit崩潰. 本人沒法解決該bug. 無力-_-!
猜想緣由多是resize時, 繪圖對象被提早刪了
而後對於QWidget來講, 能夠隨意添加. 定製webkit仍是很方便的