Qt和HTML笔记:初始化
为了应对最近的比赛,但对很对 GUI 系统都不怎么熟悉,而且又要用 C++ 进行项目核心代码的编辑。RetVal 希望团队做出一个很炫的图形界面,不过,对 C++ 的窗口系统还真的不熟悉。于是尝试用 Qt 和 HTML 5 来进行界面的编程,也算是一个新挑战。
不过似乎关于 Qt 和 HTML 5 的中文资料还不多,于是整理一下笔记吧。这个博客也很久没更新了……
新建项目
要新建 Qt HTML 5 应用程序,可以直接在 Qt Creator 里新建“HTML 5 Application”,但要注意的是,这样新建的Qt程序并没有包含菜单栏之类控件,完全是一个 Qt 窗口里面有一个 Webkit 组件。但有一个好处是,新建的 Webkit 组件被 Qt Creator 对移动设备(主要是触摸屏设备)优化过,可以应用于桌面端和手机端。但也由于针对了触摸屏,所以,默认禁用了“hover”事件(即鼠标悬停事件)。使我还纠结了很久为什么 Qt Webkit 不支持鼠标悬停事件。
如果我们是针对桌面端开发,那么其实不必要考虑Webkit的移动支持,因此,我们可以自己新建一个 Qt GUI 项目。此时,要注意的是在 .pro 文件中添加对 Webkit 的编译支持。
参考 .pro 文件如下:
#------------------------------------------------- # # Project created by QtCreator 2012-04-02T09:29:02 # #------------------------------------------------- QT += core gui webkit TARGET = ColdTest TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ sampleobject.cpp HEADERS += mainwindow.h \ sampleobject.h FORMS += mainwindow.ui uiml.source = html uiml.target = . DEPLOYMENTFOLDERS = uiml defineTest(qtcAddDeployment) { for(deploymentfolder, DEPLOYMENTFOLDERS) { item = item$${deploymentfolder} itemsources = $${item}.sources $$itemsources = $$eval($${deploymentfolder}.source) itempath = $${item}.path $$itempath= $$eval($${deploymentfolder}.target) export($$itemsources) export($$itempath) DEPLOYMENT += $$item } MAINPROFILEPWD = $$PWD win32 { copyCommand = for(deploymentfolder, DEPLOYMENTFOLDERS) { source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) source = $$replace(source, /, \\) sourcePathSegments = $$split(source, \\) target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) target = $$replace(target, /, \\) !isEqual(source,$$target) { !isEmpty(copyCommand):copyCommand += && isEqual(QMAKE_DIR_SEP, \\) { copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" } else { source = $$replace(source, \\\\, /) target = $$OUT_PWD/$$eval($${deploymentfolder}.target) target = $$replace(target, \\\\, /) copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" } } } !isEmpty(copyCommand) { copyCommand = @echo Copying application data... && $$copyCommand copydeploymentfolders.commands = $$copyCommand first.depends = $(first) copydeploymentfolders export(first.depends) export(copydeploymentfolders.commands) QMAKE_EXTRA_TARGETS += first copydeploymentfolders } } else:unix { desktopfile.path = /usr/share/applications copyCommand = for(deploymentfolder, DEPLOYMENTFOLDERS) { source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) source = $$replace(source, \\\\, /) macx { target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) } else { target = $$OUT_PWD/$$eval($${deploymentfolder}.target) } target = $$replace(target, \\\\, /) sourcePathSegments = $$split(source, /) targetFullPath = $$target/$$last(sourcePathSegments) !isEqual(source,$$targetFullPath) { !isEmpty(copyCommand):copyCommand += && copyCommand += $(MKDIR) \"$$target\" copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" } } !isEmpty(copyCommand) { copyCommand = @echo Copying application data... && $$copyCommand copydeploymentfolders.commands = $$copyCommand first.depends = $(first) copydeploymentfolders export(first.depends) export(copydeploymentfolders.commands) QMAKE_EXTRA_TARGETS += first copydeploymentfolders } installPrefix = /opt/$${TARGET} for(deploymentfolder, DEPLOYMENTFOLDERS) { item = item$${deploymentfolder} itemfiles = $${item}.files $$itemfiles = $$eval($${deploymentfolder}.source) itempath = $${item}.path $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) export($$itemfiles) export($$itempath) INSTALLS += $$item } icon.files = $${TARGET}.png icon.path = /usr/share/icons/hicolor/64x64/apps desktopfile.files = $${TARGET}.desktop target.path = $${installPrefix}/bin export(icon.files) export(icon.path) export(desktopfile.files) export(desktopfile.path) export(target.path) INSTALLS += desktopfile icon target } export (ICON) export (INSTALLS) export (DEPLOYMENT) export (TARGET.EPOCHEAPSIZE) export (TARGET.CAPABILITY) export (LIBS) export (QMAKE_EXTRA_TARGETS) } qtcAddDeployment()
项目依赖部分(qtcAddDeployment)是参考了 Qt Creator 为 HTML 5 Application 项目自动生成的代码。
然后,在项目根目录下新建文件夹 html ,把用到的 HTML 5 构建的文件添加到这里。
初始化 QtWebkit
新建 Qt GUI 项目后,默认应该会生成 MainWindow 类,简单起见,直接以 MainWindow 类为基础,用 Qt Desginer 画好界面。
然后回到 MainWindow 类(或者你自己新建的其他类)的初始化函数中,添加slot:
private slots: void addToJavaScript();
然后,方法实现为:
void MainWindow::addToJavaScript() { ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("Qt", qt); ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("app", this); }
这个函数是为 Webkit 组件建立页面的时候,把 C++ 对象包装为 JavaScript对象传递给 JavaScript 调用的。这里,即是把 qt(一个QApplication 对象)、app(QMainWindow 对象)添加到 QtWebkit 的 JavaScript 运行环境中。
然后,添加本地路径调整函数:(这里省略头文件的声明了)
QString MainWindow::adjustPath(const QString &path) { #ifdef Q_OS_UNIX #ifdef Q_OS_MAC if (!QDir::isAbsolutePath(path)) return QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/") + path; #else const QString pathInInstallDir = QCoreApplication::applicationDirPath() + QLatin1String("/../") + path; if (pathInInstallDir.contains(QLatin1String("opt")) && pathInInstallDir.contains(QLatin1String("bin")) && QFileInfo(pathInInstallDir).exists()) { return pathInInstallDir; } #endif #endif return path; }
这段代码也是参考 HTML 5 Application 生成的函数,可以把相对项目路径转化为 QUrl 标识。
于是,初始化 WebView 的时候就可以:
ui->webView->setUrl(QUrl(MainWindow::adjustPath("html/ui.html")));
来调用 html 文件夹下面的 ui.html 文件了。
到这里,一个 Qt HTML 5 程序的初始化工作就完成了。可以编辑一下 ui.html 文件试用一下 Qt Webkit ~