038_High_Level_Skip_in_Matlab中的高端跳过循环

ops/2024/11/25 6:16:32/

在这里插入图片描述

循环控制

Matlab的循环控制语句有两个,分别是forwhilefor循环是一种计数循环while循环是一种条件循环。在循环中,有时候我们需要跳过一些循环,这时候就需要用到continue语句;当我们需要提前结束循环,这时候就需要用到break语句或者return语句。

for_5">for循环

Matlab的for循环基本语法如下。

matlab">for column = Columns% for each column of Columns, do the following% ...if needsToBreakbreakendif needsToReturnreturnendif needsToSkipFollowingcontineend
end

循环过程中,有三种控制循环的方式,其中break直接跳到end的外面;return(在函数里)直接跳出函数;continue则忽略接下来到end的所有代码,进入下一个列的循环

值得注意的是,for循环循环数组的列。1:10是一个行向量,所以for i = 1:10循环10次,i从1到10;如果for c = CC是一个矩阵,那么就是循环C的每一个列。

matlab">for i = magic(3), disp(i), end834159672

while_47">while循环

这个循环语法则更为简单,也更加本质。

matlab">while conditionExpression    if needsToBreakbreakendif needsToReturnreturnendif needsToSkipFollowingcontineend
end

首先检测表达式conditionExpression是否为真,否则跳到对应的end之后。在这个循环体重,同样可以采用break/return/contine进行中断和跳过的操作。

这两种低级的操作太没有水准,今天我们必须高一点高端的跳过循环的操作。

高端的跳过之一

这个实现这样的功能,后台计算过程中,有一个进度条,提示计算的当前步骤,提供一个按钮来发送跳过当前步骤的提示,然后的命令窗口进行确认。

在这里插入图片描述

这个界面上有一个按钮,这个按钮的文字我还没找到办法修改,按照道理,应该可以找到一个Childeren,改掉那啥…

每次点击取消,就可以把控制权切换到命令行窗口,确认跳过,继续运行。
在这里插入图片描述

这个代码里面有几个有意思的函数:

  • waitbar,产生一个等待进度条窗口,是传统基于Figure的界面的一部分
  • setappdata/getappdata,把数据存储在图形对象中,用一个字符串作为索引,邪路
  • commandwindow把焦点放回命令行窗口,是个很实用的函数
  • gcbf返回回调函数调用的对象,比如delete(gcbf)删掉回调函数对应的图形对象
  • pause,暂停运行若干时间,函数是一个浮点数,则为暂停的秒数

这里就是一个典型的while循环continue跳过部分代码继续运行。从这里也可以看到,恰面的break代码的判断部分,很容易就在while的表达式中隐含。所以,breakfor循环中是刚需,在while中有可能简化合并。

  • 源代码
matlab">function skipExamplecleanObj = onCleanup(@cleanAll);hWaitbar = waitbar(0, 'Iteration 1', 'Name', 'Solving problem', ...'CreateCancelBtn', @(~,~)fcn);hWaitbar.CloseRequestFcn = @(~,~)cleanAll;setappdata(hWaitbar, 'skip', false);n = 3;
i = 0;
trywhile(ishandle(hWaitbar))if getappdata(hWaitbar, 'skip')setappdata(hWaitbar, 'skip', false);% for keyboard conformation to continuefprintf("%d   - skip this round, ", i)fprintf("Press any key to continue...")commandwindow; % switch to command windowpause % delete to just run throughfprintf("\n");continue;end% pretent to calculate sthpause(0.5)i = i + 1;waitbar( mod(i, n) / (n-1),  hWaitbar,  ['Iteration ' num2str(i)]);end
catch MEfprintf("%s: %s\n", ME.identifier, ME.message);cleanAll;
end
endfunction cleanAll
delete(gcbf);
endfunction fcn
setappdata(gcbf, 'skip', true);
end

这里的整个都很丑,还会因为这样那样的情况无法暂停导致窗口关不掉,用close all也不行,因为,handleVisibility='off'。这个时候就需要下面这个大杀器,干掉所有窗口,一旦你走上用Matlab编GUI程序的邪路,就会发现下面这两个语句的魅力!

matlab">set(groot,'ShowHiddenHandles','on')
delete(get(groot,'Children'))

太丑不能忍之后的考虑

因为要用同一个按钮(右上角 × \times ×)来完成两个职责:跳过和退出,造成了上面那个例子所有的混乱,窗口的关闭和句柄删除会干扰程序的逻辑。这就告诉我们,在设计GUI是一定要好好分析业务逻辑,一个界面元素(一组界面元素)应该有内聚性很高的职责,也就是只做一件事情。

出于这个考虑,我们又设计了下面的例子,这里,取消按钮和右上角的关闭按钮,都按照原有的语义,负责关闭进度条,取消/停止计算任务。那么跳过怎么办呢?我们不能用Ctrl-C来完成,因为这个快捷键有很高的优先级,会中止正在进行的计算。

那么我们设置一个快捷键,Ctrl-K来跳过一步计算。这里的关键就是给进度条设置监控键盘事件的回调函数。

matlab">f.KeyReleaseFcn = @skipABeat;function skipABeat(src, evt)if ismember('control', evt.Modifier) && evt.Key == 'k'setappdata(src, 'skip', true);end
end

基本上,基于Figure或者基于UiFigure的GUI程序的回调函数都至少包含两个基本的参数,一个是发出消息的来源,一个是事件对象。对于键盘事件就是一个KeyData数据结构:

matlab">KeyData - 属性:Character: 'k'Modifier: {1x0 cell}Key: 'k'Source: [1x1 Figure]EventName: 'KeyRelease'

上面这个对象,很容易得到,我们只需要运行这个,然后把焦点放在图窗上,按动键盘就可以得到实际拿到的事件对象是什么样子的。这是GUI编程中一个很重要的思路:因为系统可以运行,所以想要什么信息就要构造程序来获得。

matlab">f = figure;
f.KeyReleaseFcn = @(src, evt)disp(evt)

大概就是这样的,所以我们可以判断是否按下了k,是否同时按着control

这个GUI就让人满意很多,因为概念上更加清晰,就不需要打那么多补丁。

  • 源代码
matlab">function skipExample3f = waitbar(0,'1','Name','Approximating pi...',...'CreateCancelBtn','setappdata(gcbf,''canceling'',1)', ...'Position', [0, 0, 480, 360]);movegui(f, 'center');f.KeyReleaseFcn = @skipABeat;setappdata(f,'canceling',0);% Approximate pi^2/8 as: 1 + 1/9 + 1/25 + 1/49 + ...
pisqover8 = 1;
denom = 3;
valueofpi = sqrt(8 * pisqover8);steps = 20000;
for step = 1:steps% Check for clicked Cancel buttonif getappdata(f,'canceling')breakendif getappdata(f, 'skip')fprintf("Skip step = %d\n", step);setappdata(f, 'skip', false);continueend% Update waitbar and messagewaitbar(step/steps,f,sprintf('%12.9f',valueofpi))% Calculate next estimate pisqover8 = pisqover8 + 1 / (denom * denom);denom = denom + 2;valueofpi = sqrt(8 * pisqover8);
enddelete(f)
endfunction skipABeat(src, evt)if ismember('control', evt.Modifier) && evt.Key == 'k'setappdata(src, 'skip', true);end
end

总结

  1. 两种循环方式,forwhile
  2. break/return/continue控制循环提前结束和跳过
  3. for循环中使用break更加自然
  4. while循环中使用break的条件可以合并到while表达式中
  5. 设计UI的过程中,一定要考虑清楚每个元素的职责,不要让一个元素负责多个职责

http://www.ppmy.cn/ops/136498.html

相关文章

【Unity How】Unity中如何实现物体的匀速往返移动

直接上代码 using UnityEngine;public class CubeBouncePingPong : MonoBehaviour {[Header("移动参数")][Tooltip("移动速度")]public float moveSpeed 2f; // 控制移动的速度[Tooltip("最大移动距离")]public float maxDistance 5f; // 最大…

DataGrip 连接 Redis、TongRDS

连接 Redis 或 TongRDS 有些旧版本 没有 redis 驱动用不了 1)选择驱动 2)添加连接信息 3)测试连接 4)保存连接 5)使用案例

【阵列信号处理】相干信号和非相干信号生成

文章目录 一、总结二、知识点相干(coherent)和非相干(incoherent)信号相干信号生成代码 相关信号(correlated signal)相关信号生成代码 正交信号定义 本文记录博主的科研日记。如果对博主的其他文章感兴趣&…

uni-app 玩转条件编译:自定义平台的条件编译实战详解

一. 条件编译支持的场景 uni-app 的条件编译能支持以下几种场景,具体如图所示: 1. API 的条件编译 简言之,同一功能实现,可能有不同的逻辑处理,比如:在 js 文件中,或者在 Vue 文件中的 scrip…

PW系列工控电脑复制机:效率与精度双重提升

工控电脑复制应用:效率与精度的双重提升 随着现代企业对大数据、数据备份、和跨平台兼容性需求的快速增长,工控电脑已成为数据密集型产业的核心设备。针对工控环境中大量数据复制的特殊需求,PW系列NVMe/SATA PCIe SSD复制机(如PW…

深入理解 Seata:分布式事务的最佳解决方案

随着微服务架构的广泛应用,分布式事务管理成为系统设计中一项重要且极具挑战的任务。在微服务架构下,服务之间通过网络调用,单个业务操作往往需要多个服务的协作来完成,这样分布式事务的问题就不可避免。Seata 是目前较为流行的一…

python 正则表达式re 模块的基本使用方法

目录 一、正则化表达式语法1、如下表格:2、元字符 二、re模块常用方法1、compile2、findall3、search4、match5、split6、sub7、finditer 一、正则化表达式语法 1、如下表格: 语法意义.匹配除换行外的任意字符(如果DOTALL则连换行也匹配)^匹配字符串开…

修改一下达梦disql 提示符

经常用disql的有时某些信息希望提示一下,默认的只显示SQL> 为了方便使用,可以在 glogin.sql 中增加些内容。 vi $DM_HOME/bin/disql_conf/glogin.sql增加以下几行 set time on set lineshow offcol global_name new_value global_name SELECT ins…