使用python制作MODBUS RTU主站调试工具(一)—— GUI编程

0前言

我实际上并没有用过python进行GUI编程,按照我的C#窗体编程习惯,应该先布置GUI,再对各控件的具体功能进行编程,所以本文就先介绍GUI的python实现。

OS:win10 x64 1909
开发工具:VS Code
Python GUI 库:tkinter

1参考

首先当然是参考现成的modbus调试工具,这里以modscan32为例:
在这里插入图片描述
在这里插入图片描述
需要参考的地方有两块,一块是连接配置(省去硬件流控制),一块是modbus协议配置。

2控件选择

打开VS Code,首先先创建程序主体:

import tkinter as tk #导入Tkinter模块,Python3环境下首字母t小写
menu = tk.Tk()  #创建Tkinter主窗口
menu.title("MODBUS MASTER") #更改窗体标题
... #添加控件
menu.mainloop() #进入主循环

现在要添加控件,结合对modscan32的参考,这个小工具(至少)需要达成的配置内容有:

  1. 串口编号
  2. 波特率
  3. 字长度
  4. 奇偶校验
  5. 停止位
  6. 设备ID
  7. 从站地址
  8. 功能码
  9. 地址显示区显示长度
  10. 地址显示区

可以看到串口、波特率、字长度、奇偶校验、停止位、功能码都具备下拉框:
在这里插入图片描述

但实际上tkinter并没有combobox控件。在tkinter中有三个控件可以实现类似的效果,分别是checkbutton, Radiobutton 和 Listbox ,其中前者更适合二选一的情况,而后两者则适合于多选一的情况,就我个人觉得后两者在功能上并无太大不同,更多在美观性上考虑:

Radiobutton:

var = tk.IntVar()
MPT = [("01 COIL STATUS",1),("02 INPUT STATUS",2),("03 HOLIDING REGISTER",3),("04 INPUT REGISTER",4)]
for mptype, num in MPT:
    pointtype_list = tk.Radiobutton(text=mptype, variable=var,value=num)
    pointtype_list.grid() 

在这里插入图片描述

Tkinter 组件详解(四):Radiobutton

Listbox:

var = tk.StringVar()
var.set(("01 COIL STATUS","02 INPUT STATUS","03 HOLIDING REGISTER","04 INPUT REGISTER"))
pointtype_list = tk.Listbox(listvariable=var,height=4).grid()

在这里插入图片描述
注意有多个listbox的时候,选中其中一个控件中的内容后再选择另一个控件,会使之前选中的内容消失,可以通过修改exportselection属性来保持选中:

parity_enter = tk.Listbox(connect_group,listvariable=varp,height=3,exportselection=False) #exportselection=False

在这里插入图片描述
————
数据输入框可以使用label控件和搭配entry控件实现;
数据输出框可以使用label控件和搭配text控件实现;

3布局

tkinter共有3种布局方法:pack()、grid()和place():

方法含义
pack按添加顺序排列控件
grid按行列形式排列控件
place允许程序员指定控件的大小和位置

这里选用grid()方法,最直接的原因是pack()不支持在同一行布置两个控件,这会破坏画面的简洁性:

pack()方法:

deviceid = tk.Label(text = "device id:").pack()
deviceid_enter = tk.Entry().pack()

在这里插入图片描述
grid()方法:

deviceid = tk.Label(text = "device id:").grid(row=0,column=0)
deviceid_enter = tk.Entry().grid(row=0,column=1)

在这里插入图片描述
grid()方法的基本使用,参考:Tkinter 布局管理器(二):grid

4美观性

4.1组件跨行/列

在使用了grid()方法后,画面布局被分为两列(在本项目中),如果希望控件(如用于表示标题的控件)在两列中位于居中位置,可以使用columnspan实现,其值为所跨的列数:

title = tk.Label(text = "Modbus调试工具",font = 15).grid(row=0,columnspan=2) #columnspan=2 组件跨两列

跨列前:
在这里插入图片描述
跨列后:
在这里插入图片描述
————
同理可使用rowspan实现跨行。

4.2控件对齐

参考上一张图,label控件默认居中对齐,但在使用习惯中控件一般需要右对齐,在grid()方法中提供了对齐选项:
sticky = “e”/“w”/“s”/"n"

deviceid = tk.Label(config_group,text = "device id:").grid(row=2,column=0,sticky="E") #sticky="E" 右对齐

在这里插入图片描述

4.3控件间距调整

在默认情况下控件和控件之间严密贴合,仅留有少量空隙,在视觉上会给人造成一种拥挤感,在grid()中可设置控件间间距:

属性含义
ipadx指定水平方向上的内边距
ipady指定垂直方向上的内边距
padx指定水平方向上的外边距
pady指定垂直方向上的外边距

调整前:

start = tk.Button(config_group,text = "开始",width=10).grid(columnspan=2)

在这里插入图片描述
调整后:

start = tk.Button(config_group,text = "开始",width=10).grid(columnspan=2,pady=5) #pady=5 按钮组件垂直方向上的外边距为5

在这里插入图片描述

4.4控件分区

工具可分为两部分:数据输入域数据输出域
在这里插入图片描述

可以使用LabelFrame将数据输入域包裹起来:

config_group = tk.LabelFrame(text="设置栏") #边框注释
config_group.grid(row=1,columnspan=2,padx=10, pady=10)

LabelFrame是一种容器,可以存放各类控件,如果希望将指定控件移入容器内,需要修改该控件的父容器:

deviceid = tk.Label(config_group,text = "device id:").grid(row=2,column=0,sticky="E")#label组件位于LabelFrame(config_group)容器中

在这里插入图片描述

5样品展示

在这里插入图片描述

后续加入功能后GUI肯定会修改的。

附录 获取控件输入值/令控件输出值

如何获取在entry()、listbox()和radiobutton()控件中输入的值,并通过text()输出?

这里设计了一个小程序进行演示:

import tkinter as tk
window=tk.Tk()

#创建entry控件
e=tk.Entry(window)
e.pack()

#创建listbox控件
varw = tk.StringVar()
varw.set(("7","8"))
wlength_enter = tk.Listbox(listvariable=varw,height=2,exportselection=False)
wlength_enter.pack()

#创建radiobutton控件
var = tk.IntVar()
MPT = [("01 COIL STATUS",1),("02 INPUT STATUS",2),("03 HOLIDING REGISTER",3),("04 INPUT REGISTER",4)]
for mptype, num in MPT:
    pointtype_list = tk.Radiobutton(text=mptype, variable=var,value=num)
    pointtype_list.pack()

################核心代码##################
#获取控件值通过text控件输出
def entry_enter():
    var1=e.get() #获取控件输入值     
    t.insert('insert',var1)
def listbox_enter():
    var1 = wlength_enter.get(wlength_enter.curselection())  #获取控件输入值   
    t.insert('insert',var1)
def radiobutton_enter():
    var1 = var.get() #获取控件输入值    
    t.insert('insert',var1)

# 创建button控件
b1=tk.Button(window,text='entry',width=15,height=2,command=entry_enter)
b1.pack()
b2=tk.Button(window,text='listbox',width=15,height=2,command=listbox_enter)
b2.pack()
b3=tk.Button(window,text='radiobutton',width=15,height=2,command=radiobutton_enter)
b3.pack()

#创建text控件
t=tk.Text(window,height=2)     
t.pack()

window.mainloop()

画面中布置了3个按钮,按动不同的按钮,会将不同控件中的输入值输出到text中,这样设置的原因是程序似乎不支持实时输出 输入值,所以需要通过这种方法手动执行。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值