楔子、前言

最近一个项目需要用到python图形界面的快速开发,还要求在我们可以看到的代码上看不到类和对象的使用痕迹,这里直接先把pyqt排除了,pyqt臃肿且复杂,比较适合大型界面开发,小型界面开发再使用这个东西,学习成本极大(因为无法使用designer工具,这个designer生成的代码是有的)。然后这里考虑使用tkinter或者gooey,这里我先尝试了tkinter,感觉不是特别美观,那就直接再次尝试Gooey这个框架的使用。

开发的是一个python图形界面的网易云音乐下载播放器,播放为直接运行(使用本地默认音乐播放器)。网易云的API集成则是在我的个人服务器上面。

局限性

这个框架是基于另一个框架wxpython的,属于阉割版本,相比于wxpython也许功能会少一些,但是我这里用的正好合适,勉强可以凑活着用。但是虽然组件有点少,但是正好使用其他框架的组件来代替也不是不可以。而且这个Gooey好像没有页面跳转,稍显生硬,目前没发现怎么将执行完程序后的界面进行改动,如果能改动也会更好一些,总之对于这个项目能用就行了。

一、实现功能

开发周期太短,所以做出来的内容也很简单,只预算使用不到3个小时开发出来。

  1. 一个搜索框
  2. 两个搜索按钮(一个歌单、一个单曲)
  3. 一个list控件(放搜索结果)
  4. 一个下载按钮
  5. 一个播放按钮

二、图形界面开发

首先进行一个Gooey库的安装

pip install Gooey

搜索结果直接通过程序执行后出现的界面输出了,省了一点麻烦,但是用户使用的时候又多了一点麻烦,但是没办法,没找到list空间来放搜索结果。
左侧为command选择,相当于菜单项;右侧为具体的选项。

三、遇到的问题

1.界面获取的数据如何使用

界面获得的数据会被存放在一个namespace空间内部,这个人namespace的数据使用方式为args.变量名,直接就能把数据给点出来了。

2.与用户交互

因为这个框架似乎没有实现按钮功能,所以怎么与用户交互呢?因为程序执行时的控制台输出会被转到这个框架内显示出来,所以呈现给用户这个我们的响应还是很简单的,直接print出数据即可。

3.程序出错

如果程序运行出错了的话,程序就会直接结束运行,而不会给用户有提示,这里可以考虑使用python的异常处理其他框架的弹出交互框

四、代码如下

我的代码如下:

# WindowUi.py
import timefrom gooey import Gooey, GooeyParser
import CloudMusicDownloaderAndPlayer@Gooey(richtext_controls=True,  # 打开终端对颜色支持program_name="网易云下载播放器",  # 程序名称encoding="utf-8",  # 设置编码格式,打包的时候遇到问题progress_regex=r"^progress: (\d+)%$"  # 正则,用于模式化运行时进度信息
)
def main():settings_msg = '本程序提供对网易云音乐的歌单、单曲的搜索;单曲的下载与播放。\n使用网易云官方公开的API,API服务部署在我的个人服务器上(将于2022年3月份过期)'parser = GooeyParser(description=settings_msg)  # 添加上方的应用信息subs = parser.add_subparsers(help='commands', dest='command')"""搜索界面"""Searchparser = subs.add_parser('搜索')Searchparser.add_argument("SearchKeyWords", metavar='搜索关键词', default='牵丝戏')verbosity = Searchparser.add_mutually_exclusive_group("搜索类型选择")verbosity.add_argument('-t', '--verbozze', dest='单曲',action="store_true", help="搜索类型:单曲")verbosity.add_argument('-q', '--quiet', dest='歌单',action="store_true", help="搜索类型:歌单")"""获取歌单内单曲界面"""Leftparser = subs.add_parser('歌单详情')Leftparser.add_argument("GotPlayListId", metavar='歌单id', help="请输入上面搜索后获得的歌单id", default='30352891')"""下载播放界面"""Leftparser = subs.add_parser('下载播放')Leftparser.add_argument("GotMusicId", metavar='歌曲id', help="请输入你想下载播放的歌曲id", default='30352891')"""播放界面"""Leftparser = subs.add_parser('播放')"""程序功能实现"""args = parser.parse_args()"""界面获得的数据进行处理"""global GlobalMusicId, GlobalMusicNameif args.command == "搜索":inputSearchKeywords = args.SearchKeyWordsif args.单曲 == True:searchType, searchKeywords = CloudMusicDownloaderAndPlayer.search("单曲:" + inputSearchKeywords)songIds, songNames, singers = CloudMusicDownloaderAndPlayer.getSingleMusicSearchResult(searchType,searchKeywords)else:searchType, searchKeywords = CloudMusicDownloaderAndPlayer.search("歌单:" + inputSearchKeywords)CloudMusicDownloaderAndPlayer.getPlayListSearchResult(searchType, searchKeywords)elif args.command == "歌单详情":songIds, songNames, singers = CloudMusicDownloaderAndPlayer.getMusicsDetail(args.GotPlayListId)for i in range(len(songIds)):print(songIds[i], songNames[i], singers[i])elif args.command == "下载播放":try:tmp = args.GotMusicIdif tmp != "":GlobalMusicId = int(tmp)songUrl, songType = CloudMusicDownloaderAndPlayer.getMusicUrl(GlobalMusicId)GlobalMusicName = CloudMusicDownloaderAndPlayer.getMusicName(GlobalMusicId)songFileName = CloudMusicDownloaderAndPlayer.downloadMusic(GlobalMusicName, songUrl, songType)print("歌曲下载成功,地址为:", songFileName)except:print("歌曲下载错误,请检查您的输入是否正确!")passelif args.command == "播放":print("请选择你想要播放的歌曲")time.sleep(1)CloudMusicDownloaderAndPlayer.playMusic()else:print("非常感谢您的使用,期待您的下次使用。再见!")time.sleep(1)return# print(args, flush=True)  # 坑点:flush=True在打包的时候会用到if __name__ == '__main__':main()

另一个文件内容为:

"""
打包:pyinstaller -F --icon=icon.ico CloudMusicDownloaderAndPlayer.py
传递参数的时候带着格式,参数格式如下:
name: 前两个字为格式,用来判断搜索的是歌曲还是歌单
"""
import os
import requests
import tkinter
from tkinter import filedialog
import timebaseUrl = "http://m4xlmum.top:3000"help = """《小工具使用指南》单曲搜索:1. 搜索单曲(歌单)->搜索单曲->输入你想搜索的歌曲关键词->根据搜索到的歌曲id的输出输入你想下载播放的歌曲->下载(后播放)歌曲->输入你想下载的歌曲的id。歌单搜索:2. 搜索单曲(歌单)->搜索歌单->输入你想搜索的歌单关键词->根据搜索到的歌单id的输出输入你想具体查看的歌单的详细信息(包括歌单内所包含的歌曲额详细信息)>之后的流程就跟单曲的操作相同了。
"""mainMenu = """*******************1. 搜索单曲(歌单)2. 下载(后播放)歌曲3. 播放歌曲0. 退出
*******************
[+]请输入你的选择:"""searchMenu = """*******************1. 搜索单曲2. 搜索歌单3. 返回上级选择
*******************
[+]请输入你的选择:"""# 存放用户经过搜索处理之后选择的歌曲id
GlobalMusicId = 30352891  # 牵丝戏 ['银临', 'Aki阿杰']
GlobalMusicName = "牵丝戏"# P1搜索处理,返回信息为{搜索类型、搜索关键词}
def search(name):"""type: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频, 1018:综合"""searchType = name[:2]searchKeywords = name[3:]typeDict = {"单曲": 1, "歌单": 1000}return typeDict[searchType], searchKeywords# 有songs格式的数据获得`songIds, songNames, singers`这几个数据
def getSongsInfo(songs):songIds, songNames, singers = [], [], []for i in range(len(songs)):song = songs[i]songId = song["id"]songName = song["name"]# 设置歌手名的格式singer = "歌手:"artists = "artists" if "artists" in song.keys() else "ar"for artist in song[artists]:singer = singer + artist["name"] + "、"print(songId, songName, singer)# 获取的数据,加入listsongIds.append(songId)songNames.append(songName)singers.append(singer)return songIds, songNames, singers# P2单曲处理,返回信息包括{歌曲id、歌曲名、歌手}
def getSingleMusicSearchResult(searchType, searchKeywords):searchUrl = baseUrl + "/search""""type:    搜索类型limit:   限制返回个数keywords:搜索关键词"""params = {"type": searchType,"limit": 10,"keywords": searchKeywords}resp = requests.get(url=searchUrl, params=params).json()songs = resp["result"]["songs"]songIds, songNames, singers = getSongsInfo(songs)return songIds, songNames, singers# P2歌单处理,返回值为{歌单包含歌曲id}   注:歌单是为了区别歌曲类型,所以这里搜索歌单只返回一个歌单值,歌单内包含很多歌曲
def getPlayListSearchResult(searchType, searchKeywords):searchUrl = baseUrl + "/search"params = {"type": searchType,"limit": 10,"keywords": searchKeywords}resp = requests.get(url=searchUrl, params=params).json()playLists = resp["result"]["playlists"]playListIds, playListNames, creators, descriptions = [], [], [], []for i in range(len(playLists)):playList = playLists[i]id, name, creator = playList["id"], playList["name"], playList["creator"]["nickname"] if playList["creator"] is not None else "未找到Creator"print("[-] id:{0}\tname:{1}\tcreator:{2}".format(id, name, creator))playListId = playLists[0]["id"]  # 获取搜索到的第一个歌单的idreturn playListIddef getPlayListDetail(playListId):playListDetailUrl = baseUrl + "/playlist/detail"params = {"id": playListId}playListDetail = requests.get(url=playListDetailUrl, params=params).json()  # 获取歌单详情print("该歌单的描述为: " + playListDetail["playlist"]["description"] if playListDetail["playlist"]["description"] is not None else "该歌单无描述" + "\n")playListMusics = playListDetail["playlist"]["trackIds"]  # 获取歌单内的所有音乐id,此时获得的还不是id,只是一个包含id的待处理数据集playListMusicIds = []  # 获取歌单内所有音乐的id# print(len(playListMusics))for i in range(len(playListMusics)):playListMusicIds.append(playListMusics[i]["id"])# print(playListMusicIds)return playListMusicIds# P2扩展,获取歌单内的歌曲信息
def getMusicsDetail(playListId):playListMusicIds = getPlayListDetail(playListId)playListDetailUrl = baseUrl + "/song/detail"params = {"ids": str(playListMusicIds)[1:-1]}resp = requests.get(url=playListDetailUrl, params=params).json()songs = resp["songs"]songIds, songNames, singers = getSongsInfo(songs)return songIds, songNames, singersdef getMusicUrl(songId):musicUrl = baseUrl + "/song/url"params = {"id": songId}resp = requests.get(url=musicUrl, params=params).json()songUrl = resp["data"][0]["url"]songType = resp["data"][0]["type"]return songUrl, songType# 歌曲的命名格式应为"牵丝戏 歌手:银临、Aki阿杰"
def getMusicName(songId):musicUrl = baseUrl + "/song/detail"params = {"ids": songId}resp = requests.get(url=musicUrl, params=params).json()song = resp["songs"][0]songName = song["name"]# 加上歌手名songName += " 歌手:"for i in range(len(song["ar"])):songName = songName + song["ar"][i]["name"] + "、"songName = songName[:-3]return songNamedef downloadMusic(songName, songUrl, songType="mp3"):# 设置文件的保存路径root = tkinter.Tk()root.withdraw()folder = filedialog.askdirectory()songFileName = "{0}.{1}".format(songName, songType)Filepath = r"{0}/{1}".format(folder, songFileName)with open(Filepath, "wb") as file:musicContent = requests.get(url=songUrl).contentfile.write(musicContent)os.system('"' + Filepath + '"')return Filepathdef playMusic():root = tkinter.Tk()root.withdraw()# 设置文件的保存路径Filepath = filedialog.askopenfilename()  # 获得选择好的文件# 使用本机默认播放器播放音频os.system('"' + Filepath + '"')def playerMenu():global GlobalMusicId, GlobalMusicNamewhile True:inputChoice = input(mainMenu)if inputChoice == "1":inputSearchChoice = input(searchMenu)if inputSearchChoice == "1":inputSearchKeywords = input("[+] 请输入您搜索的关键词:")searchType, searchKeywords = search("单曲:" + inputSearchKeywords)songIds, songNames, singers = getSingleMusicSearchResult(searchType, searchKeywords)tmp = input("请输入你想要进行后续播放下载的歌曲id(默认歌曲id为30352891):")try:GlobalMusicId = int(tmp)GlobalMusicName = songNames[songIds.index(GlobalMusicId)] + " " + singers[songIds.index(GlobalMusicId)]except:passelif inputSearchChoice == "2":inputSearchKeywords = input("[+] 请输入您搜索的关键词:")searchType, searchKeywords = search("歌单:" + inputSearchKeywords)songIds, songNames, singers = getMusicsDetail(searchType, searchKeywords)for i in range(len(songIds)):print(songIds[i], songNames[i], singers[i])else:passelif inputChoice == "2":try:tmp = input("请输入要下载的歌曲的id(此处不输入,则默认使用搜索处输入的id):")if tmp != "":GlobalMusicId = int(tmp)songUrl, songType = getMusicUrl(GlobalMusicId)GlobalMusicName = getMusicName(GlobalMusicId)songFileName = downloadMusic(GlobalMusicName, songUrl, songType)print("歌曲下载成功,地址为:", songFileName)except:print("歌曲下载错误,请检查您的输入是否正确!")passelif inputChoice == "3":playMusic()else:print("非常感谢您的使用,期待您的下次使用。再见!")time.sleep(1)return"""
if __name__ == '__main__':print(help)playerMenu()
"""

五、结束

这个软件工程的大作业到这里应该就告一段落了,写的代码还是太少了,但是也确实是工期太短了,而且我没多少时间用在这个东西上面,毕竟还有其他作业,其他项目,其他实验。

总之这300多行已经差不多是我的极限了,也确实是黔驴技穷了。

python之Gooey图形界面使用相关推荐

  1. 210811_152958-Gooey实战 | 几行代码转换Python程序为图形界面应用!

    Gooey实战 | 几行代码转换Python程序为图形界面应用! 1.概述 今天发现公众号的一个作者大大用Python写了个小工具, 发现还挺好玩, 而且代码已经分享给大家了.在文章末尾提到还没有为这 ...

  2. python怎么做图形界面-图形界面

    Python支持多种图形界面的第三方库,包括: Tk wxWidgets Qt GTK 等等. 但是Python自带的库是支持Tk的Tkinter,使用Tkinter,无需安装任何包,就可以直接使用. ...

  3. python写前端图形界面_如何Tkinter模块编写Python图形界面

    一.为何使用Tkinter而非PyQt 众所周知,在Python中创建图形界面程序有很多种的选择,其中PyQt和wxPython都是很热门的模块包,这些第三方的图形界面模块功能强大.配置丰富,界面美观 ...

  4. 【PySimpleGUI】Python用户交互图形界面开发(3)

    目录 前言 一.通过列表索引获取窗口返回值 二.通过字典的键获取返回值 前言 上一篇文章介绍了窗口关闭,按钮点击以及其他元素事件.[PySimpleGUI]Python用户交互图形界面开发(2) 这篇 ...

  5. 绝了,Gooey:一行代码将 Python 程序转换为图形界面应用

    大家好,今天给大家分享一款非常棒的工具:Gooey,它支持用一行代码将任何Python 2或3控制台程序转换为GUI应用程序. 效果如图所示,下面我来教大家如何使用 交流 本文工具包来自技术群小伙伴分 ...

  6. 一行代码将Python程序转换为图形界面应用

    击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 泠泠七弦上,静听松风寒. Gooey ...

  7. 神奇!一行代码将Python程序转换为图形界面应用

    Gooey项目支持用一行代码将(几乎)任何Python 2或3控制台程序转换为GUI应用程序. 1.快速开始 请选择以下任一种方式输入命令安装依赖: 1. Windows 环境 打开 Cmd (开始- ...

  8. 【你不知道的骚操作】一行代码将Python程序转换为图形界面应用

    AI派在读学生小姐姐Beyonce Java实战项目练习群 长按识别下方二维码,按需求添加 扫码添加Beyonce小姐姐 扫码关注 进Java学习大礼包 Gooey项目支持用一行代码将(几乎)任何Py ...

  9. 牛逼了!仅需一行代码将Python程序转换为图形界面应用

    Gooey项目支持用一行代码将(几乎)任何Python 2或3控制台程序转换为GUI应用程序. 请选择以下任一种方式输入命令安装依赖: 1. Windows 环境 打开 Cmd (开始-运行-CMD) ...

最新文章

  1. C# MemoryStream先写后读的奇怪现象
  2. 腾讯抗黑灰产——自监督发现行话黑词识别一词多义
  3. 程序员如何写好一份简历去找工作?
  4. 院士倪光南:Win10不安全 中国必须用自主操作系统
  5. GetSystemInfo()
  6. 丘成桐:用10年时间培养一批本土一流基础科学人才
  7. 基于JAVA+SpringMVC+Mybatis+MYSQL的论坛管理系统
  8. ubuntu下如何切换到root用户 --- 终端命令行方式
  9. LeetCode 简单等级
  10. 【Prison Break】第六天(4.2)
  11. 人工智能时代的风口项目,电话机器人源码和系统部署
  12. 银河麒麟桌面操作系统sp1 2203双硬盘ghost备份及手动分区还原
  13. 2011-2017年中国各地政府BIM相关标准政策汇总
  14. ie浏览器java 脚本下载_如何设置ie浏览器中的activeX控件和插件java脚本下载?
  15. Pick定理 有趣的证明
  16. 个人经典音乐收藏(五)love to be loved by you,Marc Terenzi
  17. CKPlayer视频地址加密方法
  18. 搞定 WeakHashMap 的工作原理一篇文章就够了!!!
  19. Android和DLT日志系统
  20. SEO魔法书-网站优化

热门文章

  1. linux怎么用启动u盘恢复系统,一种U盘引导下的linux系统备份还原方法与流程
  2. centos下部署davinci
  3. 工业互联网-工业企业大数据交换通道-数据通道产品描述
  4. 第八届ACM山东省赛 F quadratic equation
  5. 大话系列 | 贝叶斯(上)—下雨天吃什么?
  6. 文献管理工具 | Mendeley使用方法
  7. dropdown多选下拉框
  8. CListCtrl 虚拟列表技术
  9. 什么是API?谈对API的理解
  10. 什么是API接口,具体是什么意思?