Python的GUI编程(一)

前言:最近一段时间在写论文,2.2W字的论文终于达成了2.3%查重的终极奥义,可能需要后续的更改,论文写完之后,毕业设计的指导老师曲老师又针对毕业设计项目的内容提出了一些建议,然后就改呗,其实我之前是觉得做的太简单了,现在加上一些有关GUI的内容,交互页面便于操作,做出来的结果还是惨不忍睹, 不过好在还算完成了,老师还没有验收,我个人觉得还可以,有些需求看起来很简单,自己真正动手做的时候还真不是那么回事,不知道哪些模块可以完成这项内容,只能自己挨个试,中间查了很多的资料而且涉及到一些有关Python中GUI的内容,所以继续写一篇博客记录下来,主要使用了Python中tkinter模块进行编写,所以项目的内容也是基于tkinter模块进行编写的。

Python GUI编程

Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下:

Tkinter: Tkinter模块(Tk接口)是Python的标准Tk GUI 工具包的接口。Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh 系统里。Tk8.0的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。(在python3.x中改为tkinter)

wxPython:wxPython是一款开源软件,是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的、功能健全的GUI用户界面。

Jython:Jython 程序可以和 Java 无缝集成。除了一些标准模块,Jython 使用 Java 的模块。Jython几乎拥有标准的Python中不依赖于C 语言的全部模块。比如,Jython的用户界面将使用 Swing,AWT或者 SWT。Jython可以被动态或静态地编译成Java字节码。

tkinter编程

tkinter是Python的标准GUI库。Python使用Tkinter可以快速的创建GUI应用程序。由于tkinter是内置到python的安装包中、只要安装好Python之后就能import tkinter 库。

  import tkinter

创建一个GUI程序

  • 1、导入 Tkinter 模块
  • 2、创建控件
  • 3、指定这个控件的 master,即这个控件属于哪一个
  • 4、告诉GM(geometry manager)有一个控件产生

example1:

 #!/usr/bin/python
 # -*- coding: UTF-8 -*-
 import tkinter
 top = tkinter.Tk()
 # 进入消息循环
 top.mainloop()

运行结果如下:

1

example2:

 #!/usr/bin/python
 # -*- coding: UTF-8 -*-
 from tkinter import *           # 导入 Tkinter 库
 root = Tk()                     # 创建窗口对象的背景色
                                 # 创建两个列表
 li     = ['C','python','php','html','SQL','java']
 movie  = ['CSS','jQuery','Bootstrap']
 listb  = Listbox(root)          #  创建两个列表组件
 listb2 = Listbox(root)
 for item in li:                 # 第一个小部件插入数据
     listb.insert(0,item)
 for item in movie:              # 第二个小部件插入数据
     listb2.insert(0,item)
 listb.pack()                    # 将小部件放置到主窗口中
 listb2.pack()
 root.mainloop()

运行结果如下:

2

tkinter组件

  • Button 按钮控件;在程序中显示按钮。
  • Canvas 画布控件;显示图形元素如线条或文本
  • Checkbutton 多选框控件;用于在程序中提供多项选择框
  • Entry 输入控件;用于显示简单的文本内容
  • Frame 框架控件;在屏幕上显示一个矩形区域,多用来作为容器
  • Label 标签控件;可以显示文本和位图
  • Listbox 列表框控件;在Listbox窗口小部件是用来显示一个字符串列表给用户
  • Menubutton 菜单按钮控件,由于显示菜单项。
  • Menu 菜单控件;显示菜单栏,下拉菜单和弹出菜单
  • Message 消息控件;用来显示多行文本,与label比较类似
  • Radiobutton 单选按钮控件;显示一个单选的按钮状态
  • Scale 范围控件;显示一个数值刻度,为输出限定范围的数字区间
  • Scrollbar 滚动条控件,当内容超过可视化区域时使用,如列表框。.
  • Text 文本控件;用于显示多行文本
  • Toplevel 容器控件;用来提供一个单独的对话框,和Frame比较类似
  • Spinbox 输入控件;与Entry类似,但是可以指定输入范围值
  • PanedWindow PanedWindow是一个窗口布局管理的插件,可以包含一个或者多个子控件。
  • LabelFrame labelframe 是一个简单的容器控件。常用与复杂的窗口布局。
  • tkMessageBox 用于显示你应用程序的消息框。

标准属性

标准属性也就是所有控件的共同属性,如大小,字体和颜色等等。

  • Dimension 控件大小;
  • Color 控件颜色;
  • Font 控件字体;
  • Anchor 锚点;
  • Relief 控件样式;
  • Bitmap 位图;
  • Cursor 光标;

几何管理

tkinter控件有特定的几何状态管理方法,管理整个控件区域组织,一下是Tkinter公开的几何管理类:包、网格、位置。

  • pack() 包装;
  • grid() 网格;
  • place() 位置;

项目代码:

import tkinter
import pandas as pd
import numpy as np
from sklearn.cluster import AffinityPropagation
import matplotlib.pyplot as plt
from PIL import Image,ImageDraw
from math import radians, cos, sin, asin, sqrt


class FindLocation(object):
    def __init__(self):

        # 创建主窗口,用于容纳其它组件
        self.root = tkinter.Tk("聚类")
        # 给主窗口设置标题内容
        self.root.title("基于近邻传播算法的交通道路划分")
        # 创建一个输入框,并设置尺寸
        self.time_input = tkinter.Entry(self.root,width=20)
        # 创建一个输入框,并设置尺寸
        self.result_button1 = tkinter.Button(self.root, command=self.find_AP, text="道路状况查询")
        #输入车牌返回位置
        self.ID_input = tkinter.Entry(self.root, width=20)
        # 创建一个查询结果的按钮
        self.result_button = tkinter.Button(self.root, command=self.find_position, text="车辆信息查询")
        self.result_button2 = tkinter.Button(self.root, command=self.find, text="车辆定位显示")
        # 创建一个回显列表
        self.display_info = tkinter.Listbox(self.root, width=80)
    
    # 完成布局
    def gui_arrang(self):
        self.time_input.pack()
        self.result_button1.pack()
        self.ID_input.pack()
        self.result_button.pack()
        self.result_button2.pack()
        self.display_info.pack()



    # 查找地理位置
    def find_AP(self):
        self.time_addr = self.time_input.get()
        # 获取输入信息
        '''
        
        插入生成速度代码
        
       '''

        data = pd.read_table('data.txt', sep=',', names=["Speed"])
        data1 = data.fillna(0)
        l = data1["Speed"].tolist()

        dataSet = []
        fileIn = open('jvzhen.txt')
        for line in fileIn.readlines():
            lineArr = line.strip().split(' ')
            dataSet.append([float(lineArr[0]), float(lineArr[1])])
        simi = []
        for m in l:
            ##每个数字与所有数字的相似度列表,即矩阵中的一行
            for n in l:
                ##采用速度之差计算相似度
                s = -abs(m - n)
                simi.append(s)
        p = np.median(simi)
        ap = AffinityPropagation(damping=0.5, max_iter=500, convergence_iter=30,
                                 preference=p).fit(dataSet)
        cluster_centers_indices = ap.cluster_centers_indices_
        # 计算子区域平均速度
        for n in ap.labels_:
            l[cluster_centers_indices[n]] = l[cluster_centers_indices[n]] + l[n]
        Z = [0] * 25
        for n in ap.labels_:
            Z[cluster_centers_indices[n]] = Z[cluster_centers_indices[n]] + 1
        for i in ap.cluster_centers_indices_:
            l[i] = l[i] / Z[i]
        # 可视化输出
        l = np.array(l).reshape(5, 5)

        plt.imshow(l, interpolation='nearest', cmap='hot', origin='upper')
        plt.xticks(())
        plt.yticks(())
        plt.savefig("E:\canvas\est.png")
        path = "E:\\canvas\\map.png"
        path1 = "E:\\canvas\\est.png"
        img1 = Image.open(path)
        img4 = Image.open(path1)
        img1.convert("RGBA")
        img4.convert("RGBA")
        img3 = Image.blend(img1, img4, 0.5)  # img1和img2的size要相同,不然会引起一个ValueError
        img3.show()

    def find_position(self):
        # 获取输入信息
        self.ID_addr = self.ID_input.get()
        a="0:12-0:22"
        b = a.split('-')
        c = '2011-9-14 ' + b[0] + ':00'
        d = '2011-9-14 ' + b[1] + ':00'
        data = pd.read_table('GP.txt', sep=',', names=["ID", "Time", "Longitude", "Latitude", "Speed", "No"])
        data1 = data[(data.Time > c) & (data.Time < d)]
        po = data1[data1['ID'].isin([self.ID_addr])]
        # 为回显列表赋值
        dfplist = np.array(po).tolist()
        for item in dfplist:
            for i in range(0, item.__len__()):
                item[i] = str(item[i])
            str1= ','.join(item)
            self.display_info.insert(0,str1)

    # 轨迹显示
    def find(self):
        # 获取输入信息
        self.ID_addr = self.ID_input.get()
        a = "0:12-0:22"
        b = a.split('-')
        c = '2011-9-14 ' + b[0] + ':00'
        d = '2011-9-14 ' + b[1] + ':00'
        data = pd.read_table('GP.txt', sep=',', names=["ID", "Time", "Longitude", "Latitude", "Speed", "No"])
        data1 = data[(data.Time > c) & (data.Time < d)]
        po = data1[data1['ID'].isin([self.ID_addr])]

        po1 = po.sort_values(by='Time', ascending=True)
        # 为回显列表赋值
        loc=po1[["Longitude", "Latitude"]]
        loclist = np.array(loc).tolist()
        k=0
        im01 = Image.open("E:\\canvas\\map.png")
        draw = ImageDraw.Draw(im01)
        for item in loclist:
                x=item[0]
                y=item[1]
                X1=108.851955
                Y1=34.372111
                X2=109.00157
                Y2=34.203101
                xi=((x-X1)/(X2-X1))*640
                yi=((Y1-y)/(Y1-Y2))*480

                if k!=0:
                    draw.line((tempx, tempy, xi, yi), fill=128)
                tempx = xi
                tempy =yi
                k=k+1
        im01.show()


def main():
    # 初始化对象
    FL = FindLocation()
    # 进行布局
    FL.gui_arrang()
    # 主程序执行
    tkinter.mainloop()
    pass
if __name__ == "__main__":
    main()


这个是主要可视化代码,完成功能是可视化的查询,集成了近邻传播算法和车辆位置信息等功能,还有部分代码没有晚上但是基本功能已经实现,还有车辆轨迹显示功能,操作界面如下:

3

其中车辆轨迹功能同样是基于python的GUI功能,使用了PIL库的Image,ImageDraw模块等主要完成对图片的操作,之前采用了数据分析可视化模块matplotlib,但是这个模块缺少基于图片的操作,因此只能采用PIL库的模块,进行实现。

PIL

PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单易用。由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。

关于PIL的内容下篇博客进行介绍。