Python之点到为止: 关于GUI开发

2020年04月09日 5839点热度 0人点赞 0条评论

DLL有了, API也上了. 是时候来点"画面"了.

其实我是搞后端的, 对于这个GUI一直不感冒, 觉得有功能几个字母敲上去能用就挺好了. 但是多数情况你写的程序是需要给用户使用的, 那么这种情况你不得不去考虑自己写个界面, Python的GUI库也非常多, 本文只将常见并且简单的.

是否需要GUI

如果你的程序需要分发给用户使用, 并且想要用户有一个良好的体验, 那么有一个GUI是个加分项. 但是一个难用的GUI还不如CLI来的舒服. 如果你的程序一般用于服务器, 那GUI就多余了, 就算是你的服务器装了桌面环境(没多少人这么干)也没必要. 如果自己用那就随意了, 看心情了.

相关库

tkinter是Python自带的一个Tcl/Tk的库, 跨平台. Python自带的IDLE就是用tkinter编写的. PySimpleGUI是基于tkinter、Qt、WxPython 和 Rem, 称GUI开发不是困难和痛苦的而是有趣的. wxPython和上面个两个一样都是常见的GUI库. 使用方法与tkinter均类似. PyQT是QT的Python版本, 学过C gui方面应该没有不知道QT的, QT就非常强大了, 只能说没有你想不到没有它做不到了, 但是学习成本高, 文件也大. 所以本期就排除PyQT, 因为QT我也只会个Hello World. ???

如果在Windows其实不用这些库也可以创建GUI, 不是还有Windows API呢么. Windows中那些库大部分底层都是用Windows API创建的窗口. 只是这些库可以使创建GUI更方便.

实操

简单的界面就不需要安装其他第三方库了, 自带的tkinter就可以解决了. 当然PySimpleGUI号称将GUI开发变得快乐. 一会我们看看到底快不快乐. 而wxPython我没有接触过, https://www.wxpython.org/pages/overview/#hello-world 看例子我觉得和tkinter差不多. 但他有一个窗口设计器wxFormbuilder有兴趣可以了解下.

一个简单的需求, 用户登录. 用户输入账户密码登录, 登录成功弹窗提示或者载入主界面.

tkinter

# Tk窗口 StringVar字符串变量 Label标签 Entry输入框 Button按钮 messagebox信息框
from tkinter import Tk, StringVar, Label, Entry, Button, messagebox

# 默认用户名密码
DEFAULT_USERNAME = 'root'
DEFAULT_PASSWORD = 'root'

# 创建根窗口, 指的就是主窗口. 之后的一切组件全在root上展现
root = Tk()
# 设置窗口标题
root.title('第一个GUI程序.')

# 设置窗口大小长x宽, 单位像素. 通常tk组件都有geometry方法
# 最后显示出的长宽是受系统缩放影响的.
root.geometry('350x200')

# 创建两个变量来存放用户名和密码
username = StringVar()
password = StringVar()

# 创建两个标签用来提示, place为设置组件在窗口中的坐标位置
Label(root, text='用户名:').place(x=20, y=50)
Label(root, text='密码:').place(x=20, y=90)
# 创建两个输入框, 并将文本变量与其对接
Entry(root, textvariable=username).place(x=120, y=50)
# show就是输入框显示的样子, 一般密码设置为星号. 可以随意设置符号
Entry(root, textvariable=password, show='✿').place(x=120, y=90)


def event_login():
    """
    登录按钮事件
    :return:
    """
    global username
    global password
    # 去除空格, 并且全部小写
    str_username = username.get().strip().lower()
    # 密码也去除空格, 除非允许密码带空格
    str_password = password.get().strip()
    if str_username == '' or str_password == '':
        messagebox.showwarning('输入错误', '用户名密码不能为空')
    elif str_username == DEFAULT_USERNAME and str_password == DEFAULT_PASSWORD:
        messagebox.showinfo('成功', '登录成功')
        # 登录成功后做别的东西
    else:
        messagebox.showwarning('错误', '用户名或密码错误')


# 登录按钮, 并绑定event_login函数. 按下按钮即触发
Button(root, text='Login', command=event_login).place(x=150, y=130)

# 窗口循环
root.mainloop()

很简单点需求, 用tkinter用了20多行代码. 只是上面加了注释显得代码很多. 很多函数都是组件通用的像上面用到的 geometry 和 place. 绑定函数事件的还有bind等等. 如果你的需求简单, 上面的代码拿走改一改就能用了. 另外这个代码只展示这种按流程写法, 还有基于集成类的写法.

重点来了, 所有的代码都会在文章最末尾给出链接. 你脚本文件名切记不要和已存在的包一样. 注意哈我可说了, 我分享的代码都是一样的. 运行前改下名. 看下还有没有人说没办法运行. ???

PySimpleGUI

import PySimpleGUI as sg

# 默认用户名密码
DEFAULT_USERNAME = 'root'
DEFAULT_PASSWORD = 'root'

sg.theme('LightGrey4')  # 没错设置主题

# 创建布局, 多维数组. 将窗口组件按行排列, 想要如何显示全靠你的数组"长啥样"
layout = [[sg.Text('用户名:', size=(6, 1)), sg.InputText()],
          [sg.Text('密码:', size=(6, 1)), sg.InputText(password_char='❀')],
          [sg.Button('登录')]]

# 创建窗口
window = sg.Window('第二个GUI程序.', layout)

# 窗口事件循环
while True:
    event, values = window.read()  # 读取事件和值
    if event == '登录':
        # 去除空格, 并且全部小写
        str_username = values[0].strip().lower()
        # 密码也去除空格, 除非允许密码带空格
        str_password = values[1].strip()
        if str_username == '' or str_password == '':
            sg.Popup('输入错误', '用户名密码不能为空')
        elif str_username == DEFAULT_USERNAME and str_password == DEFAULT_PASSWORD:
            sg.Popup('成功', '登录成功')
            # 登录成功后做别的东西
        else:
            sg.Popup('错误', '用户名或密码错误')
    elif event is None:
        break

window.close()

打眼一看, 嘶~~~ 都是一堆看不懂的啊波次得(abcd). 相比tkinter最大得特点就是它将窗口设计按行分化, 使得在布局上更易规划. 你甚至不用考虑高分屏系统缩放问题(也得小改改~~). 而事件循环也简单明了. 有童鞋可能会说了: "你这个事件循环是方便, 但你这个取值也太难受了吧,如果一个窗口里有是几十个输入框那还怎么用数组取值?"

这个问题问得就很好?. 首先window.read()返回得是 事件和值, 然而这个值并不是数组, 而是字典. 可以通过给组件加上key属性来设置这些字典的key. 如果将上面的代码改写一下:

layout = [[sg.Text('用户名:', size=(6, 1)), sg.InputText(key="_username")],
          [sg.Text('密码:', size=(6, 1)), sg.InputText(password_char='❀', key="_pasword")],
          [sg.Button('登录')]]

那么实际输出的value就是 {'_username': '123', '_pasword': '123'}, 这样舒服多了吧. 如果在tkinter中想要调用某个输入框的值, 就需要设置全局变量, 或者类中内部变量.

总结

文中提到的四个库前两个其实使用起来都很简单方便, 但是就是没有窗口设计器. 不能实时的查看到窗口内容的变化. 对大型项目来说有点难受. 而第三四个PyQT是QT的python实现, 这是一个跨平台GUI大户, 有自家完成的设计器. 唯一缺点就是商业授权和学习成本. wxPython可以理解为是QT高压版, 而且还开源.

小伙子, 这几个库还有更多的组件等你去探索, 等嘛呢~ ?

那么我就点到为止了
Just give a hint.

相关链接:
tkinter: https://docs.python.org/zh-cn/3/library/tkinter.html
PySimpleGUI: https://pysimplegui.readthedocs.io/en/latest/
PyQt: https://www.riverbankcomputing.com/static/Docs/PyQt5/
代码: https://github.com/Virace/python-jgah/tree/master/Main/2153

文章评论