串网直通车——界面篇(Python+Tkinter)

阅读说明:

我本人使用的是VScode和Python3.8,是初学者,这是我Python学习的第一份作品。如评论有我不能回复的问题,请见谅。
本章节主要讲解界面如何构建,包括窗口和控件的显示布局,控件的操作事件等。代码中的 #引用 主要方便用于后续讲解插入相关代码,方便理解。
基于聚沙成塔的学习理念,将代码一步一步复制到自己的工程里测试,会更容易理解。
在这里插入图片描述
完整代码链接:
https://download.csdn.net/download/qq_34162147/54904655

1、主程序框架

init_window.mainloop()这条语句,在后续编程时,放在所有控件代码的最后,而且放在main函数内。这样才能保证所有控件一直显示。

from tkinter import *
from tkinter import ttk  # 导入ttk模块,因为下拉菜单控件在ttk中
from tkinter.scrolledtext import ScrolledText #带滚动条文本框

#引用1

def main():
    init_window = Tk()
    #引用2
    #引用3
    init_window.mainloop()#窗口一直展示
#引用16
if __name__ == "__main__":
    main()

2、窗口

以下代码放在 引用2 位置。
这代码主要是关于窗口的相关属性配置。对应更改对应的数据、路径、文字即可实现。
resizable如此设置后,窗口的最大化操作也会屏蔽。
geometry(‘800x400+200+100’) ,800x400是窗口大小,200+100是窗口在屏幕的位置,200是x轴横向,100是y轴纵向。

    #设置窗口
    init_window.geometry('800x400+200+100')      #窗口大小及位置
    init_window.resizable(0,0) #阻止Python GUI的大小调整
    init_window.iconbitmap("E:\\我才必用\串网直通车\\icon_arrow.ico")#窗口图标
    init_window.title('串网直通车V1.0')          #窗口名  

3、控件

3.1外框,LabelFrame控件

以下代码放在 引用3 位置。

    # 定义串口容器
    com_title = LabelFrame(init_window,text=" 串 口 接 收 区",labelanchor="n")
    com_title.place(relx=0.03, rely=0.03, relwidth=0.45, relheight=0.95)


     #引用4
   
   
    # 定义网口容器
    net = LabelFrame(init_window, text=" 网 口 接 收 区", labelanchor="n")
    net.place(relx=0.525, rely=0.03, relwidth=0.45, relheight=0.95)

     #引用5
     

3.2文字显示,Label控件
Label控件,可以是文字,可以是图片(后续讲解)。这部分代码,place后的参数,可以直接填数据。由于布局具有相关性,符合规律,所以使用了计算。布局还可以用grid。根据个人喜好处理。

以下代码放在 引用4 位置。

 	# 坐标计算基础值
    cbase_y=0.123 #纵坐标基础值
    cbase_x0=0.05
    cbase_x1=cbase_x0+0.06
    #标签
    title_com_num = Label(init_window, text="串口号")
    title_com_num.place(relx=cbase_x0, rely=cbase_y*1)

    title_com_rate = Label(init_window, text="波特率")
    title_com_rate.place(relx=cbase_x0, rely=cbase_y*2)

    title_com_check = Label(init_window, text="校验位")
    title_com_check.place(relx=cbase_x0, rely=cbase_y*3)

    title_com_bits = Label(init_window, text="数据位")
    title_com_bits.place(relx=cbase_x0, rely=cbase_y*4)

    title_com_stop = Label(init_window, text="停止位")
    title_com_stop.place(relx=cbase_x0, rely=cbase_y*5)

    title_com_show = Label(init_window, text="显   示")
    title_com_show.place(relx=cbase_x0, rely=cbase_y*6)

     #引用6

以下代码放在 引用5 位置。

    # 坐标计算基础值
    nbase_y0=0.123 #纵坐标基础值
    ny=1.2 #纵坐标偏移值
    nbase_y1=0.0615 
    nbase_x0=0.6
    nbase_x1=nbase_x0-0.045

    #标签
    title_net_num = Label(init_window, text="协  议")
    title_net_num.place(relx=nbase_x0, rely=nbase_y0*1)  
    local_IP = Label(init_window, text="本机 IP 地址")
    local_IP.place(relx=nbase_x0-0.02, rely=nbase_y0*(ny*1+1))
    local_port = Label(init_window, text="本机端口号")
    local_port.place(relx=nbase_x0-0.015, rely=nbase_y0*(ny*2+1))   
    opposite_IP = Label(init_window, text="远程 IP 地址")
    opposite_IP.place(relx=nbase_x0-0.02, rely=nbase_y0*(ny*3+1)) 
    opposite_port = Label(init_window, text="远程端口号")
    opposite_port.place(relx=nbase_x0-0.015, rely=nbase_y0*(ny*4+1))   

     #引用7

3.3图片显示,Label、PhotoImage控件
Label控件可以用于显示图片,但是需要结合PhotoImage使用。
此部分代码均有两张图片的定义。是用来替换使用,后续会讲解到。

以下代码放在 引用6 位置。

    # 指示灯
    com_light0 = PhotoImage(file="E:\我才必用\串网直通车\stop.png")
    com_light1 = PhotoImage(file="E:\我才必用\串网直通车\open.png")
    com_led = Label(init_window,image=com_light0)
    com_led.place(relx=0.05, rely=0.848)
     #引用8

以下代码放在 引用7 位置。

    # 指示灯
    net_light0 = PhotoImage(file="E:\我才必用\串网直通车\stop.png")
    net_light1 = PhotoImage(file="E:\我才必用\串网直通车\open.png")
    net_led = Label(init_window,image=net_light0)
    net_led.place(relx=0.55, rely=nbase_y0*7-0.013)
    #引用9

3.4下拉菜单,Combobox控件
Combobox控件属于tkinter下的ttk组件,在代码一开始时需要引入。详见1主程序框架代码

以下代码放在 引用8 位置。

    #串口参数
    init_com_num = ttk.Combobox(init_window,width=7,justify='center')
    init_com_num.place(relx=cbase_x1, rely=cbase_y*1)
    init_com_num['value'] = ('COM1','COM2','COM3','COM4','COM5','COM6')
    init_com_num.current(0)


    init_com_rate = ttk.Combobox(init_window,width=7,justify='center')
    init_com_rate.place(relx=cbase_x1,rely=cbase_y*2)
    init_com_rate['value'] = \
    ('300','600','1200','2400','4800','9600','19200','38400','43000','56000','57600','115200')
    init_com_rate.current(5)

    init_com_check = ttk.Combobox(init_window,width=7,justify='center')
    init_com_check.place(relx=cbase_x1 ,rely=cbase_y*3)
    init_com_check['value'] = ('NONE','ODD', 'EVEN')
    init_com_check.current(0)
    init_com_check.config(state=DISABLED)

    init_com_bits = ttk.Combobox(init_window,width=7,justify='center')
    init_com_bits.place(relx=cbase_x1, rely=cbase_y*4)
    init_com_bits['value'] = ('8', '7', '6')
    init_com_bits.current(0)
    init_com_bits.config(state=DISABLED)

    init_com_stop = ttk.Combobox(init_window,width=7,justify='center')
    init_com_stop.place(relx=cbase_x1, rely=cbase_y*5)
    init_com_stop['value'] = ('1', '2')
    init_com_stop.current(0)
    init_com_stop.config(state=DISABLED)

    init_com_show = ttk.Combobox(init_window,width=7,justify='center')
    init_com_show.place(relx=cbase_x1, rely=cbase_y*6)
    init_com_show['value'] = ('16进制','ASCII')
    init_com_show.current(1)
    init_com_show.config(state=DISABLED)
    #引用10

3.4单行文本框,Entry控件
Entry控件与text都是文本框。我在测试过程中,发现Entry在取值时比较可靠。text取值时发现取值到END,连空格都全部取完,无法仅仅获取有效的所有字符内容。后来更改使用entry后功能实现。
如有大神找到问题所在,麻烦告知,在此感谢!

以下代码放在 引用9 位置。

    #单行文本框
    net_treaty = Entry(init_window, width=16,font=('宋体',10),justify='center')  
    net_treaty.place(relx=nbase_x1, rely=nbase_y0*1+nbase_y1)
    net_treaty.insert(INSERT, 'U D P')
    net_treaty.config(state=DISABLED)
    local_IP_text = Entry(init_window, width=16,font=('宋体',10),justify='center')  
    local_IP_text.place(relx=nbase_x1, rely=nbase_y0*(ny*1+1)+nbase_y1)
    local_IP_text.insert(INSERT, '127.0.0.1')
    local_port_text = Entry(init_window, width=16,font=('宋体',10),justify='center')   
    local_port_text.place(relx=nbase_x1, rely=nbase_y0*(ny*2+1)+nbase_y1)
    local_port_text.insert(INSERT, '3311')
    opposite_IP_text = Entry(init_window, width=16,font=('宋体',10),justify='center')   
    opposite_IP_text.place(relx=nbase_x1, rely=nbase_y0*(ny*3+1)+nbase_y1)
    opposite_IP_text.insert(INSERT, '127.0.0.1')
    opposite_port_text = Entry(init_window, width=16,font=('宋体',10),justify='center')   
    opposite_port_text.place(relx=nbase_x1, rely=nbase_y0*(ny*4+1)+nbase_y1)
    opposite_port_text.insert(INSERT, '3322')
    #引用11

3.5带滚动条文本框,ScrolledText控件
ScrolledText控件与text都是文本框。text没有滚动条,如果用text加上scroll两个控件使用,达不到在文本框嵌入滚动条的效果。ScrolledText是内置滚动条的文本框,使用时很方便,而且可以让滚动条随显示更新。后续有讲解。
ScrolledText在使用时需要引入。详见1主程序框架代码

代码中END是指在最后输入位置,’\n’是回车。

以下代码放在 引用10 位置。

    # 文本框
    global com_text
    com_text = ScrolledText(init_window, width=25, height=24.5) 
    com_text.place(relx=cbase_x0+0.18, rely=cbase_y*1)
    com_text.insert(END,'\n''\n''\n''\n''\n''\n''\n''\n''\n''\n''\n')
    com_text.insert(END,'     很高兴遇见你!')
    #引用12

以下代码放在 引用11 位置。

    # 文本框
    global net_text
    net_text = ScrolledText(init_window, width=25, height=24.5)  
    net_text.place(relx=0.55+0.17, rely=nbase_y0*1)
    net_text.insert(END,'\n''\n''\n''\n''\n''\n''\n''\n''\n''\n''\n')
    net_text.insert(END,'     Nice to meet you!')
    #引用13

3.6按钮,Button控件
代码中的Button控件使用了StringVar。因为绑定了操作事件,用于操作时文字根据操作进行改变。

以下代码放在 引用12 位置。

    # 按钮
    com_var = StringVar()
    com_var.set("打开串口")
    com_sw=Button(textvariable=com_var,width=9)
    com_sw.place(relx=cbase_x1, rely=cbase_y*7)
    #引用14

以下代码放在 引用13 位置。

    # 按钮
    net_var = StringVar()
    net_var.set("打开网口")
    net_sw=Button(init_window,textvariable=net_var, width=9)  
    net_sw.place(relx=0.61, rely=nbase_y0*7)
    #引用15

4、控件绑定事件

界面中的控件可以绑定事件,常用的是按钮操作。按钮操作绑定事件时,可以传递参数。
注意,仅传递简单的参数。例如仅仅把图片label控件传递过去,然后更改图片,此操作不可行。所以采用了仅把图片和label控件一起传递过去进行操作。可能未找对方法,如有大神知道缘由,麻烦评论告知,在此感谢啦!

以下代码放在 引用14 位置。

    # 绑定操作事件
    com_sw.bind("<Button-1>",lambda event:com_ctrl(
        cn_var=com_var,cp_var=init_com_num.get(),cr_var=init_com_rate.get(),
        cl_var=com_led,p0=com_light0,p1=com_light1))

以下代码放在 引用15 位置。

    # 绑定操作事件
    net_sw.bind("<Button-1>",lambda event:net_ctrl(
        nn_var=net_var,lip_var=local_IP_text.get(),lp_var=local_port_text.get(),
        oip_var=opposite_IP_text.get(),op_var=opposite_port_text.get(),
        nl_var=net_led,p0=net_light0,p1=net_light1))

每个事件对应的函数,请查看1、主程序框架的对应引用位置。
事件函数与界面显示的main函数同级。
以下代码放在 引用16 位置。

# 串口打开关闭函数
def  com_ctrl(cn_var,cp_var,cr_var,cl_var,p0,p1):

    global com_state
    global com_text
    
    if cn_var.get() == "打开串口":
        com_state=1
        com_text.delete(1.0,END)#清空文本框
    else :
        pass

    if cn_var.get() == "关闭串口":
        com_state=0
        cn_var.set("打开串口")
        cl_var.configure(image=p0) 
    else:
        pass

    if (com_state==1) :
        cn_var.set("关闭串口")
        cl_var.configure(image=p1) 
    else:
        pass   


# 网口打开关闭函数
def  net_ctrl(nn_var,lip_var,lp_var,oip_var,op_var,nl_var,p0,p1):

    global net_text
    global net_state
    
    if nn_var.get() == "打开网口":
        net_state=1
        net_text.delete(1.0,END)#清空文本框
        nl_var.configure(image=p1) 
    else :
        pass


    if nn_var.get() == "关闭网口" :
        net_state=0
        nn_var.set("打开网口")    
        nl_var.configure(image=p0) 
    else:
        pass  


    if (net_state==1) :
        nn_var.set("关闭网口")
        nl_var.configure(image=p1) 
    else:
        pass  

加入后的代码架构如下图所示。
在这里插入图片描述

5、测试

点击“打开串口”按钮和“打开网口”按钮,按钮文字改变,旁边的指示灯会改变。再次点击,指示灯随之改变。如下图所示。
在这里插入图片描述

6、拓展

我在学习过程,参考资料太多了,有合适的有不合适的,有的代码有错误的不能直接用。经过我的过滤测试,认为比较好的主要参考是以下网址,非常感谢前辈们的贡献,也推荐给大家进一步学习探究。
真希望有一个全面而且快捷搜索所需内容的地方。这也是我写这篇文章的初衷,希望对大家有用。

python图形GUI基本示例
https://www.cnblogs.com/cdxing/p/7147133.html

tkinter库最全使用教程
https://blog.csdn.net/qq_46018418/article/details/105927203

Python的GUI编程(二)Button(按钮)
https://blog.csdn.net/m0_37264397/article/details/79059381

Python-Tkinter 窗口组件之Text
https://www.jianshu.com/p/bf3b49c66801?from=singlemessage

【tkinter-Scrollbar】下面的两个文本框该如何添加滚动条
https://fishc.com.cn/thread-141148-1-1.html

python Tkinter事件绑定,参数传递
https://www.cnblogs.com/liyuanhong/articles/10718217.html

python tkinter(二) 下拉框(combobox)组件的属性说明及示例
https://liushipeng.blog.csdn.net/article/details/102563786

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值