精华内容
下载资源
问答
  • 反应计时器设计
    2021-07-01 01:53:59

    《微机课程设计报告抢答器.doc》由会员分享,可免费在线阅读全文,更多与《微机课程设计报告抢答器(最终版)》相关文档资源请在帮帮文库(www.woc88.com)数亿文档库存里搜索。

    1、enableAdb?enableBdb?DATAENDS;STACKSSEGMENTDBDUP(?)STACKSENDS;CODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXMOVES,AXMOVAH,HMOVDX,OFFSETMESS;显示提示信息INTHMOVAX,DATAMOVDS,AXmovax,stacksmovss,ax;初始化MOVDX,PMMOVAL,H;初始化控制字A口输入,B、C输出OUTDX,AL;初始化movdx,PMmoval,B;CNT=方式Boutdx,almovax,;赋初值movdx,PAoutdx,almoval,ahoutdx,almovdx,PMmoval,B;CNT=方式Doutdx,almoval,movdx,PBoutdx,almovdx,PMmoval,B;CNT=方式Doutdx,almoval,h;如赋初值,则数码管显示初值为movdx,PCoutdx,alcallrorand;产生初始随机数wait_for_start:;游戏的初始化;B接led;cL关主持人灯moval,bmovdx,PMo。

    2、ayerA抢答灯PlayerB抢答灯抢答灯开始灯数码管S数码管S调试:()按照电路图连接电路,主要是用于定时器的作用,给两位数码管输出秒的倒计时,的PA口为输入,PA和PA是作为抢答器的输入端,抢答器的输入采取脉冲发生器产生的脉冲作为抢答信号。PA是屏幕显示反应时间的按键输入,PA是开始键的输入。PC是PlayerA抢答灯按键输入,PC是PlayerB抢答灯按键输入,PC为抢答灯的输出,PC为开始灯输出,PC连接的GATEGATE,PC为数码管S,PC为数码管S。PBPB接ah。()在调试中,主要的调试还是代码的调试,通过TD和DEBUG两种调试方式,通过逐步调试,发现和找到错误之处,进行更改,最终得到正确的调试结果。五.分析与总结通过此次的微机实验,通过编程了解到了汇编语言的编程,并且在编写程序的过程,进一步地熟悉了一个系统程序的编写和调试工作。编程中,最重要的是通过TD或者DEBUG两种调试手段来进行程序的调试,从而找到程序的运行中出错的地方,进行调试,最终能够运行出正确的代码。代码调试正确后,通过在实验板上连线,进行验证,最终得到正确的实验结果。在此次的微机实验过程中,由于时间的仓促,我们只完成了基。

    3、ms,decreact_smoval,start_mssueact_ms,alcmreact_ms,JLNdealsueact_ms,increact_sNdeal:movdx,PAinal,dx;检测test键testal,b;有无按下检测键jzntest;未按下;按下,显示反应时间keyt:movdl,react_smovrandom,aladdrandom,;用上次的反应时间做下次的随机数初值movcl,rordl,clanddl,fhadddl,hmovah,hinthmovdl,react_sanddl,fhadddl,hinthmovdl,ehinthmovdl,react_msmovcl,rordl,clanddl,fhadddl,hinthmovdl,end_msanddl,fhadddl,hinthntes:;停止计数;cgate,,moval,bmovdx,PMoutdx,al;cL主持人灯;关主持人灯moval,b;movdx,PMoutdx,al;cL抢答提示灯;关抢答提示灯moval,b;movdx,PMoutdx,aljmw_f_resetski:jmstart;*******。

    4、jnenextB;否则A抢答有效testal,bjznextBmoval,b;点亮A抢答灯movdx,PMoutdx,aljmquitnextB:cmenableB,jnenext;B抢到了,亮Ltestal,bjznextmoval,b;点亮B抢答灯movdx,PMoutdx,aljmquitski:jmwait_for_start;跳板next:;A、B都抢答无效或A、B都没抢答movdx,PAinal,dxtestAL,H;判断主持人开关是复位还是启动JZski;取当前时间movdx,PCinal,dxmovah,almovc_time,alandal,fhmovledl,almovcl,rorah,clandah,fhmovledh,ah;段灯扫描不能停止movbl,al;cL关抢答提示灯moval,bmovdx,PMoutdx,al;c;cL关layerA灯moval,bmovdx,PMoutdx,al;cL关layerB灯moval,bmovdx,PMoutdx,almoval,;段led灭movdx,ledoutdx,al;c接cs,c接cs;c接gate,,;关计数moval,bmovdx。

    5、******************w_f_reset:movdx,PAinal,dx;检测test键testal,b;有无按下检测键jnzkeyt;按下,显示反应时间movdx,PAinal,dxtestAL,H;判断主持人开关是复位还是启动JZskijmw_f_resetdelayrocushcxmovcx,zzz:loozzzocxretdelayendrorandrocushcxushsimovcx,movsi,haddr:xoral,almoval,[si]addrandom,alincsilooaddrandrandom,hosiocxretrorandendCODEENDSENDSTART灯;cL抢答提示灯;c;cLlayerA灯;cLlayerB灯;H接PAequbHPBequbHPCequbHPMequbHledequbH;接数码管七段输入LEDDBfh,h,bh,fh,h,dh,dh,h,fh,fh;共阴七段码start_sdb?start_msdb?end_sdb?end_msdb?react_sdbreact_msdb?ledhdb?ledldb?randomdbc_timedb?。

    6、部分的功能,提高部分的功能基本没有来得及做。相信在基础部分的前提下,在以后的时间里,可以进一步地提高,将功能再进一步的完善。参考书目:(五号,宋体加粗)[]东南大学《微机系统与接口》课程组,《微机实验及课程设计教程(试用版)》,年[]杨素行等,《微型计算机原理与应用(第版)》,北京,清华大学出版社,年源代码:;抢答反应测试仪DATASEGMENTMESSdb'********madebyadministrator********',dh,ah,'$';接PAequbH;开关输入PBequbHPCequbAHPMequbBH;ccs;ccs;cgate,,;cL主持人微机课程设计报告抢答器设计目录一.课程设计目的与要求二.方案论证与原理设计三.详细(机理)设计四.方案实现与测试(或调试)五.分析与总结一课程设计目的与要求(含设计指标).课程设计目的()检验和提高在微机原理和接口综合应用方面分析问题和解决问题的能力;()锻炼系统级别汇编语言编程和硬件调试能力;()培养团队分工合作能力。.设计要求和指标设计要求:设计一个用于智力竞赛的抢答器计时器,同时能测试人的反应时间。按启动键,测试开始,个八段码倒计时开始(。

    7、ledhmovbh,leasi,LEDaddsi,bxmoval,bytetr[si];moval,led[bl]???????????????????movdx,ledoutdx,al;开启csmoval,bmovdx,PMoutdx,alcalldelay;延时一点;关闭csmoval,bmovdx,PMoutdx,almovbl,ledlmovbh,leasi,LEDaddsi,bxmoval,bytetr[si];moval,led[bl]???????????????????movdx,ledoutdx,al;开启csmoval,bmovdx,PMoutdx,alcalldelay;延时一点;关闭csmoval,bmovdx,PMoutdx,aljmlight;继续检测按键,是否有人抢答quit:;收尾;取当前精确时间ushcxushdxmovah,chinthmovend_s,dhmovend_ms,dlodxocxmoval,end_s;计算反应时间movreact_s,almoval,start_ssueact_s,almoval,end_msmovreact_ms,aladdreact_。

    8、如从秒或秒倒计时),在随机时间内点亮抢答允许灯,参赛双方分别按各自的抢答按钮参与抢答。一旦其中一方按下按钮,相应的LED显示灯亮,此时若其他按钮按下均无效。若一直计数到零,均无人按下按钮,则抢答结束(以后再按抢答钮无效)。按测试钮,在PC机上显示反应时间XXXX秒。指标要求:()编制一个随机数产生子程序,又随机数决定从按启动钮到点亮抢答允许灯的时间(如在秒~秒之间任意变动),使被测试者对LED亮的时间无法预见,以保证测试结果的可信性;()必须在见到LED点亮后按测试钮才有效,即一直按着按钮或提前按下按钮无效;()反应时间显示XXXX秒,准确到百分之一。分工()核心代码编写:()代码编译、修改:()搭建、调试:()后期代码优化、修改:二方案论证与原理设计(或基本原理)首先分析系统输入输出量,输入为一系列开关量和时钟,输出为数码管的段码和LED显示以及计算机屏幕信息。所以使用并行输入输出功能实现这些数字量的输入输出,又由于要求倒计时和计算选手反应时间,所以采用的计时功能。在实现基本功能下,本系统的核心硬件为和硬件框图为:CPU数字量交换定时数字量输入数字量输出方案设计:设置为A口输入,BC口输出工作方式,A口。

    9、tdxtdx,al;开启csmoval,bmovdx,PMoutdx,alcalldelay;延时一点;关闭csmoval,bmovdx,PMoutdx,al;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;movenableA,;屏蔽先抢答行为movenableB,movbl,c_timesubbl,negbl;求blmovdl,randomcmbl,dl;是否到了点亮抢答灯的时间jglightjmstart_gamelight:ushcx;DOS功能调用取点亮抢答灯时的精确时间用于计算反应时间ushdxmovah,chinthmovstart_s,dhmovstart_ms,dlodxocxlight:;cL抢答提示灯;打开抢答提示灯moval,bmovdx,PMoutdx,almovdx,PA;检测开关状态inal,dx;A接Alayer,A接Blayertestal,b;如果灯亮的时候是没有按下就开启抢答使能jnznextmovenableA,next:testal,bjnznextmovenableB,next:cmenableA,;如果抢答使能而且按下了抢答键。

    10、dx,alcalldelay;延时一点;关闭csmoval,bmovdx,PMoutdx,almovbl,ledlmovbh,leasi,LEDaddsi,bxmoval,bytetr[si];moval,led[bl]???????????????????movdx,ledo时,从而用硬件实现倒计时功能。程序流程图:开始写、初始值关LED显示灯开始倒计时开始键=YN随机数产生点亮抢答灯计算反应时间是否抢答?是否显示时间结束YYNN三详细(机理)设计()随机数产生为确保从每次按启动键到LED点亮的时间是不同的(真正随机变化的),一开始可随机读取某个RAM单元值求和作为初始值,这可以通过设置一个random变量,在程序初始化部分调用随机数产生子程序rand给其赋值实现:randrocushcxushsimovcx,movsi,haddr:xoral,almoval,[si]addrandom,alincsilooaddrandrandomhosiocxretrandend()倒计时的计数器接实验箱上MHz脉冲,设初值为,工作方式为,OUT产生频率kHz低脉冲;OUT接计数器时钟端,初值设为,工作方式为,OU。

    11、PMoutdx,al;关断段moval,b;数字低位movdx,PMoutdx,almoval,b;数字高位movdx,PMoutdx,almovdx,PAinal,dxtestAL,H;判断主持人开关是复位还是启动;K是开始开关,高电平开始JZwait_for_start;按下启动钮开始游戏;cL主持人灯;开启主持人灯Lmoval,bmovdx,PMoutdx,al;开始计数;cgate,,moval,bmovdx,PMoutdx,alstart_game:movdx,PAinal,dxtestAL,H;判断主持人开关是复位还是启动JZwait_for_start;按下启动钮取当前时间movdx,PCinal,dxmovah,almovc_time,alandal,fhmovledl,almovcl,rorah,clandah,fhmovledh,ah;动态显示段movbl,ledhmovbh,leasi,LEDaddsi,bxmoval,bytetr[si];moval,led[bl]???????????????????movdx,ledoutdx,al;开启csmoval,bmovdx,PMout 。

    12、产生频率为Hz的第脉冲,所以计数器表示倒计时ms;OUT接计数器时钟端,初值设为,工作方式设为,实现秒倒计时功能。初始化movdx,PMmoval,B;CNT=方式Boutdx,almovax,;赋初值movdx,PAoutdx,almoval,ahoutdx,almovdx,PMmoval,B;CNT=方式Doutdx,almoval,movdx,PBoutdx,almovdx,PMmoval,B;CNT=方式Doutdx,almoval,h;如赋初值,则数码管显示初值为movdx,PCoutdx,al()计算选手反应时间在点亮抢答允许灯前提取当前时间。;按下启动钮取当前时间movdx,PCinal,dxmovah,almovc_time,alandal,fhmovledl,almovcl,rorah,clandah,fhmovledh,ah四方案实现与测试(或调试)方案的实现,系统的硬件电路图如下:CLKGATEOUTCLKGATEOUTCLKGATEOUTPAPAPAPAPCPCPCPCPCPCPCPBPBPBPBPBPBPBPBMHzhgfedcba抢答按键A抢答按键B时间显示按键K开始按键KPl

    更多相关内容
  • 手眼协调是一种眼睛和手一起工作执行一项任务的能力,反应计时器电路能够测量一个 人在看见一种视觉刺激后,手的响应有多快。 实验要求: 1. 基本部分 (1)电路有三个输入按键:clear,start 和 stop,使用一个 ...
  • 手眼反应计数器

    2018-08-24 12:15:05
    测试手眼反应速度,当按下开始键时,led灯熄灭1~6s,时间不定,然后点亮,眼睛看到led灯亮后按下停止键,此时数码管显示时间即为手眼反应时间。可实现两人比赛,获胜者对应的led灯会点亮;还可查询所有反应时间的...
  • 计时器设计

    2014-01-02 14:05:44
    嘛就是一个计时器设计mlltisim的文件
  • stateflow 计时器

    2017-09-14 16:35:41
    基于simulink的计时器,方便学习stateflow,Stateflow是一个跟Simulink联合起来使用的,可视化图形界面工具。在Simulink环境下,它是用来模拟和控制一些逻辑系统. Stateflow跟Simulink是完美结合在一起的,可以建模...
  • 课程设计,数电,计时器,是自己写的,大学二年级第一期
  • LED指示灯功能

    2014-01-17 11:36:57
    MT6572上的通知指示灯、上层控制指示灯效果。(未读短信、未读彩信、未接来电、未读邮件) \packages\apps\Settings\src\com\android\settings\IndicatorLightSettings.java \frameworks\base\services\java\...
  • 毫秒计时器功能如下: 1)LCD1602.上显示累积计时时间(分:秒:毫秒) ; 2)计时方式:实时时钟DS1302或单片机内部定时器(任选其一)3)计时开始:按钮命令; 3) 计时结束:按钮命令或累计计时超过1分钟;及时结束将显示时间...

    毫秒计时器功能如下:

    1)LCD1602.上显示累积计时时间(分:秒:毫秒) ;

    2)计时方式:实时时钟DS1302或单片机内部定时器(任选其一)3)计时开始:按钮命令;

    3) 计时结束:按钮命令或累计计时超过1分钟;及时结束将显示时间清零

    4) 计时报警:累计计时超过1分钟,红色LED灯以1亮灭-一次的速度闪烁,可以按键停止报警。报警超过1分钟自动停止报警。

    【资源下载】下载地址如下(908):https://docs.qq.com/doc/DTlRSd01BZXNpRUxl

    
    
    #include<reg51.h>	
    #include"lcd.h"
    
    sbit LED = P3^0;
    
    #define GPIO_KEY P1
    
    #define TH0_DATA  0xfd
    #define TL0_DATA  0x12  
    
    unsigned char Time;
    unsigned char minit=0,second=0;
    unsigned int second_m=0;
    //用来计时间的值
    unsigned char KeyValue=0;
    
    void Delay1ms(unsigned int);
    void TimerConfiguration();
    void Int0Configuration();
    
    unsigned char SetPlace;
     
    
    char KeyDown(void)
    {
    	char a;
    	GPIO_KEY=0x0f;
    	if(GPIO_KEY!=0x0f)
    	{
    		Delay10ms();
    		if(GPIO_KEY!=0x0f)
    		{
    			//测试列
    			GPIO_KEY=0X0F;

     

    展开全文
  • 计时器的种类包括电磁打点计时器、电火花计时器、坚持计时器、停车计时器、反应计时器、放大计时器以及windows计时器等等。本设计是在基于单片机的原理上设计的计时器,有C和汇编两种语言编写的程序来实现。
  • 你们想要的汇编课程设计抢答计时器,计一个用于智力竞赛的抢答计时器,同时能测试人的反应(响应)时间。按启动钮,测试开始,2个八段码倒计时开始(如从10秒或20秒倒计时),一旦看到灯亮,参赛双方(或三方)分别按...
  • Java 设计模式最佳实践:六、让我们开始反应式吧

    原文:Design Patterns and Best Practices in Java

    协议:CC BY-NC-SA 4.0

    贡献者:飞龙

    本文来自【ApacheCN Java 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。

    这一章将描述反应式编程范式,以及为什么它能很好地适用于带有函数元素的语言。读者将熟悉反应式编程背后的概念。我们将介绍在创建反应式应用时从观察者模式和迭代器模式中使用的元素。这些示例将使用反应式框架和名为 RxJava(版本 2.0)的 Java 实现。

    我们将讨论以下主题:

    • 什么是反应式编程?
    • RxJava 简介
    • 安装 RxJava
    • 可观察对象、可流动对象、观察者和订阅
    • 创建可观察对象
    • 变换可观察对象
    • 过滤可观察对象
    • 组合可观察对象
    • 错误处理
    • 调度者
    • 主题
    • 示例项目

    什么是反应式编程?

    根据《反应宣言》,无功系统具有以下属性:

    • 响应:系统以一致的、可预测的方式及时响应。
    • 恢复:系统对故障有弹性,能快速恢复。
    • 弹性:系统通过增加或减少分配的资源,在不同的工作负载下保持其响应能力。这是通过动态查找和修复瓶颈来实现的。这不能与可伸缩性混淆。弹性系统需要根据需要上下伸缩——见这个页面
    • 消息驱动:依赖异步消息传递,确保松耦合、隔离、位置透明和容错。

    需求是真实的。如今,无响应系统被认为是有缺陷的,用户将避免使用。根据这个页面的说法,一个没有回应的网站在搜索引擎中的排名很低:

    “响应式设计是谷歌的推荐设计模式”

    反应式系统是一种使用元素构成复杂系统的架构风格,有些元素是用反应式编程技术构建的。

    反应式编程是一种依赖于异步数据流的范例。它是异步编程的事件驱动子集。相反,反应式系统是消息驱动的,这意味着接收器是预先知道的,而对于事件,接收器可以是任何观察者。

    反应式编程不仅仅是基于事件的编程,因为它利用了数据流,它强调数据流而不是控制流。以前,诸如鼠标或键盘事件之类的事件,或者诸如服务器上的新套接字连接之类的后端事件,都是在线程事件循环(thread of execution)中处理的。现在一切都可以用来创建一个数据流;假设来自某个后端端点的 JSON REST 响应成为一个数据流,它可以被等待、过滤,或者与来自不同端点的其他响应合并。这种方法通过消除开发人员显式创建在多核和多 CPU 环境中处理异步调用的所有样板代码的需要,提供了很大的灵活性。

    一个最好的也是最被过度使用的反应式编程示例是电子表格示例。定义流(flow)类似于声明 Excel 的 C1 单元格的值等于 B1 单元格和 A1 单元格的内容。每当 A1 或 B1 单元更新时,就会观察到变化并对其作出反应,其副作用是 C1 值得到更新。现在假设 C2 到 Cn 单元格等于 A2 到 An 加上 B2 到 Bn 的内容;同样的规则适用于所有单元格。

    反应式编程使用以下一些编程抽象,有些抽象取自函数式编程世界:

    • Optional/Promise:这些提供了一种手段,可以对不久的将来某个地方将要提供的值采取行动。
    • :它提供了数据管道,就像列车轨道一样,为列车运行提供了基础设施。
    • 数据流变量:这些是应用于流函数的输入变量的函数的结果,就像电子表格单元格一样,通过对两个给定的输入参数应用加号数学函数来设置。
    • 节流:该机制用于实时处理环境,包括数字信号处理器DSP)等硬件,通过丢弃元件来调节输入处理的速度,以赶上输入速度;用作背压策略。
    • 推送机制:这与好莱坞原理相似,因为它反转了调用方向。一旦数据可用,就调用流中的相关观察者来处理数据;相反,拉机制以同步方式获取信息。

    有许多 Java 库和框架允许程序员编写反应式代码,如 Reactor、Ratpack、RxJava、Spring Framework 5 和 Vert.x。通过添加 JDK9 Flow API,开发人员可以使用反应式编程,而无需安装其他 API。

    RxJava 简介

    RxJava 是从 Microsoft.NET 世界移植的反应式扩展(一个库,用于使用可观察序列编写异步和基于事件的程序)的实现。2012 年,Netflix 意识到他们需要一个范式的转变,因为他们的架构无法应对庞大的客户群,所以他们决定通过将无功扩展的力量引入 JVM 世界来实现无功扩展;RxJava 就是这样诞生的。除了 RxJava 之外,还有其他 JVM 实现,比如 RxAndroid、RxJavaFX、RxKotlin 和 RxScale。这种方法给了他们想要的动力,通过公开,它也为我们提供了使用它的机会。

    RxJavaJar 是根据 Apache 软件许可证 2.0 版获得许可的,可以在中央 Maven 存储库中获得。

    有几个外部库使用 RxJava:

    • hystrix:一个延迟和容错库,用于隔离远程系统的访问点
    • rxjava-http-tail:一个 HTTP 日志跟踪库,可用方式与tail -f相同
    • rxjava-jdbc:使用 RxJava 和到ResultSets流的 JDBC 连接

    安装 RxJava 框架

    在本节中,我们将介绍 Maven 的 RxJava 安装(Gradle、SBT、Ivy、Grape、Leiningen 或 Buildr 步骤类似)以及 Java9 的 replJShell 的用法。

    Maven 安装

    安装 RxJava 框架很容易。JAR 文件和依赖的项目反应流在 Maven 下的这个页面中可用。

    为了使用它,在您的pom.xml文件中包括这个 Maven 依赖项:

    <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.packt.java9</groupId>
      <artifactId>chapter6_client</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
      <dependencies>
        <!-- https://mvnrepository.com/artifact/io.reactivex.
        rxjava2/rxjava -->
        <dependency>
          <groupId>io.reactivex.rxjava2</groupId>
          <artifactId>rxjava</artifactId>
          <version>2.1.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.
        reactivestreams/reactive-streams -->
        <dependency>
          <groupId>org.reactivestreams</groupId>
          <artifactId>reactive-streams</artifactId>
          <version>1.0.1</version>
        </dependency>
      </dependencies>
    </project>
    

    安装在 Gradle、SBT、Ivy、Grape、Leiningen 或 Buildr 中类似;查看这个页面了解需要添加到configuration文件的更多信息。

    JShell 安装

    我们将在第 9 章“Java 最佳实践”中详细讨论 JShell,现在让我们从 RxJava 的角度来看一下。在 JShell 中安装 RxJava 框架是通过将 classpath 设置为 RxJava 和 reactive streams JAR 文件来完成的。请注意,Linux 上使用冒号,Windows 上使用分号作为文件路径分隔符:

    "c:Program FilesJavajdk-9binjshell" --class-path D:Kitsrxjavarxjava-2.1.3.jar;D:Kitsrxjavareactive-streams-1.0.1.jar
    

    屏幕上将显示以下错误:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-92RYJCXQ-1657721282484)(img/081f90ec-4fec-4cf3-bfe5-4793220a018d.png)]

    前面的错误是因为我们忘记导入相关的 Java 类。

    以下代码处理此错误:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wNIrKRWU-1657721282485)(img/fd64466a-2b93-43ce-9fe2-a4fc81f8dd59.png)]

    现在我们已经成功地创建了我们的第一个可观察对象。在下面的部分中,我们将学习它的功能以及如何使用它。

    可观察对象、可流动对象、观察者和订阅者

    在 ReactiveX 中,观察者订阅一个可观察的对象。当观察者发射数据时,观察者通过消耗或转换数据做出反应。这种模式便于并发操作,因为它不需要在等待可观察对象发出对象时阻塞。相反,它以观察者的形式创建了一个哨兵,随时准备在以观察者的形式出现新数据时做出适当的反应。这个模型被称为反应堆模式。下图取自这个页面,解释了可观测数据流:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rI7dsGXh-1657721282486)(img/b33888d8-4408-4fd5-9215-3a609f5cea79.png)]

    反应式的可观察性与祈使式的可观察性相似。它解决了相同的问题,但策略不同。一旦可用,Observable通过异步推送更改来工作,而Iterable则以同步方式拉送更改机制。处理错误的方法也不同;一种使用错误回调,而另一种使用副作用,例如抛出异常。下表显示了差异:

    | 事件 | 可迭代对象 | 可观察对象 |
    | — | — |
    | 获取数据 | T next() | onNext(T) |
    | 错误 | throw new Exception | onError(Exception) |
    | 完成 | Return | onCompleted() |

    使用订阅(onNextActiononErrorActiononCompletedAction)方法将观察者连接到被观察者。观察者实现以下方法的一些子集(只有onNext是必需的):

    • onNext:每当被观察对象发出一个项目时调用,方法以被观察对象发出的项目作为参数
    • onError:调用它是为了表示它没有生成预期的数据或遇到了其他错误,并将异常/错误作为它的参数
    • onCompleted:当没有更多的数据要发出时调用

    从设计的角度来看,反应式可观测对象通过使用onErroronCompleted回调来增加在完成和错误时发出信号的能力,从而增强了四人帮的观察者模式。

    有两种类型的反应式观察结果:

    • :即使没有连接用户,也会尽快开始发送。
    • :在开始发送数据之前,等待至少一个订户连接,因此至少一个订户可以从一开始就看到序列。它们被称为“可连接的”可观察对象,RxJava 拥有能够创建此类可观察对象的操作符。

    RxJava2.0 引入了一种新的可观察类型,称为Flowable。新的io.reactivex.Flowable是一个支持背压的基本反应类,而可观察的不再是。背压是一组策略,用于处理当可观察对象发出订户可以处理的更多数据时的情况。

    RxJava Observable应用于小数据集(最长不超过 1000 个元素),以防止OutOfMemoryError或用于 GUI 事件,例如鼠标移动或小频率(1000 Hz 或以下)的触摸事件。

    在处理超过 10000 个元素、从磁盘读取(解析)文件(这在背压下很好地工作)、通过 JDBC 从数据库读取数据或执行基于块和/或拉的数据读取时,将使用Flowable

    创建可观察对象

    以下操作符用于从现有对象、其他数据结构的数组或序列或计时器中从头开始创建可观察对象。

    创建操作符

    可以通过调用以下io.reactivex.Observable方法之一(操作符)从头开始创建可观察对象:

    • 创建
    • 生成
    • 不安全创建

    下面的示例演示如何从头开始构造一个可观察的。调用onNext()直到观察者没有被释放,onComplete()onError()以编程方式获得 1 到 4 的数字范围:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ThKf4rud-1657721282486)(img/5d7d884e-4933-47c8-822e-433252cffe4d.png)]

    正如我们在前面的屏幕截图中所看到的,输出与预期一样,范围从 1 到 4,序列在使用后会被处理掉。

    延迟运算符

    一旦观察者连接,可以通过调用defer方法为每个观察者创建一个新的观察者。以下代码显示了defer在我们提供号码时的用法:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LdmVgfaQ-1657721282487)(img/d13e22a4-5612-4842-8604-45131c8b57e5.png)]

    控制台println方法输出 123,这是可观察的整数。

    空运算符

    可以通过调用empty()never() io.reactivex.Observable方法来创建从不发送的空项目。

    from运算符

    通过调用以下方法之一,可以从数组、Future或其他对象和数据结构进行转换:

    • fromArray:将数组转换为可观察数组
    • fromCallable:将提供值的Callable转换为Observable
    • fromFuture:将Future提供的值转换为可观察的值
    • fromIterable:将Iterable转换为Observable
    • fromPublisher:将反应发布者流转换为可观察发布者流
    • just:将给定对象转换为可观察对象

    下面的示例从字母列表(abc)中创建一个Observable

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fCSJCUCU-1657721282488)(img/3827aba1-f52f-4a66-a1ed-1c62e1f65eda.png)]

    abc的整个数组被消耗,并通过System.out.println方法打印到控制台。

    区间运算符

    通过使用interval方法,可以创建一个可观察的对象,该对象发出一个由特定时间间隔间隔隔开的整数序列。下面的示例从不停止;它每秒钟连续打印一次记号号:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKagf3IF-1657721282488)(img/fb9d71db-f693-4721-be43-73004eac1fa4.png)]

    尝试停止计时器也无济于事(即使是Ctrl + C,只要关闭窗口),它会继续按指令每隔一秒向控制台打印递增的数字。

    定时器运算符

    通过使用计时器方法,可以在给定的延迟之后发出单个项目。

    范围运算符

    可以使用以下方法创建序列号范围:

    • intervalRange:发出一系列长值的信号,第一个在一些初始延迟之后,接下来是周期性的
    • range:发出指定范围内的整数序列

    重复运算符

    为了重复特定的项目或特定的顺序,请使用:

    • repeat:重复给定可观测源发射的项目序列多次或永远(取决于输入)
    • repeatUntil:重复可观测源发出的项目序列,直到提供的stop函数返回true
    • repeatWhen:除了onComplete之外,发出与初始可观察对象相同的值

    以下代码重复给定的a值,直到满足条件:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bDrD4mfD-1657721282489)(img/417d530b-771a-41b7-b2b6-b8fa3283219f.png)]

    它向控制台重复三次a,直到x的值 3 大于 2。作为练习,将x++替换为++x并检查控制台。

    转换可观测对象

    这些运算符转换由可观察对象发出的项。

    订阅操作符

    这些是订户用来消耗来自可观察对象的发射和通知的方法,例如onNextonErroronCompleted。用于订阅的可观察方法有:

    • blockingForEach:消耗此可观察对象发出的每个项目,并阻塞直到可观察对象完成。
    • blockingSubscribe:订阅当前线程上的可观察事件并消耗事件。
    • forEachWhile:订阅Observable并接收每个元素的通知,直到onNext谓词返回false
    • forEach:订阅可观察到的元素并接收每个元素的通知。
    • subscribe:将给定的观察者订阅到该可观察对象。观察器可以作为回调、观察器实现或抽象io.reactivex.subscribers.DefaultSubscriber<T>类的子类型提供。

    缓冲区运算符

    buffer方法用于创建给定大小的包,然后将它们打包为列表。下面的代码显示了如何在 10 个数字中创建两个bundle,一个有 6 个,另一个有其余 4 个:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xvax2Bwa-1657721282490)(img/c4292f4c-a67d-44da-99b9-07359a89daa5.png)]

    展开映射操作符

    通过使用以下操作符之一,可以通过到达顺序(flatMap)、保持最后发射的顺序(switchMap)或通过保持原始顺序(concatMap)将给定的可观察对象转换为单个可观察对象:concatMapconcatMapDelayErrorconcatMapEagerconcatMapEagerDelayErrorconcatMapIterableflatMapflatMapIterableswitchMap,或switchMapDelayError。下面的示例演示了如何通过随机选择可观察对象的顺序来更改输出的内容。(flatMapconcatMapswitchMap

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5a7ELn9t-1657721282491)(img/c3fdb310-ec85-4469-86b6-329586a071bd.png)]

    concatMap实现将c字符串附加到给定的abc字符串中的每一个,因此,输出是acbccc

    flatMap实现将f字符串附加到给定的abc字符串中的每一个,如下所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PeMOYZtM-1657721282491)(img/96750fcd-8d66-48dc-b62d-dea37238d9bf.png)]

    由于随机延迟,顺序与预期的afbfcf不同,运行几次就会输出预期的顺序。

    下面的代码段显示了不同的输出。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AmB5BdJs-1657721282491)(img/98226dc4-761c-43f3-a4cf-d70b57c77f86.png)]

    switchMap实现将s字符串附加到给定的abc字符串列表中的最后一个元素。

    注意advanceTimeBy的用法。没有这个电话,什么都不会打印,因为发射被推迟了。

    分组运算符

    groupBy用于将一个可观察对象划分为一组可观察对象,每个可观察对象发出一组不同的项目。下面的代码按起始字母对字符串进行分组,然后打印键和特定键的组数据。请注意,这些组是可观察的,可用于构造其他数据流。

    以下输出按第一个字母显示组作为一个组,并显示组键(即第一个字母):

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TxWBqfd-1657721282492)(img/44c6e7ea-5442-4bf8-bea1-6c8f0e77e773.png)]

    映射运算符

    为每个项目应用一个函数来转换可观察对象可以通过以下方法实现:

    • cast:将结果强制转换为给定类型
    • map:对每个发出的项目应用指定的函数

    扫描运算符

    利用积累的转换可以用scan方法来完成。以下代码通过发出元素的当前和来使用它:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WO0qsS8y-1657721282492)(img/2430126e-d52b-4730-b9bb-a70032b24ff7.png)]

    窗口操作符

    window方法用于周期性地将项目从一个可观察窗口细分为可观察窗口,并突发发射这些窗口。下面的代码显示,使用一个元素的窗口不起任何作用,同时使用三个元素输出它们的总和:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RwOERutY-1657721282493)(img/4d1158a4-c0ab-495a-a14c-f298825df7e3.png)]

    过滤可观察对象

    这些操作符根据给定的条件/约束从给定的可观察对象选择性地发射项。

    去抖动算符

    只能在经过特定时间跨度后发射,可以使用以下方法:

    • debounce:镜像最初的可观察项,除了它删除源发出的项,然后在一段时间内删除另一项
    • throttleWithTimeout:仅发射那些在指定时间窗口内没有后跟另一个发射项的项

    在下面的示例中,我们将删除在 100 毫秒的去抖动时间跨度过去之前触发的项;在我们的示例中,它只是最后一个管理的值。同样,通过使用测试调度器,我们提前了时间:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YoloRy13-1657721282494)(img/14796180-af89-486d-b2c6-af30de36f343.png)]

    去重运算符

    这将使用以下方法删除可观察对象发出的不同项:

    • distinct:只发射不同的元素
    • distinctUntilChanged:仅发射与其直接前辈不同的元素

    在下面的代码中,我们将看到如何使用distinct方法从给定序列中删除重复项:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ivho3r5G-1657721282494)(img/04062498-1881-48c2-a36b-cafb2aa80c50.png)]

    我们可以看到重复的aaa字符串已经从输出中删除。

    获取元素运算符

    为了通过索引获得元素,使用elementAt方法。以下代码打印列表中的第三个元素:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjv0WNQf-1657721282495)(img/0d1cf753-0142-4ac3-bdb3-f27485bfaebc.png)]

    过滤运算符

    在以下方法上使用只允许从通过测试(谓词/类型测试)的可观察对象中发出那些项:

    • filter:只发出满足指定谓词的元素
    • ofType:只发出指定类型的元素

    以下代码显示了filter方法的用法,用于过滤掉不以字母a开头的元素:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOVoGHtg-1657721282495)(img/b231376c-4dd4-4c41-a306-c5c36fdb8475.png)]

    第一个/最后一个运算符

    这些方法用于根据给定条件返回项目的第一个和最后一个匹配项。也有阻塞版本可用。可用的io.reactivex.Observable methods是:

    • blockingFirst:返回可观察对象发出的第一项
    • blockingSingle:返回可观察对象发出的第一个Single
    • first:返回可观察对象发出的第一项
    • firstElement:返回仅发射第一个项目的Maybe
    • single:返回仅发射第一个项目的Single
    • singleElement:返回一个只发出第一个单曲的Maybe
    • blockingLast:返回可观察对象发出的最后一项
    • last:返回可观察对象发出的最后一项
    • lastElement:返回只发出最后一个单曲的Maybe

    示例运算符

    使用此运算符可发射特定项目(由采样时间段或节气门持续时间指定)。io.reactivex.Observable提供以下方法:

    • sample:在给定的时间段内发出最近发出的项目(如果有)
    • throttleFirst:仅发射给定连续时间窗口内发射的第一个项目
    • throttleLast:仅发射给定连续时间窗口内发射的最后一项

    跳过运算符

    从可观察的输出中删除第n个倒数第n个元素。以下代码显示了如何跳过给定输入的前三个元素:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPHdC0bZ-1657721282495)(img/97de704a-97d6-44a5-9d1d-d5c670cc354c.png)]

    调用skipLast方法将只输出 1 和 2。

    选取运算符

    它只从给定的可见光发送第n个倒数第n个元素。以下示例显示如何仅从可观察的数值范围中获取前三个元素:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmJs58Cw-1657721282496)(img/e8d8122d-3c2c-4d1e-bc61-ae5c9313715c.png)]

    使用具有相同参数的takeLast方法将输出 3、4 和 5。

    组合可观察对象

    这些运算符用于组合多个可观察对象。

    联合运算符

    通过调用以下方法之一,组合来自两个或多个可观测对象的最新发射值:

    • combineLatest:发出聚合每个源的最新值的项
    • withLatestFrom:将给定的可观察对象合并到当前实例中

    下面的示例(永远运行)显示了组合两个具有不同时间跨度的间隔可观察对象的结果—第一个每 6 毫秒发射一次,另一个每 10 毫秒发射一次:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPZGHU8f-1657721282496)(img/5c5081da-a559-42b7-b9fe-33696c536ca3.png)]

    前面代码的执行需要通过按Ctrl + C停止,因为它创建了一个无限列表。输出与预期一样,它包含基于创建时间戳的两个序列的组合值。

    连接运算符

    通过调用以下方法之一,可以基于给定窗口组合两个可观察对象:

    • join:使用聚合函数,根据重叠的持续时间,将两个可观察对象发出的项目连接起来
    • groupJoin:使用聚合函数,根据重叠的持续时间,将两个可观察对象发出的项目加入到组中

    下面的示例使用join组合两个可观察对象,一个每 100 毫秒触发一次,另一个每 160 毫秒触发一次,并每 55 毫秒从第一个值中获取一个值,每 85 毫秒从第二个值中获取一个值:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uPpPHYpI-1657721282497)(img/55cdf0f8-ce56-4452-a25d-5b04eaf29dc7.png)]

    前面的代码永远执行,需要手动停止。

    合并运算符

    将多个可观察对象合并为一个可观察对象,所有给定的发射都可以通过调用:

    • merge:将多个输入源展开为一个可观察源,无需任何转换
    • mergeArray:将作为数组给出的多个输入源展开为一个可观察源,而不进行任何转换
    • mergeArrayDelayError:将作为数组给出的多个输入源展开为一个可观察源,没有任何转换,也没有被错误打断
    • mergeDelayError:将多个输入源展开为一个可观察源,没有任何转换,也没有被错误打断
    • mergeWith:将这个和给定的源展开为一个可观察的,没有任何转换

    在下面的示例中,我们将合并原始 1 到 5 范围的部分,合并方式是它包含所有条目,但顺序不同:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INSCnaFz-1657721282497)(img/6e6af107-c6bc-4a15-be00-3023a00ad305.png)]

    压缩运算符

    基于组合器函数将多个可观察项组合成单个可观察项可以通过调用:

    • zip:将指定的组合器函数的结果应用于给定可观测项所发射的多个项目的组合
    • zipIterable:发出一个指定的组合器函数的结果,该函数应用于给定的可观测项发出的多个项的组合
    • zipWith:发出一个指定的组合器函数的结果,该组合器函数应用于这个和给定的可观察对象的组合

    下面的代码显示了如何基于字符串连接组合器将zip应用于从 1 到 5 到 10 到 16(更多元素)的范围发出的元素。请注意,由于没有要应用的对应项,因此不会应用额外的发射(编号 16):

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yVR7s0O-1657721282497)(img/eb0fc961-36a5-4e0b-a200-3ac7f2b45424.png)]

    错误处理

    Observable包含几个操作符,这些操作符允许错误处理、吞咽异常、转换异常、调用finally块、重试失败的序列以及即使发生错误也可以处理资源。

    捕获运算符

    这些运算符可以通过继续执行以下顺序从错误中恢复:

    • onErrorResumeNext:指示一个可观察对象将控制权传递给供应器提供的另一个可观察对象,而不是在出现问题时调用onError
    • onErrorReturn:指示可观察对象发出函数提供的默认值,以防出现错误
    • onErrorReturnItem:指示可观察对象发出提供的缺省值,以防出现错误
    • onExceptionResumeNext:指示一个可观察对象将控制传递给另一个可观察对象,而不是在出现问题时调用onError

    下面的示例演示如何使用onErrorReturnItem方法;不使用flatMap技巧调用它将停止流并在最后输出Default。通过延迟对异常抛出代码的调用并对其应用onErrorReturnItem,我们可以继续序列并使用提供的默认值:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HecmaufD-1657721282498)(img/672adc55-ebf3-4bb3-89de-850771d01fd4.png)]

    do运算符

    这些用于注册对特定生命周期事件采取的操作。我们可以使用它们来模拟final语句行为,释放分配给上游的资源,进行性能度量,或者执行不依赖于当前调用成功与否的其他任务。RxJava Observable通过提供以下方法来实现这一点:

    • doFinally:注册当前可观察对象调用onCompleteonError或被释放时要调用的动作
    • doAfterTerminate:在当前可观察对象调用onCompleteonError之后注册要调用的动作
    • doOnDispose:注册一个动作,在处理序列时调用
    • doOnLifecycle:根据序列的生命周期事件(订阅、取消、请求),为相应的onXXX方法注册回调
    • doOnTerminate:注册当前可观察对象调用onCompleteonError时要调用的动作

    以下代码段显示了前面提到的命令的用法:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D88AtnUt-1657721282498)(img/56ecf8ec-7db3-4947-85b0-5801ba97a7b5.png)]

    在前面的示例中,我们可以看到生命周期事件的顺序是:订阅、终止、完成或错误,最后通过在每个事件上注册控制台打印操作。

    using运算符

    using操作符在 Java 中有一个对应的操作符,名为资源尝试。它基本上也是这样做的,即创建一个在给定时间(当可观察对象被释放时)被释放的可支配资源。RxJava2.0 方法using实现了这个行为。

    重试运算符

    这些是在发生可恢复的故障(例如服务暂时关闭)时要使用的操作符。他们通过重新订阅来工作,希望这次能顺利完成。可用的 RxJava 方法如下:

    • retry:错误时永远重放同一流程,直到成功
    • retryUntil:重试,直到给定的stop函数返回true
    • retryWhen:基于接收错误/异常的重试逻辑函数,在错误情况下永远重放相同的流,直到成功为止

    在下面的示例中,我们使用只包含两个值的zip来创建重试逻辑,该逻辑在一个时间段后重试两次以运行失败的序列,或者用 500 乘以重试计数。当连接到无响应的 Web 服务时,尤其是从每次重试都会消耗设备电池的移动设备时,可以使用此方法:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aXhV9JCk-1657721282499)(img/70d6545a-2809-4a40-8d32-b37e6e937ae9.png)]

    调度器

    在线程调度方面,可观测是不可知的——在多线程环境中,这是调度器的工作。一些操作符提供了可以将调度器作为参数的变体。有一些特定的调用允许从下游(使用操作符的点,这是observeOn的情况)或不考虑调用位置(调用位置无关紧要,因为这是subscribeOn方法的情况)观察流。在下面的示例中,我们将从上游和下游打印当前线程。注意,在subscribeOn的情况下,线程总是相同的:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5qza8GLT-1657721282499)(img/4acf684b-55fd-4938-845d-b40f900a1022.png)]

    注意map方法中的线程主要用法:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y5mpwm36-1657721282499)(img/027fbe82-d16e-4588-99b5-8abae35211b6.png)]

    请注意,map方法不再使用线程main

    RxJava2.0 提供了更多来自io.reactivex.schedulers.Schedulers工厂的调度器,每个调度器都有特定的用途:

    • computation():返回用于计算工作的Scheduler实例
    • io():返回一个用于 I/O 工作的Scheduler实例
    • single():对于需要在同一后台线程上强顺序执行的工作,返回Scheduler实例
    • trampoline():返回一个Scheduler实例,该实例在一个参与线程上以 FIFO 方式执行给定的工作
    • newThread():返回一个Scheduler实例,该实例为每个工作单元创建一个新线程
    • from(Executor executor):将Executor转换成新的Scheduler实例,并将工作委托给它

    有一个只用于特殊测试目的的Scheduler,称为io.reactivex.schedulers.TestScheduler。我们已经使用了它,因为它允许手动推进虚拟时间,因此非常适合于测试依赖于时间的流,而不必等待时间通过(例如,单元测试)。

    主体

    主体是可观察的和订户的混合体,因为它们都接收和发射事件。RxJava2.0 提供了五个主题:

    • AsyncSubject:仅发射源可观测到的最后一个值,后跟一个完成
    • BehaviorSubject:发射最近发射的值,然后是可观测源发射的任何值
    • PublishSubject:仅向订阅方发送订阅时间之后源发送的项目
    • ReplaySubject:向任何订户发送源发出的所有项目,即使没有订阅
    • UnicastSubject:只允许单个用户在其生存期内订阅

    示例项目

    在下面的示例中,我们将展示 RxJava 在实时处理从多个传感器接收到的温度中的用法。传感器数据由 Spring 引导服务器提供(随机生成)。服务器配置为接受传感器名称作为配置,以便我们可以为每个实例更改它。我们将启动五个实例,并在客户端显示警告,如果其中一个传感器输出超过 80 摄氏度。

    使用以下命令可以从 bash 轻松启动多个传感器:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TiNyK0FI-1657721282500)(img/2570a499-f35d-448f-92a0-e008531b9272.png)]

    服务器端代码很简单,我们只配置了一个 REST 控制器,将传感器数据输出为 JSON,如下代码所示:

    @RestController
    publicclass SensorController 
    {
      @Value("${sensor.name}")
      private String sensorName;
      @RequestMapping(value="/sensor", method=RequestMethod.GET,   
      produces=MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<SensorData> sensor() throws Exception 
      {
        SensorData data = new SensorData(sensorName);
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(new     
        ObjectMapper().writeValueAsString(data).length()));
        returnnew ResponseEntity<SensorData>(data, headers,     
        HttpStatus.CREATED);
      }
    }
    

    传感器数据是在SensorData构造器中随机生成的(注意 Lombock 库的使用,以摆脱获取设置器代码):

    @Data
    publicclass SensorData 
    {
      @JsonProperty
      Double humidity;
      @JsonProperty
      Double temperature;
      @JsonProperty
      String sensorName;
      public SensorData(String sensorName) 
      {
        this.sensorName = sensorName;
        humidity = Double.valueOf(20 + 80 * Math.random());
        temperature = Double.valueOf(80 + 20 * Math.random()); 
      }
    }
    

    现在我们已经启动了服务器,我们可以从支持 RxJava 的客户端连接到它。

    客户端代码使用 rxapache http 库:

    publicclass Main 
    {
      @JsonIgnoreProperties(ignoreUnknown = true)
      staticclass SensorTemperature 
      {
        Double temperature;
        String sensorName;
        public Double getTemperature() 
        {
          return temperature;
        }
        publicvoid setTemperature(Double temperature) 
        {
          this.temperature = temperature;
        }
        public String getSensorName() 
        {
          return sensorName;
        }
        publicvoid setSensorName(String sensorName) 
        {
          this.sensorName = sensorName;
        }
        @Override
        public String toString() 
        {
          return sensorName + " temperature=" + temperature;
        }
      }  
    }
    

    SensorTemperature是我们的客户资料。它是服务器可以提供的内容的快照。其余信息将被 Jackson 数据绑定器忽略:

    publicstaticvoid main(String[] args) throws Exception 
    {
      final RequestConfig requestConfig = RequestConfig.custom()
      .setSocketTimeout(3000)
      .setConnectTimeout(500).build();
      final CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
      .setDefaultRequestConfig(requestConfig)
      .setMaxConnPerRoute(20)
      .setMaxConnTotal(50)
      .build();
      httpClient.start();
    

    在前面的代码中,我们通过设置 TCP/IP 超时和允许的连接数来设置并启动 HTTP 客户端:

    Observable.range(1, 5).map(x ->
    Try.withCatch(() -> new URI("http", null, "127.0.0.1", 8080 + x, "/sensor", null, null), URISyntaxException.class).orElse(null))
    .flatMap(address -> ObservableHttp.createRequest(HttpAsyncMethods.createGet(address), httpClient)
    .toObservable())
    .flatMap(response -> response.getContent().map(bytes -> new String(bytes)))
    .onErrorReturn(error -> "{"temperature":0,"sensorName":""}")
    .map(json ->
    Try.withCatch(() -> new ObjectMapper().readValue(json, SensorTemperature.class), Exception.class)
    .orElse(new SensorTemperature()))
    .repeatWhen(observable -> observable.delay(500, TimeUnit.MILLISECONDS))
    .subscribeOn(Schedulers.io())
    .subscribe(x -> {
    if (x.getTemperature() > 90) {
    System.out.println("Temperature warning for " + x.getSensorName());
    } else {
    System.out.println(x.toString());
    }
    }, Throwable::printStackTrace);
    }
    }
    

    前面的代码基于范围创建 URL 列表,将其转换为响应列表,将响应字节展开为字符串,将字符串转换为 JSON,并将结果打印到控制台。如果温度超过 90 度,它将打印一条警告信息。它通过在 I/O 调度器中运行来完成所有这些,每 500 毫秒重复一次,如果出现错误,它将返回默认值。请注意Try单子的用法,因为选中的异常是由 Lambda 代码引发的,因此需要通过转换为可由 RxJava 在onError中处理的未选中表达式或在 Lambda 块中本地处理来处理。

    由于客户端永远旋转,部分输出如下:

    NuclearCell2 temperature=83.92902289170053
    Temperature warning for NuclearCell1
    Temperature warning for NuclearCell3
    Temperature warning for NuclearCell4
    NuclearCell5 temperature=84.23921169948811
    Temperature warning for NuclearCell1
    NuclearCell2 temperature=83.16267124851476
    Temperature warning for NuclearCell3
    NuclearCell4 temperature=81.34379085987851
    Temperature warning for NuclearCell5
    NuclearCell2 temperature=88.4133065761349
    

    总结

    在本章中,我们学习了反应式编程,然后重点介绍了可用的最常用的反应式库之一——RxJava。我们学习了反应式编程抽象及其在 RxJava 中的实现。我们通过了解可观察对象、调度器和订阅是如何工作的、最常用的方法以及它们是如何使用的,从而通过具体的示例迈出了进入 RxJava 世界的第一步。

    在下一章中,我们将学习最常用的反应式编程模式,以及如何在代码中应用它们。

    展开全文
  • 最近在做项目的时候,需要对界面进行不断的刷新操作,在一定的时间内连续触发某个函数,按照之前Python里的思路,第一反应是用time函数,但实际的效果并不好,经常会卡住,后来尝试用pyqt5里自带的计时器,这个问题...

    最近在做项目的时候,需要对界面进行不断的刷新操作,在一定的时间内连续触发某个函数,按照之前Python里的思路,第一反应是用time函数,但实际的效果并不好,经常会卡住,后来尝试用pyqt5里自带的计时器,这个问题完美解决。
    做完项目顺边开了开脑洞,既然可以即时刷新,那么自然可以利用这一点设计个小游戏,比如打地鼠,废话不多说,先上效果!

    **(文末有素材和完整代码)**码字不易,喜欢请三联!

    请添加图片描述
    不着急动手做,先来聊聊原理性的知识!
    一、关于Timer计时器
    PyQt5中自带的timer计时器,是一种固定间隔刷新的计时器,可设置其刷新的间隔,也就是说我们可以以固定的间隔去触发某个函数等等。
    1.计时器的引入。

    from PyQt5 import QtCore
    

    2.相关的方法
    QtCore.QTimer():生成计时器
    start():启动计时器,()内设置时间,单位ms,也就是说start(1000)=1秒
    timeout():计时器启动后,发射信号
    stop():停止信号

    二、计时器测试
    1.我们先用QTdesiger做一个简单的UI界面,如下:
    在这里插入图片描述
    测试代码如下

    from PyQt5 import QtCore, QtGui, QtWidgets
    from untitled01 import Ui_MainWindow
    import sys
    
    class window(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self):
            super().__init__()
            self.setupUi(self)
            self.timer01 = QtCore.QTimer(self) #生成计时器
            self.timer01.start(1000) #设置间隔刷新间隔为1秒
            self.timer01.timeout.connect(self.test1) #每次触发调用test1
            self.nn=1 #全局变量,用于停止
    
        def test1(self):
            self.nn+=1 #每次调用增加1
            print(self.nn) 
            if self.nn==5: 
                self.timer01.stop() #调用5次后停止
                print('已经停止')
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = window()  # 创建窗体对象
        MainWindow.show()  # 显示窗体
        sys.exit(app.exec_())  # 程序关闭时退出进程
    

    具体的测试细节在代码注释中,需要注意的是,第二行引用的untitled01,是UI文件生成的py文件,至于为什么这么引用,是因为不用担心修改UI重新生成py文件后,不用担心覆盖源代码,具体的操作模板,可以参考下面的文章【Python心得】解决PyQt5 UI更新同步问题,测试效果如下:
    请添加图片描述
    三、开始开脑洞
    既然每次刷新都可以触发函数,那么就可以在刷新之后随机设置不同的背景,随机生成不同的地鼠。具体制作思路如下:
    1.设计UI,效果如下:
    在这里插入图片描述
    看起来很复杂?其实很简单,素材我会放在文末,具体的制作也只要学会一步设置背景就可以了,具体参照下面的文章
    【PyQt5】教你一招,分分钟撸一个网易云音乐的UI界面,分分钟学会!

    2.计时器开始刷新时,生成一个随机数列,包括9个数字,每个数字是0或者1,这里用1表示出现地鼠,用0表示没有地鼠,所以只要判断数列的每个数字是0或者1,然后设置不同的背景即可,比如数列的第一个数字如果是1,那么就在第一个坑设置有地鼠。具体代码如下:

        def Whac_a_mole(self):
            hole=[]
            for i in range(9):
                hole.append(str(random.randint(0,1))) #生成随机数列
            if hole[0]=='1':
                self.pushButton_1.setStyleSheet('border-image: url(:/PNG/m01.png);')#设置有地鼠
            else:
                self.pushButton_1.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[1]=='1':
                self.pushButton_2.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_2.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[2]=='1':
                self.pushButton_3.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_3.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[3]=='1':
                self.pushButton_4.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_4.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[4]=='1':
                self.pushButton_5.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_5.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[5]=='1':
                self.pushButton_6.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_6.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[6]=='1':
                self.pushButton_7.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_7.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[7]=='1':
                self.pushButton_8.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_8.setStyleSheet('border-image: url(:/PNG/k01.png);')
            if hole[8]=='1':
                self.pushButton_9.setStyleSheet('border-image: url(:/PNG/m01.png);')
            else:
                self.pushButton_9.setStyleSheet('border-image: url(:/PNG/k01.png);')```
    
    3.设置开始触发代码,具体如下:
    
    ```python
        def start(self):
            self.time01.start(2000)
            # self.time01.timeout.connect(self.color_test)
            self.time01.timeout.connect(self.Whac_a_mole)
    ``
    这里我把开始的代码放到函数中,是希望能够用开始按钮去点击触发
    
    4.敲击代码。如果点击对应的按钮,就会进行判断,如果是出现地鼠,则加载敲晕的图片,否则没有变化,这里用到的判断,如何解决?
    我的思路是,上面的第二步代码我们在随机生成的列表中,加载图片的同时,可以顺便用settext()0或者1,设置到按钮中,如果感觉设置的数字会影响按钮美观,可以将字号设置成1,几乎看不出来的。
    敲击代码如下:
    
    ```python
        def hit01(self):
            if self.pushButton_1.text()=='1':
                self.pushButton_1.setStyleSheet('border-image: url(:/PNG/m02.png);')
    

    需要对每个按钮都进行设置,这里不全部列出来了!

    上面第二步需要增加的代码如下:

          #设置标志位
            self.pushButton_1.setText(hole[0])
            self.pushButton_2.setText(hole[1])
            self.pushButton_3.setText(hole[2])
            self.pushButton_4.setText(hole[3])
            self.pushButton_5.setText(hole[4])
            self.pushButton_6.setText(hole[5])
            self.pushButton_7.setText(hole[6])
            self.pushButton_8.setText(hole[7])
            self.pushButton_9.setText(hole[8])
    

    5.最后一步,设置停止按钮,这步一行就可以,但。。。轻微强迫症让我必须回到初始状态,所以代码如下:

        #停止按钮
        def stop(self):
            self.time01.stop()
            self.pushButton_1.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_2.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_3.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_4.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_5.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_6.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_7.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_8.setStyleSheet('border-image: url(:/PNG/k01.png);')
            self.pushButton_9.setStyleSheet('border-image: url(:/PNG/k01.png);')
    

    写到这基本思路就完成了。效果如下:请添加图片描述

    最后贴上完整代码:
    UI部分

    -- coding: utf-8 --

    Form implementation generated from reading ui file ‘dadishuUI.ui’

    Created by: PyQt5 UI code generator 5.13.0

    WARNING! All changes made in this file will be lost!

    from PyQt5 import QtCore, QtGui, QtWidgets

    class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
    MainWindow.setObjectName(“MainWindow”)
    MainWindow.resize(1024, 822)
    MainWindow.setStyleSheet("")
    self.centralwidget = QtWidgets.QWidget(MainWindow)
    self.centralwidget.setObjectName(“centralwidget”)
    self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
    self.layoutWidget.setGeometry(QtCore.QRect(120, 110, 771, 661))
    self.layoutWidget.setObjectName(“layoutWidget”)
    self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
    self.gridLayout.setContentsMargins(0, 0, 0, 0)
    self.gridLayout.setObjectName(“gridLayout”)
    self.pushButton_5 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_5.sizePolicy().hasHeightForWidth())
    self.pushButton_5.setSizePolicy(sizePolicy)
    self.pushButton_5.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_5.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_5.setFont(font)
    self.pushButton_5.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_5.setObjectName(“pushButton_5”)
    self.gridLayout.addWidget(self.pushButton_5, 1, 1, 1, 1)
    self.pushButton_2 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth())
    self.pushButton_2.setSizePolicy(sizePolicy)
    self.pushButton_2.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_2.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_2.setFont(font)
    self.pushButton_2.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_2.setObjectName(“pushButton_2”)
    self.gridLayout.addWidget(self.pushButton_2, 0, 1, 1, 1)
    self.pushButton_6 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_6.sizePolicy().hasHeightForWidth())
    self.pushButton_6.setSizePolicy(sizePolicy)
    self.pushButton_6.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_6.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_6.setFont(font)
    self.pushButton_6.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_6.setObjectName(“pushButton_6”)
    self.gridLayout.addWidget(self.pushButton_6, 1, 2, 1, 1)
    self.pushButton_3 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_3.sizePolicy().hasHeightForWidth())
    self.pushButton_3.setSizePolicy(sizePolicy)
    self.pushButton_3.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_3.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_3.setFont(font)
    self.pushButton_3.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_3.setObjectName(“pushButton_3”)
    self.gridLayout.addWidget(self.pushButton_3, 0, 2, 1, 1)
    self.pushButton_7 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_7.sizePolicy().hasHeightForWidth())
    self.pushButton_7.setSizePolicy(sizePolicy)
    self.pushButton_7.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_7.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_7.setFont(font)
    self.pushButton_7.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_7.setObjectName(“pushButton_7”)
    self.gridLayout.addWidget(self.pushButton_7, 2, 0, 1, 1)
    self.pushButton_8 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_8.sizePolicy().hasHeightForWidth())
    self.pushButton_8.setSizePolicy(sizePolicy)
    self.pushButton_8.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_8.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_8.setFont(font)
    self.pushButton_8.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_8.setObjectName(“pushButton_8”)
    self.gridLayout.addWidget(self.pushButton_8, 2, 1, 1, 1)
    self.pushButton_1 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_1.sizePolicy().hasHeightForWidth())
    self.pushButton_1.setSizePolicy(sizePolicy)
    self.pushButton_1.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_1.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setFamily(".萍方-简")
    font.setPointSize(1)
    self.pushButton_1.setFont(font)
    self.pushButton_1.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_1.setObjectName(“pushButton_1”)
    self.gridLayout.addWidget(self.pushButton_1, 0, 0, 1, 1)
    self.pushButton_9 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_9.sizePolicy().hasHeightForWidth())
    self.pushButton_9.setSizePolicy(sizePolicy)
    self.pushButton_9.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_9.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_9.setFont(font)
    self.pushButton_9.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_9.setObjectName(“pushButton_9”)
    self.gridLayout.addWidget(self.pushButton_9, 2, 2, 1, 1)
    self.pushButton_4 = QtWidgets.QPushButton(self.layoutWidget)
    sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth())
    self.pushButton_4.setSizePolicy(sizePolicy)
    self.pushButton_4.setMinimumSize(QtCore.QSize(200, 200))
    self.pushButton_4.setMaximumSize(QtCore.QSize(200, 200))
    font = QtGui.QFont()
    font.setPointSize(1)
    self.pushButton_4.setFont(font)
    self.pushButton_4.setStyleSheet(“border-image: url(:/PNG/k01.png);”)
    self.pushButton_4.setObjectName(“pushButton_4”)
    self.gridLayout.addWidget(self.pushButton_4, 1, 0, 1, 1)
    self.pushButton_0 = QtWidgets.QPushButton(self.centralwidget)
    self.pushButton_0.setGeometry(QtCore.QRect(530, 60, 251, 81))
    font = QtGui.QFont()
    font.setFamily(“方正稚艺简体”)
    font.setPointSize(20)
    self.pushButton_0.setFont(font)
    self.pushButton_0.setStyleSheet(“border-image: url(:/PNG/按钮01.png);”)
    self.pushButton_0.setObjectName(“pushButton_0”)
    self.label = QtWidgets.QLabel(self.centralwidget)
    self.label.setGeometry(QtCore.QRect(-120, -660, 1500, 1500))
    self.label.setStyleSheet(“border-image: url(:/PNG/1111.jpg);”)
    self.label.setText("")
    self.label.setObjectName(“label”)
    self.pushButton_10 = QtWidgets.QPushButton(self.centralwidget)
    self.pushButton_10.setGeometry(QtCore.QRect(750, 60, 251, 81))
    font = QtGui.QFont()
    font.setFamily(“方正稚艺简体”)
    font.setPointSize(20)
    self.pushButton_10.setFont(font)
    self.pushButton_10.setStyleSheet(“border-image: url(:/PNG/按钮01.png);”)
    self.pushButton_10.setObjectName(“pushButton_10”)
    self.label.raise_()
    self.layoutWidget.raise_()
    self.pushButton_0.raise_()
    self.pushButton_10.raise_()
    MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "打地鼠"))
        self.pushButton_5.setText(_translate("MainWindow", "5"))
        self.pushButton_2.setText(_translate("MainWindow", "2"))
        self.pushButton_6.setText(_translate("MainWindow", "6"))
        self.pushButton_3.setText(_translate("MainWindow", "3"))
        self.pushButton_7.setText(_translate("MainWindow", "7"))
        self.pushButton_8.setText(_translate("MainWindow", "8"))
        self.pushButton_1.setText(_translate("MainWindow", "1"))
        self.pushButton_9.setText(_translate("MainWindow", "9"))
        self.pushButton_4.setText(_translate("MainWindow", "4"))
        self.pushButton_0.setText(_translate("MainWindow", "开始"))
        self.pushButton_10.setText(_translate("MainWindow", "停止"))
    

    import mouse_rc

    主代码部分

    在这里插入代码片
    

    from PyQt5 import QtCore, QtGui, QtWidgets
    from dadishuUI import Ui_MainWindow
    import sys,time,random
    import mouse

    class window(QtWidgets.QMainWindow, Ui_MainWindow):
    def init(self):
    super().init()
    self.setupUi(self)
    self.time01=QtCore.QTimer()
    self.pushButton_0.clicked.connect(self.start)
    self.pushButton_1.clicked.connect(self.hit01)
    self.pushButton_2.clicked.connect(self.hit02)
    self.pushButton_3.clicked.connect(self.hit03)
    self.pushButton_4.clicked.connect(self.hit04)
    self.pushButton_5.clicked.connect(self.hit05)
    self.pushButton_6.clicked.connect(self.hit06)
    self.pushButton_7.clicked.connect(self.hit07)
    self.pushButton_8.clicked.connect(self.hit08)
    self.pushButton_9.clicked.connect(self.hit09)
    self.pushButton_10.clicked.connect(self.stop)

    def start(self):
        self.time01.start(2000)
        # self.time01.timeout.connect(self.color_test)
        self.time01.timeout.connect(self.Whac_a_mole)
        
    def Whac_a_mole(self):
        hole=[]
        for i in range(9):
            hole.append(str(random.randint(0,1))) #生成随机数列
        if hole[0]=='1':
            self.pushButton_1.setStyleSheet('border-image: url(:/PNG/m01.png);')#设置有地鼠
        else:
            self.pushButton_1.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[1]=='1':
            self.pushButton_2.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_2.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[2]=='1':
            self.pushButton_3.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_3.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[3]=='1':
            self.pushButton_4.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_4.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[4]=='1':
            self.pushButton_5.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_5.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[5]=='1':
            self.pushButton_6.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_6.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[6]=='1':
            self.pushButton_7.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_7.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[7]=='1':
            self.pushButton_8.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_8.setStyleSheet('border-image: url(:/PNG/k01.png);')
        if hole[8]=='1':
            self.pushButton_9.setStyleSheet('border-image: url(:/PNG/m01.png);')
        else:
            self.pushButton_9.setStyleSheet('border-image: url(:/PNG/k01.png);')
        #设置标志位
        self.pushButton_1.setText(hole[0])
        self.pushButton_2.setText(hole[1])
        self.pushButton_3.setText(hole[2])
        self.pushButton_4.setText(hole[3])
        self.pushButton_5.setText(hole[4])
        self.pushButton_6.setText(hole[5])
        self.pushButton_7.setText(hole[6])
        self.pushButton_8.setText(hole[7])
        self.pushButton_9.setText(hole[8])
    
    
    def hit01(self):
        if self.pushButton_1.text()=='1':
            self.pushButton_1.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit02(self):
        if self.pushButton_2.text()=='1':
            self.pushButton_2.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit03(self):
        if self.pushButton_3.text()=='1':
            self.pushButton_3.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit04(self):
        if self.pushButton_4.text()=='1':
            self.pushButton_4.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit05(self):
        if self.pushButton_5.text()=='1':
            self.pushButton_5.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit06(self):
        if self.pushButton_6.text()=='1':
            self.pushButton_6.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit07(self):
        if self.pushButton_7.text()=='1':
            self.pushButton_7.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit08(self):
        if self.pushButton_8.text()=='1':
            self.pushButton_8.setStyleSheet('border-image: url(:/PNG/m02.png);')
    def hit09(self):
        if self.pushButton_9.text()=='1':
            self.pushButton_9.setStyleSheet('border-image: url(:/PNG/m02.png);')
    
    #停止按钮
    def stop(self):
        self.time01.stop()
        self.pushButton_1.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_2.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_3.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_4.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_5.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_6.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_7.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_8.setStyleSheet('border-image: url(:/PNG/k01.png);')
        self.pushButton_9.setStyleSheet('border-image: url(:/PNG/k01.png);')
    
    if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = window()  # 创建窗体对象
    MainWindow.show()  # 显示窗体
    sys.exit(app.exec_())  # 程序关闭时退出进程
    

    素材如下:
    背景图片

    坑
    地鼠01
    按钮背景
    地鼠02

    展开全文
  • Linux 时钟与计时器

    2021-05-16 18:06:07
    计时器反应的则是相对时间,即相对于系统启动后的计时。操作系统内核需要管理运行时间(uptime)和墙上时间(wall time),而内核中大量事务需要由时间驱动。系统时钟系统内核需要借助硬件设施来管理时间,实时时钟(RTC)...
  • 基于STM32的课程设计——篮球记分

    千次阅读 2022-03-13 20:31:58
    红外接收接受红外遥控发出的信号,通过控制芯片进行处理来完成各项控制功能,本设计具有比赛过程中具有比赛开始/暂停,时间倒计时(精确到0.01秒),比分加减,半场球队比分对调,比赛时间调整,24/14秒设置,大...
  • 复习js:用settimeout来做一个计时器

    千次阅读 2018-04-28 15:32:07
    的操作, 因为计时器有其他更精简的写法。 (留意: 这方式的计时并不准确。) 2. 留意计秒的 function: function  countSec ( ) {  x  =  x  +  1   z  =  x %  60  document. displaySec . displayBox ....
  • 八路数字抢答器设计

    千次阅读 多人点赞 2021-07-16 20:03:23
    本次所实现的功能是:设计由主持人控制具有优先抢答、定时抢答、抢答报警功能的多路抢答电路,利用数码管分别显示抢答者的编号及抢答时间。可同时供8名选手进行抢答的多路抢答,设置主持人控制开关,用来控制...
  • [libevent]Reactor反应器设计模式

    千次阅读 2015-04-12 01:00:47
    对象行为类的设计模式,对同步事件分拣和派发。别名Dispatcher(分发)  Reactor模式是处理并发I/O比较常见的一种模式,用于同步I/O,中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用上,同时主线程...
  • 设计模式之----- 反应器(Reactor)模式

    千次阅读 2017-02-23 09:53:29
    NIO非堵塞技术实际是采取反应器模式,或者说是观察者(observer)模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。 同步和异步...
  • DIY一个高大上带提醒的计时器,简单实用,你还在等什么发布时间:2020-07-19 15:02:29来源:51CTO阅读:1124作者:实验楼小编心语:锵锵锵!小编我又来了!昨天发了一篇比较实用的《Python聊天室》,鉴于反响还不错...
  • 设计一个用于智力竞赛的抢答器计时器,同时能测试人的反应时间。按启动键,测试开始,2个八段码倒计时开始(如从10秒或20秒倒计时),在随机时间内点亮抢答允许灯,参赛双方分别按各自的抢答按钮参与抢答。一旦其中...
  • 多线程这个令人生畏的“洪水猛兽”,很多人谈起多线程都心存畏惧。在Android开发过程中,多线程真的很难吗?多线程程序的“麻烦”源于它很抽象、与单线程程序运行模式不同,但只要掌握了它们的... 多线程案例——计时
  • Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目基于单片机的智能手环 -计步大家可用于 课程设计 或 毕业设计单片机-嵌入式毕设选题大全及项目分享:... 传统的就医形式已经通过网络互联科技而变得高效, ...
  • 抢答器设计与测试(实验报告)

    千次阅读 2020-11-30 18:30:24
    抢答 一、 实验目的 综合运用 D 触发器、门控时钟、计数器等。 用 LED 和数码管显示抢答成功的组号。 了解小型综合数字系统实验的调试和故障排除方法。 二、 实验原理及内容 完整的实验电路图如下图: 1.抢答...
  • 推荐理由:功夫拖鞋是一款考验反应力的趣味闯关游戏,拿起手中的拖鞋,用不同的技巧来消灭老鼠。游戏玩法很轻松,带来的玩法轻松解压,体验更丰富的游戏乐趣。推荐理由:千手英雄是一款一个人同时挑战多个游戏的趣味...
  • 随着我国经济和文化实业的...本设计将以PLC为核心设计了系统结构图、程序指令、梯形图以及输入输出端子的分配方案,在保留了原始抢答的基本功能的同时又增加一系列的实用功能并简化其电路结构,其将以其控制方便,
  • 可编程等待计时器 – 等待状态功率 – 70µA 典型值 – 可编程范围为 2.72 毫秒到大于 6 秒 I2C 兼容接口 – 高达 400 kHz(I2C 快速模式) – 专用中断引脚 – I2C VBUS = VDD 接口 睡眠模式功率 - 2.5µA 典型值 ...
  • 订单付款倒计时实现方案

    千次阅读 2021-04-17 22:36:30
    我们的第一反应是用 数据库轮序+任务调度 来实现此功能。但这种高效率的延迟任务用任务调度(定时器)实现就得不偿失。而且对系统也是一种压力且数据库消耗极大。因此我们使用 Java 延迟队列 DelayQueue ..
  • 基于STM32设计的数字电子秤

    千次阅读 2021-12-26 13:10:56
    //溢出计时器 dat = CS_CON; // 0100 1000 CS1237_DOUT(); OUT_HIGH delay_ms(310); //上电建立时间 CS1237_DRDY(); //配置PB15...
  • 基于51单片机的秒表设计

    千次阅读 2021-08-06 23:19:23
    51单片机基础难点知识理解后,直接通过下面3个小项目可以更好理解51单片机。中断 定时器 串口甚至是基础的IO输入输出都...项目一:秒表设计 项目二:LCD1602显示器显示 项目三:循迹+蓝牙小车 基于51单片机的秒表设计 ...
  • 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的新项目是基于单片机的智能手环 -计步学长这里给一个题目综合评分(每项满分5分)难度系数:4分工作量:4分创新点:3分。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,214
精华内容 3,285
热门标签
关键字:

反应计时器设计