Pythoner集中营思科DevNet程序猿阵线联盟-汇总各类技术干货

python界面 | 实战Tkinter图形界面开发

2018-04-07  本文已影响163人  与阳光共进早餐

0 写在前面

之前在这篇文章python 图形界面开发里记录了最开始学习python界面开发的有关知识,虽然整理了一些最常用的控件、属性,但还是缺少实践。

下面这张就是我接下来想实现的整体界面的示意图(请忽略我粗糙的UI~~)

界面

基本功能介绍:

这篇文章涉及的知识点还是挺多的哦:

真的可以自信满满地说点进来吧,不会让你失望的哈哈哈哈

1 具体实现

1.0 导入包、创建界面类

from Tkinter import *

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()

if __name__=='__main__':
    app = Application()
    # to do
    app.mainloop()

1.1 设置窗口标题、界面最大化

具体的函数如下所示,先获得当前屏幕的大小,然后设置窗口大小。

    def window_init(self):
        self.master.title('welcome to video-captioning system')
        width,height=self.master.maxsize()
        self.master.geometry("{}x{}".format(width, height))

__init__初始化中调用即可。

1.2 实现各个控件布局

1) 布局方式介绍

布局就是控制各个控件在整个界面中的位置,Tkinter总共有3中布局管理器,分别是pack gridplace

2) 布局设计图

我选择全部用pack的方式来完成页面的布局工作。

具体的设计图如下所示:


页面布局图

我已经尽力去画了,不知道这样是不是清楚~

3) 布局实现代码

我们先不管具体的细节,直接把各个控件的布局位置给定下来,界面优化的部分放到后面去再添加。

按照上面的布局设计图,视频区域暂且用一张图片替代,用pack()实现基本布局如下:


    def createWidgets(self):
        # fm1
        self.fm1=Frame(self)
        self.titleLabel=Label(self.fm1,text='video-captioning system')
        self.titleLabel.pack()
        self.fm1.pack(side= TOP)

        # fm2
        self.fm2=Frame(self)
        self.fm2_left=Frame(self.fm2)
        self.fm2_right=Frame(self.fm2)
        self.fm2_left_top=Frame(self.fm2_left)
        self.fm2_left_bottom=Frame(self.fm2_left)

        self.predictButton=Button(self.fm2_left_top,text='predict sentence')
        self.predictButton.pack(side=LEFT)
        self.predictEntry=Entry(self.fm2_left_top)
        self.predictEntry.pack(side=LEFT)
        self.fm2_left_top.pack(side=TOP)

        self.truthButton=Button(self.fm2_left_bottom,text='ground truth')
        self.truthButton.pack(side=LEFT)
        self.truthEntry=Entry(self.fm2_left_bottom)
        self.truthEntry.pack(side=LEFT)
        self.fm2_left_bottom.pack(side=TOP)

        self.fm2_left.pack(side=LEFT)
        self.nextVideoButton=Button(self.fm2_right,text='next video')
        self.nextVideoButton.pack()
        self.fm2_right.pack(side=LEFT)

        self.fm2.pack(side=TOP)
        
        # fm3
        self.fm3=Frame(self)
        load = Image.open('/home/hl/Desktop/lovelyqian/me.jpg') 
        print (load)
        render= ImageTk.PhotoImage(load)  
  
        self.img = Label(self.fm3,image=render)  
        self.img.image = render  
        self.img.pack()
        self.fm3.pack(side=TOP)

: 图片的处理要加入头文件
from PIL import Image, ImageTk

最终效果图:

基本布局效果图

对比上下两张图,可能这就是理想与现实的差距吧,哈哈哈哈

这里还只是实现了布局的定义和基本位置的放置,虽然真的很丑,但是不要着急,接下来我们就可以在这个基础上做一些控件大小的修改以及其他的界面美化工作。

4) 控件属性设置及界面优化

设置主窗口背景为黑色

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master,bg='black')
        self.pack(expand=YES,fill=BOTH)

各个控件属性设置

控件实现代码

差不多先这样吧,去吃个午饭,下午回来继续写功能函数~~~

1.3 各个函数功能

1) 显示文本

这里只需要学习一下Entry这个控件。

2) 按钮触发

只需要在按钮中添加属性command即可。

以点击predictButton按钮实现将文本显示到后面的文本框中为例:

#...
   self.predictButton=Button(self.fm2_left_top,text='predict sentence',bg='#FF4081',fg='white',font=('微软雅黑',36),width='16',command=self.output_predict_sentence)

    def output_predict_sentence(self):
        predicted_sentence_str='hello world.'
        self.predictEntry.delete(0,END)
        self.predictEntry.insert(0,predicted_sentence_str)

这样每次点击按键就会先把框框内的文字清空,然后输出你指定的文本。

3) 视频播放

这个可能是最难的一个部分了呢~

Tkinter是没有支持视频播放的原生控件的,百度找了好久都没有找到解决方案,感谢Google大法,在这里找到了一个非常好的例子,还好木有放弃~~

这个例子实现的是从摄像头获取视频流,然后放在Tkinter实现的GUI窗口中,按钮可以实现视频截屏并保存的效果。

对代码做了简化之后实现将视频播放在TKinter窗口中代码如下所示:

from __future__ import print_function
from PIL import Image,ImageTk
import Tkinter as tki
import threading
import imutils
import cv2
import time
import imageio

class videoPlayer():
    def __init__(self):
        self.frame = None
        self.thread = None
        self.stopEvent = None

        # initialize the root window and image panel
        self.root = tki.Tk()
        self.panel = None

        # start a thread that constantly pools the video sensor for
        # the most recently read frame
        self.stopEvent = threading.Event()
        self.thread = threading.Thread(target=self.videoLoop, args=())
        self.thread.start()
    
    def videoLoop(self):
        # keep looping over frames until we are instructed to stop
        video_path='/home/hl/Desktop/lovelyqian/CV_Learning/video_to_sequence/video_to_sequence-master/data/youtube_videos/_0nX-El-ySo_83_93.avi'  
        video=imageio.get_reader(video_path,'ffmpeg')
        for frame in video:    
            self.frame = imutils.resize(frame, width=300)                
            image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
            image = Image.fromarray(image)
            image = ImageTk.PhotoImage(image)
        
            # if the panel is not None, we need to initialize it
            if self.panel is None:
                self.panel = tki.Label(image=image)
                self.panel.image = image
                self.panel.pack(side="left", padx=10, pady=10)  
            # otherwise, simply update the panel
            else:
                self.panel.configure(image=image)
                self.panel.image = image

            time.sleep(0.02)

myVideoPLayer = videoPlayer()
myVideoPLayer.root.mainloop()

对上面的代码再做一个修改整合就可以了。

4) 多线程问题

因为要视频视频播放的功能,所以我们还要学习一下python的多线程。

也不是很难,想具体了解的可以点击文末的参考资料。

2 完整代码

最后要放大招啦,准备好了吗?

完整的代码都在下面了,有需要自取哦。

#-*- coding:utf-8 -*-
from Tkinter import *
from PIL import Image, ImageTk
import threading
import imageio
import imutils
import time
import cv2

class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master,bg='black')
        self.pack(expand=YES,fill=BOTH)
        self.window_init()
        self.createWidgets()

    
    def window_init(self):
        self.master.title('welcome to video-captioning system')
        self.master.bg='black'
        width,height=self.master.maxsize()
        self.master.geometry("{}x{}".format(width, height))
       
    def createWidgets(self):
        # fm1
        self.fm1=Frame(self,bg='black')
        self.titleLabel=Label(self.fm1,text="video-captioning system",font=('微软雅黑',64),fg = "white",bg='black')
        self.titleLabel.pack()
        self.fm1.pack(side= TOP,expand=YES,fill='x',pady=20)

        # fm2
        self.fm2=Frame(self,bg='black')
        self.fm2_left=Frame(self.fm2,bg='black')
        self.fm2_right=Frame(self.fm2,bg='black')
        self.fm2_left_top=Frame(self.fm2_left,bg='black')
        self.fm2_left_bottom=Frame(self.fm2_left,bg='black')

        self.predictEntry=Entry(self.fm2_left_top,font=('微软雅黑',24),width='72',fg='#FF4081')
        self.predictButton=Button(self.fm2_left_top,text='predict sentence',bg='#FF4081',fg='white',font=('微软雅黑',36),width='16',command=self.output_predict_sentence)
        self.predictButton.pack(side=LEFT)
        self.predictEntry.pack(side=LEFT,fill='y',padx=20)
        self.fm2_left_top.pack(side=TOP,fill='x')

        self.truthEntry=Entry(self.fm2_left_bottom,font=('微软雅黑',24),width='72',fg='#22C9C9')
        self.truthButton=Button(self.fm2_left_bottom,text='ground truth',bg='#22C9C9',fg='white',font=('微软雅黑',36),width='16',command=self.output_ground_truth)
        self.truthButton.pack(side=LEFT)
        self.truthEntry.pack(side=LEFT,fill='y',padx=20)
        self.fm2_left_bottom.pack(side=TOP,pady=10,fill='x')

        self.fm2_left.pack(side=LEFT,padx=60,pady=20,expand=YES,fill='x')
        self.nextVideoImg= ImageTk.PhotoImage(file = '/home/hl/Desktop/lovelyqian/nextVideo.png') 

        self.nextVideoButton=Button(self.fm2_right,image=self.nextVideoImg,text='next video',bg='black',command=self.start_play_video_thread)
        self.nextVideoButton.pack(expand=YES,fill=BOTH)
        self.fm2_right.pack(side=RIGHT,padx=60)
        self.fm2.pack(side=TOP,expand=YES,fill="x")
        
        # fm3
        self.fm3=Frame(self,bg='black')
        load = Image.open('/home/hl/Desktop/lovelyqian/me.jpg') 
        initIamge= ImageTk.PhotoImage(load)  
        self.panel = Label(self.fm3,image=initIamge)  
        self.panel.image = initIamge  
        self.panel.pack()
        self.fm3.pack(side=TOP,expand=YES,fill=BOTH,pady=10)

    def output_predict_sentence(self):
        predicted_sentence_str='hello world.'
        self.predictEntry.delete(0,END)
        self.predictEntry.insert(0,predicted_sentence_str)

    def output_ground_truth(self):
        ground_truth='this is ground truth.'
        self.truthEntry.delete(0,END)
        self.truthEntry.insert(0,ground_truth)

    def start_play_video_thread(self):
        self.thread=threading.Thread(target=self.play_next_video,args=())
        self.thread.start()

    def play_next_video(self):     
        self.predictEntry.delete(0,END)
        self.truthEntry.delete(0,END)
        
        # to play video
        self.video_path='/home/hl/Desktop/lovelyqian/CV_Learning/video_to_sequence/video_to_sequence-master/data/youtube_videos/_0nX-El-ySo_83_93.avi'
        self.video=imageio.get_reader(self.video_path,'ffmpeg')
        for self.videoFrame in self.video:
            self.videoFrame=imutils.resize(self.videoFrame,width=1760,height=1080) # to do
            self.image=cv2.cvtColor(self.videoFrame,cv2.COLOR_BGR2RGB)
            self.image=Image.fromarray(self.image)
            self.image=ImageTk.PhotoImage(self.image)

            self.panel.configure(image=self.image)
            self.panel.image=self.image

            time.sleep(0.02)

if __name__=='__main__':
    app = Application()
    # to do
    app.mainloop()

最后

这可能是我博客参考资料最多的一次, 陆陆续续也做了将近一个工作周,转载请注明出处,谢谢~~

点个小赞就更开心啦啦啦啦~

参考文献

上一篇下一篇

猜你喜欢

热点阅读