- 浏览: 2101272 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
wahahachuang5:
web实时推送技术使用越来越广泛,但是自己开发又太麻烦了,我觉 ...
细说websocket - php篇 -
wahahachuang8:
挺好的,学习了
细说websocket - php篇 -
jacking124:
学习了!支持你,继续
初窥Linux 之 我最常用的20条命令 -
aliahhqcheng:
应该是可以实现的,没有看过源码。你可以参考下:http://w ...
Jackson 框架,轻易转换JSON
Qt Quick综合实例之文件查看器
如果你基于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就是菜单栏一长条区域了,它干两件事:
- 维护一个Menu列表(menus属性)
- 绘制菜单栏背景色(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.0 ApplicationWindow { visible: true width: 480 height: 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 file if(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 = app QT += qml quick network multimedia widgets SOURCES += main.cpp RESOURCES += 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核心编程》起始于基础的开发环境搭建和Qt Creator快速介绍,帮助读者正确使用开发环境;着力于QML语言基础、事件、Qt Quick基本元素,辅以简要的... 第17章 综合实例之文件查看器 第18章 综合实例之聊哈
基于Qt的文件查看器 查看电脑的所有文件并进行打开 介绍可查看博客:https://blog.csdn.net/qq_33190913/article/details/109647660
sql文件查看器sql文件查看器sql文件查看器sql文件查看器sql文件查看器
Qt5综合实例:利用QML以及Qt Quick知识,来开发一个可以打开看多种类型文档的文件查看器。该程序可用于浏览网页,普通文本文档和图片,并支持对文本进行编辑及对图片的缩放、旋转等操作。
基于Qt5.2的文件类型查看器,c++源码,对学习Qt的朋友有帮助
pak文件查看器pak文件查看器pak文件查看器
Qt5的quick control,在原有只能查看.txt和图片的基础上加了视频查看功能,可播放,暂停和停止,需要Qt课程设计的可以下载
用Qt 5.3 纯 qml 写的文件查看器 - 支持文本、图像、音频、视频 - 支持文字大小、色彩 - 应用程序图标 - xmlhttp 读取本地文件
Opengl qt的查看器Opengl qt的查看器Opengl qt的查看器Opengl qt的查看器Opengl qt的查看器
spr文件查看器
qt实现本地\网络图片查看器,网络图片支持缓存。支持图片放大、缩小、翻转已经另存为。支持切换上一张下一张。 qt实现本地\网络图片查看器,网络图片支持缓存。支持图片放大、缩小、翻转已经另存为。支持切换上一张...
用QT设计了一个简单的图片查看器,可以查看jpg、bmp、png和gif格式的图片。选择路径错误时会有弹窗提示,图片不是gif点击播放gif是也会有弹窗提示
QT5开发实例(第4版)第27章源码,多功能文档查看器。
STP/STEP/STL文件查看器,应用小巧紧紧22M,支持测量,旋转,文件导出导入,查看方便不用再安装其他大的软件,亲测可用
资源中包括《HEX文件格式解析.pdf》文章,使用QT实现HEX文件生成、HEX文件解析、文件读写及文件拼接功能的工程源码,因项目开发写的工程,可以直接使用,也可作为HEX文件操作参考。
Qt5的课程设计,是Qt5的一个开发实例,可用查看图片,文件等各种类型的文档
//配置(默认配置请查看宏定义) //设置目录 int SetDir(const char *szDir); //设置文件名 int SetFileName(const char *szFileName); //设置至少磁盘空间 int SetDiskFreeSpace(unsigned long long ...
DDS 文件 查看器,支持dds文件开发使用