Python进阶 - GUI程序设计(tkinter)

0 概述

Python中有许多GUI模块可以用于开发GUI程序。最简单的有Turtle,然而它并不能用来创建图形用户界面。用于开发GUI的库主要有以下几种:

  • Tkinter:Python**内置**的标准GUI库,是一种小巧的开发库,开发速度快,在小型程序中仍有不少应用。它支持跨平台。
  • PyGTK:用C语言写的跨平台的GUI库,现在GTK已发展成了功能强大窗体丰富的GUI库。著名的GNOME即基于GTK。PyGTK提供了通过Python语言来访问GTK图形库的接口,所以在使用PyGTK之前需要安装GTK开发环境。
  • PyQt:拥有丰富的窗体部件。QT现在已经扩展成一个跨平台的应用开发框架。PyQt提供Python访问Qt的图形开发库接口。
  • WxPython开源框架,同样具有跨平台性。WxPython将GUI图形界面开发库wxWidgets和Python语言绑定。有丰富的窗体部件,使用户可以快速创建功能强大、界面元素丰富的GUI应用程序。

这里主要介绍Tkinter

1 开始使用Tkinter

from tkinter import *


window = Tk()    #创建一个窗口
label = Label(window, text = "Wellcome to Python")    # 创建一个带文本的标签
button = Button(window, text = "Click Me")    # 创建一个按钮
label.pack()    # 把标签放在窗口中
button.pack()    # 把按钮放在窗口中

# 包管理器将小构件一行一行地放在窗口之中

window.mainloop()    # 创建一个事件循环,持续处理事件直到关闭主窗口

2 事件处理

from tkinter import *


def processOK():    # 回调函数
    print("OK button is clicked")


def processCancel():
    print("Cancel button is clicked")


window = Tk()
btOK = Button(window, text = "OK", fg = "red", command = processOK)
btCancel = Button(window, text = "Cancel", bg = "yellow",
                  command = processCancel)

# fg前景色(文字颜色),默认黑色
# bg背景色(背景颜色),默认灰色


btOK.pack()
btCancel.pack()

window.mainloop()

将函数放到类中

from tkinter import *


class ProcessButtonEvent:
    """docstring for ProcessButtonEvent"""
    def __init__(self):
        window = Tk()
        btOK = Button(window, text = "OK", fg = "red",
                      command = self.processOK)
        btCancel = Button(window, text = "Cancel", bg = "yellow",
                          command = self.processCancel)
        btOK.pack()
        btCancel.pack()

        window.mainloop()

    def processOK(self):    # 回调函数
        print("OK button is clicked")

    def processCancel(self):
        print("Cancel button is clicked")

ProcessButtonEvent()

3 小构件

Tkinter中的小部件如下:

  • Button 按钮
  • Canvas 画布
  • CheckButton 复选框
  • Entry 输入框
  • Frame 容器,可将其他小部件放到里面
  • Label 显示文本或图像
  • Menu 实现下拉菜单或弹出菜单的菜单栏
  • Menubutton 下拉菜单项
  • Message 类似Label,但是能自动将文本放置在给定的宽度或宽高比内
  • Radiobutton 单选框
  • Text 格式化的文本显示,允许不同风格和属性显示和编辑文本,也支持内嵌的图片和窗口

一些属性:

  • 默认情况下,label或button上的文本是居中的。可以设置 justify 属性改变对齐方式,如 LEFT, RIGHT, CENTER
  • cursor光标的形状设定:可以设置 cursor 选项指定光标形状,如arrow, circle, cross, plus
  • 当构建一个小构件的时候,可以指定一些属性,如 fg、bg、font、cursor、text、command等
  • 输入域输入值,有IntVar、StringVar、DoubleVar等

示例如下:

from tkinter import *


class WidgetsDemo:
    """docstring for ClassName"""
    def __init__(self):
        window = Tk()
        window.title("Widgets Demmo")

        frame1 = Frame(window)
        frame1.pack()
        self.v1 = IntVar()
        cbtBold = Checkbutton(frame1, text = "Bold", variable = self.v1,
                              command = self.processCheckbutton)
        self.v2 = IntVar()
        # value为当radiobutton被点击时 v1 的取值
        rbRed = Radiobutton(frame1, text = "Red", bg = "red",
                            variable = self.v2, value = 1,
                            command = self.processRadiobutton)
        rbYellow = Radiobutton(frame1, text = "Yellow", bg= "yellow",
                               variable = self.v2, value = 2,
                               command = self.processRadiobutton)

        cbtBold.grid(row = 1, column = 1)
        rbRed.grid(row = 1, column = 2)
        rbYellow.grid(row = 1, column = 3)

        frame2 = Frame(window)
        frame2.pack()
        label = Label(frame2, text = "Enter your name: ")
        self.name = StringVar()
        entryName = Entry(frame2, textvariable = self.name)
        btGetName = Button(frame2, text = "Get Name",
                           command = self.processButton)
        message = Message(frame2, text = "It is widgets demo")
        label.grid(row = 1, column = 1)
        entryName.grid(row = 1, column = 2)
        btGetName.grid(row = 1, column = 3)
        message.grid(row = 1, column = 4)

        text = Text(window)
        text.pack()
        # END 表示文本被插入到当前内容的结尾
        text.insert(END, "Tip\nThe best way to learn Tkinter is to read ")
        text.insert(END, "these carefully designed examples and use them ")
        text.insert(END, "to create your applications. ")

        window.mainloop()

    def processCheckbutton(self):
        print("check button is "
              + ("checked " if self.v1.get() == 1 else "unckecked "))

    def processRadiobutton(self):
        print(("Red" if self.v2.get() == 1 else "Yellow") + " is selected")

    def processButton(self):
        print("Your name is " + self.name.get())


WidgetsDemo()

改变Label的值:

from tkinter import *


class ChangeLabelDemo:
    """docstring for ChangeLabelDemo"""
    def __init__(self):
        window = Tk()
        window.title()

        frame1 = Frame(window)
        frame1.pack()
        self.lbl = Label(frame1, text = "Programming is fun")
        self.lbl.pack()

        frame2 = Frame(window)
        frame2.pack()
        label = Label(frame2, text = "Enter text: ")
        self.msg = StringVar()
        entry = Entry(frame2, textvariable = self.msg)
        btChangeText = Button(frame2, text = "Change Text",
                              command = self.processButton)
        self.v1 = IntVar()
        rbRed = Radiobutton(frame2, text = "Red", bg = "red",
                            variable = self.v1, value = 1,
                            command = self.processRadiobutton)
        rbYellow = Radiobutton(frame2, text = "Yellow", bg = "yellow",
                               variable = self.v1, value = 2,
                               command = self.processRadiobutton)

        label.grid(row = 1, column = 1)
        entry.grid(row = 1, column = 2)
        btChangeText.grid(row = 1, column = 3)
        rbRed.grid(row = 1, column = 4)
        rbYellow.grid(row = 1, column =5)

        window.mainloop()

    def processRadiobutton(self):
        if self.v1.get() == 1:
            self.lbl["fg"] = "red"
        elif self.v1.get() == 2:
            self.lbl['fg'] = "yellow"

    def processButton(self):
        self.lbl['text'] = self.msg.get()


ChangeLabelDemo()

4 画布

from tkinter import *


class CanvasDemo:
    def __init__(self):
        window = Tk()
        window.title("Canvas Demo")

        self.canvas = Canvas(window, width = 200, height = 100, bg = "white")
        self.canvas.pack()

        frame = Frame(window)
        frame.pack()

        btRectangle = Button(frame, text = "Rectangele",
                             command = self.displayRect)
        btOval = Button(frame, text = "Oval",
                        command = self.displayOval)
        btArc = Button(frame, text = "Arc",
                       command = self.displayArc)
        btPolygon = Button(frame, text = "Polygon",
                           command = self.displayPolygon)
        btLine = Button(frame, text = "Line",
                        command = self.displayLine)
        btString = Button(frame, text = "String",
                          command = self.displayString)
        btClear = Button(frame, text = "ClearClear",
                         command = self.clearCanvas)

        btRectangle.grid(row = 1, column = 1)
        btOval.grid(row = 1, column = 2)
        btArc.grid(row = 1, column = 3)
        btPolygon.grid(row = 1, column = 4)
        btLine.grid(row = 1, column = 5)
        btString.grid(row = 1, column = 6)
        btClear.grid(row = 1, column = 7)

        window.mainloop()

    def displayRect(self):
        self.canvas.create_rectangle(10, 10, 190, 90, tags = "rect")

    def displayOval(self):
        self.canvas.create_oval(10, 10, 190, 90, fill = "red", tags = "oval")

    def displayArc(self):
        self.canvas.create_arc(10, 10, 190, 90, start = 0, extent = 90,
                               width = 8, fill = "red", tags = "arc")

    def displayPolygon(self):
        self.canvas.create_polygon(10, 10, 190, 90, 30, 50, tags = "polygon")

    # arrow 绘制箭头
    # activefill 鼠标经过时的颜色
    def displayLine(self):
        self.canvas.create_line(10, 10, 190, 90, fill = "red", tags = "line")
        self.canvas.create_line(10, 90, 190, 10, width = 9, arrow = "last",
                                activefill = "blue", tags = "line")

    def displayString(self):
        self.canvas.create_text(60, 40, text = "Hi, I am a string",
                font = "Times 10 bold underline", tags = "string")

    # 根据 tag 来删除图像
    def clearCanvas(self):
        self.canvas.delete("rect", "oval", "arc", "polygon", "line",
                           "string")


CanvasDemo()

5 几何管理器

网格管理器:按网格单元放置。

  • row指定行,column指定列
  • rowspan和columnspan跨行列
  • stiky属性:当构建比单元格小的时候怎么放置,如:S、N、E、W、NW、NE、SW、SE等。
  • padx、pady 单元格水平方向与垂直方向上的空白空间
  • ipadx、ipady 单元格内部空白空间

包管理器:让部件按一个方向放置

pack中可指设置side选项来制定小组件的放置方法,如LEFT、RIGHT、TOP、BOTTOM

from tkinter import *


class PackManagerDemo:
    def __init__(self):
        window = Tk()
        window.title("Pack Manager Demo")

        Label(window, text = "Blue", bg = "blue").pack()
        # 如果父控件比所容纳的子控件所需空间大,那么给 expand =1 的子控件分配额外的空间
        # side选项定义控件的摆放方式,有:LEFT, RIGHT, TOP, BOTTOM
        Label(window, text = "Red", bg = "red").pack(fill = BOTH, expand = 1)
        Label(window, text = "Green", bg = "green").pack(fill = BOTH)

        window.mainloop()

PackManagerDemo()

6 显示图像

7 菜单(顶部菜单 & 上下文菜单)

from tkinter import *


class MenuDemo:
    ''' 顶部菜单和右键菜单的实现 '''
    def __init__(self):
        window = Tk()
        window.title("Menu Demo")

        menubar = Menu(window)  # 新建菜单
        window.config(menu = menubar)

        operationMenu = Menu(menubar, tearoff = 0) # 菜单项operationMenu
        menubar.add_cascade(label = "Operation", menu = operationMenu)

        operationMenu.add_command(label = "Add", command = self.add)
        operationMenu.add_command(label = "Sub", command = self.sub)
        operationMenu.add_command(label = "Mul", command = self.mul)
        operationMenu.add_command(label = "Div", command = self.div)

        exitmenu = Menu(menubar, tearoff = 0)  # 菜单项exitmenu
        menubar.add_cascade(label = "Exit", menu = exitmenu)
        exitmenu.add_command(label = "Quit", command = window.quit)

        self.lbl = Label(window, text = "Menu Test")
        self.lbl.pack()

        # 弹出菜单
        self.menu = Menu(window, tearoff = 0)
        self.menu.add_command(label = "Draw line", command = self.displayLine)
        self.menu.add_command(label = "Draw Oval", command = self.diaplayOval)
        self.menu.add_command(label = "Draw rect", command = self.diaplayRect)
        self.menu.add_command(label = "Clear", command = self.clearCanvas)

        self.canvas = Canvas(window, width = 200, height = 100, bg = "white")
        self.canvas.pack()
        # 绑定右键点击事件,用popup()函数处理
        self.canvas.bind("", self.popup)

        window.mainloop()

    def add(self):
        self.lbl["text"] = "add"

    def sub(self):
        self.lbl["text"] = "sub"

    def mul(self):
        self.lbl["text"] = "mul"

    def div(self):
        self.lbl["text"] = "div"

    def displayLine(self):
        self.canvas.create_line(10, 10, 190, 90, tags = "line")
        self.canvas.create_line(10, 90, 190, 10, tags = "line")

    def diaplayOval(self):
        self.canvas.create_oval(10, 10, 190, 90, tags = "oval")

    def diaplayRect(self):
        self.canvas.create_rectangle(10, 10, 190, 90, tags = "rect")

    def clearCanvas(self):
        self.canvas.delete("line", "oval", "rect")

    def popup(self, event):
        self.menu.post(event.x_root, event.y_root)


MenuDemo()

8 鼠标、按键事件的绑定

事件列表

  • 鼠标被按住并移动
  • 单击鼠标动作。i 取值为1、2、3,分别为左键、中键、右键
  • 鼠标按键释放
  • 鼠标按键双击
  • 鼠标光标计进入
  • 单击一个键
  • 鼠标光标离开
  • 单击Enter键
  • 三连击

Event对象的属性

  • char 按键字符
  • keycode 按键的统一码
  • keysym 按键字符
  • num 鼠标的按键,为0、1、2
  • widget 事件产生的小构件对象
  • xy 鼠标在构件中的位置
  • x_rooty_root 鼠标相对于屏幕左上角的位置

示例如下:

from tkinter import *


class MouseKeyEventDemo:
    def __init__(self):
        window = Tk()
        window.title("Event Demo")
        canvas = Canvas(window, bg = "white", width = 200, height = 100)
        canvas.pack()

        canvas.bind("", self.processMouseEvent)

        canvas.bind("", self.processKeyEvent)
        canvas.focus()

        window.mainloop()

    def processMouseEvent(self, event):
        print("Cliked at: ", event.x, event.y)
        print("Position in the screen: ", event.x_root, event.y_root)
        print("Which button is clicked? ", event.num)

    def processKeyEvent(self, event):
        print("Keysym? ", event.keysym)
        print("char? ", event.char)
        print("keycode? ", event.keycode)

MouseKeyEventDemo()

9 动画

10 滚动条

11 对话框

from tkinter import *


class ProcessButtonEvent:
    """docstring for ProcessButtonEvent"""
    def __init__(self):
        window = Tk()
        btOK = Button(window, text = "OK", fg = "red",
                      command = self.processOK)
        btCancel = Button(window, text = "Cancel", bg = "yellow",
                          command = self.processCancel)
        btOK.pack()
        btCancel.pack()

        window.mainloop()

    def processOK(self):    # 回调函数
        print("OK button is clicked")

    def processCancel(self):
        print("Cancel button is clicked")

ProcessButtonEvent()

你可能感兴趣的:(Python)