请选择 进入手机版 | 继续访问电脑版

牛大大的个人博客

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2457|回复: 0

Python 图形化界面设计

[复制链接]

149

主题

201

帖子

643

积分

版主

Rank: 7Rank: 7Rank: 7

积分
643
发表于 2020-5-6 20:41:00 | 显示全部楼层 |阅读模式
1、图形化界面设计的基本理解
当前流行的计算机桌面应用程序大多数为图形化用户界面(Graphic User Interface,GUI),即通过鼠标对菜单、按钮等图形化元素触发指令,并从标签、对话框等图型化显示容器中获取人机对话信息。
Python自带了tkinter 模块,实质上是一种流行的面向对象的GUI工具包 TK 的Python编程接口,提供了快速便利地创建GUI应用程序的方法。其图像化编程的基本步骤通常包括:
  • 导入 tkinter 模块
  • 创建 GUI 根窗体
  • 添加人机交互控件并编写相应的函数。
  • 在主事件循环中等待用户触发事件响应。
2、窗体控件布局
  • 2.1、根窗体是图像化应用程序的根控制器,是tkinter的底层控件的实例。当导入tkinter模块后,调用 Tk()方法可初始化一个根窗体实例 root ,用 title() 方法可设置其标题文字,用geometry()方法可以设置窗体的大小(以像素为单位)。将其置于主循环中,除非用户关闭,否则程序始终处于运行状态。执行该程序,一个窗体就呈现出来了。在这个主循环的根窗体中,可持续呈现中的其他可视化控件实例,监测事件的发生并执行相应的处理程序。下面是根窗体呈现示例:



  1. from tkinter import *
  2. root= Tk()
  3. root.title('我的第一个Python窗体')
  4. root.geometry('240x240') # 这里的乘号不是 * ,而是小写英文字母 x
  5. root.mainloop()
复制代码







2.2、tkinter 常用控件
  • 常用控件:常用的10 多种,如下:
控件名称作用
Button按钮单击触发事件
Canvas画布绘制图形或绘制特殊控件
Checkbutton复选框多项选择
Entry输入框接收单行文本输入
Frame框架用于控件分组
Label标签单行文本显示
Lisbox列表框显示文本列表
Menu菜单创建菜单命令
Message消息多行文本标签,与Label 用法类似
Radiobutton单选按钮从互斥的多个选项中做单项选择
Scale滑块默认垂直方向,鼠标拖动改变数值形成可视化交互
Scrollbar滑动条默认垂直方向,课鼠标拖动改变数值,可与 Text、Lisbox、Canvas等控件配合移动可视化空间
Text文本框接收或输出显示多行文本
Toplevel新建窗体容器在顶层创建新窗体
  • 控件的共同属性:在窗体上呈现的可视化控件,通常包括尺寸、颜色、字体、相对位置、浮雕样式、图标样式和悬停光标形状等共同属性。不同的控件由于形状和功能不同,又有其特征属性。在初始化根窗体和根窗体主循环之间,可实例化窗体控件,并设置其属性。父容器可为根窗体或其他容器控件实例。常见的控件共同属性如下表:
    属性说明取值
    anchor文本起始位置CENTER(默认),E,S,W,N,NE,SE,SW,NW
    bg背景色无
    bd加粗(默认 2 像素)无
    bitmap黑白二值图标网上查找
    cursor鼠标悬停光标网上查找
    font字体无
    fg前景色无
    height高(文本控件的单位为行,不是像素)无
    image显示图像无
    justify多行文本的对其方式CENTER(默认),LEFT,RIGHT,TOP,BOTTOM
    padx水平扩展像素无
    pady垂直扩展像素无
    relief3D浮雕样式FLAT,RAISED,SUNKEN,GROOVE,RIDGE
    state控件实例状态是否可用NORMAL(默认),DISABLED
    width宽(文本控件的单位为行,不是像素)无标签及常见属性示例:



  1. from  tkinter import *
  2. root = Tk()
  3. lb = Label(root,text='我是第一个标签',\
  4.         bg='#d3fbfb',\
  5.         fg='red',\
  6.         font=('华文新魏',32),\
  7.         width=20,\
  8.         height=2,\
  9.         relief=SUNKEN)
  10. lb.pack()
  11. root.mainloop()
复制代码




其中,标签实例lb 在父容器root中实例化,具有代码中所示的text(文本)、bg(背景色)、fg(前景色)、font(字体)、width(宽,默认以字符为单位)、height(高,默认以字符为单位)和 relief(浮雕样式)等一系列属性。
在实例化控件时,实例的属性可以“属性=属性值”的形式枚举列出,不区分先后次序。例如:“ text='我是第一个标签' ”显示标签的文本内容,“bg='#d3fbfb'”设置背景色为十六进制数RGB色 #d3fbfb等等。属性值通常用文本形式表示。
当然如果这个控件实例只需要一次性呈现,也可以不必命名,直接实例化并布局呈现出来,例如:

  1. Label(root,text='我是第一个标签',font='华文新魏').pack()
复制代码
属性 relief 为控件呈现出来的3D浮雕样式,有 FLAT(平的)、RAISED(凸起的)、SUNKEN(凹陷的)、GROOVE(沟槽状边缘)和 RIDGE(脊状边缘) 5种。
2.2、控件布局
控件的布局通常有pack()、grid() 和 place() 三种方法。
  • 2.2.1、pack()方法:是一种简单的布局方法,如果不加参数的默认方式,将按布局语句的先后,以最小占用空间的方式自上而下地排列控件实例,并且保持控件本身的最小尺寸。如下的例子:



    • 用pack() 方法不加参数排列标签。为看清楚各控件所占用的空间大小,文本用了不同长度的中英文,并设置relief=GROOVE的凹陷边缘属性。如下所示:

  1. from tkinter import  *
  2. root = Tk()

  3. lbred = Label(root,text="Red",fg="Red",relief=GROOVE)
  4. lbred.pack()
  5. lbgreen = Label(root,text="绿色",fg="green",relief=GROOVE)
  6. lbgreen.pack()
  7. lbblue = Label(root,text="蓝",fg="blue",relief=GROOVE)
  8. lbblue.pack()
  9. root.mainloop()
复制代码
使用pack()方法可设置 fill、side 等属性参数。其中,参数fill 可取值:fill=X,fill=Y或fill=BOTH,分别表示允许控件向水平方向、垂直方向或二维伸展填充未被占用控件。参数 side 可取值:side=TOP(默认),side=LEFT,side=RIGHT,side=BOTTOM,分别表示本控件实例的布局相对于下一个控件实例的方位。如下例子
  1. from tkinter import  *
  2. root = Tk()

  3. lbred = Label(root,text="Red",fg="Red",relief=GROOVE)
  4. lbred.pack()
  5. lbgreen = Label(root,text="绿色",fg="green",relief=GROOVE)
  6. lbgreen.pack(side=RIGHT)
  7. lbblue = Label(root,text="蓝",fg="blue",relief=GROOVE)
  8. lbblue.pack(fill=X)
  9. root.mainloop()
复制代码
2.2.2、grid()方法:是基于网格的布局。先虚拟一个二维表格,再在该表格中布局控件实例。由于在虚拟表格的单元中所布局的控件实例大小不一,单元格也没有固定或均一的大小,因此其仅用于布局的定位。pack()方法与grid()方法不能混合使用。
grid()方法常用布局参数如下:
  • column: 控件实例的起始列,最左边为第0列。
  • columnspan: 控件实例所跨越的列数,默认为1列。
  • ipadx,ipady: 控件实例所呈现区域内部的像素数,用来设置控件实例的大小。
  • padx,pady: 控件实例所占据空间像素数,用来设置实例所在单元格的大小。
  • row: 控件实例的起始行,最上面为第0行。
  • rowspan: 控件实例的起始行数,默认为1行。
看下面的例子:用grid()方法排列标签,设想有一个3x4的表格,起始行、列序号均为0.将标签lbred 至于第2列第0行;将标签lbgreen置于第0列第1行;将标签lbblue置于第1列起跨2列第2行,占20像素宽。

2.2.3、place()方法:根据控件实例在父容器中的绝对或相对位置参数进行布局。其常用布局参数如下:
  • x,y:控件实例在根窗体中水平和垂直方向上的其实位置(单位为像素)。注意,根窗体左上角为0,0,水平向右,垂直向下为正方向。
  • relx,rely:控件实例在根窗体中水平和垂直方向上起始布局的相对位置。即相对于根窗体宽和高的比例位置,取值在0.0~1.0之间。
  • height,width:控件实例本身的高度和宽度(单位为像素)。
  • relheight,relwidth:控件实例相对于根窗体的高度和宽度比例,取值在0.0~1.0之间。
  • 利用place()方法配合relx,rely和relheight,relwidth参数所得的到的界面可自适应根窗体尺寸的大小。place()方法与grid()方法可以混合使用。如下例子:利用place()方法排列消息(多行标签)。




  1. from tkinter import *
  2. root = Tk()
  3. root.geometry('320x240')

  4. msg1 = Message(root,text='''我的水平起始位置相对窗体 0.2,垂直起始位置为绝对位置 80 像素,我的高度是窗体高度的0.4,宽度是200像素''',relief=GROOVE)
  5. msg1.place(relx=0.2,y=80,relheight=0.4,width=200)
  6. root.mainloop()
复制代码

3、tkinter常见控件的特征属性
  • 3.1、文本输入和输出相关控件:文本的输入与输出控件通常包括:标签(Label)、消息(Message)、输入框(Entry)、文本框(Text)。他们除了前述共同属性外,都具有一些特征属性和功能。

    • 标签(Label)和 消息(Message):除了单行与多行的不同外,属性和用法基本一致,用于呈现文本信息。值得注意的是:属性text通常用于实例在第一次呈现时的固定文本,而如果需要在程序执行后发生变化,则可以使用下列方法之一实现:1、用控件实例的configure()方法来改变属性text的值,可使显示的文本发生变化;2、先定义一个tkinter的内部类型变量var=StringVar() 的值也可以使显示文本发生变化。
      看下面的一个例子:制作一个电子时钟,用root的after()方法每隔1秒time模块以获取系统当前时间,并在标签中显示出来。

      • 方法一:利用configure()方法或config()来实现文本变化。




  1. import tkinter
  2. import time

  3. def gettime():
  4.       timestr = time.strftime("%H:%M:%S") # 获取当前的时间并转化为字符串
  5.       lb.configure(text=timestr)   # 重新设置标签文本
  6.       root.after(1000,gettime) # 每隔1s调用函数 gettime 自身获取时间

  7. root = tkinter.Tk()
  8. root.title('时钟')

  9. lb = tkinter.Label(root,text='',fg='blue',font=("黑体",80))
  10. lb.pack()
  11. gettime()
  12. root.mainloop()
复制代码
方法二:利用textvariable变量属性来实现文本变化。


  1. import tkinter
  2. import time

  3. def gettime():
  4.       var.set(time.strftime("%H:%M:%S"))   # 获取当前时间
  5.       root.after(1000,gettime)   # 每隔1s调用函数 gettime 自身获取时间

  6. root = tkinter.Tk()
  7. root.title('时钟')
  8. var=tkinter.StringVar()

  9. lb = tkinter.Label(root,textvariable=var,fg='blue',font=("黑体",80))
  10. lb.pack()
  11. gettime()
  12. root.mainloop()
复制代码
文本框(Text)
文本框的常用方法如下:
方法功能
delete(起始位置,[,终止位置])删除指定区域文本
get(起始位置,[,终止位置])获取指定区域文本
insert(位置,[,字符串]...)将文本插入到指定位置
see(位置)在指定位置是否可见文本,返回布尔值
index(标记)返回标记所在的行和列
mark_names()返回所有标记名称
mark_set(标记,位置)在指定位置设置标记
mark_unset(标记)去除标记上表位置的取值可为整数,浮点数或END(末尾),例如0.0表示第0列第0行
如下一个例子:每隔1秒获取一次当前日期的时间,并写入文本框中,如下:本例中调用 datetime.now()获取当前日期时间,用insert()方法每次从文本框txt的尾部(END)开始追加文本



  1. from tkinter import *
  2. import time
  3. import datetime

  4. def gettime():
  5.        s=str(datetime.datetime.now())+'\n'
  6.        txt.insert(END,s)
  7.        root.after(1000,gettime)  # 每隔1s调用函数 gettime 自身获取时间

  8. root=Tk()
  9. root.geometry('320x240')
  10. txt=Text(root)
  11. txt.pack()
  12. gettime()
  13. root.mainloop()
复制代码
  • 输入框(Entry):通常作为功能比较单一的接收单行文本输入的控件,虽然也有许多对其中文本进行操作的方法,但通常用的只有取值方法get()和用于删除文本的delete(起始位置,终止位置),例如:清空输入框为delete(0,END)。

3.2、按钮(Button):主要是为响应鼠标单击事件触发运行程序所设的,故其除控件共有属性外,属性command是最为重要的属性。通常,将按钮要触发执行的程序以函数形式预先定义,然后可以用一下两种方法调用函数。Button按钮的状态有:'normal','active','disabled'
  • 直接调用函数。参数表达式为“command=函数名”,注意函数名后面不要加括号,也不能传递参数。如下面的command=run1:
  • 利用匿名函数调用函数和传递参数。参数的表达式为“command=lambda”:函数名(参数列表)。例如下面的:"command=lambda:run2(inp1.get(),inp2.get())"。
  • 看下面的例子:1.从两个输入框去的输入文本后转为浮点数值进行加法运算,要求每次单击按钮产生的算是结果以文本的形式追加到文本框中,将原输入框清空。2.按钮方法一不传参数调用函数run1()实现,按钮“方法二”用lambda调用函数run2(x,y)同时传递参数实现





  1. from tkinter import *

  2. def run1():
  3.      a = float(inp1.get())
  4.      b = float(inp2.get())
  5.      s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)
  6.      txt.insert(END, s)   # 追加显示运算结果
  7.      inp1.delete(0, END)  # 清空输入
  8.      inp2.delete(0, END)  # 清空输入

  9. def run2(x, y):
  10.      a = float(x)
  11.      b = float(y)
  12.      s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)
  13.      txt.insert(END, s)   # 追加显示运算结果
  14.      inp1.delete(0, END)  # 清空输入
  15.      inp2.delete(0, END)  # 清空输入

  16. root = Tk()
  17. root.geometry('460x240')
  18. root.title('简单加法器')

  19. lb1 = Label(root, text='请输入两个数,按下面两个按钮之一进行加法计算')
  20. lb1.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.1)
  21. inp1 = Entry(root)
  22. inp1.place(relx=0.1, rely=0.2, relwidth=0.3, relheight=0.1)
  23. inp2 = Entry(root)
  24. inp2.place(relx=0.6, rely=0.2, relwidth=0.3, relheight=0.1)

  25. # 方法-直接调用 run1()
  26. btn1 = Button(root, text='方法一', command=run1)
  27. btn1.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1)

  28. # 方法二利用 lambda 传参数调用run2()
  29. btn2 = Button(root, text='方法二', command=lambda: run2(inp1.get(), inp2.get()))
  30. btn2.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1)

  31. # 在窗体垂直自上而下位置60%处起,布局相对窗体高度40%高的文本框
  32. txt = Text(root)
  33. txt.place(rely=0.6, relheight=0.4)

  34. root.mainloop()
复制代码
3.3、单选按钮:(Radiobutton)是为了响应故乡排斥的若干单选项的单击事件以触发运行自定义函数所设的,该控件排除具有共有属性外,还具有显示文本(text)、返回变量(variable)、返回值(value)、响应函数名(command)等重要属性。响应函数名“command=函数名”的用法与Button相同,函数名最后也要加括号。返回变量variable=var通常应预先声明变量的类型var=IntVar()或var=StringVar(),在所调用的函数中方可用var.get()方法获取被选中实例的value值。例如下面
  1. from tkinter import *
  2. def Mysel():
  3.       dic = {0:'甲',1:'乙',2:'丙'}
  4.       s = "您选了" + dic.get(var.get()) + "项"
  5.       lb.config(text = s)

  6. root = Tk()
  7. root.title('单选按钮')
  8. lb = Label(root)
  9. lb.pack()

  10. var = IntVar()
  11. rd1 = Radiobutton(root,text="甲",variable=var,value=0,command=Mysel)
  12. rd1.pack()

  13. rd2 = Radiobutton(root,text="乙",variable=var,value=1,command=Mysel)
  14. rd2.pack()

  15. rd3 = Radiobutton(root,text="丙",variable=var,value=2,command=Mysel)
  16. rd3.pack()

  17. root.mainloop()
复制代码
3.4、复选框:(Checkbutton) 是为了返回多个选项值的交互控件,通常不直接触发函数的执行。该控件除具有共有属性外,还具有显示文本(text)、返回变量(variable)、选中返回值(onvalue)和未选中默认返回值(offvalue)等重要属性。返回变量variable=var 通常可以预先逐项分别声明变量的类型var=IntVar() (默认)或 var=StringVar(), 在所调用的函数中方可分别调用 var.get()方法 取得被选中实例的 onvalue或offvalue值。复选框实例通常还可分别利用 select()、deselect()和 toggle() 方法对其进行选中、清除选中和反选操作。
  • 如下的例子: 利用复选框实现,单击OK,可以将选中的结果显示在标签上。效果如



方法:利用函数中的 if-else 分支实现多项显示

  1. from tkinter import *
  2. import tkinter

  3. def run():
  4.      if(CheckVar1.get()==0 and CheckVar2.get()==0 and CheckVar3.get()==0 and CheckVar4.get()==0):
  5.          s = '您还没选择任何爱好项目'
  6.      else:
  7.          s1 = "足球" if CheckVar1.get()==1 else ""
  8.          s2 = "篮球" if CheckVar2.get() == 1 else ""
  9.          s3 = "游泳" if CheckVar3.get() == 1 else ""
  10.          s4 = "田径" if CheckVar4.get() == 1 else ""
  11.          s = "您选择了%s %s %s %s" % (s1,s2,s3,s4)
  12.      lb2.config(text=s)

  13. root = tkinter.Tk()
  14. root.title('复选框')
  15. lb1=Label(root,text='请选择您的爱好项目')
  16. lb1.pack()

  17. CheckVar1 = IntVar()
  18. CheckVar2 = IntVar()
  19. CheckVar3 = IntVar()
  20. CheckVar4 = IntVar()

  21. ch1 = Checkbutton(root,text='足球',variable = CheckVar1,onvalue=1,offvalue=0)
  22. ch2 = Checkbutton(root,text='篮球',variable = CheckVar2,onvalue=1,offvalue=0)
  23. ch3 = Checkbutton(root,text='游泳',variable = CheckVar3,onvalue=1,offvalue=0)
  24. ch4 = Checkbutton(root,text='田径',variable = CheckVar4,onvalue=1,offvalue=0)

  25. ch1.pack()
  26. ch2.pack()
  27. ch3.pack()
  28. ch4.pack()

  29. btn = Button(root,text="OK",command=run)
  30. btn.pack()

  31. lb2 = Label(root,text='')
  32. lb2.pack()
  33. root.mainloop()
复制代码
3.5、列表框 与 组合框
  • 3.5.1、列表框:(Listbox) 可供用户单选或多选所列条目以形成人机交互。列表框控件的主要方法见下面的表:
方法功能描述
curselection()返回光标选中项目编号的元组,注意并不是单个的整数
delete(起始位置,终止位置)删除项目,终止位置可省略,全部清空为delete(0,END)
get(起始位置,终止位)返回范围所含项目文本的元组,终止位置可忽略
insert(位置,项目元素)插入项目元素(若有多项,可用列表或元组类型赋值),若位置为END,则将项目元素添加在最后
size()返回列表框行数执行自定义函数时,通常使用“实例名.surselection()” 或 “selected” 来获取选中项的位置索引。由于列表框实质上就是将Python 的列表类型数据可视化呈现,在程序实现时,也可直接对相关列表数据进行操作,然后再通过列表框展示出来,而不必拘泥于可视化控件的方法。看下面的一个例子:实现列表框的初始化、添加、插入、修改、删除和清空操作,如下




  1. from tkinter import *
  2. def ini():
  3.       Lstbox1.delete(0,END)
  4.       list_items = ["数学","物理","化学","语文","外语"]
  5.       for item in list_items:
  6.            Lstbox1.insert(END,item)

  7. def clear():
  8.       Lstbox1.delete(0,END)

  9. def ins():
  10.       if entry.get() != '':
  11.           if Lstbox1.curselection() == ():
  12.               Lstbox1.insert(Lstbox1.size(),entry.get())
  13.           else:
  14.               Lstbox1.insert(Lstbox1.curselection(),entry.get())

  15. def updt():
  16.       if entry.get() != '' and Lstbox1.curselection() != ():
  17.            selected=Lstbox1.curselection()[0]
  18.            Lstbox1.delete(selected)
  19.            Lstbox1.insert(selected,entry.get())

  20. def delt():
  21.       if Lstbox1.curselection() != ():
  22.            Lstbox1.delete(Lstbox1.curselection())

  23. root = Tk()
  24. root.title('列表框实验')
  25. root.geometry('320x240')

  26. frame1 = Frame(root,relief=RAISED)
  27. frame1.place(relx=0.0)

  28. frame2 = Frame(root,relief=GROOVE)
  29. frame2.place(relx=0.5)

  30. Lstbox1 = Listbox(frame1)
  31. Lstbox1.pack()

  32. entry = Entry(frame2)
  33. entry.pack()

  34. btn1 = Button(frame2,text='初始化',command=ini)
  35. btn1.pack(fill=X)

  36. btn2 = Button(frame2,text='添加',command=ins)
  37. btn2.pack(fill=X)

  38. btn3 = Button(frame2,text='插入',command=ins) # 添加和插入功能实质上是一样的
  39. btn3.pack(fill=X)

  40. btn4 = Button(frame2,text='修改',command=updt)
  41. btn4.pack(fill=X)

  42. btn5 = Button(frame2,text='删除',command=delt)
  43. btn5.pack(fill=X)

  44. btn6 = Button(frame2,text='清空',command=clear)
  45. btn6.pack(fill=X)

  46. root.mainloop()
复制代码




















回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|牛大大的个人博客 ( 苏ICP备17043571号-2 )

GMT+8, 2021-6-15 11:08 , Processed in 0.197440 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表