VincentWei / MiniGUI

A modern and mature cross-platform window system for embedded systems and smart IoT devices.
http://www.minigui.com
GNU General Public License v3.0
694 stars 157 forks source link

关于minigui优化的一些问题 #90

Closed htk719809837 closed 1 year ago

htk719809837 commented 2 years ago

目前ui引擎我们打算从3.0升级成5.0,由于以前适配问题,我们修改过底层,经过慎重考虑,为了方便以后minigui升级更新更加方便,并且优化其他用户的体验,我们希望minigui可以修改部分底层代码,具体的建议如下:

/*****button****/ 1、(请务必考虑修改)按钮在一些场景中button按钮点击以后出现崩溃(正在响应事件,但是窗口被关闭了),引起崩溃的代码为 :

button.c

btnGetRects (pctrl, &rcClient, &rcContent, &rcBitmap); if (BUTTON_IS_PUSHBTN(pctrl) || (pctrl->dwStyle & BS_PUSHLIKE)) InvalidateRect((HWND)pctrl, NULL, TRUE); else InvalidateRect((HWND)pctrl, &rcBitmap, FALSE);

建议的修改意见是: 移动这部分代码到下方代码之前:

/*complete a click if the click if valid
 * (mouse lbutton up in button )*/
if (old_pose == BST_PUSHED && new_pose != BST_DISABLE

2、button在按下时是否可以新增按下图片的改变

3、(请务必考虑修改)button在显示图片时,设置 BS_REALSIZEIMAGE 属性时,图片不显示,修改意见为:

button.c 中,做一个强制转换

        x += (int)(w - bmp->bmWidth) >> 1;
        y += (int)(h - bmp->bmHeight) >> 1;

4、button在显示图片后,是否可以新增在图片上叠加显示字符

5、button是否可以默认去除虚线框以及白色边框

win_rdr->draw_push_button win_rdr->draw_focus_frame

/*****iconview****/

1、(请务必考虑修改)修复空区域也可以响应点击事件

if (NULL == pci)
{
    return -1;
}

/*****event****/

1、希望可以默认支持长按消息的响应

/*****scrollview****/

1、希望能够加入scroll view列表滑动以及长按响应

2、修复空区域也可以响应点击事件

if (-1 == mglst->iop.isInItem) break;

以上所有的修改,如果您赞同修改,并且有需要,我们可以提供修改方案,希望minigui越来越好!

VincentWei commented 2 years ago

感谢!这些修改基本上都没问题,可以直接提交 PR,我们这边合并即可。

htk719809837 commented 2 years ago

我们这边方案还不成熟,还在调试测试,讨论之后还是希望官方给出一个比较独立的完整方案,希望能尽快给出修复版本,方便的话请给出修复版本的更新时间。 上述问题最紧急的部分是: 1、event.c init.c 中新增一个触摸长按的事件处理。

2、scrollview可以支持滑动以及响应长按事件。

3、button可以设置按下时的图片改变,以及可以在图片上叠加显示字符。

4、其余的优化以及空区域响应的解决方案在上文中已经提出。

非常感谢!

htk719809837 commented 2 years ago

还有一个问题,目前scrollview我们这边新增了滑动响应以后,存在回退到滑动项的问题,定位发现在init.c如下的if判断中,将其注释以后不会发现问题,希望官方可以给一个修改意见,谢谢! if (me->event != ME_MOVED && (mouse_x != me->x || mouse_y != me->y))

VincentWei commented 2 years ago

建议将这些问题分开成一个个的议题处理,这样会方便我们讨论和跟踪:

  1. 一些小的修改,尤其局部型的,比如对控件的增强或者缺陷修复,您可以直接提 PR。
  2. 可能产生全局性影响的,尤其是尚未有解决方案的,按议题(issue)提出具体的需求说明,我们来跟踪处理。

谢谢!

VincentWei commented 2 years ago

关于本议题中所提需求的处理方案:

第一,通过增加长按消息来支持特定控件的长按处理,这个思路把事情搞复杂了。我们给出的解决方案如下:

  1. 使用定时器处理。在控件回调函数中,按下时捕获鼠标并设置定时器,定时器到期后检查是否仍然捕获鼠标,如果是,则可产生一个自定义的长按消息。
  2. 使用 rel-5-0 分支中的最新代码,我们增强了 MSG_IDLE 的处理,会自动转发 MSG_IDLE 消息到当前捕获了鼠标的控件。这样,控件代码中不需要设置定时器,只要处理 MSG_IDLE 消息,根据按下鼠标时的时间戳(GetTickCount 函数获取)以及该消息的 wParam 所带的时间戳信息来判断按下是否达到了足够长的时间,如果达到,则产生自定义的长按消息。

第二,对 button、scrollview 等内置控件的增强需求,我们建议在 MiniGUI 源代码之外自行维护一套适合自己需求的控件,通过 MiniGUI 提供的控件类注册接口(RegisterWindowClass 函数)注册到系统中使用。针对触摸屏操作,我们通过 mGNCS 和 mGNCS4Touch 组件提供了大量现成控件,可供参考。

第三,关于按钮去除虚线框以及白色边框的需求,可通过重载对应渲染器的 draw_focus_frame 方法实现,不需要修改 MiniGUI:调用 GetWindowRendererFromName() 函数获得窗口外观渲染器(默认应该是 classic)的数据结构结构,然后用自己的 draw_focus_frame 方法替换掉默认的方法即可。您甚至可以自行开发一个符合自己需求的外观渲染器,然后添加到系统中使用,并设置为默认渲染器。

第四,button 和 iconview 两个控件相关的修改已经合并到 rel-5-0 分支。但 scrollview 控件的修改不知道上下文在哪里。

第五,您提到的 init.c 中的那个条件判断,主要用于在收到按钮的按下和释放事件时判断鼠标位置是否有移动,如果有移动,则自动产生一条鼠标的移动事件。就您提到的现象,有如下几种可能:

  1. 释放时,底层输入引擎提供了不正确的位置数据。
  2. 捕获鼠标后的鼠标消息未做坐标转换。MiniGUI 中,控件捕获鼠标后,发送到控件的鼠标位置是相对于屏幕左上角的,通常要做一次屏幕坐标到控件坐标的转换,具体可参考已有控件的代码。
htk719809837 commented 2 years ago

非常感谢提供方案,我们这边会在讨论一下,对于上面提到的修改,貌似还没有提交到rel-5-0中,还没有看到修改。

一、关于第三点自定义渲染器:

extern WINDOW_ELEMENT_RENDERER __mg_wnd_rdr_classic;

ifdef _MGLF_RDR_FLAT

extern WINDOW_ELEMENT_RENDERER __mg_wnd_rdr_flat;

endif

ifdef _MGLF_RDR_SKIN

extern WINDOW_ELEMENT_RENDERER __mg_wnd_rdr_skin;

endif

看到有三个风格,我们自定义了一个新的渲染器,但是需要改动底层才可以引入进去使用,不知道你们可以提供一个custom的风格让我们自己实现吗,就比如我们使用自己的commlcd一样,定义一个target=external 就可以使用,是不是渲染器也可以有一个custom呢,还是有更好的可以实现自定义渲染器的方法?如果有,可以给一个如何在上层修改的实例吗

二、关于scrollview 响应空区域,在listmodel.c中, DefaultItemViewProc函数 if ( !mglst->iop.isInItem ) 修改为 if (-1 == mglst->iop.isInItem) 即可。

其余的我们会讨论,如今后若仍有问题,还希望官方予以支持,谢谢!

VincentWei commented 2 years ago

非常感谢提供方案,我们这边会在讨论一下,对于上面提到的修改,貌似还没有提交到rel-5-0中,还没有看到修改。

转发 MSG_IDLE 消息的处理带来了一些副作用,先暂时不要使用。

看到有三个风格,我们自定义了一个新的渲染器,但是需要改动底层才可以引入进去使用,不知道你们可以提供一个custom的风格让我们自己实现吗,就比如我们使用自己的commlcd一样,定义一个target=external 就可以使用,是不是渲染器也可以有一个custom呢,还是有更好的可以实现自定义渲染器的方法?如果有,可以给一个如何在上层修改的实例吗

MiniGUI 提供有相关接口来添加自定义的渲染器以及设置为默认渲染器。具体样例,请参考 mGPlus 组件中的 fashion 渲染器实现。这个渲染器使用二维矢量图形绘制窗口元素,使用了相关的接口。mg-samples 中的 lf_skin 和 lf_tiny 两个示例程序更加检点一点。

二、关于scrollview 响应空区域,在listmodel.c中, DefaultItemViewProc函数 if ( !mglst->iop.isInItem ) 修改为 if (-1 == mglst->iop.isInItem) 即可。

好的,多谢!

htk719809837 commented 2 years ago

好的,谢谢,如果可以,希望有一个完善的触摸长按消息,拿到就可以用的那种,毕竟这一个长按在众多开发者中,用到的肯定很多!

VincentWei commented 2 years ago

二、关于scrollview 响应空区域,在listmodel.c中, DefaultItemViewProc函数 if ( !mglst->iop.isInItem ) 修改为 if (-1 == mglst->iop.isInItem) 即可。

isInItem 是一个函数指针,初始化为 NULL,代码中其他地方没有设置为 -1 的情形。如果通过接口改变了 iop,应确保对无效的函数指针设置为 NULL,而不是 -1。

好的,谢谢,如果可以,希望有一个完善的触摸长按消息,拿到就可以用的那种,毕竟这一个长按在众多开发者中,用到的肯定很多!

关于这项需求,考虑到长按消息的需求本身可能多变,比如按下时移动,要不要产生长按消息?多长算长按?左键算长按,右键要不要长按?等等。从设计角度讲,这类需求本质上是使用的策略问题,不适合置于底层来处理。作为反例,MiniGUI 3.0 中增加的针对键盘按键的 LONGPRESS 消息,其实现就非常难看,接口很糟糕,理应移除,但为了兼容性不得不保留了下来。

对您的情况,为了方便使用,对所有需要此类处理的控件,我们可以实现一个自定义的控件窗口过程,然后使用这个窗口过程替换 DefaultControlProc 函数,这样就只需要实现一次,而不需要修改所有需要此类控件的窗口过程。

VincentWei commented 2 years ago

好的,谢谢,如果可以,希望有一个完善的触摸长按消息,拿到就可以用的那种,毕竟这一个长按在众多开发者中,用到的肯定很多!

应用层的长按处理,我们通过 5.0.10 中增强的 MSG_IDLE 消息处理机制写了一个通用的实现,作为控件类的默认消息处理过程,基本上可以直接拿来用。供参考:

https://github.com/VincentWei/mg-tests/blob/master/5.0/longpressctrl.c

htk719809837 commented 2 years ago

感谢!

htk719809837 commented 2 years ago

你好,想问一下MSG_IDLE 在什么情况下会一直发给当前的控件呢,是不是需要 setenv("MG_IAL_ENGINE", "auto", 1); setenv("MG_ENV_RECORD_IAL", "capture-input.dat", 1); 将ial的引擎设置为auto,我们自己使用的是custom的ial引擎。 然后我看MSG_IDLE是需要捕获到当前控件才发的,那么我要整个窗口,包括这个窗口的所有控件都响应长按,这样子的设计是不是不太完美呢? 然后想问一下,如果我单独在鼠标按下的时候启一个定时器,抬起的时候杀掉,在这之间检测长按,开销和MSG_IDLE 这个方法比,哪一个更大一点呢

VincentWei commented 2 years ago

你好,想问一下MSG_IDLE 在什么情况下会一直发给当前的控件呢,是不是需要 setenv("MG_IAL_ENGINE", "auto", 1); setenv("MG_ENV_RECORD_IAL", "capture-input.dat", 1);

这是做自动化测试使用的,不要在应用中使用。

然后我看MSG_IDLE是需要捕获到当前控件才发的,那么我要整个窗口,包括这个窗口的所有控件都响应长按,这样子的设计是不是不太完美呢?

所有需要长按的控件,都要按照例子的写法调用那个函数。我们通常称这种函数为消息过滤器(或者钩子)。你可以将这个消息过滤器设计成一个公共的函数,在所有需要长按消息的控件类消息回调函数中调用。具体实现时,过滤器可以在 switch 消息之前调用,这样不需要另行产生自定义的鼠标按下和抬起消息。

所有需要处理长按的控件,都会在按下时成为当前活动控件,不存在同时出现两个活动控件的情形,为避免鼠标按下后,后续的鼠标消息被其他控件处理,一般都需要捕获鼠标,所以并不存在您担心的问题。

然后想问一下,如果我单独在鼠标按下的时候启一个定时器,抬起的时候杀掉,在这之间检测长按,开销和MSG_IDLE 这个方法比,哪一个更大一点呢

定时器的开销当然要大一些,MSG_IDLE 消息几乎没有任何额外开销。

htk719809837 commented 1 year ago

谢谢