《零基础入门学习Python》(35)--图形用户界面入门:EasyGui

0. 安装 EasyGUI

官网:https://github.com/robertlugg/easygui

进行下载,下载好了尽量将它放在你python安装目录下面,方面查找

使用 pip 进行安装:

1. 什么是 EasyGUI?

EasyGUI 是 Python 中一个非常简单的 GUI 编程模块,不同于其他的 GUI 生成器,它不是事件驱动的。相反,所有的 GUI 交互都是通过简地函数调用就可以实现。

EasyGUI 为用户提供了简单的 GUI 交互接口,不需要程序员知道任何有关 tkinter,框架,部件,回调或 lambda 的任何细节。

EasyGUI 可以很好地兼容 Python 2 和 3,并且不存在任何依赖关系。

EasyGUI 是运行在 Tkinter 上并拥有自身的事件循环,而 IDLE 也是 Tkinter 写的一个应用程序并也拥有自身的事件循环。因此当两者同时运行的时候,有可能会发生冲突,且带来不可预测的结果。因此如果你发现你的 EasyGUI 程序有这样的问题,请尝试在 IDLE 外去运行你的程序。 

2. 一个简单的例子

在 EasyGui 中,所有的 GUI 互动均是通过简单的函数调用,下边一个简单的例子告诉你 EasyGui 确实很 Easy!

import easygui as g
import sys

while 1:
        g.msgbox("嗨,欢迎进入第一个界面小游戏^_^")

        msg ="请问你希望在鱼C工作室学习到什么知识呢?"
        title = "小游戏互动"
        choices = ["谈恋爱", "编程", "OOXX", "琴棋书画"]
        
        choice = g.choicebox(msg, title, choices)

        # 注意,msgbox的参数是一个字符串
        # 如果用户选择Cancel,该函数返回None
        g.msgbox("你的选择是: " + str(choice), "结果")

        msg = "你希望重新开始小游戏吗?"
        title = "请选择"

        # 弹出一个Continue/Cancel对话框
        if g.ccbox(msg, title):
                pass            # 如果用户选择Continue
        else:
                sys.exit(0)     # 如果用户选择Cancel

3. EasyGUI 的各种功能演示

要运行 EasyGUI 的演示程序,在命令行调用 EasyGUI 是这样的:

python easygui.py

或者可以从 IDE(例如 IDLE, PythonWin, Wing, 等等)上调用:

>>> import easygui
>>> easygui.egdemo()

成功调用后将可以尝试 EasyGUI 拥有的各种功能,并将结果打印至控制台

4. 导入 EasyGUI

为了使用 EasyGUI 这个模块,你应该先导入它。

最简单的导入语句是:

import easygui

如果使用上面这种形式导入的话,那么你使用 EasyGUI 的函数的时候,必须在函数的前面加上前缀 easygui,像这样:

easygui.msgbox(...)

另一种选择是导入整个 EasyGUI 包:

from easygui import *

这使得我们更容易调用 EasyGUI 的函数,可以直接这样编写代码:

msgbox(...)

第三种方案是使用类似下边的 import 语句:

import easygui as g

这种方法还可以让你保持 EasyGUI 的命名空间,同时减少你的打字数量。

导入之后就可以这么调用 EasyGUI 的函数:

g.msgbox(...)

5. 使用 EasyGUI

一旦你的模块导入 EasyGUI,GUI 操作就是一个简单的调用 EasyGUI 函数的几个参数的问题了。

例如,使用 EasyGUI 来实现世界上最著名的打招呼:

import easygui as g

g.msgbox("Hello, world!")

6. EasyGUI 函数的默认参数

对于所有对话框而言,前两个参数都是消息主体和对话框标题。

按照这个规律,在某种情况下,这可能不是理想的布局设计(比如当对话框在获取目录或文件名的时候会选择忽略消息参数),但保持这种一致性且贯穿于所有的窗口部件是更为得体的考虑!

绝大部分的 EasyGUI 函数都有默认参数,几乎所有的组件都会显示消息主体和对话框标题。

标题默认是空字符串,消息主体通常有一个简单的默认值。

这使得你可以尽可能少的去设置参数,比如 msgbox() 函数标题部分的参数是可选的,因此你调用 msgbox() 的时候只需要指定一个消息参数即可,例如:

>>> g.msgbox('hello world!!!!')

当然你也可以指定标题参数和消息参数,例如:

>>> g.msgbox('hello world','go go go')

在各类按钮组件里,默认的消息是 “Shall I continue?”,所以你可以不带任何参数地去调用它们。

这里我们演示不带任何参数地去调用 ccbox(),当选择 “cancel” 或关闭窗口的时候返回一个布尔类型的值:

import easygui as g
while True:
    if g.ccbox():
        pass         # user chose to continue
    else:
        exit()     # user chose to cancel

7. 使用关键字参数调用EasyGui函数

调用EasyGui函数还可以使用关键字参数

现在假设你需要使用一个按钮组件,但你不想指定标题参数(第二个参数),你仍可以使用关键字参数的方法指定choices参数(第三个参数),像这样:

import easygui as g
xz = ['棒','真棒','超级棒']
replay = g.choicebox('我棒不棒?',choices=xz)

8. 使用按钮组建

根据需求,EasyGui在buttonbox()上建立了一系列的函数供调用。

8.1 msgbox()

>>> help(g.msgbox)
Help on function msgbox in module easygui.boxes.derived_boxes:

msgbox(msg='(Your message goes here)', title=' ', ok_button='OK', image=None, root=None)
    Display a message box
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param str ok_button: text to show in the button
    :param str image: Filename of image to display
    :param tk_widget root: Top-level Tk widget
    :return: the text of the ok_button

重写OK按钮最简单的方法是使用关键字参数:

import easygui as g
g.msgbox('我一定要学会Python', ok_button='加油')

8.2 ccbox()

>>> help(g.ccbox)
Help on function ccbox in module easygui.boxes.derived_boxes:

ccbox(msg='Shall I continue?', title=' ', choices=('C[o]ntinue', 'C[a]ncel'), image=None, default_choice='Continue', cancel_choice='Cancel')
    Display a msgbox with choices of Continue and Cancel.
    
    The returned value is calculated this way::
    
        if the first choice ("Continue") is chosen,
          or if the dialog is cancelled:
            return True
        else:
            return False
    
    If invoked without a msg argument, displays a generic
    request for a confirmation
    that the user wishes to continue.  So it can be used this way::
    
        if ccbox():
            pass # continue
        else:
            sys.exit(0)  # exit the program
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param str image: Filename of image to display
    :param str default_choice: The choice you want highlighted
      when the gui appears
    :param str cancel_choice: If the user presses the 'X' close,
      which button should be pressed
    
    :return: True if 'Continue' or dialog is cancelled, False if 'Cancel'

ccbox()提供一个选择:Continue或者Cancel,并相应的返回1(选中Continue)或者0(选中Cancel)。

【注意】:ccbox()是返回整形的1或0,不是布尔类型的True或False。但你仍然可以这么些:

import sys
import easygui as g
if g.ccbox('要再来一次吗?',choices=('要啊要啊^_^', '算了吧T_T')):
    g.msgbox('不给玩了,再玩就玩坏了……')
else:
    sys.exit(0)

8.3 ynbox()

>>> help(g.ynbox)
Help on function ynbox in module easygui.boxes.derived_boxes:

ynbox(msg='Shall I continue?', title=' ', choices=('[<F1>]Yes', '[<F2>]No'), image=None, default_choice='[<F1>]Yes', cancel_choice='[<F2>]No')
    Display a msgbox with choices of Yes and No.
    
    The returned value is calculated this way::
    
        if the first choice ("Yes") is chosen, or if the dialog is cancelled:
            return True
        else:
            return False
    
    If invoked without a msg argument, displays a generic
    request for a confirmation
    that the user wishes to continue.  So it can be used this way::
    
        if ynbox():
            pass # continue
        else:
            sys.exit(0)  # exit the program
    
    :param msg: the msg to be displayed
    :type msg: str
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param str image: Filename of image to display
    :param str default_choice: The choice you want highlighted
        when the gui appears
    :param str cancel_choice: If the user presses the 'X' close, which
      button should be pressed
    
    :return: True if 'Yes' or dialog is cancelled, False if 'No'

同8.2

8.4 buttonbox()

>>> help(g.buttonbox)
Help on function buttonbox in module easygui.boxes.button_box:

buttonbox(msg='', title=' ', choices=('Button[1]', 'Button[2]', 'Button[3]'), image=None, images=None, default_choice=None, cancel_choice=None, callback=None, run=True)
    Display a msg, a title, an image, and a set of buttons.
    The buttons are defined by the members of the choices global_state.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param str image: (Only here for backward compatibility)
    :param str images: Filename of image or iterable or iteratable of iterable to display
    :param str default_choice: The choice you want highlighted when the gui appears
    :return: the text of the button that the user selected

可以使用buttonbox()定义自己的一组按钮,buttonbox()会显示一组你定义好的按钮。

当用户点击任意一个按钮的时候,buttonbox()返回按钮的文本内容。如果用户取消或者关闭窗口,那么会返回默认选项(第一个选项)。请看示例:

import easygui as g
g.buttonbox(choices=('草莓','西瓜','芒果','巧克力'))

8.5 indexbox()

>>> help(g.indexbox)
Help on function indexbox in module easygui.boxes.derived_boxes:

indexbox(msg='Shall I continue?', title=' ', choices=('Yes', 'No'), image=None, default_choice='Yes', cancel_choice='No')
    Display a buttonbox with the specified choices.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param str image: Filename of image to display
    :param str default_choice: The choice you want highlighted
      when the gui appears
    :param str cancel_choice: If the user presses the 'X' close,
      which button should be pressed
    :return: the index of the choice selected, starting from 0

基本上跟上边一样,区别就是当用户选择第一个按钮的时候返回序号0,选择第二个按钮的时候返回序号1

8.6 boolbox()

>>> help(g.boolbox)
Help on function boolbox in module easygui.boxes.derived_boxes:

boolbox(msg='Shall I continue?', title=' ', choices=('[Y]es', '[N]o'), image=None, default_choice='Yes', cancel_choice='No')
    Display a boolean msgbox.
    
    The returned value is calculated this way::
    
        if the first choice is chosen, or if the dialog is cancelled:
            returns True
        else:
            returns False
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param str image: Filename of image to display
    :param str default_choice: The choice you want highlighted
      when the gui appears
    :param str cancel_choice: If the user presses the 'X' close, which button
      should be pressed
    :return: True if first button pressed or dialog is cancelled, False if
      second button is pressed

如果第一个按钮被选中返回1,否则返回0.

9. 如何在buttonbox里显示图片

当你调用一个buttonbox函数(例如:msgbox(),ynbox(),indexbox()等)的时候,你还可以为关键字参数image赋值,这是设置一个.gif格式的图像(注意仅支持GIF格式)

import easygui as g
g.buttonbox('大家说我长得帅吗?', image='1.gif', choices=('帅', '不帅', '你大爷'))

10. 为用户提供一系列选项

10.1 choicebox()

>>> help(g.choicebox)
Help on function choicebox in module easygui.boxes.choice_box:

choicebox(msg='Pick an item', title='', choices=[], preselect=0, callback=None, run=True)
    Present the user with a list of choices.
    return the choice that he selects.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param list choices: a list or tuple of the choices to be displayed
    :param preselect: Which item, if any are preselected when dialog appears
    :return: List containing choice selected or None if cancelled

按钮组建方便提供用户一个简单的按钮选项,但如果有很多选项,或者选项的内容特别长的话,更好的策略是为它们提供一个可选择的列表。

choicebox()为用户提供了一个可选择的列表,使用序列(元祖或列表)作为选项,这些选项显示前会按照不区分大小写的方法排好序。

另外还可以使用键盘来选择其中一个选项(比较纠结,但一点儿都不重要): 

- 例如当按下键盘上g键,将会选中第一个以g开头的选项。再次按下g键,则会选中下一个以g开头的选项。在选中最后一个以g开头的选项时候,再次按下g键将重新回到在列表的开头的第一个以g开头的选项。 

- 如果选项中没有以g开头的,则会选中字符排序在g之前f的那个字符开头的选项 

- 如果选项中没有字符排序在g之前,那么在列表中第一个元素将会被选中。

综合我们之前的学习文件功能,举个例子:
 

import easygui as g

target = ['.mp4','.avi','.rmvb','.mkv','.torrent']
vedio_list = []

import os
def serach_file(start_dir,target):
    os.chdir(start_dir)

    for each_file in os.listdir(os.curdir):
        ext = os.path.splitext(each_file)[1]
        if ext in target:
            vedio_list.append(os.getcwd() + os.sep +each_file + os.linesep)
        if os.path.isdir(each_file):
            serach_file(each_file,target)
            os.chdir(os.pardir)
start_dir = input('请输入需要查找的目录:')
program_dir = os.getcwd()
serach_file(start_dir,target)

f = open(program_dir + os.sep + 'vedioList.txt','w')
f.writelines(vedio_list)
f.close()

g.choicebox(msg='在 【%s】 系列路径下工搜索满足条件的文件如下' % start_dir,choices=vedio_list)

12. 让用户输入密码

有时候我们需要让用户输入密码,就是用户输入的东西看上去都是**********

12.1 passwordbox()

>>> help(g.passwordbox)
Help on function passwordbox in module easygui.boxes.derived_boxes:

passwordbox(msg='Enter your password.', title=' ', default='', image=None, root=None)
    Show a box in which a user can enter a password.
    The text is masked with asterisks, so the password is not displayed.
    
    :param str msg: the msg to be displayed.
    :param str title: the window title
    :param str default: value returned if user does not change it
    :return: the text that the user entered, or None if he cancels
      the operation.

passwordbox()跟enterbox()样式一样,不同的是用户输入的内容用*显示,返回用户输入的字符串:

12.2 multpasswordbox()

>>> help(g.multpasswordbox)
Help on function multpasswordbox in module easygui.boxes.multi_fillable_box:

multpasswordbox(msg='Fill in values for the fields.', title=' ', fields=(), values=(), callback=None, run=True)
    Same interface as multenterbox.  But in multpassword box,
    the last of the fields is assumed to be a password, and
    is masked with asterisks.
    
    :param str msg: the msg to be displayed.
    :param str title: the window title
    :param list fields: a list of fieldnames.
    :param list values: a list of field values
    :return: String
    
    **Example**
    
    Here is some example code, that shows how values returned from
    multpasswordbox can be checked for validity before they are accepted::
    
        msg = "Enter logon information"
        title = "Demo of multpasswordbox"
        fieldNames = ["Server ID", "User ID", "Password"]
        fieldValues = []  # we start with blanks for the values
        fieldValues = multpasswordbox(msg,title, fieldNames)
    
        # make sure that none of the fields was left blank
        while 1:
            if fieldValues is None: break
            errmsg = ""
            for i in range(len(fieldNames)):
                if fieldValues[i].strip() == "":
                    errmsg = errmsg + ('"%s" is a required field.\n\n' %
                     fieldNames[i])
                if errmsg == "": break # no problems found
            fieldValues = multpasswordbox(errmsg, title,
              fieldNames, fieldValues)
    
        print("Reply was: %s" % str(fieldValues))

multpasswordbox()跟multenterbox()使用相同的接口,但当它显示的时候,最后一个输入框显示为密码的形式*

from easygui import *
msg = "验证登陆信息"
title = "密码函数multpasswordbox示例"
fieldNames = ["服务器 ID", "用户 ID", "密码"]
fieldValues = []  # we start with blanks for the values
fieldValues = multpasswordbox(msg, title, fieldNames)
print("输入的信息是: %s" % str(fieldValues))

13. 显示文本

EasyGui还提供函数用于显示文本。

13.1 textbox()

>>> help(g.textbox)
Help on function textbox in module easygui.boxes.text_box:

textbox(msg='', title=' ', text='', codebox=False, callback=None, run=True)
    Display a message and a text to edit
    
    Parameters
    ----------
    msg : string
        text displayed in the message area (instructions...)
    title : str
        the window title
    text: str, list or tuple
        text displayed in textAreas (editable)
    codebox: bool
        if True, don't wrap and width is set to 80 chars
    callback: function
        if set, this function will be called when OK is pressed
    run: bool
        if True, a box object will be created and returned, but not run
    
    Returns
    -------
    None
        If cancel is pressed
    str
        If OK is pressed returns the contents of textArea

textbox()函数默认会以比例字体(参数codebox = 1设置为等宽字体)来显示文本内容(会自动换行哦),这个函数适合用于显示一般的书面文字。

【注意】:text参数(第三个参数)可以是字符串,列表或者元祖类型。

13.2 codebox()

>>> help(g.codebox)
Help on function codebox in module easygui.boxes.derived_boxes:

codebox(msg='', title=' ', text='')
    Display some text in a monospaced font, with no line wrapping.
    This function is suitable for displaying code and text that is
    formatted using spaces.
    
    The text parameter should be a string, or a list or tuple of lines to be
    displayed in the textbox.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param str text: what to display in the textbox

codebox()以等宽字体显示文本内容,相当于testbox(codebox = 1)

14. 目录与文件

GUI编程中一个常见的场景是要求用户输入目录及文件名,EasyGui提供了一些基本函数让用户来浏览文件系统,选择一个目录或文件。

14.1 diropenbox()

>>> help(g.diropenbox)
Help on function diropenbox in module easygui.boxes.diropen_box:

diropenbox(msg=None, title=None, default=None)
    A dialog to get a directory name.
    Note that the msg argument, if specified, is ignored.
    
    Returns the name of a directory, or None if user chose to cancel.
    
    If the "default" argument specifies a directory name, and that
    directory exists, then the dialog box will start with that directory.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :param str default: starting directory when dialog opens
    :return: Normalized path selected by user

diropenbox()函数用于提供一个对话框,返回用户选择的目录名(带完整路径),如果用户选择Cancel则返回None。 
default参数用于设置默认的打开目录(请确保设置的目录已存在。)

>>> g.diropenbox()

14.2 fileopenbox()

>>> help(g.fileopenbox)
Help on function fileopenbox in module easygui.boxes.fileopen_box:

fileopenbox(msg=None, title=None, default='*', filetypes=None, multiple=False)
    A dialog to get a file name.
    
    **About the "default" argument**
    
    The "default" argument specifies a filepath that (normally)
    contains one or more wildcards.
    fileopenbox will display only files that match the default filepath.
    If omitted, defaults to "\*" (all files in the current directory).
    
    WINDOWS EXAMPLE::
    
        ...default="c:/myjunk/*.py"
    
    will open in directory c:\myjunk\ and show all Python files.
    
    WINDOWS EXAMPLE::
    
        ...default="c:/myjunk/test*.py"
    
    will open in directory c:\myjunk\ and show all Python files
    whose names begin with "test".
    
    
    Note that on Windows, fileopenbox automatically changes the path
    separator to the Windows path separator (backslash).
    
    **About the "filetypes" argument**
    
    If specified, it should contain a list of items,
    where each item is either:
    
    - a string containing a filemask          # e.g. "\*.txt"
    - a list of strings, where all of the strings except the last one
      are filemasks (each beginning with "\*.",
      such as "\*.txt" for text files, "\*.py" for Python files, etc.).
      and the last string contains a filetype description
    
    EXAMPLE::
    
        filetypes = ["*.css", ["*.htm", "*.html", "HTML files"]  ]
    
    .. note:: If the filetypes list does not contain ("All files","*"), it will be added.
    
    If the filetypes list does not contain a filemask that includes
    the extension of the "default" argument, it will be added.
    For example, if default="\*abc.py"
    and no filetypes argument was specified, then
    "\*.py" will automatically be added to the filetypes argument.
    
    :param str msg: the msg to be displayed.
    :param str title: the window title
    :param str default: filepath with wildcards
    :param object filetypes: filemasks that a user can choose, e.g. "\*.txt"
    :param bool multiple: If true, more than one file can be selected
    :return: the name of a file, or None if user chose to cancel

fileopenbox()函数用于提供一个对话框,返回用户选择的文件名(带完整路径),如果用户选择Cancel则返回None

关于default参数的设置方法: 
- default参数指定一个默认路径,通常包含一个或多个通配符。 
- 如果设置了default参数,fileopenbox()显示默认的文件路径和格式。 
- default默认的参数是*,即匹配所有格式的文件。

例如: 
1. default = ‘c:/fishc/*.py’即显示c:\fishc文件夹下所有的Python文件 
2. default = ‘c:/fishc/test*.py’即显示c:\fishc文件夹下所有的名字以test开头的Python文件

关于filetypes参数的设置方法: 
- 可以是包含文件掩码的字符串列表。例如:filetypes = ['*.txt'] 
- 可以是字符串列表,列表的最后一项字符串是文件类型的描述,例如:filetypes = ['*.css',['*.htm','*.html','*.HTML files']]

>>> g.fileopenbox(default = 'E:\software\*.exe')
'E:\\software\\pycharm-professional-2018.1.1.exe'


>>> g.fileopenbox(filetypes = ['*.py',['*.py','*.python file']])
'D:\\untitled\\Python_learn\\将一个数分解成列表.py'

事例3: 

提供一个文件夹浏览框,让用户选择需要打开的文件,打开并显示文件内容:

import easygui as g
import os

file_path = g.fileopenbox(default="*.txt")

with open(file_path) as f:
    title = os.path.basename(file_path)
    msg = "文件【%s】的内容如下:" % title
    text = f.read()
    g.textbox(msg, title, text)

14.3 filesavebox()

>>> help(g.filesavebox)
Help on function filesavebox in module easygui.boxes.filesave_box:

filesavebox(msg=None, title=None, default='', filetypes=None)
    A file to get the name of a file to save.
    Returns the name of a file, or None if user chose to cancel.
    
    The "default" argument should contain a filename (i.e. the
    current name of the file to be saved).  It may also be empty,
    or contain a filemask that includes wildcards.
    
    The "filetypes" argument works like the "filetypes" argument to
    fileopenbox.
    
    :param str msg: the msg to be displayed.
    :param str title: the window title
    :param str default: default filename to return
    :param object filetypes: filemasks that a user can choose, e.g. " \*.txt"
    :return: the name of a file, or None if user chose to cancel

filesavebox()函数提供一个对话框,让用于选择的文件需要保存的路径(带完整路劲),如果用户选择Cancel则返回None。

default参数应该包含一个文件名(例如当前需要保存的文件名),当然你也可以设置为空的,或者包含一个文件格式掩码的通配符

filetypes参数类似于fileopenbox()函数的filetypes参数。

>>> g.filesavebox(default='test.txt')

事例4

事例3的基础上增强功能:当用户点击OK按钮的时候,比较当前文件是否修改过,如果修改过,则提示覆盖保存,放弃保存另存为...并实现相应功能。 

(提示:解决这道题可能需要点耐心,因为你有可能被一个小问题卡住,但请坚持,自己想办法找到这个小问题并解决它!)

import easygui as g
import os

file_path = g.fileopenbox(default='*.txt')

with open(file_path) as old_file:
    title = os.path.basename(file_path)
    msg = '文件【%s】的内容如下:' % title
    text = old_file.read()
    text_after = g.textbox(msg,title,text)

if text != text_after[:-1]: #textbox的返回值会在末尾追加一个换行符    
    #buttonbox(msg='', title=' ', choices=('Button1', 'Button2', 'Button3'), image=None, root=None)
    choice = g.buttonbox('检测到文件内容发生改变,请选择以下操作:','警告',('覆盖保持','放弃保存','另存为...'))
    if choice == '覆盖保存':
        with open(file_path,'w') as old_file:
            old_file.write(text_after[:-1])
    if choice == '放弃保存':
        pass
    if choice == '另存为...':
        another_path = g.filesavebox(default='.txt')
        if os.path.splitext(another_path)[1] != '.txt':
            another_path += '.txt'
        with open(another_path,'w') as new_file:
            new_file.write(text_after[:-1])

15. 记住用户的设置

15.1 EgStore

>>> help(g.EgStore)
Help on class EgStore in module easygui.boxes.egstore:

class EgStore(builtins.object)
 |  EgStore(filename)
 |  
 |  A class to support persistent storage.
 |  
 |  You can use ``EgStore`` to support the storage and retrieval
 |  of user settings for an EasyGui application.
 |  
 |  **First: define a class named Settings as a subclass of EgStore** ::
 |  
 |      class Settings(EgStore):
 |          def __init__(self, filename):  # filename is required
 |              # specify default values for variables that this application wants to remember
 |              self.user_id = ''
 |              self.target_server = ''
 |              settings.restore()
 |  *Second: create a persistent Settings object** ::
 |  
 |      settings = Settings('app_settings.txt')
 |      settings.user_id = 'obama_barak'
 |      settings.targetServer = 'whitehouse1'
 |      settings.store()
 |  
 |      # run code that gets a new value for user_id, and persist the settings
 |      settings.user_id = 'biden_joe'
 |      settings.store()
 |  
 |  **Example C: recover the Settings instance, change an attribute, and store it again.** ::
 |  
 |      settings = Settings('app_settings.txt')
 |      settings.restore()
 |      print settings
 |      settings.user_id = 'vanrossum_g'
 |      settings.store()
 |  
 |  Methods defined here:
 |  
 |  __getstate__(self)
 |      All attributes will be pickled
 |  
 |  __init__(self, filename)
 |      Initialize a store with the given filename.
 |      
 |      :param filename: the file that backs this store for saving and loading
 |  
 |  __repr__(self)
 |      Return repr(self).
 |  
 |  __setstate__(self, state)
 |      Ensure filename won't be unpickled
 |  
 |  __str__(self)
 |      "Format this store as "key : value" pairs, one per line.
 |  
 |  kill(self)
 |      Delete this store's file if it exists.
 |  
 |  restore(self)
 |  
 |  store(self)
 |      Save this store to a pickle file.
 |      All directories in :attr:`filename` must already exist.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

GUI编程中一个常见的场景就是要求用户设置一下参数,然后保存下来,以便下次用户使用你的程序的时候可以记住他的设置。

为了实现对用户的设置进行存储和恢复这一过程,EasyGui提供了一个EgStore的类。为了记住某些设置,你的应用程序必须定义一个类(暂时称之为“设置”类,尽管你随意的使用你想要的名称设置它)继承自EgStore类。

然后你的应用程序必须创建一个该类的对象(暂时称之为“设置”对象)

设置类的构造函数(__init__方法)必须初始化所有的你想要它记住的那些值。

一旦你这样做了,你就可以在“设置”对象中通过设定值去实例化变量,从而简单地记住设置。之后使用setting.store()方法在硬盘上持久化设置对象。
下面是创建一个“设置”类的例子:

#-----------------------------------------------------------------------
# create "settings", a persistent Settings object
# Note that the "filename" argument is required.
# The directory for the persistent file must already exist.
#-----------------------------------------------------------------------
settingsFilename = os.path.join("C:", "FishCApp", "settings.txt")  # Windows example
settings = Settings(settingsFilename)

下面是使用“设置”对象的例子:

# we initialize the "user" and "server" variables
# In a real application, we'd probably have the user enter them via enterbox
user    = "奥巴马"
server  = "白宫"

# we save the variables as attributes of the "settings" object
settings.userId = user
settings.targetServer = server
settings.store()    # persist the settings

# run code that gets a new value for userId
# then persist the settings with the new value
user    = "小甲鱼"
settings.userId = user
settings.store()

16. 捕获异常

  • exceptionbox()
>>> help(g.exceptionbox)
Help on function exceptionbox in module easygui.boxes.derived_boxes:

exceptionbox(msg=None, title=None)
    Display a box that gives information about
    an exception that has just been raised.
    
    The caller may optionally pass in a title for the window, or a
    msg to accompany the error information.
    
    Note that you do not need to (and cannot) pass an exception object
    as an argument.  The latest exception will automatically be used.
    
    :param str msg: the msg to be displayed
    :param str title: the window title
    :return: None

使用EasyGui编写GUI程序,有时候难免会产生异常。当然这取决于你如何运行你的应用程序,当你的应用程序崩溃的时候,堆栈追踪可能会被抛出,或者被写入到stdout标准输出函数中。

EasyGui通过exceptionbox()函数提供了更好的方式去处理异常,异常出现的时候,exceptionbox()会显示堆栈追踪在一个codebox()中并且允许你做进一步的处理。

exceptionbox()很容易使用,请看下例:

import easygui as g

try:
    print('i love fishc.com')
    int('FishC') #这里会产生异常
except:
    g.exceptionbox()

事例5:

写一个程序统计你当前代码量的总和,并显示离十万行代码量还有多远?

  • 要求1:递归搜索各个文件夹
  • 要求2:显示各个类型的源文件和源代码数量
  • 要求3:显示总行数与百分比

截图1: 

截图2:

import easygui as g
import os

def show_result(start_dir):
    lines = 0
    total = 0
    text = ""

    for i in source_list:
        lines = source_list[i]
        total += lines
        text += "【%s】源文件 %d 个,源代码 %d 行\n" % (i, file_list[i], lines)
    title = '统计结果'
    msg = '您目前共累积编写了 %d 行代码,完成进度:%.2f %%\n离 10 万行代码还差 %d 行,请继续努力!' % (total, total/1000, 100000-total)
    g.textbox(msg, title, text)

def calc_code(file_name):
    lines = 0
    with open(file_name) as f:
        print('正在分析文件:%s ...' % file_name)
        try:
            for each_line in f:
                lines += 1
        except UnicodeDecodeError:
            pass # 不可避免会遇到格式不兼容的文件,这里忽略掉......
    return lines

def search_file(start_dir) :
    os.chdir(start_dir)

    for each_file in os.listdir(os.curdir) :
        ext = os.path.splitext(each_file)[1]
        if ext in target :
            lines = calc_code(each_file) # 统计行数
            # 还记得异常的用法吗?如果字典中不存,抛出 KeyError,则添加字典键
            # 统计文件数
            try:
                file_list[ext] += 1
            except KeyError:
                file_list[ext] = 1
            # 统计源代码行数
            try:
                source_list[ext] += lines
            except KeyError:
                source_list[ext] = lines

        if os.path.isdir(each_file) :
            search_file(each_file) # 递归调用
            os.chdir(os.pardir) # 递归调用后切记返回上一层目录

target = ['.c', '.cpp', '.py', '.cc', '.java', '.pas', '.asm']
file_list = {}
source_list = {}

g.msgbox("请打开您存放所有代码的文件夹......", "统计代码量")
path = g.diropenbox("请选择您的代码库:")

search_file(path)
show_result(path)

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_38721302/article/details/83306137
今日推荐