当前位置:   article > 正文

python之Gooey图形界面使用_gooey教程

gooey教程

楔子、前言

最近一个项目需要用到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
  • 1

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

三、遇到的问题

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

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

2.与用户交互

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

3.程序出错

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

四、代码如下

我的代码如下:

# WindowUi.py
import time

from 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, GlobalMusicName
    if args.command == "搜索":
        inputSearchKeywords = args.SearchKeyWords
        if 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.GotMusicId
            if tmp != "":
                GlobalMusicId = int(tmp)

            songUrl, songType = CloudMusicDownloaderAndPlayer.getMusicUrl(GlobalMusicId)
            GlobalMusicName = CloudMusicDownloaderAndPlayer.getMusicName(GlobalMusicId)
            songFileName = CloudMusicDownloaderAndPlayer.downloadMusic(GlobalMusicName, songUrl, songType)
            print("歌曲下载成功,地址为:", songFileName)
        except:
            print("歌曲下载错误,请检查您的输入是否正确!")
            pass
    elif args.command == "播放":
        print("请选择你想要播放的歌曲")
        time.sleep(1)
        CloudMusicDownloaderAndPlayer.playMusic()
    else:
        print("非常感谢您的使用,期待您的下次使用。再见!")
        time.sleep(1)
        return
    # print(args, flush=True)  # 坑点:flush=True在打包的时候会用到


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

另一个文件内容为:

"""
打包:pyinstaller -F --icon=icon.ico CloudMusicDownloaderAndPlayer.py
传递参数的时候带着格式,参数格式如下:
name: 前两个字为格式,用来判断搜索的是歌曲还是歌单
"""
import os
import requests
import tkinter
from tkinter import filedialog
import time

baseUrl = "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)
        # 获取的数据,加入list
        songIds.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"]  # 获取搜索到的第一个歌单的id
    return playListId


def 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, singers


def 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 songName


def 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).content
        file.write(musicContent)
    os.system('"' + Filepath + '"')
    return Filepath


def playMusic():
    root = tkinter.Tk()
    root.withdraw()
    # 设置文件的保存路径
    Filepath = filedialog.askopenfilename()  # 获得选择好的文件
    # 使用本机默认播放器播放音频
    os.system('"' + Filepath + '"')


def playerMenu():
    global GlobalMusicId, GlobalMusicName
    while 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:
                    pass
            elif 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:
                pass
        elif 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("歌曲下载错误,请检查您的输入是否正确!")
                pass
        elif inputChoice == "3":
            playMusic()
        else:
            print("非常感谢您的使用,期待您的下次使用。再见!")
            time.sleep(1)
            return


"""
if __name__ == '__main__':
    print(help)
    playerMenu()
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248

五、结束

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/186645
推荐阅读
相关标签
  

闽ICP备14008679号