如果你基于Qt SDK 5.3.1来创建一个Qt Quick App项目,项目模板为你准备的main.qml文档的根元素是ApplicationWindow或Window。这次我们就以ApplicationWindow为例,围绕着它实现一个综合实例:文件查看器。通过文件查看器的实现,我们来再次领略一下Qt Quick的犀利。

版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。

本实例将会用到下列特性:

  • ApplicationWindow
  • MenuBar
  • ToolBar、ToolButton
  • Action
  • StatusBar
  • MediaPlayer
  • Image
  • XMLHttpRequest
  • ColorDialog
  • FileDialog
  • TextArea
  • 动态创建QML组件
  • 多界面切换

我们之前的文章都是就某一个主题来展开的,这次要出个大招。先看点儿图。

文件查看器效果

图1,初始状态

图1 初始状态

图2 是浏览文本文件的效果:

图2 浏览文本文件

图3是浏览图片:

图3 浏览图片

图4是播放视频:

图4 播放视频

图5是播放音乐:

图5 播放音乐

好啦,看代码前,先大概介绍下用到的Qt Quick元素。

Image、动态创建组件、界面切换这些没什么好说的,我之前的文章中已经涉及到。只讲新的了。

ApplicationWindow

ApplicationWindow,类似Qt C++中的QMainWindow,请对照着理解。

ApplicationWindow有菜单栏(menuBar属性)、工具栏(toolBar属性)、状态栏(statusBar属性)。咦,没有centralWidget哈,别急,有的,就是ContentItem,就是那个你不与任何属性绑定的Item。例如:

ApplicationWindow{...Rectangle{id: centralView;anchors.fill: parent;color: "red";}
}

上面代码中的centralView就对应QMainWindow的centralWidget了。

看起来没有DockWidgets……兄弟,别要求太高了,你想要么,真的想要么,你真的确定你想要么?好吧,自己实现就好了,QML里很多元素的哈。

MenuBar

MenuBar就是菜单栏一长条区域了,它干两件事:

  1. 维护一个Menu列表(menus属性)
  2. 绘制菜单栏背景色(style属性)

Menu

看截图中的“文件”、“设置”、“帮助”三个菜单,点一下弹出一个子菜单,Menu就代表文件这个菜单和它下面的子菜单。

列表属性items指向Menu的子菜单项,它的类型是list<Object>,是默认属性。

title属性是string类型,你看到的“文件”、“设置”等字样就是它指定的。

有这两个属性,Menu就可以开始干活了。看Qt帮助里的示例代码片段:

Menu {title: "Edit"MenuItem {text: "Cut"shortcut: "Ctrl+X"onTriggered: ...}MenuItem {text: "Copy"shortcut: "Ctrl+C"onTriggered: ...}MenuItem {text: "Paste"shortcut: "Ctrl+V"onTriggered: ...}MenuSeparator { }Menu {title: "More Stuff"MenuItem {text: "Do Nothing"}}
}

MenuItem

Menu的孩子啊,最受待见的就是MenuItem了。

MenuItem代表一个具体的菜单项,点一下就干一件事情的角色。你可以实现onTriggered信号处理响应用户对它的选择。

MenuItem的text属性指定菜单文字,iconSource属性指定菜单图标。

Action属性很强大哦,MenuItem的text、iconSource、trigger信号等实现的效果,都可以通过Action来实现,这两种方式是等同的。咱们来看Action。

Action

Action类有text、iconSource等属性,还有toggled、triggered两个信号。这些在MenuItem里有对应的属性,不必多说了。

使用Action的一大好处是,你可以给它指定一个id(比如叫open),然后在使用ToolButton构造ToolBar时指定ToolBatton的action属性为之前定义的id为open的那个action,这样工具栏的按钮就和菜单关联起来了。

好啦,总结一下,实现菜单栏的典型代码结构是酱紫的:

MenuBar {Menu{title:"文件";MenuItem{text:"打开";iconSource: "res/ic_open.png";onTriggered:{...}}MenuItem{action: Action {text:"保存";iconSource: "res/ic_save.png";onTriggered:{...}}}        }
}

如你所见,我使用了两种构造MenuItem的方式,一种用到了Action,一种没有。

ToolBar

ToolBar就是工具栏对应的类,它只有一个属性,contentItem,类型为Item。一般我们可以将一个Row或者RowLayout对象赋值给contentItem,而Row或RowLayout则管理一组ToolButton来作为工具栏上的按钮。

ToolButton

ToolButton是Button的派生类,专为ToolBar而生,一般情况下定义ToolButton对象时只需要指定其iconSource属性即可。例如:

ToolButton {iconSource: "res/ic_open.png";
}

还有一种方式是将一个已定义好的Action对象关联到ToolButton对象上。例如:

ToolButton{action: openAction;
}

这样的话,ToolButton会使用Action定义的iconSource或iconName作为其图标。

好啦,构造工具栏的典型代码结构如下:

ToolBar{RowLayout {ToolButton{action: textAction;}ToolButton{action: imageAction;}ToolButton{iconSource: "res/exit.png";onClicked:{...}}}
}

状态栏

ApplicationWindow的属性statusBar代表状态栏,其类型为Item,你可以将任意的Item赋值给它,可以随心所欲构建你妖娆多姿的状态栏。比如这样:

ApplicationWindow{statusBar: Text {text: "status bar";color: "blue";}
}

MediaPlayer

Qt Quick里,播放视频、音频文件都直接使用MediaPlayer类,它是万能的,不要说你万万没想到哈。

对于音乐,最简单,设置source属性,调用play()方法,就可以了。例如:

ApplicationWindow{...MediaPlayer{id: player;source: "xxx.mp3";}Component.onCompleted:{player.play();}
}

对于视频,MediaPlayer还得寻求场外帮助,求助对象就是它的好基友:VideoOutput !简单的示例代码:

ApplicationWindow{...MediaPlayer {id: player;source: "test.ts";}VideoOutput {anchors.fill: parent;source: player;}Component.onCompleted: player.play();
}

哦,黄小琥唱过的歌:没那么简单。是的,实际做项目比较复杂,你还要关注各种播放状态,要seek,要pause,要处理错误,简直烦死人了。请移步到Qt帮助里了解详情。

XMLHttpRequest

在Qt Quick里,要访问网络肿么办泥?答案是:XMLHttpRequest !

不要被它傲娇的外表迷惑,以为它只接受XML文档,其实,它什么都能处理,txt、html、json、binary……它温柔坚定强悍无比。

本实例用它来加载本地的文本文件,耶,这样都可以哈。谁叫Qt Quick不提供直接访问本地文件的类库呢!我可不想跑到C++里用QFile、QTextStream这对黄金搭档。

XMLHttpRequest的文档,Qt帮助里语焉不详,只有一个示例,请看这里:

http://www.w3school.com.cn/xml/xml_http.asp

TextArea

这有什么好讲的,看Qt帮助吧。只提一点:

TextArea自动处理翻页按键、上下键、鼠标中键,正确的滚动文本;而TextEdit,抱歉,我是来打酱油的。

标准对话框

Qt Quick提供了很多标准对话框,比如FileDialog用来选择文件或文件夹,ColorDialog用来选择颜色,MessageDialog用来显示一些提示信息。这些我们实例中用到了,参考Qt帮助吧。

我只说点儿经验。

我一开始使用qmlscene来加载main.qml,出来的界面比较正常,工具栏的图标、菜单项前也有图标。可是当我创建了一个Qt Quick App,灵异事件发生了:

菜单项前面没有图标了……

工具栏图标好大好大……

颜色对话框、消息框,点击右上角的关闭按钮,收不到rejected信号啊……

查了老半天,猛回头,警世钟响起,我了悟了。原来是酱紫的:

Qt Quick提供了这些标准对话框的默认实现,如果应用运行的平台没有可用的,就用这些默认实现。那在Windows上,如果你的main()函数,使用QGuiApplication而非QApplication,就会用到Qt Quick实现的版本,一切都变了模样

资源管理

Qt SDK 5.3之后,Qt Creator创建的Qt Quick App项目,就为我们建立了一个qrc文件,把main.qml扔里啦。我在实例中也把很多图标扔里了。

使用qrc来管理资源,这是跨平台的,推荐使用。

我还自己画了些图标,真费劲,弄得也不好看。不过应用的大眼睛图标,看起来还像那么一回事儿。

源代码

前戏太长,也许你已经失去了兴趣。好吧,G点来咧。

QML代码

版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。

所有QML代码都在这里了,竟然有450行啊亲。

import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import QtMultimedia 5.0ApplicationWindow {visible: truewidth: 480height: 360;color: "black";title: "文件查看器";id: root;property var aboutDlg: null;property var colorDlg: null;property color textColor: "green";property color textBackgroundColor: "black";menuBar: MenuBar{Menu {title: "文件";MenuItem{iconSource: "res/txtFile.png";action: Action{id: textAction;iconSource: "res/txtFile.png";text: "文本文件";onTriggered: {fileDialog.selectedNameFilter = fileDialog.nameFilters[0];fileDialog.open();}tooltip: "打开txt等文本文件";}}MenuItem{action: Action {id: imageAction;text: "图片";iconSource: "res/imageFile.png";onTriggered: {fileDialog.selectedNameFilter = fileDialog.nameFilters[1];fileDialog.open();}tooltip: "打开jpg等格式的图片";}}MenuItem{action: Action {id: videoAction;iconSource: "res/videoFile.png";text: "视频";onTriggered: {fileDialog.selectedNameFilter = fileDialog.nameFilters[2];fileDialog.open();}tooltip: "打开TS、MKV、MP4等格式的文件";}}MenuItem{action: Action {id: audioAction;iconSource: "res/audioFile.png";text: "音乐";onTriggered: {fileDialog.selectedNameFilter = fileDialog.nameFilters[3];fileDialog.open();}tooltip: "打开mp3、wma等格式的文件";}}MenuItem{text: "退出";onTriggered: Qt.quit();}}Menu {title: "设置";MenuItem {action: Action {id: textColorAction;iconSource: "res/ic_textcolor.png";text: "文字颜色";onTriggered: root.selectColor(root.onTextColorSelected);}}MenuItem {action: Action{id: backgroundColorAction;iconSource: "res/ic_bkgndcolor.png";text: "文字背景色";onTriggered: root.selectColor(root.onTextBackgroundColorSelected);}}MenuItem {action: Action{id: fontSizeAddAction;iconSource: "res/ic_fontsize2.png";text: "增大字体";onTriggered: textView.font.pointSize += 1;}}MenuItem {action: Action{id: fontSizeMinusAction;iconSource: "res/ic_fontsize1.png";text: "减小字体";onTriggered: textView.font.pointSize -= 1;}}}Menu {title: "帮助";MenuItem{text: "关于";onTriggered: root.showAbout();}MenuItem{text: "访问作者博客";onTriggered: Qt.openUrlExternally("http://blog.csdn.net/foruok");}}}toolBar: ToolBar{RowLayout {ToolButton{action: textAction;}ToolButton{action: imageAction;}ToolButton{action: videoAction;}ToolButton{action: audioAction;}ToolButton{action: textColorAction;}ToolButton {action: backgroundColorAction;}ToolButton {action: fontSizeAddAction;}ToolButton {action: fontSizeMinusAction;}}}statusBar: Rectangle {color: "lightgray";implicitHeight: 30;width: parent.width;property alias text: status.text;Text {id: status;anchors.fill: parent;anchors.margins: 4;font.pointSize: 12;}}Item {id: centralView;anchors.fill: parent;visible: true;property var current: null;BusyIndicator {id: busy;anchors.centerIn: parent;running: false;z: 3;}Image {id: imageViewer;anchors.fill: parent;visible: false;asynchronous: true;fillMode: Image.PreserveAspectFit;onStatusChanged: {if (status === Image.Loading) {centralView.busy.running = true;}else if(status === Image.Ready){centralView.busy.running = false;}else if(status === Image.Error){centralView.busy.running = false;centralView.statusBar.text = "图片无法显示";}}}TextArea {id: textView;anchors.fill: parent;readOnly: true;visible: false;wrapMode: TextEdit.WordWrap;font.pointSize: 12;style: TextAreaStyle{backgroundColor: root.textBackgroundColor;textColor: root.textColor;selectionColor: "steelblue";selectedTextColor: "#a00000";}property var xmlhttp: null;function onReadyStateChanged(){if(xmlhttp.readyState == 4){text = xmlhttp.responseText;xmlhttp.abort();}}function loadText(fileUrl){if(xmlhttp == null){xmlhttp = new XMLHttpRequest();xmlhttp.onreadystatechange = onReadyStateChanged;}if(xmlhttp.readyState == 0){xmlhttp.open("GET", fileUrl);xmlhttp.send(null);}}}VideoOutput {id: videoOutput;anchors.fill: parent;visible: false;source: player;onVisibleChanged: {playerState.visible = visible;}MouseArea {anchors.fill: parent;onClicked: {switch(player.playbackState){case MediaPlayer.PausedState:case MediaPlayer.StoppedState:player.play();break;case MediaPlayer.PlayingState:player.pause();break;}}}}Rectangle {id: playerState;color: "gray";radius: 16;opacity: 0.8;visible: false;z: 2;implicitHeight: 80;implicitWidth: 200;anchors.horizontalCenter: parent.horizontalCenter;anchors.bottom: parent.bottom;anchors.bottomMargin: 16;Column {anchors.fill: parent;anchors.leftMargin: 12;anchors.rightMargin: 12;anchors.topMargin: 6;anchors.bottomMargin: 6;spacing: 4;Text {id: state;font.pointSize: 14;color: "blue";}Text {id: progress;font.pointSize: 12;color: "white";}}}MediaPlayer {id: player;property var utilDate: new Date();function msecs2String(msecs){utilDate.setTime(msecs);return Qt.formatTime(utilDate, "mm:ss");}property var sDuration;onPositionChanged: {progress.text = msecs2String(position) + sDuration;}onDurationChanged: {sDuration = " / " + msecs2String(duration);}onPlaybackStateChanged: {switch(playbackState){case MediaPlayer.PlayingState:state.text = "播放中";break;case MediaPlayer.PausedState:state.text = "已暂停";break;case MediaPlayer.StoppedState:state.text = "停止";break;}}onStatusChanged: {switch(status){case MediaPlayer.Loading:case MediaPlayer.Buffering:busy.running = true;break;case MediaPlayer.InvalidMedia:root.statusBar.text = "无法播放";case MediaPlayer.Buffered:case MediaPlayer.Loaded:busy.running = false;break;}}}}function processFile(fileUrl, ext){var i = 0;for(; i < fileDialog.nameFilters.length; i++){if(fileDialog.nameFilters[i].search(ext) != -1) break;}switch(i){case 0://text fileif(centralView.current != textView){if(centralView.current != null){centralView.current.visible = false;}textView.visible = true;centralView.current = textView;}textView.loadText(fileUrl);break;case 1:if(centralView.current != imageViewer){if(centralView.current != null){centralView.current.visible = false;}imageViewer.visible = true;centralView.current = imageViewer;}imageViewer.source = fileUrl;break;case 2:case 3:if(centralView.current != videoOutput){if(centralView.current != null){centralView.current.visible = false;}videoOutput.visible = true;centralView.current = videoOutput;}player.source = fileUrl;player.play();break;default:statusBar.text = "抱歉,处理不了";break;}}function showAbout(){if(aboutDlg == null){aboutDlg = Qt.createQmlObject('import QtQuick 2.2;import QtQuick.Dialogs 1.1;MessageDialog{icon: StandardIcon.Information;title: "关于";\ntext: "仅仅是个示例撒";\nstandardButtons:StandardButton.Ok;}', root, "aboutDlg");aboutDlg.accepted.connect(onAboutDlgClosed);aboutDlg.rejected.connect(onAboutDlgClosed);aboutDlg.visible = true;}}function selectColor(func){if(colorDlg == null){colorDlg = Qt.createQmlObject('import QtQuick 2.2;import QtQuick.Dialogs 1.1;ColorDialog{}',root, "colorDlg");colorDlg.accepted.connect(func);colorDlg.accepted.connect(onColorDlgClosed);colorDlg.rejected.connect(onColorDlgClosed);colorDlg.visible = true;}}function onAboutDlgClosed(){aboutDlg.destroy();aboutDlg = null;}function onColorDlgClosed(){colorDlg.destroy();colorDlg = null;}function onTextColorSelected(){root.textColor = colorDlg.color;}function onTextBackgroundColorSelected(){root.textBackgroundColor = colorDlg.color;}FileDialog {id: fileDialog;title: qsTr("Please choose an image file");nameFilters: ["Text Files (*.txt *.ini *.log *.c *.h *.java *.cpp *.html *.xml)","Image Files (*.jpg *.png *.gif *.bmp *.ico)","Video Files (*.ts *.mp4 *.avi *.flv *.mkv *.3gp)","Audio Files (*.mp3 *.ogg *.wav *.wma *.ape *.ra)","*.*"];onAccepted: {var filepath = new String(fileUrl);//remove file:///if(Qt.platform.os == "windows"){root.statusBar.text = filepath.slice(8);}else{root.statusBar.text = filepath.slice(7);}var dot = filepath.lastIndexOf(".");var sep = filepath.lastIndexOf("/");if(dot > sep){var ext = filepath.substring(dot);root.processFile(fileUrl, ext.toLowerCase());}else{root.statusBar.text = "Not Supported!";}}}
}

C++代码

其实,我只对模板生成的C++代码改动了三行,一行include,一行QApplication,一行设置应用图标。main.cpp如下:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QIcon>int main(int argc, char *argv[])
{QApplication app(argc, argv);app.setWindowIcon(QIcon(":/res/eye.png"));QQmlApplicationEngine engine;engine.load(QUrl(QStringLiteral("qrc:///main.qml")));return app.exec();
}

PRO文件

有人喊,兄弟,这也要贴!你凑字数呢……你管,就放这里了:

TEMPLATE = appQT += qml quick network multimedia widgetsSOURCES += main.cppRESOURCES += qml.qrc# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =# Default rules for deployment.
include(deployment.pri)HEADERS +=

版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。

好啦,彪悍的人生不需要解释,都扒光了,你自己仔细看吧。

回顾一下我的Qt Quick系列文章:

  • Qt Quick 简介
  • QML 语言基础
  • Qt Quick 之 Hello World 图文详解
  • Qt Quick 简单教程
  • Qt Quick 事件处理之信号与槽
  • Qt Quick事件处理之鼠标、键盘、定时器
  • Qt Quick 事件处理之捏拉缩放与旋转
  • Qt Quick 组件与对象动态创建详解
  • Qt Quick 布局介绍
  • Qt Quick 之 QML 与 C++ 混合编程详解
  • Qt Quick 图像处理实例之美图秀秀(附源码下载)
  • Qt Quick 之 PathView 详解
  • Qt Quick实例之挖头像

Qt Quick综合实例之文件查看器相关推荐

  1. 一步一步学Silverlight 2系列(18):综合实例之RSS阅读器

    概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

  2. (18):Silverlight 2 综合实例之RSS阅读器

    概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

  3. 使用广泛的开源PCB文件查看器 Gerbv 含多个严重漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 专栏·供应链安全 数字化时代,软件无处不在.软件如同社会中的"虚拟人",已经成为支撑社会正常运转的最基本元素之一,软件的安全 ...

  4. 《Windows 程序设计(第3版)》——6.7 【实例】窗口查看器

    本节书摘来自异步社区<Windows 程序设计(第3版)>一书中的第6章,第6.7节,作者:王艳平 , 张铮著,更多章节内容可以访问云栖社区"异步社区"公众号查看 6. ...

  5. IFC模型文件查看器(基于IFC++开源库实现)

    关于IFC IFC是由buildingSMART以工业的产品资料交换标准STEP编号ISO-10303-11的产品模型信息描述用EXPERSS语言为基础,基于BIM中AEC/FM相关领域信息交流所指定 ...

  6. 文件查看器示例支持 文件预览,编辑和视频播放

    以下为文件查看器示例,支持 文件预览,和视频播放: import QtQuick 2.2 import QtQuick.Window 2.1 import QtQuick.Controls 1.2 i ...

  7. QT Quick QML 实例之 Popup 弹出界面

    QT Quick QML 实例之 Popup 弹出界面 一.演示 二.实现过程 1. 居中弹出 2. 正下方弹出 所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧! GIT工程文件 ...

  8. mhtml文件查看器MHT Viewer Mac版

    MHT Viewer 是一个轻量级的 MHT (MHTML/MIME HTML) 文档查看器/阅读器. 点击获得MHT Viewer for Mac(mhtml文件查看器) MHT Viewer fo ...

  9. Linux 下高级日志文件查看器Log File Navigator

    Log File Navigator,简称lnav,是一款面向小规模的适用于 Linux 的高级日志文件查看器.它是一个终端应用程序,可以理解您的日志文件,让您轻松找到问题,几乎不需要什么设置. ln ...

  10. 【玩转.Net MF – 03】远程文件查看器

    虽说目前.Net Micro Framework已经支持文件系统(FAT16/FAT32),但在远程还无法直接访问,从某种意义上讲,无法和PC交互的存储介质显得有些鸡肋.我做SideShow相关开发的 ...

最新文章

  1. 程序员的灯下黑:能认识自己吗?
  2. lambda ::_Lambdas中的例外:有点混乱的优雅解决方案
  3. php javascript对象,JavaScript 对象
  4. 积分上下限无穷_数学分析|第九章 定积分利用等价无穷小量和定积分定义解决数列极限问题总结...
  5. RHEL4- ssh服务(二)ssh服务器的配置和启动
  6. python 多层for循环转递归/迭代
  7. php 检查数据库查询结果,php数据库连接、查询、显示结果的小例子
  8. oa软件测试用例,OA标准系统测试用例.doc
  9. asp.net中通过HyperLinkField传值
  10. 开关灯问题 BulbSwitch
  11. unity项目对音效的优化处理
  12. 哈工大中文分词系统LTP(pyltp)学习笔记
  13. Android3dtouch xposed,乐2 MIUI10 8.10.26增强版 主题和谐 黑域 3Dtouch 分屏 Gay设置-刷机之家...
  14. NLPIR/ICTCLAS中文分词系统 java相关api文档总结
  15. 信号及传播介质 综合布线系统
  16. HelloWorld Detail Earth 3D Engine(一)总体介绍
  17. python爬取物流信息_手把手教你用Python爬取快递100查询你的物流信息
  18. firsthead学习笔记
  19. 【添坑】高博ORB_SLAM
  20. 【ROS】将odom里程计数据转换为path路径消息

热门文章

  1. 计算机内码和国际码的转换,汉字机内码、国标码和区位码之间转换关系图
  2. 前端学习笔记-22-浏览器中的DOM操作
  3. Java并发编程——创建线程的三种方法以及区别
  4. 子之错父之过什么意思_子不教,父之过。教不严,师之惰。是什么意思?
  5. 游戏网站SEO优化技术简介
  6. itextpdf使用总结
  7. SAP FICO面试题
  8. NBU备份恢复Vmware
  9. 如何把pdf转换成excel表格
  10. Java 二叉树完整代码(递归迭代)