硬汉嵌入式论坛

 找回密码
 立即注册
查看: 751|回复: 9
收起左侧

[emWin] WM_Timer 导致的刷新问题

[复制链接]

2

主题

13

回帖

19

积分

新手上路

积分
19
发表于 2022-10-27 22:15:17 | 显示全部楼层 |阅读模式
我在 freertos 下创建了一个 emwin 的 task。写了一个窗口,上面有几个文本控件,表示时间(年月日等),预期的效果是能逐个闪烁以提示用户修改。为了实现闪烁的效果,我用 Timer 每隔一段时间重新绘制文本(显示值或者不显示)。现在遇到的问题是,如果我把这个 Timer 的时间放长到 1 s ,就一切正常;但是如果调整到 500ms ,就会发现 GUI task 的 while 1 里面的每轮时间拉长了(原来是 GUI_Delay 100 ms,现在变成了600 ms)。请问这是什么原因造成的呢?
代码如下:
[C] 纯文本查看 复制代码
#define TEXT_BLINKING_SPEED 500

static void presentDateTime(WM_HWIN hWin)
{
  static U8 isDisplayNbr = 0;
  char nullStr[3] = "";
  WM_HWIN hItem;
  int i;
	
  for (i = ID_TEXT_0; i <= ID_TEXT_4; i++) {
    char *pValue;
    if (i == currWidgetId) {
      pValue = (isDisplayNbr ? getDateTimeFieldStr(i) : &nullStr[0]);
    } else {
      pValue = getDateTimeFieldStr(i);
    }
    hItem = WM_GetDialogItem(hWin, i);
    TEXT_SetText(hItem, pValue);
  }

  isDisplayNbr = isDisplayNbr ? 0 : 1;
}

static void _cbDialog(WM_MESSAGE * pMsg) {
  const void * pData;
  WM_HWIN      hItem;
  U32          FileSize;
  // USER START (Optionally insert additional variables)
  WM_HWIN hWin = pMsg->hWin;
  int i;

  switch (pMsg->MsgId) {
  case WM_INIT_DIALOG:
    // ...
  case WM_PAINT:
    presentDateTime(pMsg->hWin);
    break;
  case WM_TIMER:
    WM_InvalidateWindow(hWin);
    WM_RestartTimer(pMsg->Data.v, TEXT_BLINKING_SPEED);
    break;
  // USER END
  default:
    WM_DefaultProc(pMsg);
    break;
}

WM_HWIN CreateWindow_clock(void);
WM_HWIN CreateWindow_clock(void) {
  WM_HWIN hWin;
  WM_HTIMER hTimer;

  TEXT_SetDefaultFont(GUI_FONT_32B_ASCII);
  TEXT_SetDefaultTextColor(GUI_WHITE);
  getDateTimeToStr(&g_textDateTime);

  hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);

  hTimer = WM_CreateTimer(hWin, 0, TEXT_BLINKING_SPEED, 0);
  WM__ahWinFocus[0] = hWin;

  return hWin;
}


void MainTask(void) 
{
	WM_SetCreateFlags(WM_CF_MEMDEV);
	GUI_Init();

        CreateWindow_clock();
	while(1)
	{
		printf("before GUI_Delay\r\n");
		GUI_Delay(100);
		printf("after GUI_Delay\r\n");
	}
}



log 如下:

[C] 纯文本查看 复制代码
[21:50:27.852]before GUI_Delay
[21:50:28.490]after GUI_Delay
[21:50:28.491]before GUI_Delay
[21:50:29.146]after GUI_Delay
[21:50:29.147]before GUI_Delay
[21:50:29.785]after GUI_Delay
[21:50:29.785]before GUI_Delay
[21:50:30.425]after GUI_Delay
[21:50:30.425]before GUI_Delay


回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-10-28 00:16:10 | 显示全部楼层
补充一下,我的窗口里用 image 做了一个背景
[C] 纯文本查看 复制代码
  case WM_INIT_DIALOG:
    //
    // Initialization of 'Image'
    //
    hItem = WM_GetDialogItem(pMsg->hWin, ID_IMAGE_0);
    WM_SetCallback(hItem, _cbImage);


调试下来发现,似乎是这个现实背景图片的函数每次都在重绘,耗用了时间

[C] 纯文本查看 复制代码
static void _cbImage(WM_MESSAGE * pMsg)
{
  switch (pMsg->MsgId) {
  case WM_PAINT:
#ifdef F_DEBUG
	  printf("before _cbImage paint\r\n");
#endif	
    drawJpeg(BK_IMAGE_PATH, 0, 0, 0, 1, 1);
#ifdef F_DEBUG
	  printf("after _cbImage paint\r\n");
#endif		
    break;
  default:
    WM_DefaultProc(pMsg);
    break;
  }
}


怎么让 Timer 每次到的时候只重绘那几个 Text 控件呢?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2022-10-28 02:56:24 | 显示全部楼层
f0g 发表于 2022-10-28 00:16
补充一下,我的窗口里用 image 做了一个背景
[mw_shl_code=c,true]
  case WM_INIT_DIALOG:

IMAG改成使用DrawBitmap位图实现(如果你显存空间大的话,使用存储设备画图是最快的),放在WM_PAINT里面。

然后你的更新函数 WM_InvalidateWindow(hWin);换成局部刷新函数,看看整体效果是否好点。
回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-10-28 21:27:40 | 显示全部楼层
谢谢答复。我的图片因为可能经常更换,所以希望能从文件系统读取,而不是转换成 c 文件二进制读取。用 DramBitmap 的话是要先转成字节流数据的吧? 如果每次都从文件系统读取应该如何实现呢?
我搜索了一下,没找到局部刷新函数,麻烦给个函数名。
我测试发现,这个显示图片的函数耗时大约500毫秒,并且会影响到 rtos 里的其他 task 执行,请问 emwin 在 f429 上面绘制 320*240 的图片这么久正常吗?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2022-10-29 01:05:41 | 显示全部楼层
f0g 发表于 2022-10-28 21:27
谢谢答复。我的图片因为可能经常更换,所以希望能从文件系统读取,而不是转换成 c 文件二进制读取。用 Dram ...

这个显示速度太慢了,换用存储设备的API绘制。

然后局部刷新时这两个
image.png
回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-10-29 21:22:04 | 显示全部楼层
原来如此。我以为在 emwin 的主 task 里面调用了函数 WM_SetCreateFlags(WM_CF_MEMDEV); 然后在 emwin 里所有的图形操作都走存储设备呢

改写了一下,在 init_dialog 的时候把图片载入到 memdev,然后在 image paint 的时候通过 memdev 绘制。速度变成不到 20 毫秒了。
回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-11-1 17:53:48 | 显示全部楼层
eric2013 发表于 2022-10-28 02:56
IMAG改成使用DrawBitmap位图实现(如果你显存空间大的话,使用存储设备画图是最快的),放在WM_PAINT里面 ...

这里还有一个问题,如果不在 IMAGE 那里绘制,而是按照您的建议在 WM_PAINT 里面绘制图片的话,会覆盖掉我在 INIT_DIALOG 里面绘制的其他控件,这个如何解决呢?
回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-11-1 21:51:09 | 显示全部楼层
我现在的做法是在 INIT_DIALOG 里面创建存储设备,然后绘制图片,在切换窗口的时候(比如按了某个键),关闭当前窗口,释放存储设备,然后打开新的窗口。感觉这样做的话很不优雅,有没有什么消息可以在 DIALOG 关闭之前使用,用来释放存储设备呢?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106882
QQ
发表于 2022-11-2 10:10:14 | 显示全部楼层
f0g 发表于 2022-11-1 17:53
这里还有一个问题,如果不在 IMAGE 那里绘制,而是按照您的建议在 WM_PAINT 里面绘制图片的话,会覆盖掉 ...

绘制位图,不是绘制IMAG
回复

使用道具 举报

2

主题

13

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-11-3 09:55:36 | 显示全部楼层
了解了,谢谢。
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-8 21:58 , Processed in 0.220329 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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