SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3344|回复: 1
打印 上一主题 下一主题

[gui2] tprogress, popup_new_window, quiet_mouse_leave

[复制链接]

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
跳转到指定楼层
楼主
发表于 2017-11-29 19:28:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ancientcc 于 2018-8-18 21:40 编辑

tprogress是用于表示进度的弹出式对话框。它可分为两种使用场景,判断哪种场景的依据是构造tprogress时传入的did_first_drawn参数是否是NULL。

did_first_drawn是NULL时,表示片断式操作下的等待

  1. ......
  2. 收到N个字节的数据
  3. progress_->set_percent(...);
  4. 系统调用了事件循环events::pump
  5. 收到M个字节数据
  6. progress_->set_percent(...);
  7. 系统调用了事件循环events::pump
  8. ......
复制代码
以上可表示网络读取至少N+M字节的数据包的过程。一次read不能收到全部数据,于是被拆为片断式的几个包,而在这几个包的中间,系统过会动调用events::pump。因为有这个events::pump,之前被set_percent弄脏的界面将被绘制。

set_percent会操作gui,因而只能在主线程被调用。如果那些操作不是在主线程,用main_->Invoke去执行set_percent。

did_first_drawn非NULL时,表示阻塞式等待
有时app要想执行个阻塞式操作,这个操作需要点时间,这时为显示进度就可用非NULL方式的tprogress。
  1. void ocr_controller::recognize()
  2. {
  3.         gui2::tprogress dlg(null_str, boost::bind(&ocr_controller::did_recognize, this, _1), 0, false);
  4.         dlg.show(gui_->video());
  5. }

  6. void ocr_controller::did_recognize(gui2::tprogress_& progress)
  7. {
  8.         ......
  9.         progress.set_message(...);
  10.         ......
  11.         progress.set_percentage(...);
  12.         ......
  13. }
复制代码

以上是阻塞式等待的通用处理流程。app首先要构造tprogress,传入写有具体执行过程的参数did_recognize。接下就调用dlg.show让进入显示对话框。did_recognize写具体执行过程,中间按须夹杂set_message和set_percentage。

在逻辑上,dlg.show开始显示tprogress,执行完第一次twindow::draw后,tprogress会回调起注册的did_recognize,系统控制权就交给了did_recognize。由于阻塞在did_recognize,控制权不会再交到系统自动的events::pump,由于set_message/percentage弄脏的界面自然不会被重绘,因而相比片断式操作,此时的tprogress在处理set_message/percentage时多调用了absolute_draw。
回复

使用道具 举报

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
沙发
 楼主| 发表于 2018-8-18 21:39:18 | 只看该作者
本帖最后由 ancientcc 于 2018-8-18 22:04 编辑

函数时机实现示例
bool popup_new_window()tdialog::show。在创建新窗口前,会调用已存的最顶上窗口的此函数  一旦“我”的行为需导致重画,返回true。tscroll_container,发现正显示滚动条,为美观要在此函数隐藏,并返回true。ttext_box:销毁掉放大镜、上下文按钮等悬浮控件。
void quiet_mouse_leave()tdistributor::lower_quiet_mouse_leave。1)新窗口放入dispatchers_前,会调用已在的次顶上窗口的此函数。2)鼠标在当前窗口松开或非正常失去(像focus_lost、leave_windows),会调用下层的最顶上窗口的此函数。tscroll_container:模拟触发一次leave_window事件,让first_coordinate_置为null。 ttrack:类似tscroll_container。


为什么要加上quiet_mouse_leave
窗口A是最顶上窗口,正按着鼠标时,弹出个窗口B,此时要支持窗口B销毁时,若一直没松开过鼠标,那鼠标后面的motion、up对窗口A依旧生效。举个例子,为发网络心跳包而创建进度条窗口B,要是网络状态好,用户就看不到窗口B,窗口B就销毁了。为有良有用户体验,自然希望在窗口A拖着鼠标的后绪操作在窗口B销毁后继续有效,而不致被“莫名”打断了(用户就没看到窗口B)。

基于以上原因,正按着鼠标弹出窗口B时,窗口A中一些控件可能存储着和鼠标状态相关的值,像tscroll_container、ttrack的first_coordinate_。接下在窗口B时松开鼠标,按正常途径,鼠标事件只能发向顶上的窗口,无法到A,于是就会使得first_coordinate_处在错误值(实际已松开了)。quiet_mouse_leave的作用就是解决这问题,让窗口A有机会修正first_coordinate_。

每次鼠标松开或非正常失去,就会调用下层最顶上窗口的quiet_mouse_leave,后者要从窗口广播到控件,毕竟是需要时间。如何节省这时间?考虑到只要一次广播就能让窗口A中控件设置到正确状态,给twindow增加个bool变量quiet_mouse_leaved_,避免第二次或之后还要调用quiet_mouse_leave。

能否不使用quiet_mouse_leave
至少到现在,我认为使用quiet_mouse_leave目的就是为了解决app会“中间”弹出进度条,而且这个进度条是新窗口。无法避免app会“中间”弹出进度条,但只要让进度条不是新窗口,那也是可以不使用quiet_mouse_leave。

ttrack_progress是试着代替的方法,它让一个悬浮控件track去显示进度,从而不弹新窗口。可是,用这方法会有个问题:在显示进度条时,不会自动屏蔽发向该窗口其它控件的事件,这些事件可能导致弹出新窗口,于是界面、甚至内中逻辑就混乱了。为解决这问题,要求app对每个可能弹窗操作的入口都进行判断,那这工作量太大了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2024-5-20 04:27 , Processed in 0.054044 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表