图形用户界面(GUI)开发教程

news2024/11/15 21:56:17

文章目录

  • 写在前面
  • MATLAB GUI启动方式
  • 按钮(Push Button)
    • 查看属性
    • `tag`的命名方式
    • 回调函数
    • 小小的总结
  • 下拉菜单(Pop-up Menu)
  • 单选框(Radio Button)和复选框(Check Box)
  • 静态文本(Static Text)和可编辑文本(Edit Text)
  • 轴(Axes)
  • 组(Group)
  • 进度条(Progress Bar)
  • GUI设计成品
  • 最后

写在前面

图形用户界面(Graphic user interface,GUI),实际上就是人与计算机交互的界面显示格式。广义来说,现在正在看这篇文章使用的浏览器,也是一个GUI。阅读者可以通过这个浏览器获取信息,可以点击“最小化”、“窗口”和“关闭”按钮实现自己想要的功能,可以阅读浏览器中的文字。

我们常说的做个“软件”,其实大概率是做一个实现与后端算法交互的界面。因为绝大多数用户看不懂后端代码,但又想使用这个算法实现自己想要的功能,所以做一个简明、整洁、易用、美观的GUI,对于提升后端算法的适用性是十分有必要的。

总不可能开发一个项目,把算法写好之后,直接给用户,说:“喏,这就是你想要的功能,你简简单单改几个参数就可以实现你想要的功能啦!”显然是不可行的。用户看见代码的时候只会感到头脑眩晕,开始抗拒,并且怀疑我们的代码能力到底行不行?

举个例子。

程序员小雷写了一套卡尔曼滤波算法,交付给用户的时候,是这样的:

mode = 'IF'; 
% mode = 'UD';
% mode = 'FD';
% mode = 'FT1';
% mode = 'FT2';

和用户说,“想要用信息滤波就取消mode = 'IF'的注释就可以啦!”

“想要用UD滤波就取消mode = 'UD'的注释就可以啦!”

……

“但别忘记把其他不想用的滤波算法给注释掉噢,不然会出bug的!”

用户听完小雷的介绍之后说不定就已经头脑发昏,也不知道什么算法要注释哪行代码了。

或者更加极端一点,小雷写代码也不规范,变量名乱写,比如这样:

aaa = '1';
% aaa = '2';
% aaa = '3';
% aaa = '4';
% aaa = '5';

天知道哪行对应哪个滤波算法啊!!

但如果写一个GUI呢,比方像下面这样简单的选择框:

在这里插入图片描述
是不是清楚好多?

用户也不用自己翻开后端算法的代码看来看去了,那样看半天说不定也看不出来门道。现在用户想要用什么滤波模式,自己选择想要的滤波模式,然后点击确定就可以啦。

不过这样的界面还没有满足用户的需要。

假如用户想自己改算法参数呢?想改改仿真时长啊初始状态啊噪声矩阵啊……上面的选择框显然没有提供合适的地方让用户可以改算法参数。

所以小雷又重新设计了一下界面,把它改成了下面这样:
在这里插入图片描述
现在给用户的选项可丰富啦。可以选择滤波模式,可以选择是否保存图片、数据,可以修改仿真参数,还可以显示不同滤波算法的核心原理公式,给用户直观的感性认识。广义来说这样就可以当作一个软件来用啦。

用户感到很满意。

所以,这样的界面怎么开发呢?

下面根据自己的实战经验,给出开发GUI的完整流程,或许会少掉一些控件不作介绍,因为觉得在自己开发过程中没有使用这些控件。但我觉得控件的使用方法大同小异,核心逻辑掌握之后,换另外一个控件只需要自己在网上搜索一下经验学习一下,很快就能掌握。

先说明,这里说的GUI全部指的是MATLAB 2018版本上的GUI,MATLAB后续版本中推出了APP功能,将原来的GUI替代了。但本人常用的软件还是MATLAB 2018,所以写的都是MATLAB 2018上GUI开发的教程。至于其他真的像个“软件”一样的教程,请见《PyQt5+Anaconda+PyCharm安装、配置和使用》(https://blog.csdn.net/Ruins_LEE/article/details/116279032)。使用QT可以做一个像“软件”的软件出来了。

下面是整篇教程的顺序:

  • MATLAB GUI启动方式;

  • 按钮:

    • 查看属性;
    • 回调函数;
  • 下拉菜单;

  • 单选框和复选框;

  • 静态文本和可编辑文本;

  • 轴;

  • 组;

  • 进度条;

  • GUI源代码。

MATLAB GUI启动方式

打开MATLAB,在命令行输入

guide;

得到下图所示界面。
在这里插入图片描述
这里我们选“新建 GUI”,点击第1项“Blank GUI (Default)”,选好要保存的位置后,点击“确定”。

之后会出现一个新的界面,如图所示。

在这里插入图片描述
按照图片中的分区一一介绍功能。

  1. 分区“1”中常用的按钮是最后一个绿色三角形,用于设计好GUI后运行,查看效果。其他的按键不常用,不用花费精力在上面。
  2. 分区“2”是控件区,给出了MATLAB GUI中可以使用的控件。我们在设计GUI时,常用的控件主要有(按照从上往下、从左往右的顺序):
    • 按钮;
    • 单选按钮;
    • 复选框;
    • 可编辑文本;
    • 静态文本;
    • 下拉菜单;
    • 轴;
    • 组;
      后面的内容里会一一介绍。
  3. 分区“3”说明了该GUI的标签(tag),在句柄(handles)操作中会用到。
  4. 分区“4”说明了当前鼠标的在GUI中的位置和选中控件的位置与尺寸。
    • 当前点: [369,451]意为鼠标在距离GUI(用figure1更加准确,但出于文章易读性考虑,使用GUI更易理解。后面提到的GUI均为figure1之义。)最左侧369像素、最下侧451像素的位置;
    • 位置: [760, 584, 567, 630]意为选中控件在距离父对象1最左侧369像素、最下侧451像素的位置;尺寸大小为宽度567像素、长度630像素。

按钮(Push Button)

查看属性

在功能区中选中“按钮”的标签,将其拖进GUI中。

在这里插入图片描述
第1步和第2步很简单,第3步需要左键双击“按钮”,弹出来“检查器”窗口。

检查器很重要啊,绝大部分操作都是在检查器里面完成的。
在这里插入图片描述
检查器有2种查看方式,在红框里面标出来了。第1种是按照功能分类列好,第2种是按照字母顺序列好。这里推荐使用第1种方式查看按钮的属性。需要关注的属性不多,只有4种,分别是:

  • Appearance:设定按钮的外观,比如背景颜色和文字颜色;
  • Font Style:设定按钮字体风格;
  • Identifiers:设定该按钮的标识,也就是tag
  • Text:设定按钮显示的内容。

把按钮美化一下,可以得到下图这样的按钮风格。

在这里插入图片描述
其余控件都是这样设置,在这里用按钮作为例子讲解一下,后面介绍其他控件的时候不再赘述。

tag的命名方式

多提一嘴tag这里该怎么设置。

将按钮拖进GUI后,tag默认为pushbutton1。这个tag不好,没有辨识度,将来控件多了之后不知道哪个tag对应哪个功能了,所以需要加上标识,方便以后阅读代码。

我自己的习惯是用下划线法命名tag,即“功能_控件标识”,这里按钮的tagsimu_btn,意思就是用于实现仿真的按钮。

其余控件命名原则如下:

  • 下拉菜单:xxx_ppmenu
  • 单选框:xxx_rbtn
  • 复选框:xxx_cbox
  • 静态文本:xxx_txt
  • 可编辑文本:xxx_edit
  • 轴:xxx_axes
  • 组:xxx_group

回调函数

选中按钮,单击右键,选中“查看回调”,再选中“Callback”,在MATLAB中会生成对应的回调函数。

在这里插入图片描述
MATLAB中会显示下图所示的代码。
在这里插入图片描述
这个功能很重要。

是实现所有我们想要开发功能的地方。因为一开始自己对GUI也是一头雾水,不知道要用GUI实现功能的话,要在什么地方写自己的逻辑。后来查了资料之后才知道——噢,要在回调函数里面写逻辑啊~

其他控件的逻辑也都是在相应的回调函数里面写,这点不要忘记,后面就不再提其他控件的回调函数怎么弄出来了。

小小的总结

总结一下,按钮(包括其他控件)的使用步骤分为3步:

  1. 将要用的控件拖进GUI中;
  2. 打开该控件的检查器,根据需要设置属性;
  3. 编写回调函数。

下拉菜单(Pop-up Menu)

下拉菜单和下拉列表(Listbox)作用差不多,但是下拉菜单更加节省空间。在项目GUI设计中,个人习惯用下拉菜单实现多个选项的逻辑。

它在GUI里面长这样:

在这里插入图片描述
图中的“选项1”、“选项2”、“选项3”和“选项4”要在检查器中设置。

在这里插入图片描述
也就是text中的string属性,一个选项一个回车键,这样就可以排列好。

设置好弹出式菜单的选项之后,很重要的一步就是怎么读弹出式菜单的选项?

代码在这里:

mode_flag = get(handles.filter_ppmenu,'value');

通过get()函数就可以取到弹出式菜单的值啦。这里我给这个弹出式菜单设的tagfilter_ppmenu,代码的意思就是获得句柄为filter_ppmenu的值(value)。

得到弹出式菜单的值之后,可以用switch()函数来选择相应的操作,代码如下:

switch mode_flag
	case 1
		% 想要实现的功能
	case 2
		% 想要实现的功能
	case 3
		% 想要实现的功能
	case 4
		% 想要实现的功能
	case 5
		% 想要实现的功能
end

注意哈,mode_flag=1的时候,实际上就是默认选项的值,也就是弹出式菜单这个选项的值。mode_flag=2开始才是真正要选的选项的值,这一点很容易出错,要记住。

如果怕出错,可以在第1行不要弄什么弹出式菜单这样的值,直接写要选的选项就好。

单选框(Radio Button)和复选框(Check Box)

单选框是一个圆圆的可以选中的按钮,通常用来实现与其他功能互斥的选择功能。

复选框是方方正正的样子,通常用来实现多种功能选择的组合。

一般单选框选中之后就没法儿取消,或者选择这个选项之后,其他被选中的功能被取消;复选框则是选中这个功能之后,还可以继续选择其他的功能,而且被选中的功能是可以取消的。

它们长下图这样。

在这里插入图片描述
这俩框没有什么复杂的,要记住的地方就是它们在GUI中的作用就是获取它们的值。除了这个作用之外,其他的作用还没开发出来。

代码为:

% 单选框获取值的方式
xxx_rbtn_flag = get(handles.xxx_rbtn,'value');
% 复选框获取值的方式
xxx_cbox_flag = get(handles.xxx_cbox,'value');

静态文本(Static Text)和可编辑文本(Edit Text)

静态文本通常显示固定不动的标签,可编辑文本可以用来输入参数,这是两者功能的区别。它们俩分别长下面这样。

在这里插入图片描述
静态文本放在GUI里就不用动了,可以不去管它,要管的是可编辑文本。

获取可编辑文本中的文本,代码为:

xxx_edit_str = get(handles.xxx_edit,'string');
xxx_edit = str2double(xxx_edit_str);
% xxx_edit = str2num(xxx_edit_str);

这里的属性不能用value,要用string,因为得到是可编辑文本中的字符(string)。

如果要使用可编辑文本中的数值,需要先将字符转换为数值,用str2double()或者str2num()实现。

也可以设置可编辑文本中的值,一种方法是直接在可编辑文本框里设置,另外一种方式可以写代码,为:

set(handles.xxx_edit,'string','Hello, world!');

这样就可以设置可编辑文本的代码了。

轴(Axes)

轴,通常用来画仿真曲线图或者插入图片。

在这里插入图片描述
在之前的项目中用轴画过算法仿真曲线,代码为:

axes(handles.xxx_axes);
plot(xxx);

如果要清除轴上的图,可以用下面的代码。

axes(handles.xxx_axes);
cla;

可以看到不论是画仿真结果还是清除结果都要先用axes(handles.xxx_axes),这行代码意思是指定对应的轴。如果一个GUI中有很多轴的话,不指定对应的轴,那么GUI就不知道该在哪个轴上进行操作了。

轴的另一个用处是插入图片,代码为

axes(handles.xxx_axes)
image(imread('xxx.png'));
axis off;

第一行代码是指定对应的轴。

第二行代码是插入对应的图片。

第三行代码是取消轴的坐标轴显示。

这里我遇见了一个还没有解决的问题,就是在xxx_axes_CreateFcn()里写上面的代码的时候,再一次打开GUI的.fig文件,这个轴对应的tag就会消失不见,假如在其他控件下的Callback()里写上面的代码就不会出现这样的问题。

所以,可以用轴插入图片,给GUI做一个背景。先提前规划好GUI各个部分的用处,用PS做一个简单的背景,比如下面这样。

在这里插入图片描述
要比没有背景的GUI好看一些吧?可以花些巧思在绘制背景上,这样能够提升GUI的美观程度。

组(Group)

组,通常用来容纳其他的控件,可以把实现同一作用或实现同一对象功能的控件全部放在一个组里。在操作过程中,只需要对组进行操作即可。

在这里插入图片描述
组a.k.a.面板,长上面那个样子,一个对象一个组,多个对象多个组。这样可以提高效率,不必每个对象都再重新调整一遍控件,初始的组调好之后,后面的组只需要ctrl+c,ctrl+v即可。

进度条(Progress Bar)

进度条起一个提示作用,告诉用户现在算法进行到哪一步了,还有多久结束,让用户心里有数,不用着急。

进度条是一个很重要的控件!

没有进度条,用户都不知道算法的状况,可能等得不太耐烦了,把GUI关了。但是这样容易让电脑崩溃。

就连我们在生活里面做很多事情,假如没有进度条,也不知道这件事情到底在什么情况了,很容易放弃。

使用进度条的代码是:

h = waitbar(1,'算法仿真中......','name','目标跟踪仿真软件');

在这里插入图片描述
对上面的代码进行解释。

  • 1代表进度条被全部占满;
  • '算法仿真中......'代表进度条中间显示的文字;
  • name','目标跟踪仿真软件'代表进度条左上角显示的文字。

如果想让进度条显示百分比的话,可以用下面的代码:

h = waitbar(0,'算法仿真中......','name','目标跟踪仿真软件');
for i = 1:nt-1
	per_str = fix(i/nt*100);
	str = ['算法仿真中......',num2str(per_str),'%'];
	waitbar(i/nt,h,str);
end
close(h);

如果想简单一点,不用显示百分比,就让进度条动起来的话,用下面的代码:

h = waitbar(0,'算法仿真中......','name','目标跟踪仿真软件');
for i = 1:nt-1;
	waitbar(i/nt);
end
close(h);

close(h)代表关闭句柄为h的进度条,不然之后画图的时候会错画到进度条上,或者出现其他奇奇怪怪的错误。

GUI设计成品

好啦,该教的知识都已经教过了,下面开始实战吧!

下面这个GUI是添加了亿点点细节的成品,请看vcr。

在这里插入图片描述
源代码放在这里,大家按需取用,https:\luwin1127.github.io\assets\download\files-2024-01-22\MainGUI_Filter_Release_v1.0.zip。我的MATLAB是MATLAB 2018b版本,其他版本不保证能正常使用。

这个GUI实现的功能有:

  • 多种滤波方式的选择功能,包括:
    • 信息滤波;
    • UD滤波;
    • 遗忘滤波;
    • 自适应遗忘滤波。
  • 滤波器和目标状态参数输入功能。
  • 保存数据功能;
  • 保存仿真结果图功能;
  • 根据不同的滤波算法显示相应的滤波公式功能;
  • 进行仿真功能;
  • 退出软件功能。

保存数据功能可以实现带当天日期和不带当天日期两种格式,如下图所示。

在这里插入图片描述
这样就实现了不同滤波算法,不同时间下仿真的数据保存。

保存图片功能得到的图如下图所示。

在这里插入图片描述
按照不同滤波器和不同功能将仿真结果保存下来了。

将GUI所在的文件夹进行了适当美化,按照不同功能,将文件存于不同的文件夹,如下图所示。
在这里插入图片描述
这样不至于让用户打开GUI时看见文件夹很乱,干干净净的,比较美观,而且这样写代码也比较优雅。

最后

欢迎通过邮箱联系我:lordofdapanji@foxmail.com

来信请注明你的身份,否则恕不回信。


  1. 父对象,在我的理解中意思就是其他的控件都依存该对象存在,比如说有一个组,组里有两个按钮,那么该按钮显示位置就是在组里的坐标。组又依存于GUI之上,那么组的位置就是在GUI中的坐标。 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将vue组件发布成npm包

文章目录 前言一、环境准备1.首先最基本的需要安装nodejs,版本推荐 v10 以上,因为需要安装vue-cli2.安装vue-cli 二、初始化项目1.构建项目2.开发组件/加入组件3. 修改配置文件 三、调试1、执行打包命令2、发布本地连接包3、测试项目 四、发布使用1、注册…

开源客户沟通平台Chatwoot账号激活问题

安装docker docker-compose 安装git clone https://github.com/chatwoot/chatwoot 下载之后根目录有一个docker-compose.production.yaml将其复制到一个目录 重命名 docker-compose.yaml 执行docker-compose up -d 构建 构建之后所有容器都安装好了 直接访问http://ip:3…

基于 Docker 部署 Pingvin Share 文件共享平台

一、Pingvin Share 介绍 Pingvin Share 简介 Pingvin Share 是自托管文件共享平台,是 WeTransfer 的替代方案。 Pingvin Share 特点 在 2 分钟内启动您的实例使用可通过链接访问的文件创建共享没有文件大小限制,只有你的磁盘是你的限制设置共享到期时间…

Mysql全局优化

Mysql全局优化总结 从上图可以看出SQL及索引的优化效果是最好的,而且成本最低,所以工作中我们要在这块花更多时间。 补充一点配置文件my.ini或my.cnf的全局参数: 假设服务器配置为: CPU:32核内存:64GDIS…

highcharts.css文件的样式覆盖了options的series里面的color问题解决

文章目录 一、问题背景二、解决问题 一、问题背景 原本的charts我们的每个数据是有对应的color显示的,如下图: 后面我们系统做了黑白模式,引入了highcharts的css文件,结果highcharts的css文件中class的颜色样式覆盖了我们数据中的…

vue打包后与本地测试样式不同问题,element-ui样式打包部署前后样式不同。

个别文件的样式中<style>未加scope。 查找到一些文件中修改了对应页面的elementUI的样式&#xff0c;但未加scope 给<style>加上scope&#xff0c;就好了。

shell脚本登录dlut-lingshui并设置开机连网和断网重连

本文提供了一个用于无图形界面linux系统自动连接dlut-lingshui校园网的shell脚本&#xff0c;并提供了设置开机联网以及断网重连的详细操作步骤。本文的操作在ubuntu 22.04系统上验证有效&#xff0c;在其他版本的linux系统上操作时遇到问题可以自行百度。 1. 获取校园网认证界…

面试题之RocketMq

1. RocketMq的组成及各自的作用&#xff1f; 在RocketMq中有四个部分组成&#xff0c;分别是Producer&#xff0c;Consumer&#xff0c;Broker&#xff0c;以及NameServer&#xff0c;类比于生活中的邮局&#xff0c;分别是发信者&#xff0c;收信者&#xff0c;负责暂存&#…

C#学习(十)——WPF重构与美化

一、Entity Framework Core 特点&#xff1a;【跨平台】&#xff0c;【建模】&#xff0c;【查询、更改、保存】&#xff0c;【并发】&#xff0c;【事务】&#xff0c;【缓存】&#xff0c;【数据迁移】 EF的组件 二、重构&#xff1a;构建数据模型 项目延续C#学习(九)的 项…

【GitHub项目推荐--生成你的马赛克风格头像】【转载】

这个开源项目有意思&#xff0c;这是一个利用各种其他更小的图像来创建新图像的工具&#xff0c;小的图像包括圆圈、线条、波浪、十字绣、积木、Minecraft 积木、回形针、字母等&#xff0c;所以通过这些小图像开生成的新图像的可能性是无限的。 所以&#xff0c;它与其他马赛…

微信小程序(十四)分包和分包预加载

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.分包的配置 2.分包预加载的写法 先说说为什么需要分包&#xff1a; 小程序追求小而快&#xff0c;主包的大小控制是小程序上线的硬性要求&#xff0c;分包有利于小程序优化加载速度 分包的注意事项&#xff1a; 单个分…

Sulfo-Cy3-dCTP,Sulfo Cyanine3 dCTP,能够发出高强度的荧光信号

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;Sulfo-Cy3-dCTP&#xff0c;Sulfo Cyanine3 dCTP&#xff0c;磺化-Cy3-dCTP&#xff0c;Sulfo-Cyanine3-dCTP 一、基本信息 产品简介&#xff1a;Sulfo Cy3 dCTP, a water-soluble cyanine dye CY3 labeled dCTP, i…

链表OJ---排序链表

https://leetcode.cn/problems/7WHec2/description/ //合并 struct ListNode* merge_link(struct ListNode* head1, struct ListNode* head2) {struct ListNode* temhead malloc(sizeof(struct ListNode));temhead->val 0;struct ListNode *tmp temhead, *cur1 head1, *…

Endnote中文献数据库的整体导出迁移,以及导入到新计算机具体步骤-以Endnote X8为例

Endnote中文献数据库的整体导出迁移&#xff0c;以及导入到新计算机具体步骤-以Endnote X8为例 在学习和研究中&#xff0c;有时会使用文献管理工具Endnote会积累一些重要的文献&#xff0c;当对某个问题进行了深入研究后&#xff0c;可能会积累成百上千的文献及其文献批注等。…

【GitHub项目推荐--网站归档平台】【转载】

ArchiveBox&#xff1a;网站归档平台 ArchiveBox 是基于 Python 的强大网页归档解决方案&#xff0c;可以自动把网页变成静态页面&#xff08;HTML、PDF、图片&#xff09;&#xff0c;并自动提取和保存文本、音频等内容&#xff0c;可以用来做镜像站、档案馆、离线阅读等。 开…

笔记本外接显示器的配置方法

目录 第一步 点击左下角&#xff0c;选择“设置” 第二步 选择系统&#xff0c;默认进入屏幕页面&#xff0c;页面往下拉&#xff0c;找到多显示器下拉框 前提&#xff1a;插好显示器的电源插头且插上笔记本HDMI线 第一步 点击左下角&#xff0c;选择“设置” 第二步 选择系…

探索 XMLHttpRequest:网页与服务器的异步通信之道(上)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

gin路由篇

1. 基本路由 gin 框架中采用的路由库是基于httprouter做的 import ("net/http""github.com/gin-gonic/gin" )func main() {// 1.创建路由r : gin.Default()// 2.绑定路由规则&#xff0c;执行的函数// gin.Context&#xff0c;封装了request和responser.…

C++内存泄漏检测工具

在程序中增加相应的内存检测工具 #define CRTDBG MAP ALLOC #include <stdlib.h> #include <crtdbg.h> #ifdef DEBUG #ifndef DBGNEW #define DBG_NEW new (_NORMAL_BLOCK&#xff0c;_FILE_LINE_) #define new DBG NEW #endif #endif _CrtDumpMemoryLeaks(); …

linux条件判断练习

1.实现自动生成相应的压缩包 1.写一个脚本&#xff0c;完成如下功能 传递一个参数给脚本&#xff0c;此参数为gzip、bzip2或者xz三者之一&#xff1b; (1) 如果参数1的值为gzip&#xff0c;则使用tar和gzip归档压缩/etc目录至/backups目录中&#xff0c;并命名为/backups/etc-…