Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
RT-Thread RTOS组件:RTGUI教程 workbench(上)
发布于 2009-11-02 22:02:06 浏览:5455
订阅该版
RTGUI教程之二 -- workbench 上 workbench从英文的意思来看, n. 1. 工作台;作业台 RTGUI的workbench是一件很有意义的划分,特别是当RTGUI不支持窗口的时候。RTGUI中的工作台是指,屏幕上互不重叠的区域,或者说这块区域是由每个工作台独占的(如果不存在window的情况下)。 在这个概念下,相当于上层应用可以直接访问物理底层帧缓冲,而不用通知别人,我这个工作台更新了,你这里如果有重叠部分,那么应该重新刷新你的图形。所以可以说,RTGUI的工作台具备独占性。 上次和东南的研究生聊到了一个示波器的原型,他们采用的是FPGA采集数据,而且可能是采集的数据速度远远大于ARM9的处理速度。不过这个系统有个好处,FPGA的数据实际上就是一幅图像,可以直接放到帧缓冲中进行显示。类似于这类应用,可以在RTGUI如何展开呢:首先可以把显示波形的部分单独独立成一个工作台,即独占的了!然后采用DMA的方式直接从FPGA中把图像数据搬移到帧缓冲的相应位置。够直接吧,速度也超级快的,因为ARM这边的干预非常少,只有DMA的动作。 好了,工作台大致使用目的知道了,那么看看,如何在RTGUI中操作工作台呢。首先一个,需要对屏幕面板进行划分,划分出各自的互不重叠的区域:(以下的代码都可在stm32 radio开发板上运行,下同) ``` /* register dock panel */ rect.x1 = 0; rect.y1 = 0; rect.x2 = 240; rect.y2 = 25; rtgui_panel_register("info", &rect); /* register main panel */ rect.x1 = 0; rect.y1 = 25; rect.x2 = 240; rect.y2 = 320; rtgui_panel_register("main", &rect); ``` 这段代码的就是用来注册不同的区域的,总计包括: (00, 00) - (240, 25)的info区域 (00, 25) - (240, 320)的main区域 rtgui_panel_register函数用来注册区域,每个区域需要一个名字,以及它的位置信息。 有了个各个互不重叠的区域信息之后,那就是如何在工作台上绘图了,先看看如何创建一个工作台: ``` /* 相类似的,GUI应用总是依赖于一个可执行的线程环境,先创建一个GUI线程 */ void workbench_init() { static rt_bool_t inited = RT_FALSE; if (inited == RT_FALSE) /* 避免重复初始化而做的保护 */ { rt_thread_t tid; tid = rt_thread_create("wb", workbench_entry, RT_NULL, 2048, 25, 10); if (tid != RT_NULL) rt_thread_startup(tid); inited = RT_TRUE; } } #ifdef RT_USING_RTGUI #include
void workbench() { workbench_init(); } /* finsh的命令输出,可以直接执行workbench()函数以执行上面的函数 */ FINSH_FUNCTION_EXPORT(workbench, workbench demo) #endif ``` 接下来是,做一个Hello World,这个比上一节窗口稍微复杂些,上节采用的是label控件,这里则直接用绘图的形式绘制出来。 ``` static void workbench_entry(void* parameter) { rt_mq_t mq; struct rtgui_view* view; struct rtgui_workbench* workbench; /* 创建GUI应用需要的消息队列 */ mq = rt_mq_create("qWB", 256, 4, RT_IPC_FLAG_FIFO); /* 注册当前线程为GUI线程 */ rtgui_thread_register(rt_thread_self(), mq); /* 创建一个工作台 */ workbench = rtgui_workbench_create("main", "workbench"); if (workbench == RT_NULL) return; /* 创建一个工作台上的一个视图 */ view = rtgui_view_create("widget"); rtgui_widget_set_event_handler(RTGUI_WIDGET(view), view_event_handler); /* 在工作台上添加一个视图 */ rtgui_workbench_add_view(workbench, view); /* 显示这个视图 */ rtgui_view_show(view); /* 执行工作台事件循环 */ rtgui_workbench_event_loop(workbench); /* 去注册GUI线程 */ rtgui_thread_deregister(rt_thread_self()); rt_mq_delete(mq); } ``` 在上面的例子中,我们还看到,除了创建一个工作台之外,还创建了一个view - 视图。我们可以类比下,工作台好比自己的办公桌,桌子上满满的铺上了一张地图,占据了桌面的所有面积。但是,如何换一张地图呢?所以这里有了视图的概念,桌面上的地图可以一张张换,当然了,也可以只是一张。 另外,如上说的,这个例子中要使用的是自行绘制字符串的方式显示“Hello World”,那么如何才能自行绘制呢?要进行绘制必须首先获得一个图形设备的上下文,可以调用函数: rtgui_dc_begin_drawing(widget); 获得,参数是一个控件(workbench、view也是一类特殊控件) 当绘图完成时,调用 rtgui_dc_end_drawing(dc); 函数即可(当应用绘制完图形时,可能这个图形还只存在于缓冲中,并没有刷新到LCD上,所以rtgui_dc_end_drawing会自动通知底层驱动,进行一次更新操作)。 RTGUI内部是完全事件驱动的,特别是当有窗口支持时,事件会显得特别重要,例如:当覆盖到一个工作台的窗口消失时,RTGUI就需要通知被覆盖的工作台做相应的更新动作。 (还记得上一节定时器窗口,当计数器减到0时,为什么窗口还在吗?因为,它所覆盖的地方没有任何应用,RTGUI也当然不会通知更新了) 应用需要做的就是截获相应的事件: ``` static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) { /* 我们目前只对绘制事件感兴趣 */ if (event->type == RTGUI_EVENT_PAINT) { struct rtgui_dc* dc; struct rtgui_rect rect; /* 获得一个设备上下文 */ dc = rtgui_dc_begin_drawing(widget); if (dc == RT_NULL) return RT_FALSE; /* 如果获取失败代表什么?这个控件是隐藏的或... */ rtgui_widget_get_rect(widget, &rect); /* 获得控件的可视区域 */ /* 先对所在可视区域全部填充为背景色 */ rtgui_dc_fill_rect(dc, &rect); /* 绘制一个hello! */ rtgui_dc_draw_text(dc, "hello world", &rect); /* 通知RTGUI,绘制结束 */ rtgui_dc_end_drawing(dc); return RT_FALSE; } /* 如果不是绘制事件,使用view原来的事件处理函数处理 */ return rtgui_view_event_handler(widget, event); } ``` 完整的代码如下: ``` #include
#include
#include
#include
static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) { /* 我们目前只对绘制事件感兴趣 */ if (event->type == RTGUI_EVENT_PAINT) { struct rtgui_dc* dc; struct rtgui_rect rect; /* 获得一个设备上下文 */ dc = rtgui_dc_begin_drawing(widget); if (dc == RT_NULL) return RT_FALSE; /* 如果获取失败代表什么?这个控件是隐藏的或... */ rtgui_widget_get_rect(widget, &rect); /* 获得控件的可视区域 */ /* 先对所在可视区域全部填充为背景色 */ rtgui_dc_fill_rect(dc, &rect); /* 绘制一个hello! */ rtgui_dc_draw_text(dc, "hello world", &rect); /* 通知RTGUI,绘制结束 */ rtgui_dc_end_drawing(dc); return RT_FALSE; } /* 如果不是绘制事件,使用view原来的事件处理函数处理 */ return rtgui_view_event_handler(widget, event); } static void workbench_entry(void* parameter) { rt_mq_t mq; struct rtgui_view* view; struct rtgui_workbench* workbench; /* 创建GUI应用需要的消息队列 */ mq = rt_mq_create("qWB", 256, 4, RT_IPC_FLAG_FIFO); /* 注册当前线程为GUI线程 */ rtgui_thread_register(rt_thread_self(), mq); /* 创建一个工作台 */ workbench = rtgui_workbench_create("main", "workbench"); if (workbench == RT_NULL) return; /* 创建一个工作台上的一个视图 */ view = rtgui_view_create("view"); rtgui_widget_set_event_handler(RTGUI_WIDGET(view), view_event_handler); /* 在工作台上添加一个视图 */ rtgui_workbench_add_view(workbench, view); /* 显示这个视图 */ rtgui_view_show(view); /* 执行工作台事件循环 */ rtgui_workbench_event_loop(workbench); /* 去注册GUI线程 */ rtgui_thread_deregister(rt_thread_self()); rt_mq_delete(mq); } void workbench_init() { static rt_bool_t inited = RT_FALSE; if (inited == RT_FALSE) /* 避免重复初始化而做的保护 */ { rt_thread_t tid; tid = rt_thread_create("wb", workbench_entry, RT_NULL, 2048, 25, 10); if (tid != RT_NULL) rt_thread_startup(tid); inited = RT_TRUE; } } #ifdef RT_USING_RTGUI #include
void workbench() { workbench_init(); } /* finsh的命令输出,可以直接执行workbench()函数以执行上面的函数 */ FINSH_FUNCTION_EXPORT(workbench, workbench demo) #endif ``` ![filelist.png](https://oss-club.rt-thread.org/uploads/53_f5fa973c9d7dbb420ea582b2fe93ffdb.png) ![SV400002.JPG](https://oss-club.rt-thread.org/uploads/53_928a7c59f7f8a97cc860fc2d123c725b.jpg)
查看更多
6
个回答
默认排序
按发布时间排序
bernard
2009-11-02
这家伙很懒,什么也没写!
为radio做的文件列表视图,用于打开mp3文件,明天弄到板子上再拍一张照片出来,后面应该会有更多radio的照片放出。
bernard
2009-11-14
这家伙很懒,什么也没写!
STM32上的文件浏览图片
alexbert
2009-11-15
这家伙很懒,什么也没写!
各位好! 我将上述RTGUI的绘图代码放到application.c里面,去掉FINSH函数,创建了一个线程: int rt_application_init() { rt_thread_t init_thread; #if (RT_THREAD_PRIORITY_MAX == 32) init_thread = rt_thread_create("init", workbench_entry, RT_NULL, 2048, 25, 10); #else 。。。 #endif 烧到板子运行出现异常,不知应该如何解决: register a rtgui thread: init, tid: 0x20002d34 hard fault on thread: init psr: 0x01000000 pc: 0x0800b7be lr: 0x0800b729 r12: 0x08016425 r03: 0x00000010 r02: 0x00000000 r01: 0x20002d4c r00: 0x20002a48 thread pri status sp stack size max used left tick error -------- ---- ------- ---------- ---------- ---------- ---------- --- tidle 0x1f ready 0x00000040 0x00000100 0x00000040 0x00000020 000 tshell 0x14 ready 0x00000040 0x00000800 0x00000040 0x00000064 000 init 0x08 suspend 0x00000040 0x00000800 0x000000cc 0x00000012 000 刚接触RT-Thread不久,请各位指教!
bernard
2009-11-15
这家伙很懒,什么也没写!
你的初始化序列是否不对?在RTGUI server还没启动就把应用给启动起来了
alexbert
2009-11-15
这家伙很懒,什么也没写!
是的,今天下午已经发现了该问题。谢谢!
撰写答案
登录
注册新账号
关注者
0
被浏览
5.5k
关于作者
bernard
这家伙很懒,什么也没写!
提问
414
回答
5940
被采纳
76
关注TA
发私信
相关问题
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部