嵌入式系统课程设计-音乐播放器_第1页
嵌入式系统课程设计-音乐播放器_第2页
嵌入式系统课程设计-音乐播放器_第3页
嵌入式系统课程设计-音乐播放器_第4页
嵌入式系统课程设计-音乐播放器_第5页
已阅读5页,还剩57页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

./课程设计说明书课程设计名称:嵌入式系统课程设计课程设计题目:音乐播放器学院名称:信息工程学院专业:计算机科学与技术__090451__09045102__评分:教师:20xx11月30日.TOC\o"1-4"\h\u9904摘要:14234第一章课程设计要求和内容28441.1设计目标和要求2137031.2设计内容227910第二章开发工具介绍321223第三章系统设计与实现4223633.1宿主机开发环境配置4220523.2功能分析与方案论证5271443.2.1功能分析580773.2.2可行性分析514373.3需求分析5289323.4详细设计64433.4.1系统的功能模块设计650613.4.2界面窗口模块详细设计与实现66724MP3文件播放控制模块详细设计与实现9300453.4.6主要程序文件〔代码见附录〕27397第四章调试分析1215656第五章设计总结125531主要参考文献:1310014附录<流程图、源代码>:1419370附录1相关流程图145564附录2系统运行效果161946附录3程序源代码17音乐播放器摘要:随着用户要求的不断提高,越来越多的嵌入式设备使用功能强大、价格低廉的嵌入式Linux作为操作系统并开始采用较为复杂的图形用户界面。Qt以其强大的功能、良好的可移植性逐渐成为一种被广泛使用的GUI系统。正是由于嵌入式操作系统与其相应图形用户界面的不断发展,嵌入式软件的开发显得越来越重要,其中嵌入式媒体播放器由于能够满足人们的视听享受已经逐渐成为了系统中不可或缺的重要组成部分,在嵌入式系统上开发媒体播放器已经成为了一个技术热点,当前许多嵌入式产品中都包含媒体播放器。因此在基于Qt的嵌入式Linux系统中实现媒体播放器具有深刻的意义和实用价值。本次课程设计运用Qt技术在Linux下进行GUI设计,以一个图形界面为例,运用QTcreator软件编程,实现一个简单的音乐播放器。此播放器能够播放本地的音频文件,在功能方面,它具备一些基本的音乐操作处理功能,如暂停、播放、音量调节、停止等,此外,界面还能显示歌曲信息,比如显示播放列表,播放的时候能够通过按钮来实现歌词显示的功能。关键词:嵌入式系统音乐播放器QTLinux第一章课程设计要求和内容1.1设计目标和要求掌握linux应用开发的基本理论知识和基本方法技能,概念清楚明确,系统分析、系统设计、系统实现、系统测试符合软件工程的相关规X,结构合理,程序运行良好。实现Linux系统下的音乐播放器设计,实现一个播放Mp3格式音乐的嵌入式多媒体播放系统。具有良好的图形用户设计界面。1.2设计内容运用Qt技术在Linux下进行GUI设计,以一个图形界面为例,运用QTcreator软件编程,实现一个简单的音乐播放器。此播放器能够播放本地的音频文件,在功能方面,它具备一些基本的音乐操作处理功能,如暂停、播放、音量调节、停止等,此外,界面还能显示歌曲信息,比如显示播放列表,播放的时候能够通过按钮来实现歌词显示的功能。第二章开发工具介绍Qt从4.4版本开始提供的一套多媒体框架,提供多媒体回放的功能。目前在Qt4.6中实现多媒体播放图形界面主要依赖于phonon框架,其实qt中还有一个Multimedia模块,帮助文档中对它的描述是:实现底层的多媒体播放功能,在一般情况下上层的接口phonon模块更适合实现这些功能。phonon最初是一个源于KDE的项目,为使用音频和视频的应用程序开发提供的一个框架。应用程序不用去管多媒体播放是通过什么实现的〔如gstreamer、xine〕,只需调用相应的接口就行,但这中间需要一个中转,被称为backend。Qt也是通过phonon来实现夸平台的多媒体播放。多媒体文件的播放主要过程包括:文件读取、分流、解码、输出。如图1所示图1多媒体文件的播放主要过程这些在不同的系统中实现方式不同,如windows下的DirectX、Linux下的gstreamer或xine与Mac下的QuickTime。而Qt中的phonon作为夸平台的多媒体解决方案,就因该为用户屏蔽掉这些差异。而实际上它做得还不够好,因为用户还需要自己来安装相应的后端插件来完成播放任务。如图2图2Phonon库的调用使用过程应用Phonon框架实质上分4个部分,你的程序,Phonon库,Phonon后端插件<phonon_backend>,真正的后端。Phonon其实什么都不干,他只是提供了一套API接口,这套接口可以给你的程序调用,同时也是给编写后端插件提供一个规X。程序完全不知道最后谁来放我的Mp3,谁来解码我的视频,播放的又是哪个设备。同样,Phonon库也不知道,他只管搜索符合自己规X的插件。并告诉这些插件,现在程序发出的指令是什么,从插件返回给程序现在的媒体状态和信息。而后端才是实际进行读入媒体、解码并且播放的部分,他们和后端插件是一一对应的。后端可以是任何形式,只要你写出了相应的后端插件。所以,使用Phonon必需要先做2件事:1、编译Phonon库:通常情况下,Qt默认没有编译,需要configure后加好参数,然后单独进入phonon的文件夹进行编译就可以了2、编译Phonon后端插件:Qt为3大平台分别提供了一个可用的后端插件,放在src\plugins\phonon目录下。进入目录编译即可,Qt会自动选择你当前系统的后端插件的。<出现phononbackendplugincouldnotbeloaded就是这步没有做>.如果是MinGW用户,Windows下Qt只提供了DirectShow这个后端插件,而这个后端插件因为调用了DX的SDK,所以只能由VC编译。当然其实有更好的选择,比如这个phonon-vlc-mplayer插件,通过他,可以将mplayer作为后端,彻底抛弃臃肿的VS以与读ID3v2都会出错的DirectShow,Phonon是KDE4的多媒体API。Phonon提供一个稳定的API允许KDE4独立于任何一个声音系统服务器如xine。Phonon让各种后端提供界面给开发者所谓的"引擎";每个引擎运作在一个具体的后端。每个后端都可让Phonon控制基本功能,如播放、暂停和搜寻。Phonon也支持更高层次的功能,如让音轨转化之间变微弱。使用Solid,Phonon将给予用户更多配件的控制能力如耳机、扬声器、麦克风。一个例子是,因为你可能只有一个VoIP会话使用您的耳机,但所有其他的声音通过扬声器出来。支援Unix-like系统下的后端xine、VLC、MPlayer。支援Windows下的后端DirectShow、VLC和MPlayer.支援MacOSX下的后端QuickTime。如上所述,如果想要运行使用Qt中的phonon写的程序,需要满足一下条件:Qt基本库、Qtphonon库、phonon_backend<后端插件>和多媒体播放后台。第三章系统设计与实现3.1宿主机开发环境配置安装Linux系统:宿主开发环境,我们选用在windows下安装VMwareWorkStation虚拟机RedHatLinux5的组合来组建。在虚拟机中安装Linux系统:我们选择标准安装<Typical>安装过程中先创建一个虚拟空白盘,然后选择Linux系统版本为RedHatLinux5,整个安装流程参照用户手册来完成。在Linux下安装QTCreator:从QT官网上可以直接下载到QTCreator,下载完毕后,直接在终端运行安装包,选择默认安装类型,即可完成QTCreator的安装。3.2功能分析与方案论证3.2.1功能分析通过运用Qt技术在嵌入式Linux操作系统下,进行GUI设计,以一个图形界面为例,运用QTcreator软件编程,来完成音乐播放器的设计和实现音乐播放器的各种功能,使播放器能够显示播放列表,播放本地的音频文件,通过点击相应的按钮来实现歌曲的播放、暂停、停止等功能,此外,界面还能进行音量调节,显示歌曲信息,比如显示正在播放在音频文件的时间信息,播放的时候能够通过按钮来实现播放列表和歌词的显示的功能。3.2.2可行性分析计算机技术的发展目前Linux已被广泛应用于信息家电、数据网络、工业控制、医疗卫生、航空航天等众多领域。在嵌入式领域,由于价格低廉、结构小巧的各种微处理器的出现为外设连接提供了稳定可靠的硬件架构限制嵌入式系统发展的瓶颈就突出表现在软件方面。近年来随着芯片技术的快速发展嵌入式系统的性能逐步提高,功能也越来越丰富。嵌入式系统在众多领域的应用给我们的生活带来了便利并且对人们的生活方式的改变和生活质量的提高具有重要的影响。在这些领域中,消费电子产品的应用具有更为广泛的潜力,尤其是便携式消费电子产品。3.3需求分析程序设计目标:程序设计目标是:结合QT技术和C++语言实现一个图形界面mp3音频播放器。具体目标如下:1>能够方便地选择本机上的一个mp3文件进行播放。选择mp3文件时,不需要有键盘输入操作。2>播放过程中可以暂停,暂停后可以从暂停处再次播放。播放过程中可以停止,点击播放按钮后,可以再次从开头播放本文件。3>播放、暂停、或停止状态中,都可以选择其它mp3文件代替当前mp3文件进行播放。4>在面板上显示mp3文件当前播放的时间和mp3文件的名字。播放时间随时刷新,配合好前面的播放调节操作。5>本程序中要有一个滚动条来显示当前的mp3文件播放位置,拖动滚动条,可以调节mp3文件的播放位置。6>本程序中要有一个滑块来显示当前的mp3音频文件的播放音量,拖动滑块,可以调节音频的播放音量。7〕点击打开按钮可以打开/关闭播放列表。8〕点击歌词按钮可以显示/关闭桌面歌词。9>界面尽量美观,程序运行时不要出现异常。3.4详细设计3.4.1系统的功能模块设计一个软件系统设计的成败,除了在功能上要尽可能地完善以外,在界面设计上也有很大的决定性作用。如果你的软件界面很糟糕,不能让使用该软件的用户满意,那么你开发的产品将被"冻结"起来,得不到用户的响应。所以,软件产品的界面设计应该具有友好性这一特点。除此之外,还应该有简洁性。如果你的产品只注意了友好美观的界面,而使得你的界面很复杂,将会给用户带来极大的不便,从而会适得其反。比如,一个最简单的操作用户要点击一个按钮,而你的界面上到处都是按钮图片之类的,这就会让用户花上很长的时间去寻找要点击的按钮,这样一来,当然就不能使用户满意了。基于此,本系统使用Qt来设计界面,并且共有2个界面窗口,分别是:播放器控制窗口、播放列表窗口、歌词显示窗口。为了更好地实现系统的各项功能与这些功能的完整性,现在把系统共分为以下2大模块进行设计:<1>系统的播放控制窗口模块<2>MP3文件的播放列表管理模块<3>MP3歌词的实时显示模块3.4.2界面窗口模块详细设计与实现一款软件的界面设计的成败直接关系到该产品的成败。本MP3播放器系统的界面设计,利用Qt提供的强大的控件设计而成。系统的界面窗口包括有2个主要的界面,分别是:播放器的控制界面窗口和媒体文件播放列表窗口,背景都为蓝绿色调,下面分别作出详细介绍。控制界面窗口:播放器的控制界面是播放器系统与播放器的使用者直接交互的媒介。按照控制界面上的组件的功能来分,可以将这些组件分成两部分:信息显示和控制组件,如下图3所示图3控制界面窗口信息显示组件信息显示是系统与使用者进行交流的通道,它可以与时地将各种有用的信息提供给用户,以便用户对系统进行控制。本播放器系统的所有信息显示在操作控件四周,很方便看到1.播放状态显示的作用,是与时准确地显示当前播放器所处的状态。其中,状态有"播放"、"暂停"和"停止"三种,随播放器状态的改变而改变。2.音量显示这部分与音量控制滑动杆控件和菜单项中的"声音"相关联,当音量滑动杆的滑块位置改变以后,音量大小会随着变化。控制组件:信息显示是播放器系统提供给使用者各种有用的信息,而控制组件则刚好相反,它可以看作是使用者提供给播放器系统的各种有用的信息,用来指示系统是否工作与如何工作。1>播放/暂停按钮设计这个按钮对一个播放器来说是最为重要的。如果一个播放器不能够播放/暂停的话,就不能称之为播放器了。对本播放器系统来说,这个按钮集成了两个重要的功能:"开始播放"和"暂停播放",这样将两个功能集成到一个位置上的好处就是减少了界面上的按钮的个数,这使得整个界面更加简洁。这个按钮的作用是:如果当前播放器的状态为正在播放,点击它之后就会暂停播放;如果当前播放器的状态为暂停播放,点击它之后就会继续播放。如果播放器的状态没有播放,也不是处于暂停状态,点击之后,系统就会从媒体播放列表中加载一个媒体文件并开始播放。因此,基于上述功能,为实现播放和暂停功能,使之重叠放置,按照播放状态的改变在同一时间只显示一个按钮,这样就模拟实现了播放/暂停功能按钮,如果在播放状态时想点击播放按钮播放其他MP3可以通过菜单中实现。表1播放器控件的组成部分组成控件功能播放/暂停按钮播放当前音乐文件或者暂停播放停止按钮停止播放当前音乐文件上一首按钮播放列表中当前MP3文件的上一首MP3文件下一首按纽播放列表中当前MP3文件的下一首MP3文件打开按钮选择一首MP3文件列表按钮显示隐藏播放列表窗口歌词按钮显示隐藏歌词显示窗口静音按钮打开/关闭播放器的输出声音音量控制条对播放器的音量大小进行调节进度控制条对当前播放的MP3文件的播放进度进行调节2>停止按钮的设计停止功能按钮的设计,是让本播放器系统的使用者可以以手动的方式来停止当前媒体文件的播放。如果播放器当前没有文件正在进行播放时,该按钮将置为无效状态,此时该按钮不能点击。3>上一首按钮的设计如果没有播放列表的话就不存在有多个媒体文件,也就不存在有上一首可以选择了。所以,一个播放器的设计有这个功能按钮的话,就表示它一定有一个用来保存媒体文件的播放列表。在本系统中,上一首按钮设计在播放/暂停功能按钮的前面。这样设计的目的,是使得整个功能控制按钮的顺序与MP3文件在列表中的顺序相似。4>下一首按钮的设计同样,它的设计也是与播放列表的存在有关,如果没有播放列表的话就不存在有多个媒体文件,也就不存在有下一首可以选择了。在本系统中,下一首按钮设计在播放/暂停功能按钮的后面。这样设计的目的,是使得整个功能控制按钮的顺序与文件在列表中的顺序相似。5>打开按钮的设计打开功能按钮的设计,是方便用户选择一个媒体文件,并立即进行播放。6>列表按钮的设计它主要是对播放列表窗口进行显示/隐藏控制,当用户点击此按钮后,如果当前列表窗口的状态为显示状态的话,用户的操作将会隐藏列表窗口。相反,如果当前列表窗口的状态为隐藏状态,用户的操作将会显示列表窗口。7>歌词按钮的设计LRC是MP3歌词文件的格式,此按钮可以控制歌词显示窗口的显示与隐藏。当用户点击此按钮时,将检查歌词显示窗口的状态。如果当前状态为显示,则将其隐藏;反之,如果当前状态为隐藏,则将其显示。8〕静音按钮该按钮可以控制播放器输出声音的开启和关闭。当用户点击此按钮时,系统将检查播放器的声音状态。如果当前声音状态为开启,则将其管理,即静音;如果当前声音状态为关闭,则将其开启。因为与音量控制有关,所以在播放器中将其置于音量控制条的左方。9>音量控制条音量控制条的设计与音量大小和播放器的输出音量关联,它的改变将直接影响播放器输出音量的大小,其主要功能是用来控制系统播放媒体文件时发出的音量大小。10〕进度控制条进度控制条的设计,是用来方便用户进行控制播放媒体文件进度的,它的移动将直接改变媒体文件的当前播放进度,同时歌词显示实时窗口的歌词也将按照进度进行调整。当控制条滑到最左边时表示MP3文件的初始位置,当控制条滑到最右边时表示当前位置为MP3文件的最后位置。播放列表界面:本播放器系统的播放列表窗口界面的设计主要是用来方便使用者配置管理播放器的播放列表,以提供给播放器更完整的功能。效果如图4所示图4播放列表界面MP3文件播放控制模块详细设计与实现MP3文件的播放控制模块是本播放器系统的很重要的组成部分。在本播放器系统中,播放控制主要集中在对播放器的控制界面上的操作。首先说明的是,媒体播放器的播放控制的类型,如表2所示表2播放控制模块组成控件功能播放按钮从媒体文件打开播放或从暂停状态继续播放暂停暂停当前MP3文件的播放停止停止播放当前MP3音乐文件上一首播放列表中当前MP3文件的上一首MP3文件下一首播放列表中当前MP3文件的下一首MP3文件打开选择一首MP3文件在本播放器中,总共有三种状态,即播放状态、暂停状态和停止状态,通过表中所列的各种播放控制类型可以实现这三种状态之间的转换,其具体转换如图5〔见附录1〕所示。下面将根据上图的各种转换关系,详细介绍各种播放控制类型的设计与实现播放:播放功能是媒体播放器所有控制功能中最重要的一个功能,没有了它,播放器不能播放,也就不能称之为播放器了。在本播放器系统中,当点击播放会有三种状态转换:第一种是从播放状态仍然转换到播放状态;第二种是从停止状态转换到播放状态;第三种是从暂停状态转换到播放状态。下面具体介绍播放功能是怎样设计的,其具体流程如图6〔见附录1〕所示。当播放器接收到播放命令后,会依次执行下面的过程:<1>检查播放器的当前状态是否是暂停状态。如果是暂停状态,那么继续播放,如果不是暂停状态,则执行第2步;<2>检查播放列表中是否有媒体文件,如果没有则调用添加歌曲过程进行添加,然后再次执行本过程进行播放;如果播放列表中有文件则执行第3步;<3>检查播放列表索引,判断是否选中了播放列表的一首MP3来进行播放,如果没有选择,则选择播放列表中的第一首后执行第4步,如果已经选择了要播放的MP3则直接执行第4步〔4>判断要播放的MP3在播放列表中的位置,如果是第一首则将上一首按钮置为无效,否则置为有效;如果是最后一首,则将下一首按钮置为无效,否则置为有效。暂停:当用户播放一个媒体文件到某一个特定的点时,由于某些原因需要暂停当前媒体文件的播放,这就要求设计的媒体播放器具有暂停播放的功能。既然是暂停播放,那么它前面的状态就必然是播放状态,即暂停状态只能由播放状态转换而来。而这个状态转换的条件,就是在系统播放时用户点击暂停按钮,暂停功能的流程如图7〔见附录1〕所示。停止播放:停止当前MP3文件的播放有三种方式,第一种是当播放器播放到当前文件的最后,系统会自动停止播放;第二种是用户可以点击停止播放按钮来停止当前媒体文件的播放。进入停止状态的初始状态也有两种:第一种是播放状态;第二种是暂停状态,当播放器转换为停止状态后,暂停功能和停止功能都变为无效功能,不能使用,直到转换到播放状态。停止功能的设计流程如图8〔见附录1〕所示。当播放器接收到停止命令后,会执行以下过程:<1>设置各按钮状态,播放为有效,暂停和停止置为无效;<2>检查停止命令是用户手动停止,还是播放器播放完一首MP3后自动转换到停止状态。如果是手动停止则使播放控件停止播放,计时器停止计时,并将当前播放进度置0;如果是自然停止这执行第3步;<3>检查播放模式是否是单曲播放模式,如果是则结束停止过程,否则执行第4步;<4>如果播放模式是循环播放且播放结束的是播放列表中的最后一首,这将播放列表的索引置0,否则直接播放下一首。上一首:上一首是针对播放列表所定义的操作。它是指用户对播放器系统发送的命令〔播放上一首〕,然后由播放器系统做出播放上一首的反应。因为在本播放器系统中,如果当前播放的MP3文件是播放列表中的第一首时,上一首功能设置为无效状态,所以在系统发送播放上一首命令时,不需要检查当前播放的文件是否是播放列表中的第一文件,而可以执行播放上一首的操作。上一首的具体流程如图9〔见附录1〕所示。下一首:同样,播放下一首也是针对播放列表所定义的操作。它是指用户对播放器系统发送播放下一首的命令,然后由播放器系统做出播放下一首的反应。同样,在本播放器系统中,如果当前播放的文件是播放列表中最后一个文件,那么播放下一首功能会设置为无效状态,所以系统在响应播放下一首命令时,无需检查当前播放文件是否是播放列表的最后一个文件。它的具体操作过程是:当用户发送了播放下一首的命令后,系统就会停止当前正在播放的文件,然后去播放当前播放文件的后面一个文件。下一首功能的流程可参照图9。打开文件并播放:打开文件并播放是用户通过点击打开按钮向系统发送的命令。当系统接收到该命令时,先会弹出一个打开文件对话框,然后由用户选择所要打开的MP3文件,把这个文件添加到播放列表,然后使用播放功能播放该文件。具体的操作流程如图10〔见附录1〕所示。向列表中添加单首MP3文件:向播放列表中添加媒体文件,都是在系统的播放列表窗口界面上进行操作的,以添加单首MP3文件。具体的添加过程是:当系统获取了一个添加媒体文件的命令时,会弹出一个文件对话框,等待用户选择媒体文件,这时,用户可以选择一个MP3文件。当用户点击文件对话框上的打开按钮以后,用户所选择的MP3文件就会被添加到播放列表中供用户查看和控制。删除列表中的一首MP3文件:对播放列表有添加功能当然也必然存在删除操作。在对播放列表中的MP3文件进行删除操作时,前提是播放列表中必须有一首MP3文件被选中,否则将不会有任何事件发生。其具体操作是:当用户想要删除一个MP3文件时,首先用鼠标选择该文件,然后右击音乐曲目点击删除就可以了,剩下的工作由系统完成。其中,系统所做的工作是:记录当前用户所删除的文件在列表中的索引,然后根据这个索引值删除掉播放列表中的该索引项,然后系统会自动将该项后面的项向前移动一位。3.4.6主要程序文件〔代码见附录〕1〕头文件<为类加入相应的标准流,库>lrcwindow.hmusiclist.hwidget.h2〕源文件〔完成各种类的定义与实现〕main.cpplrcwindows.cppmusiclist.cppwidget.cpp第四章调试分析QTcreator在使用的过程中也出现了很多问题,首先是版本的问题,一开始编写调试程序的时候应当选择在WINDOWS下能够直接运行的QTSDK,下一步就是在虚拟机下QTcreator的安装这里要注意的问题就是QT编译环境的建立。其次就是QTcreator的库依赖问题,在创建工程的时候可以用GUI选择你需要依赖的Qt模块,这样你可以仅仅通过包含头文件名即可正确包含头文件,但是没有选择的话,你需要包含相对目录。我此次的任务是多媒体播放器的设计,而播放器需要用到QTphonon。Qt从4.4版本开始提供的一套多媒体框架,提供多媒体回放的功能。目前在Qt4.6中实现多媒体播放图形界面主要依赖于phonon框架,它能实现底层的多媒体播放功能,在一般情况下上层的接口phonon模块更适合实现这些功能。phonon最初是一个源于KDE的项目为使用音频和视频的应用程序开发提供的一个框架。应用程序不用去管多媒体播放是通过什么实现的,如gstreamer、xine,只需调用相应的接口就行,但这中间需要一个中转,被称为backend。Qt也是通过phonon来实现夸平台的多媒体播放。最终通过编译后可看到如附录2的界面,可以通过按钮实现播放器的简单功能。第五章设计总结本次设计在Linux操作系统下,Qt作为嵌入式系统图形用户界面GUI,通过虚拟机的RedHatEnterpriseLinux5系统进行模拟,基本完成了基于QT的多媒体播放器的实现。在嵌入式系统基础上,主要分析了Linux操作系统的的特点和优势,通过Linux系统下的QT编译环境的学习,了解了音频解码模块,简单应用的QTcreator下的phonon构架设计了音乐播放器。不过本次设计过程中,由于时间因素的限制,对于QT库的研究还不够彻底,基于QT的播放器的设计与实现是需要依赖phonon框架的,我从网上下载的所有的版本都缺乏phonon库,使得在最终结果的实现有了很大的阻碍。此外,在虚拟机下运行的QT也遇到了版本的问题,这些问题都将在以后的学习过程中加以解决。主要参考文献:1、邢吉生等.嵌入式系统设计与应用,:大学,20xx2、王勇编著.《嵌入式系统原理与设计》.XX:XX大学,20xx3、<美>ChristopherHallinan著,华XX见嵌入式培训中心译《嵌入式Linux基础教程》,人民邮电,20xx4、俞辉主编,嵌入式Linux程序设计案例与实验教材,机械工业,20xx5、韦东山主编,嵌入式Linux应用开发完全手册,人民邮电,20xx版6、俞建新等编,嵌入式应用程序开发综合实验9例,清华大学,20xx7、〔英〕萨默菲尔德著,白建平等译,Qt高级编程,电子工业20xx8、X阿奇,《Qt4开发实践》,电子工业。20xx附录<流程图、源代码>:附录1相关流程图图5播放的三种状态图6播放功能流程图图7暂停功能的流程图8停止功能流程图9上一首功能流程图10打开功能操作流程附录2系统运行效果本播放器系统一共有3个界面窗口,分别是播放器的主控制窗口、播放列表窗口和歌词显示窗口。在此,将详细介绍这些窗口在不同状态下的图示,尤其是播放器的主要播放控制窗口。播放器运行时的整体效果如图11所示:图11播放器整体运行时效果1.播放状态时播放器主控制窗口界面此时播放器的主控制窗口界面如图12所示。图12播放状态2.暂停状态时播放器的主控制窗口界面此时播放器的主控制窗口界面如图13所示图13暂停状态3.停止状态时播放的主控制窗口界面此时播放器的主控制窗口界面如图14所示图14停止状态播放器的列表窗口界面也是由两部分组成的,第一部分是播放列表项目;第二部分是MP3媒体文件显示列表。其界面窗口如图15所示。图15播放器的播放列表窗口界面效果附录3程序源代码lrcwindow.h:#ifndefLRCWINDOW_H#defineLRCWINDOW_H#include<QLabel>#include<QTimer>classlrcWindow:publicQLabel{Q_OBJECTpublic:lrcWindow<QWidget*parent>;QAction*exit;voidsetTime<intnum>{time=num;}voidsetLrcWidth<>;QTimer*timer;private:QPointdragPosition;inttime;qreallength;qreallrcWidth;protected:voidmousePressEvent<QMouseEvent*>;voidmouseMoveEvent<QMouseEvent*>;voidcontextMenuEvent<QContextMenuEvent*ev>;voidpaintEvent<QPaintEvent*>;privateslots:voidtimeout<>;};#endif//LRCWINDOW_Hmusiclist.h:#ifndefMUSICLIST_H#defineMUSICLIST_H#include<QWidget>namespaceUi{classmusicList;}classmusicList:publicQWidget{Q_OBJECTpublic:musicList<QWidget*parent=0>;~musicList<>;Ui::musicList*ui;voidlistReadSettings<>;voidlistWriteSettings<>;protected:voidchangeEvent<QEvent*e>;voidcloseEvent<QCloseEvent*>;voidmoveEvent<QMoveEvent*>;signals:voidlistClose<>;private:};#endif//MUSICLIST_Hwidget.h:#ifndefWIDGET_H#defineWIDGET_H#include<QWidget>#include<phonon>#include"lrcwindow.h"#include"musiclist.h"#include<QTimer>#include<QSystemTrayIcon>#include<QMenu>#include<QTextEdit>classQLabel;namespaceUi{classWidget;}classWidget:publicQWidget{Q_OBJECTpublic:Widget<QWidget*parent=0>;~Widget<>;voidcreatActions<>;voidsetCurrentLrc<>;protected:voidchangeEvent<QEvent*e>;voidwheelEvent<QWheelEvent*>;booleventFilter<QObject*,QEvent*>;voidcontextMenuEvent<QContextMenuEvent*>;voiddragEnterEvent<QDragEnterEvent*>;voiddropEvent<QDropEvent*>;voidcloseEvent<QCloseEvent*>;voidmoveEvent<QMoveEvent*>;voidmouseDoubleClickEvent<QMouseEvent*>;private:Ui::Widget*ui;musicList*mList;Phonon::MediaObject*audio;Phonon::MediaObject*musicInformationMediaObject;Phonon::VideoWidget*videoWidget;Phonon::AudioOutput*audioOutput;Phonon::SeekSlider*seekSlider;Phonon::VolumeSlider*volumeSlider;QList<Phonon::MediaSource>musicSourceList;QWidget*lrcWidget;QLabel*lrcLabel;lrcWindow*lrc;lrcWindow*lrc2;QTimer*timer;QIcon*iconplay;QIcon*iconpause;QAction*play;QAction*stop;QAction*open;QAction*sound;QAction*exit;QAction*remove;QSystemTrayIcon*trayicon;QMenu*trayiconMenu;voidreadSettings<>;voidwriteSettings<>;QTextEdit*text;boolisTouched;privateslots:voidon_toolButton_List_clicked<boolchecked>;voidtableWidget_cellDoubleClicked<introw,intcolumn>;voidon_toolButton_lrcD_clicked<boolchecked>;voidon_toolButton_next_clicked<>;voidon_toolButton_stop_clicked<>;voidon_toolButton_playpause_clicked<>;voidon_toolButton_previous_clicked<>;voidon_toolButton_open_clicked<>;voidshowTime<qint64>;voidTimeout<>;voidmusicInformationStateChanged<Phonon::State,Phonon::State>;voidmediaObjectStateChanged<Phonon::State,Phonon::State>;voidmusicAboutToFinish<>;voidcurrentMusicSourceChanged<Phonon::MediaSource>;voidremoveSlot<>;voidexitSlot<>;voidiconActivated<QSystemTrayIcon::ActivationReasonreason>;signals:voidmySignal<>;};#endif//WIDGET_Hmain.cpp:#include<QtGui/QApplication>#include"widget.h"#include<QTextCodec>intmain<intargc,char*argv[]>{QApplicationa<argc,argv>;QTextCodec::setCodecForTr<QTextCodec::codecForLocale<>>;Widgetw;w.show<>;returna.exec<>;}lrcwindow.cpp:#include"lrcwindow.h"#include<QMouseEvent>#include<QMenu>#include<QTimer>#include<QDebug>#include<QPainter>lrcWindow::lrcWindow<QWidget*parent>:QLabel<parent>{this->setWindowFlags<Qt::SubWindow|Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint>;this->resize<1024,60>;this->setText<tr<"Music...">>;this->setAttribute<Qt::WA_TranslucentBackground>;//背景透明this->setCursor<Qt::OpenHandCursor>;exit=newQAction<tr<"隐藏<&D>">,this>;connect<exit,SIGNAL<triggered<>>,this,SLOT<close<>>>;timer=newQTimer<this>;connect<timer,SIGNAL<timeout<>>,this,SLOT<timeout<>>>;this->move<400,700>;lrcWidth=0;}voidlrcWindow::mousePressEvent<QMouseEvent*event>{if<event->button<>==Qt::LeftButton>{dragPosition=event->globalPos<>-frameGeometry<>.topLeft<>;event->accept<>;}elseif<event->button<>==Qt::MidButton>//点击鼠标滚轮close<>;QLabel::mousePressEvent<event>;}voidlrcWindow::mouseMoveEvent<QMouseEvent*e>{if<e->buttons<>&Qt::LeftButton>{move<e->globalPos<>-dragPosition>;e->accept<>;}QLabel::mouseMoveEvent<e>;}voidlrcWindow::contextMenuEvent<QContextMenuEvent*ev>{QMenumenu;menu.addAction<exit>;menu.exec<ev->globalPos<>>;QLabel::contextMenuEvent<ev>;}voidlrcWindow::paintEvent<QPaintEvent*>{QPainterpainter<this>;//painter.setRenderHints<QPainter::Antialiasing|QPainter::TextAntialiasing>;//使用该行代码可以实现反锯齿,使歌词显示更漂亮,但是会明显增加CPU占用率QFontfont<tr<"TimesNewRoman">,30,QFont::Bold>;painter.setFont<font>;QLinearGradientlg<0,20,0,50>;lg.setColorAt<0,QColor<0,170,255,255>>;lg.setColorAt<0.2,QColor<61,214,191,250>>;lg.setColorAt<0.5,QColor<85,255,255,255>>;lg.setColorAt<0.8,QColor<61,214,191,250>>;lg.setColorAt<1,QColor<0,170,255,255>>;painter.setBrush<lg>;painter.setPen<Qt::NoPen>;QPainterPathtextPath;textPath.addText<0,50,font,text<>>;painter.drawPath<textPath>;length=textPath.currentPosition<>.x<>;painter.setPen<Qt::yellow>;painter.drawText<0,14,lrcWidth,50,Qt::AlignLeft,text<>>;}voidlrcWindow::timeout<>{lrcWidth+=length/85;update<>;}voidlrcWindow::setLrcWidth<>{lrcWidth=0;}musiclist.cpp:#include"musiclist.h"#include"ui_musiclist.h"#include<QSettings>#include<QCloseEvent>musicList::musicList<QWidget*parent>:QWidget<parent>,ui<newUi::musicList>{ui->setupUi<this>;listReadSettings<>;ui->tableWidget->setAcceptDrops<true>;this->setWindowFlags<Qt::Tool>;}musicList::~musicList<>{deleteui;}voidmusicList::changeEvent<QEvent*e>{QWidget::changeEvent<e>;switch<e->type<>>{caseQEvent::LanguageChange:ui->retranslateUi<this>;break;default:break;}}voidmusicList::closeEvent<QCloseEvent*e>{emitlistClose<>;listWriteSettings<>;e->accept<>;}voidmusicList::listReadSettings<>//读取播放列表的位置,大小信息{QSettingssettings<"yafeilinux","PhononLIST">;QPointpos=settings.value<"pos",QPoint<this->x<>,this->y<>+150>>.toPoint<>;QSizesize=settings.value<"size",QSize<300,320>>.toSize<>;move<pos>;resize<size>;}voidmusicList::listWriteSettings<>//记录播放列表的位置,大小信息{QSettingssettings<"yafeilinux","PhononLIST">;settings.setValue<"pos",pos<>>;settings.setValue<"size",size<>>;}voidmusicList::moveEvent<QMoveEvent*e>{if<qAbs<<this->y<>-this->parentWidget<>->y<>-this->parentWidget<>->frameGeometry<>.height<>>><20>{this->move<this->x<>,this->parentWidget<>->y<>+this->parentWidget<>->frameGeometry<>.height<>>;}if<qAbs<this->x<>+this->frameGeometry<>.width<>-this->parentWidget<>->x<>><20>{this->move<this->parentWidget<>->x<>-this->frameGeometry<>.width<>,this->y<>>;}if<qAbs<this->x<>-this->parentWidget<>->frameGeometry<>.width<>-this->parentWidget<>->x<>><20>{this->move<this->parentWidget<>->x<>+this->parentWidget<>->frameGeometry<>.width<>,this->y<>>;}QWidget::moveEvent<e>;}widget.cpp:#include"widget.h"#include"ui_widget.h"#include"lrcwindow.h"#include"musiclist.h"#include"ui_musiclist.h"#include<QtGlobal>#include<QtGui>Widget::Widget<QWidget*parent>:QWidget<parent>,ui<newUi::Widget>{ui->setupUi<this>;mList=newmusicList<this>;mList->setFixedSize<300,320>;//固定播放列表的大小mList->ui->tableWidget->setColumnWidth<0,150>;mList->ui->tableWidget->setColumnWidth<1,150>;connect<mList->ui->tableWidget,SIGNAL<cellDoubleClicked<int,int>>,SLOT<tableWidget_cellDoubleClicked<int,int>>>;//mList->show<>;connect<mList,SIGNAL<listClose<>>,ui->toolButton_List,SLOT<toggle<>>>;text=newQTextEdit<this>;text->hide<>;//用于查找下句歌词以计算时间间隔ui->textEdit->setVisible<false>;//文本编辑框不可见,〔解析歌词〕this->setAcceptDrops<true>;this->setFixedSize<300,150>;this->setWindowTitle<tr<"音乐播放器">>;readSettings<>;//读取上次关闭窗口时窗口的位置QPalettepalette=ui->label_lrc->palette<>;//设置窗体内歌词颜色palette.setColor<QPalette::WindowText,Qt::darkBlue>;ui->label_lrc->setPalette<palette>;lrc=newlrcWindow<0>;//桌面歌词//lrc->show<>;/**初始化媒体**/audio=newPhonon::MediaObject<>;//媒体对象audio->setTickInterval<1>;audioOutput=newPhonon::AudioOutput<Phonon::VideoCategory>;//音频输出Phonon::createPath<audio,audioOutput>;//连接媒体对象与音频输出musicInformationMediaObject=newPhonon::MediaObject<this>;//音乐信息对象volumeSlider=newPhonon::VolumeSlider<audioOutput,this>;//音量滑动条volumeSlider->move<190,80>;volumeSlider->resize<50,20>;volumeSlider->setStyleSheet<"background-color:rgb<255,255,255,100>">;volumeSlider->setFixedWidth<100>;//固定音量条大小seekSlider=newPhonon::SeekSlider<audio,this>;//进度滑动条seekSlider->move<10,35>;seekSlider->resize<170,20>;seekSlider->setStyleSheet<"background-color:rgb<255,255,255,100>">;connect<audio,SIGNAL<tick<qint64>>,this,SLOT<showTime<qint64>>>;//时间显示与歌词的更新connect<audio,SIGNAL<stateChanged<Phonon::State,Phonon::State>>,this,SLOT<mediaObjectStateChanged<Phonon::State,Phonon::State>>>;connect<musicInformationMediaObject,SIGNAL<stateChanged<Phonon::State,Phonon::State>>,this,SLOT<musicInformationStateChanged<Phonon::State,Phonon::State>>>;//当加入新音乐时执行connect<audio,SIGNAL<aboutToFinish<>>,this,SLOT<musicAboutToFinish<>>>;connect<audio,SIGNAL<currentSourceChanged<Phonon::MediaSource>>,this,SLOT<currentMusicSourceChanged<Phonon::MediaSource>>>;connect<lrc->exit,SIGNAL<triggered<bool>>,ui->toolButton_lrcD,SLOT<setChecked<bool>>>;timer=newQTimer<this>;//定时器,若0.1秒不显示歌词,则显示"Music..."timer->start<100>;connect<timer,SIGNAL<timeout<>>,SLOT<Timeout<>>>;creatActions<>;mList->installEventFilter<this>;mList->ui->tableWidget->installEventFilter<this>;//事件过滤器connect<audioOutput,SIGNAL<mutedChanged<bool>>,sound,SLOT<setChecked<bool>>>;connect<this,SIGNAL<mySignal<>>,this,SLOT<close<>>,Qt::QueuedConnection>;}voidWidget::changeEvent<QEvent*e>{QWidget::changeEvent<e>;switch<e->type<>>{caseQEvent::LanguageChange:ui->retranslateUi<this>;break;caseQEvent::WindowStateChange:if<isMinimized<>>{emitmySignal<>;e->ignore<>;}default:break;}}voidWidget::mouseDoubleClickEvent<QMouseEvent*e>{QPointtemp=e->pos<>;constintpos_min_x=this->pos<>.x<>;constintpos_max_x=pos_min_x+this->width<>;constintpos_min_y=this->pos<>.y<>;constintpos_max_y=pos_min_y+this->height<>;if<temp.x<>>pos_min_x&&temp.x<><pos_max_x&&temp.y<>>pos_min_y&&temp.y<><pos_max_y>{//只对标题栏X围内的鼠标事件进行处理this->close<>;}}voidWidget::moveEvent<QMoveEvent*e>{if<isTouched>{QPointp=e->pos<>-e->oldPos<>;mList->move<mList->pos<>+p>;}else{isTouched=false;if<qAbs<mList->y<>-this->y<>-this->frameGeometry<>.height<>><20>{isTouched=true;this->move<this->x<>,mList->y<>+this->frameGeometry<>.height<>>;}if<qAbs<this->x<>-mList->x<>-mList->frameGeometry<>.width<>><20>{isTouched=true;this->move<mList->x<>+mList->frameGeometry<>.width<>,this->y<>>;}if<qAbs<this->x<>+this->frameGeometry<>.width<>-mList->x<>><20>{isTouched=true;this->move<mList->x<>-this->frameGeometry<>.width<>,this->y<>>;}}QWidget::moveEvent<e>;}voidWidget::readSettings<>//读取主窗口的位置信息{QSettingssettings<"yafeilinux","PhononExample">;QPointpos=settings.value<"pos",QPoint<400,200>>.toPoint<>;//QSizesize=settings.value<"size",QSize<298,412>>.toSize<>;move<pos>;//resize<size>;}voidWidget::writeSettings<>//记录主窗口的位置信息{QSettingssettings<"yafeilinux","PhononExample">;settings.setValue<"pos",pos<>>;//settings.setValue<"size",size<>>;}voidWidget::closeEvent<QCloseEvent*e>//关闭事件{writeSettings<>;mList->listWriteSettings<>;if<this->isVisible<>>{this->hide<>;mList->hide<>;trayicon->showMessage<tr<"音乐播放器">,tr<"最小化到系统托盘,要关闭请右击此图标选择"退出"。">,QSystemTrayIcon::Information,15000>;e->ignore<>;}}boolWidget::eventFilter<QObject*object,QEvent*event>{qDebug<><<object;if<object==mList->ui->tableWidget>//过滤表格的事件{qDebug<><<"event"<<event;if<event->type<>==QEvent::ContextMenu>{QContextMenuEvent*contextevent=static_cast<QContextMenuEvent*><event>;QMenumenu<this>;menu.addAction<remove>;menu.exec<contextevent->globalPos<>>;returntrue;}elseif<event->type<>==QEvent::DragEnter>{QDragEnterEvent*dragEnterevent=static_cast<QDragEnterEvent*><event>;if<dragEnterevent->mimeData<>->hasFormat<"text/uri-list">>dragEnterevent->acceptProposedAction<>;returntrue;}elseif<event->type<>==QEvent::Drop>{QDropEvent*dropevent=static_cast<QDropEvent*><event>;dropEvent<dropevent>;returntrue;}elsereturnfalse;}returnQWidget::eventFilter<object,event>;}voidWidget::removeSlot<>//清空列表{audio->stop<>;intj=mList->ui->tableWidget->rowCount<>;for<inti=0;i<j;i++>{mList->ui->tableWidget->removeRow<0>;}mList->ui->tableWidget->close<>;mList->ui->tableWidget->show<>;audio->clear<>;musicSourceList.clear<>;}voidWidget::wheelEvent<QWheelEvent*wheelevent>//滚轮事件{if<wheelevent->delta<>>0>//上滚{qrealnewvolume=audioOutput->volume<>+<qreal>0.05;if<newvolume>=<qreal>1>newvolume=<qreal>1;audioOutput->setVolume<newvolume>;}else//下滚{qrealnewvolume=audioOutput->volume<>-<qreal>0.05;if<newvolume<=<qreal>0>newvolume=<qreal>0;audioOutput->setVolume<newvolume>;}}voidWidget::contextMenuEvent<QContextMenuEvent*e>{QMenumenu<this>;menu.addAction<play>;menu.addAction<stop>;menu.addAction<open>;menu.addSeparator<>;menu.addAction<sound>;menu.addSeparator<>;menu.addAction<exit>;menu.exec<e->globalPos<>>;}voidWidget::setCurrentLrc<>//设置当前歌词显示{QStringfileName=audio->currentSource<>.fileName<>;QStringlrcName=fileName.remove<fileName.right<3>>+"lrc";QFilefile<lrcName>;if<!file.open<QFile::ReadOnly|QFile::Text>>{ui->label_lrc->setText<tr<"当前目录下未找到歌词文件">>;lrc->setText<tr<"当前目录下未找到歌词文件">>;}QTextStreamin<&file>;ui->textEdit->setText<in.readAll<>>;}voidWidget::Timeout<>//若0.1秒不显示歌词,则显示"Music..."{if<lrc->text<>.isEmpty<>>{lrc->setText<tr<"yafeilinux">>;ui->label_lrc->setText<tr<"yafeilinux">>;}}voidWidget::showTime<qint64time>//时间与歌词的更新显示{qint64temp=audio->totalTime<>;QTimetotalTime<0,<temp/60000>%60,<temp/1000>%60,time%1000>;QTimecurTime<0,<time/60000>%60,<time/1000>%60,time%1000>;ui->label_time->setText<tr<"%1/%2">.arg<curTime.toString<"mm:ss">>.arg<totalTime.toString<"mm:ss">>>;ui->label_time->update<>;/**歌词的更新显示**/if<ui->textEdit->find<curTime.toString<"mm:ss.zzz">.left<7>>>//向后找{QStringstr=ui->textEdit->textCursor<>.block<>.text<>.replace<QRegExp<"\\[\\d{2}:\\d{2}\\.\\d{2}\\]">,"">;ui->label_lrc->setText<str>;lrc->setText<str>;lrc->setLrcWidth<>;//设置用于遮罩label的宽度为0//lrc->show<>;////////////////////////////////////////////////QTimett=curTime;intb=1;intc=0;text->setText<ui->textEdit->document<>->toPlainText<>>;boolover=ui->textEdit->textCursor<>.block<>.next<>.text<>.isEmpty<>;while<!over&&!text->find<tt.addMSecs<b*100>.toString<"mm:ss.zzz">.left<7>>>{b++;c++;}while<over&&!text->find<tt.addMSecs<b*100>.toString<"mm:ss.zzz">.left<7>,QTextDocument::FindBackward>>{b++;c++;break;}lrc->timer->start<c>;}//找不到后向前找elseif<ui->textEdit->find<curTime.toString<"mm:ss.zzz">.left<7>,QTextDocument::FindBackward>>{QStringstr=ui->textEdit->textCursor<>.block<>.text<>.replace<QRegExp<"\\[\\d{2}:\\d{2}\\.\\d{2}\\]">,"">;ui->label_lrc->setText<str>;lrc->setText<str>;lrc->setLrcWidth<>;//设置用于遮罩label的宽度为0//lrc->show<>;////////////////////////////////////////////////QTimett=curTime;intb=1;intc=0;text->setText<ui->textEdit->document<>->toPlainText<>>;boolover=ui->textEdit->textCursor<>.block<>.next<>.text<>.isEmpty<>;while<!over&&!text->find<tt.addMSecs<b*100>.toString<"mm:ss.zzz">.left<7>>>{b++;c++;}while<over&&!text->find<tt.addMSecs<b*100>.toString<"mm:ss.zzz">.left<7>,QTextDocument::FindBackward>>{b++;c++;break;}lrc->timer->start<c>;}}Widget::~Widget<>{deleteui;}voidWidget::creatActions<>{QIconiconremove<":/images/remove.png">;QIconiconstop<":/images/gtk-media-stop.png">;QIconiconopen<":/images/gtk-open.png">;QIconiconsound<":/images/sound.png">;QIconiconexit<":/images/exit.png">;iconpause=newQIcon<":/images/gtk-media-pause.png">;iconplay=newQIcon<":/images/gtk-media-play-ltr.png">;remove=newQAction<iconremove,tr<"清空播放列表">,this>;connect<remove,SIGNAL<triggered<>>,this,SLOT<removeSlot<>>>;play=newQAction<*iconplay,tr<"播放">,this>;connect<play,SIGNAL<triggered<>>,this,SLOT<on_toolButton_playpause_clicked<>>>;stop=newQAction<iconstop,tr<"停止">,this>;connect<stop,SIGNAL<triggered<>>,audio,SLOT<stop<>>>;open=newQAction<iconopen,tr<"打开文件">,this>;connect<open,SIGNAL<triggered<>>,this,SLOT<on_toolButton_open_clicked<>>>;sound=newQAction<iconsound,tr<"静音">,this>;sound->setCheckable<true>;connect<sound,SIGNAL<triggered<bool>>,audioOutput,SLOT<setMuted<bool>>>;exit=newQAction<iconexit,tr<"退出">,this>;connect<exit,SIGNAL<triggered<>>,this,SLOT<exitSlot<>>>;/***系统托盘****/trayicon=newQSystemTrayIcon<this>;QIconico<":/images/VMP2.png">;trayiconMenu=newQMenu<this>;trayiconMenu->addAction<play>;trayiconMenu->addAction<stop>;trayiconMenu->addAction<open>;trayiconMenu->addSeparator<>;trayiconMenu->addAction<exit>

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论