Gorgon_Meducer
发表于 2018-3-26 19:18:21
gamep 发表于 2018-3-26 18:18
UBOUND(c_tTopMenuItems), //!< menu item count
是这个吗?
不是这个。如果你不知道定义,我回头补上去。
#define UBOUND(__ARRAY) (sizeof(__ARRAY)/(sizeof(__ARRAY)))
gamep
发表于 2018-3-27 08:08:05
Gorgon_Meducer 发表于 2018-3-26 19:18
不是这个。如果你不知道定义,我回头补上去。
知道这种用法,没搜索到这个定义,还以为故意留的,我想简单了。
wendajie123
发表于 2018-3-28 09:33:24
Gorgon_Meducer 发表于 2018-3-26 19:18
不是这个。如果你不知道定义,我回头补上去。
老师你好!!!!你这个思想好像和这个思想一致 。不知道我分析的对不对发不了链接 等级不够搜索LCD菜单程序(多层菜单)
gamep
发表于 2018-3-28 17:28:02
const menu_t c_tTopMenu = {
(menu_item_t *)c_tTopMenuItems, //!< menu item list
UBOUND(c_tTopMenuItems), //!< menu item count
NULL, //!< top menu has no parent
top_menu_engine,
};
最后一个逗号是不是不需要
Gorgon_Meducer
发表于 2018-3-28 20:42:33
gamep 发表于 2018-3-28 17:28
const menu_t c_tTopMenu = {
(menu_item_t *)c_tTopMenuItems, / ...
可以不要,但留下不错。
很细心,但也不是这个问题。
Gorgon_Meducer
发表于 2018-3-28 20:43:08
wendajie123 发表于 2018-3-28 09:33
老师你好!!!!你这个思想好像和这个思想一致 。不知道我分析的对不对发不了链接 等级不够搜索LC ...
很开心我们的想法一致。
caixiong
发表于 2018-3-28 21:43:49
{:smile:}{:smile:}{:smile:}{:smile:}{:smile:}
gamep
发表于 2018-3-29 10:35:07
hmsfeng
发表于 2018-3-29 13:31:33
膜拜大神,又学习了
gamep
发表于 2018-3-29 14:15:46
#define __declare_menu_item_template(__NAME) \
typedef struct __##__NAME __NAME;
#define declare_menu_item_template(__NAME) \
__declare_menu_item_template(__NAME)
请问大师,这种预定义为什么要用两个预定义实现??
#define declare_menu_item_template(__NAME) \
typedef struct __##__NAME __NAME;
直接这样写一个不好吗??
Gorgon_Meducer
发表于 2018-3-29 21:11:10
本帖最后由 Gorgon_Meducer 于 2018-3-29 21:15 编辑
gamep 发表于 2018-3-29 10:35
前两个个都木有说对,最后一个回答正确,鼓掌。然鹅,还有一个!
更新楼主位。
Gorgon_Meducer
发表于 2018-3-29 21:13:40
gamep 发表于 2018-3-29 14:15
#define __declare_menu_item_template(__NAME) \
typedef struct ...
直接写不好。如果你填写的内容里还包涵别的宏,直接写就坑了……
JACK847070222
发表于 2018-3-29 23:01:34
佩服,学习了
wendajie123
发表于 2018-3-30 10:24:55
Gorgon_Meducer 发表于 2018-3-28 20:43
很开心我们的想法一致。
{:lol:} 老师你看了吗?那个架构
gamep
发表于 2018-3-30 10:33:19
switch(this.tState) {
里面没有
default:
不知道算不算?
coslight_dt
发表于 2018-3-30 10:39:57
强帖收藏学习
Gorgon_Meducer
发表于 2018-3-30 21:33:10
wendajie123 发表于 2018-3-30 10:24
老师你看了吗?那个架构
你觉得呢?
Gorgon_Meducer
发表于 2018-3-30 21:33:32
gamep 发表于 2018-3-30 10:33
switch(this.tState) {
里面没有
呃……不算吧
ilikemcu
发表于 2018-3-30 22:07:15
楼主说的这种管理技术的模式,让我想起当前国内排名第一的台湾大润发超市的人员储备制度,他们领导层管理最牛逼也最让下属害怕的,就是谁走了马上有人顶上,有多人也是有足够人员顶,除非集体罢工,^_^楼主也道出了国内很多人忽略的一个严重问题:很多公司的设计永远在夯地基,前面的人造了一层楼,后面的推倒再造一遍,一直在低层次上重复劳动,GDP是很多,但是高度上进展小。给楼主点赞!
Gorgon_Meducer
发表于 2018-3-31 11:26:48
ilikemcu 发表于 2018-3-30 22:07
楼主说的这种管理技术的模式,让我想起当前国内排名第一的台湾大润发超市的人员储备制度,他们领导层管理最 ...
兄弟是明眼人,其中的哀叹和绝望想必你也能体会吧。
ilikemcu
发表于 2018-3-31 15:37:25
Gorgon_Meducer 发表于 2018-3-31 11:26
兄弟是明眼人,其中的哀叹和绝望想必你也能体会吧。
因为曾经在日企呆过几年,开始的时候,日本人的一些做法让人觉得匪夷所思,感觉非常呆板,死脑筋,死教条,一点都不灵活。
后来,一个偶然的机会,听了或者说看了一部台湾余世维的《成功经理人》的讲座,里边就是讲到日本公司训练新人的做法,终于豁然开朗,虽然表面看起来日本人的效率很低,但是从长远看,他们做的每一件事,基本上都会有一个积累,经验、技术、管理,等等各方面,都会有积累,而且这些是一个可以传承继承的积累,前面的人在一个事情上看似非常低效率工作了很长时间的结果,后面的人可以毫无怀疑直接拿来用,并且会一直用下去,直到有更好的替代。这样的优点是前面的低效投入,在未来的很长的时间里一直在产生效益,在这个效益消失之前所产生的总效益,和前面看似傻乎乎的低效率投入做一个比较,其投入产出比远远高于自以为聪明的国人的那种所谓灵活机动!
日本人就是这表面的低效率,实际的高效率,太特么可怕了。以现在国人的思维,想干过日本人,简直是看不到希望。
Gorgon_Meducer
发表于 2018-3-31 17:07:59
ilikemcu 发表于 2018-3-31 15:37
因为曾经在日企呆过几年,开始的时候,日本人的一些做法让人觉得匪夷所思,感觉非常呆板,死脑筋,死教条 ...
是这样的。但故事有后续,关于日本企业的这种做法,其实长久以来一直有一种怀疑的声音,
也就是,前期的低效率是否有办法改进?答案是肯定的,现在欧美企业很多用的就是改进版
本,使得日本企业这种做法的改进版得到充分应用,且前期的效率问题也得到了充分的改善。
pchf005
发表于 2018-4-1 07:34:41
牛B杠杠的
wendajie123
发表于 2018-4-2 10:56:23
Gorgon_Meducer 发表于 2018-3-30 21:33
你觉得呢?
。。。应该看了吧!!!!!!只是想确定下思路框架是不是一样{:loveliness:}
apeng2012
发表于 2018-4-2 11:30:39
字数补丁
Gorgon_Meducer
发表于 2018-4-2 17:10:40
apeng2012 发表于 2018-4-2 11:30
字数补丁
呃,并不是这个问题,我这个格式是正确的。
chenguanghua
发表于 2018-4-4 14:45:13
本帖最后由 chenguanghua 于 2018-4-4 15:37 编辑
struct __default_menu_item_t {
//! inherit from base class menu_item_t
menu_item_t;
//! depends on your application, you can add/remove/change following members
char *pchTitle; //!< Menu Title
char *pchDescription; //!< Description for this menu item
char chShortCutKey; //!< Shortcut Key value in current menu
};
①此处继承基类直接这样写: menu_item_t;
没这么用过,请教学习一下
②另外一处不明白的地方:
结构体定义含有chShortCutKey,初始化为何不用这项
default_menu_item_t c_tTopMenuItems[] = {
{
top_menu_item_a_handler,
NULL, //!< child menu
"Top Menu A",
"This is Top Menu A",
}
};
Gorgon_Meducer
发表于 2018-4-4 17:16:02
本帖最后由 Gorgon_Meducer 于 2018-4-4 17:17 编辑
chenguanghua 发表于 2018-4-4 14:45
①此处继承基类直接这样写: menu_item_t;
没这么用过,请教学习一下
关于匿名结构体的使用,我在这个帖子里有详细讨论
结构体的初始化应该是基础知识了,省略的部分会被自动初始化为0——因为例子中我确实没有用到这个内容,所以就用默认的0了。
chenguanghua
发表于 2018-4-4 18:56:19
Gorgon_Meducer 发表于 2018-4-4 17:16
关于匿名结构体的使用,我在这个帖子里有详细讨论
结构体的初始化应该是基础知识了,省略的部分会被自动 ...
惭愧,好几年没写程序了,对您的菜单架构比较感兴趣,还请不吝赐教
另外一个问题:.ptCurrentMenu这是什么用法,特别是这前面的这个点(.)
static menu_engine_cb_t s_tMenuDemo = {
.ptCurrentMenu = &menu(TopMenu),
};
擦鞋匠
发表于 2018-4-4 19:04:49
Gorgon_Meducer 发表于 2018-3-15 06:26
故意埋了一个不影响编译和功能的笔误在里面,看看谁真正的读了代码。
大神,多了一个#endif算不算?
闲鱼翻身
发表于 2018-4-4 19:59:04
收藏学习,感谢大师
Gorgon_Meducer
发表于 2018-4-4 21:27:04
擦鞋匠 发表于 2018-4-4 19:04
大神,多了一个#endif算不算?
哪里多了?求指出,如果有,估计是笔误,我会更正。
Gorgon_Meducer
发表于 2018-4-4 21:29:58
chenguanghua 发表于 2018-4-4 18:56
惭愧,好几年没写程序了,对您的菜单架构比较感兴趣,还请不吝赐教
另外一个问题:.ptCurrentMenu这是 ...
这是C99(如果我没有记错的话)引入的一种初始化结构体的方法……这种方法甚至可以用来初始化数组——也就是你可以指定只初始化哪个数组元素。
结构体初始化了解一下。
chenguanghua
发表于 2018-4-5 07:07:30
struct __default_menu_item_t {
//! inherit from base class menu_item_t
menu_item_t;
//! depends on your application, you can add/remove/change following members
char *pchTitle; //!< Menu Title
char *pchDescription; //!< Description for this menu item
char chShortCutKey; //!< Shortcut Key value in current menu
};
struct __menu {
menu_item_t *ptItems; //!< menu item list
uint_fast8_t chCount; //!< menu item count
menu_t *ptParent; //!< parent menu;
menu_engine_t *fnEngine; //!< engine for process current menu
};
__menu作为容器, ptItems的定义采用default_menu_item_t是不是比较好?
当然menu_item_t也没问题,因为 pchTitle 这些不是必须的。
Gorgon_Meducer
发表于 2018-4-5 17:12:00
chenguanghua 发表于 2018-4-5 07:07
__menu作为容器, ptItems的定义采用default_menu_item_t是不是比较好?
当然menu_item_t也没问题,因为 p ...
如果使用default_menu_item_t在menu_t中,那么menu_t就失去了基类的扩展性——因为绑定死了某一个派生类,
如果别人实现了自己的xxxxx_menu_item_t类型,是不是就没法正确使用menu_t了?(因为假设按照你的建议,
menu_t里面使用了default_menu_item_t而不是 menu_item_t)
chenguanghua
发表于 2018-4-5 23:44:44
Gorgon_Meducer 发表于 2018-4-5 17:12
如果使用default_menu_item_t在menu_t中,那么menu_t就失去了基类的扩展性——因为绑定死了某一个派生类 ...
请教default_menu_item_t和menu_t的问题,其实是看到这块代码,结构体指针的强制类型转换
如果要使用pchTitle,pchDescription这些成员,结构体指针的强制类型转换会不会出现数据访问的不安全性?
static menu_engine_cb_t s_tMenuDemo = {
.ptCurrentMenu = &menu(TopMenu),
};
Gorgon_Meducer
发表于 2018-4-6 03:39:00
chenguanghua 发表于 2018-4-5 23:44
请教default_menu_item_t和menu_t的问题,其实是看到这块代码,结构体指针的强制类型转换
如果要使用pch ...
具体举个例子?
chenguanghua
发表于 2018-4-6 07:14:54
本帖最后由 chenguanghua 于 2018-4-6 10:20 编辑
Gorgon_Meducer 发表于 2018-4-6 03:39
具体举个例子?
转:
比如在一个项目中,有大量的数据结构,他们都是双向链表,但又想共用一套对链表的操作算法,这怎么做到呢,C中又没有C++中的继承,不然我可以继承一父(类中只有两个指针,一个向前一个向后),而其算法可以写在你类中的虚函数中,供子类使用。如:
class Links
{
public:
Links* back;
Links* forword;
virtual Add(){ ... };
virtual Del(){ ... };
virtual Ins(){ ... };
virtual Print() =0;
....
};
于是对于特定的数据结构我们可以:
class mylinks : public Links
{
public:
char* myname;
char sex;
intage;
...
virtual Print(){ .... }
};
对其操作时都可以使用你类的泛型算法。
在C中,该如何做呢?我们用C中的指针和强制类型转可以做到。
下面是我总结出来的一个小的程序,体现了用指针的弹性来实现这一继承的效果:
(我在Liniux下的GCC调试通过)
#include <stdio.h>
/* 双向链表 (类似于父类)*/
typedef struct hLinks{
struct hLinks *bwLink;
struct hLinks *fwLink;
} hLinks;
/*
* 一个使用双向链表的结构
* (类似于子类)
*/
typedef struct hEnt{
hLinks links;
int hData;
char key;
} hEnt;
/*
*双向链插入泛型算法 (类似于父数中的成员函数)
*/
Insert( hLinks* elem, hLinks *dest )
{
if ( !elem || !dest ) return;
elem->bwLink = dest->bwLink;
elem->fwLink = dest;
dest->bwLink->fwLink = elem;
dest->bwLink = elem;
}
/*
*打印 (类似于子类重载父类的成员函数)
*/
PrintLink( hLinks *h )
{
hEnt *p ;
for( p = ( hEnt* ) h->fwLink; /*<-----------把hLink再转回来*/
p != ( hEnt* ) h;
p = ( hEnt* )( (hLinks*)p )->fwLink )
{
printf("hData=[%d], key=[%s]/n", p->hData, p->key);
}
}
main()
{
hLinks head;
hEnt a;
int i;
head.bwLink = &head;
head.fwLink = &head;
for(i=0;i<4;i++)
{
a.hData = i*10;
sprintf(a.key,"id=%d", i);
/*使用泛型算法构造双向链*/
Insert( (hLinks *) &a, (hLinks *) &head ); /* <-----注意这个强制转换*/
}
PrintLink( (hLinks *) &head ); /* <-------也注意这个强制转换*/
}
chenguanghua
发表于 2018-4-6 07:29:43
本帖最后由 chenguanghua 于 2018-4-6 10:21 编辑
可以看出,在前两个内存单元中两个结构体存储的内容是相同的,当然不管相不相同计算机是不管的,
当hLinks类型转换成hEnt类型时,计算机就将原结构体看做是hEnt类型的。
转换后的hEnt类型结构体的前面两个内存单元的内容就是hLinks中的前两个单元内容,
而hEnt的后两个内存单元中的内容取得是hLinks后的两个单元(这两个单元不是hLinks类型的成员,而是别的内容,所以如果转换后的hEnt要访问hData和key的话是不安全的!)。
/*----------------------------------------*/
续:对宏的定义不熟悉,理解错了
/*----------------------------------------*/
如果在default_menu_engine想通过指针访问pchDescription这些成员,是否可以通过结构体指针进行强制类型转换得到?
比如:
LCD_disp(((default_menu_item_t *)(this.ptCurrentMenu->ptItems))->pchDescription);
xiangbin099
发表于 2018-4-6 08:16:09
学习,学习
Gorgon_Meducer
发表于 2018-4-6 17:53:12
本帖最后由 Gorgon_Meducer 于 2018-4-6 18:29 编辑
chenguanghua 发表于 2018-4-6 07:29
可以看出,在前两个内存单元中两个结构体存储的内容是相同的,当然不管相不相同计算机是不管的,
当hLinks ...
我明白你的意思了,其实这里涉及到一个本质上的问题:C语言不是 Type-Safe 的,对于强制类型转换,如果不在使用时
加以一定的规则限制,否则无论如何都会出现你担心的问题。实际上,规则很简单:
规定,强制类型转换只能从派生类向基类进行,反之则禁止——除非你对传入指针的类型非常确信(然而这一点通常是很
难做到的)。
在这个例子中,default_menu_item_t就是 menu_item_t 的派生类,因此,用menu_item_t 来访问仅属于 menu_item_t
的成员是安全的;同时绝对禁止通过 menu_item_t 类型的指针经过强制类型转化以后来访问派生类的成员。
如果你看我另外一个帖子,就会知道,其实还有另外一个安全的做法:
https://www.amobbs.com/thread-5582609-1-1.html?_dsign=4d743ffc
注意这里:
//! \brief macro for inheritance
#define INHERIT_EX(__TYPE, __NAME) \
union { \
__TYPE __NAME; \
__TYPE; \
};
/*! \note When deriving a new class from a base class, you should use INHERIT
* other than IMPLEMENT, although they looks the same now.
*/
#define INHERIT(__TYPE) INHERIT_EX(__TYPE, base__##__TYPE)
/*! \note You can only use IMPLEMENT when defining INTERFACE. For Implement
* interface when defining CLASS, you should use DEF_CLASS_IMPLEMENT
* instead.
*/
#define IMPLEMENT(__INTERFACE) INHERIT_EX(__INTERFACE, base__##__INTERFACE)
/*! \note if you have used INHERIT or IMPLEMENT to define a CLASS / INTERFACE,
you can use OBJ_CONVERT_AS to extract the reference to the inherited
object.
\*/
#define OBJ_CONVERT_AS(__OBJ, __INTERFACE) (__OBJ.base__##__INTERFACE)
当我们要访问基类/接口时(这里支持多重继承),使用OBJ_CONVERT_AS(__OBJ, __INTERFACE) 宏,而不是
直接强制类型转换,这种方法就从根本上避免了由 强制类型转换带来的入侵问题——也就是说:
我们要尽可能在C语言的面向对象实践中遵守Type-Safe 的规则。
进一步说,就是借由INHERIT() 和 IMPLEMENT() 宏实现的接口/类继承,我们在访问时也要通过原有类型来进行,
而不是强制类型转换——这就是OBJ_CONVERT_AS() 存在的本意——当然,支持多个接口也是用途之一。
另外,对于你说的 链表操作,你提到了C++的泛型,其实C的宏配合一定代码模板实现出来的效果是一样的:
比如你看这个链表操作的例子:
https://github.com/GorgonMeducer/Generic_MCU_Software_Infrastructure/blob/master/sources/gmsi/utilities/template/t_list.h
比如,你看这个堆的泛型(C source code + macro),就是用了上述链表进行实现的,同时这个堆的泛型还能根据不同的目标类型进行专用堆类的生成。
https://github.com/GorgonMeducer/Generic_MCU_Software_Infrastructure/tree/master/sources/gmsi/service/memory/epool
在上述的例子中,你可以注意到,我遵守了“只允许将派生类向基类进行强制类型转换”的原则——在派生类中,指针都是指向派生类,而不是
基类的,这就避免了出现你说的问题。
关于C语言的面向对象实践,欢迎进行讨论。
更进一步说,在C语言中构建 type-safe 的面向对象实践,当年深入浅出MFC给出过详细的分析,简单说就是在每一个抽象类的结构体里,
第一个成员都会包含一个指向最基础的基类的指针,又叫 type 类,大体定义如下:
typedef const struct __type_t type_t;
struct {
type_t *ptBase; //!< 类型的继承链
const char *chTypeName;
void *constructor(void *, ...); //!< 构造函数
void *destructor(void *); //!< 析构函数
};
为了让这一工作变得更自然,通常会定义一个object类:
typedef struct {
type_t *ptType;
} object_t
基于这一结构,所有的 abstract 类 都会 继承object 类,而所有abstract 类的派生类则无需这么做,只需要将object类的ptType指针重新初始化即可。
可以看出,type是借助 type_t 静态成员实现的一个链表,这个链表在编译时刻完成初始化。借助这个链表,我们可以实现is_type_of() 这样的操作,甚至还能借助获取
type类型实现动态的构造和析构,如果你更进一步的对 type_t 进行继承和派生,甚至可以把派生类的虚函数表一起放到派生出来的 xxxx_type_t
里面(也就是放在constructor和destructor后面)……
最后的最后,借助 is_type_of ,我们能完成最基本的 type-safe 的检查——如果你觉得很有必要的话——这只不过是一个简单的指针判断而已。
说了这么多,其实已经把C++的物理层面的实现说的差不多了……这种时候,如非必要,真心不如直接用C++。我觉得没有必要,所以只做了很基本
的事情——制定规则,遵守规则,尽可能不乱用强制类型转换。
最后针对你的具体问题:
如果在default_menu_engine想通过指针访问pchDescription这些成员,是否可以通过结构体指针进行强制类型转换得到?
比如:
LCD_disp(((default_menu_item_t *)(this.ptCurrentMenu->ptItems))->pchDescription);
答案是:不行,因为default_menu_engine 只知道什么是menu_item_t,并不知道default_menu_item_t的存在,因此不应该出现基类的成员函数访问
派生类的成员变量的问题。
如果你要访问default_menu_item_t,那么理论上你应该有一个针对 default_menu_item_t 的 menu_engin函数,由于menu_t 是 menu_item_t 的容器,
menu_t 里面有一个指针指向专门针对当前容器内 menu_item_t 的对应 menu_engine(这就是面向对象的意义,数据和方法打包),因此在当前的menu
下,用专用的menu_engine处理对应的 xxxx_menu_item_t 是肯定安全的。楼主位的例子中, default_menu_engine只是一个范例,它展示了基本的菜单
导航操作的处理,你可以注意到,里面连 显示函数都没有调用,所以它真的只是一个伪代码——用来做demo演示这个菜单的数据结构如何工作的。
flyfox8
发表于 2018-4-9 16:28:27
虽然不合时宜,我还是想说全文我只关注到了小姐姐一段。{:lol:}
liangyi518
发表于 2018-4-9 16:33:45
厉害兄弟!{:victory:}
l.htlht
发表于 2018-4-9 19:55:41
收藏 学习
lqzhw
发表于 2018-4-9 21:23:56
哎 水平不行 各种不懂都是裸奔加状态机标志都是随意定义只要自己看得懂
Gorgon_Meducer
发表于 2018-4-10 18:55:20
lqzhw 发表于 2018-4-9 21:23
哎 水平不行 各种不懂都是裸奔加状态机标志都是随意定义只要自己看得懂 ...
这也是裸奔加状态机啊。哪里看不懂,我给你详细说说。
xieweibiao
发表于 2018-4-10 22:22:00
大神的东西就是精辟
gamep
发表于 2018-4-11 17:58:18
请问大师,在多级菜单中,想实现,在任意菜单,长按菜单键返回最顶层菜单。
怎么实现才比较优雅呢?
QP的方案是用层次状态机做类似设计。但是,QP相关的组件相对少些。
很想听听大师对层次状态机的讲解和意见。
另外,本主题中讲到的菜单都包含菜单项。在实时数据显示界面,就是数据在更新,
好像不含菜单项。是否就不属于本主题的讨论范围?
Gorgon_Meducer
发表于 2018-4-11 23:07:48
gamep 发表于 2018-4-11 17:58
请问大师,在多级菜单中,想实现,在任意菜单,长按菜单键返回最顶层菜单。
怎么实现才比较优雅呢?
你说的问题基本在93楼有讨论。
层次状态机不就是子状态机调用么……不知道你想知道啥……
长按回到顶层,抛开长按(按键扫描或者按键消息),回到顶层……不就是顺着父指针一路向上么……
你具体遇到什么问题了呢?
gamep
发表于 2018-4-12 14:27:17
我再慢慢领悟
hpdell
发表于 2018-4-12 16:22:56
正在找牛逼的菜单程序,感谢感谢,有空试试
hy2515131
发表于 2018-4-12 16:26:31
LZ开贴讲解,厉害啊!
hy2515131
发表于 2018-4-12 16:29:55
有没有结合按键KEY与菜单menu的交换程序吗?
Gorgon_Meducer
发表于 2018-4-12 19:53:37
hy2515131 发表于 2018-4-12 16:29
有没有结合按键KEY与菜单menu的交换程序吗?
看 default_menu_engine, 在楼主位
gao_hailong
发表于 2018-4-15 08:40:41
Gorgon_Meducer 发表于 2018-4-12 19:53
看 default_menu_engine, 在楼主位
请教傻大侠:我想把结构体同时用于独立定义和结构体嵌套,并且嵌套时用匿名结构,应该怎么操作。
例如:
typedef struct {}childstr;
typedef struct {childstr cstr;}fatherstr;
此时嵌套的结构体不是匿名的,调用起来太麻烦。
hy2515131
发表于 2018-4-15 09:05:16
Gorgon_Meducer 发表于 2018-4-12 19:53
看 default_menu_engine, 在楼主位
多谢多谢!
wangyeqing333
发表于 2018-4-15 09:51:08
感觉菜单、GUI这些还是适合用面向对象的思路来写
Gorgon_Meducer
发表于 2018-4-15 21:17:38
gao_hailong 发表于 2018-4-15 08:40
请教傻大侠:我想把结构体同时用于独立定义和结构体嵌套,并且嵌套时用匿名结构,应该怎么操作。
例如:
...
答案在142楼里提到的几个宏,不明白再问。
Gorgon_Meducer
发表于 2018-4-15 21:18:30
wangyeqing333 发表于 2018-4-15 09:51
感觉菜单、GUI这些还是适合用面向对象的思路来写
没错,就是要用OO的思想
cjc2010
发表于 2018-4-21 18:41:38
赞。
gao_hailong
发表于 2018-4-21 20:25:06
Gorgon_Meducer 发表于 2018-4-15 21:17
答案在142楼里提到的几个宏,不明白再问。
直接用声明,不加变量名就行了,谢谢大侠。
bigk2000
发表于 2018-4-21 20:48:45
多谢多谢!
淋湿的鸡毛
发表于 2018-5-16 11:32:43
常看常新
我要吃大葱
发表于 2018-5-22 20:24:32
纽币,很幸运能够学习前辈的编程思想。
ztrx
发表于 2018-5-23 07:20:46
rtos下怎么玩
dtdzlujian
发表于 2018-5-23 07:30:28
好好学习,认真听课
Gorgon_Meducer
发表于 2018-5-23 18:40:42
ztrx 发表于 2018-5-23 07:20
rtos下怎么玩
没有区别啊……你的具体担心点在哪里?可以详细描述下你的疑惑么?
ztrx
发表于 2018-5-23 23:53:13
任务循环里要加延时吗,延时多长
Gorgon_Meducer
发表于 2018-5-24 00:27:24
本帖最后由 Gorgon_Meducer 于 2018-5-24 00:33 编辑
ztrx 发表于 2018-5-23 23:53
任务循环里要加延时吗,延时多长
你说的任务循环是超级循环么?还是说在RTOS下任务里面的超级循环?
为什么要加延时?目的是什么?
如果加延时的目的是为了让出处理器时间给其它任务,我想说,这是很通用的多任务协作问题,跟菜单引擎没有任何关系。
认真说起来,在多任务环境下,应该是不需要你说的这个延迟的。因为多任务环境下,运行菜单的任务应该是受按键队列
驱动的——如果按键队列为空,则阻塞该任务,如果按键队列不为空,则读取按键并进行菜单操作——这里值得注意的是,
最好把显示和菜单任务分离开,菜单任务只是个后台骨架,而显示(尤其是你需要有动态效果的情况下)应该由一个独立的
任务来完成,这个任务接受来自菜单的消息来决定如何处理前台显示的问题。我觉得,如果说延时,恐怕是这个前台显示需
要延时——主要是处理类似gif的效果,或者是滚动字幕之类的。
从这个角度来说,负责菜单的任务是不需要任何延时的,它是完全由数据流(按键队列)驱动的。这是一个典型的生产者消
费者模型。
希望这个回答解决了你的疑问。如果还有什么问题,请提的具体一些。
ztrx
发表于 2018-5-24 07:50:29
谢谢,学习 了
bigwei
发表于 2018-7-5 20:59:55
{:victory:} 谢谢分享,收藏学习!
netking2012
发表于 2018-7-11 09:18:21
大师一出必是精品啊
CH_anyin
发表于 2018-7-11 12:49:21
感谢分享,学习了!
gentlerain
发表于 2018-7-11 15:47:40
先收藏再细看
cgbabc
发表于 2018-7-18 21:03:35
有个问题想请教一下,每个菜单内都有一个需要调整的参数,如何把按键的动作(加或者减)与菜单关联起来?有什么好的解决方案吗?
yunqing_abc
发表于 2018-7-19 16:23:06
大师强帖必须顶!!!
数据结构真的很重要
Gorgon_Meducer
发表于 2018-7-19 18:00:27
cgbabc 发表于 2018-7-18 21:03
有个问题想请教一下,每个菜单内都有一个需要调整的参数,如何把按键的动作(加或者减)与菜单关联起来?有 ...
菜单只是个导航,你看到的所谓菜单里有个值要修改那是错觉。
要修改的值实际上是通过窗体里的控件来实现的,而真正的菜单只是帮你打开这个窗体而已。
如果你一直试图把菜单和窗体混淆来看……估计就没法降低菜单的耦合度和复杂度了。
cgbabc
发表于 2018-7-19 19:23:09
Gorgon_Meducer 发表于 2018-7-19 18:00
菜单只是个导航,你看到的所谓菜单里有个值要修改那是错觉。
要修改的值实际上是通过窗体里的控件来实现 ...
好吧,我以前一都按菜单就是一个参数来看待,看来需要改变这种观念。还需要另外实现一个窗体的程序来实现调整参数。
Gorgon_Meducer
发表于 2018-7-20 18:40:28
cgbabc 发表于 2018-7-19 19:23
好吧,我以前一都按菜单就是一个参数来看待,看来需要改变这种观念。还需要另外实现一个窗体的程序来实现 ...
分开以后,你会发现更多模块化的机会。
R8C
发表于 2018-7-23 19:06:31
看不明白,如果用emwin还要这么写吗?
Gorgon_Meducer
发表于 2018-7-24 17:53:49
R8C 发表于 2018-7-23 19:06
看不明白,如果用emwin还要这么写吗?
用已有的架构就不用这么写了。这个主要是从原理上帮助一些好奇的人,现代的比较先进的嵌入式GUI从原理上
说是如何处理类似的事情的——当然很多系统用了消息机制,不过本质上与这个结构并不冲突。
R8C
发表于 2018-7-24 21:03:56
谢谢回帖,明白了
lhhsea2004
发表于 2018-7-24 22:23:32
先收藏,慢慢消化
ailibuli
发表于 2018-8-14 14:07:48
楼主菜单技术精湛,最近在研究开源遥控器,无线协议和摇杆混控都能看懂,但是菜单部分完全没有头绪,不知道楼主收能帮忙看看:https://github.com/DeviationTX/deviation/tree/master/src/gui
这个菜单还是很不错的,在开源遥控领域,Deviation也是老大哥,他的GUI貌似是为每一个Button注册回调,然后菜单怎么做的,就完全看不明白了。
ailibuli
发表于 2018-8-14 14:08:46
Gorgon_Meducer 发表于 2018-7-24 17:53
用已有的架构就不用这么写了。这个主要是从原理上帮助一些好奇的人,现代的比较先进的嵌入式GUI从原理上
...
楼主,可以一起讨论下这个吗?
楼主菜单技术精湛,最近在研究开源遥控器,无线协议和摇杆混控都能看懂,但是菜单部分完全没有头绪,不知道楼主收能帮忙看看:https://github.com/DeviationTX/deviation/tree/master/src/gui
这个菜单还是很不错的,在开源遥控领域,Deviation也是老大哥,他的GUI貌似是为每一个Button注册回调,然后菜单怎么做的,就完全看不明白了。
Gorgon_Meducer
发表于 2018-8-14 21:06:15
ailibuli 发表于 2018-8-14 14:08
楼主,可以一起讨论下这个吗?
楼主菜单技术精湛,最近在研究开源遥控器,无线协议和摇杆混控都能看懂, ...
没有认真看,实在没有时间,但我猜它所谓的菜单只是一个窗体吧……既然给每个按钮都加了回调,那更有可能就只是一个普通的窗体了。
mengtiantang
发表于 2018-8-15 17:31:03
好吧,看到和大神的差距了
asbzhang
发表于 2018-8-17 09:09:01
这个菜单结构帮助了不少人
曾经的诸葛二蛋
发表于 2018-8-23 17:31:20
后排听课,瞻仰大神的帖子
gaoxiaohu2018
发表于 2018-9-2 00:25:21
标记复制+粘贴
xiaoliusheng
发表于 2018-9-28 22:37:50
争取早点能看懂...{:lol:}
Gorgon_Meducer
发表于 2018-9-28 22:53:41
xiaoliusheng 发表于 2018-9-28 22:37
争取早点能看懂...
争取早点用起来是比较实际的。
xxc007
发表于 2018-9-28 23:03:01
强帖收藏学习
LB342342
发表于 2018-10-21 09:47:35
谢谢大神的好贴。说下自己读后的感受:
对于初学者来说,读懂并且使用确实很难,要花大量的时间,如果能以一个实例来展开(就想前面的说的出一个工程),会很快掌握。
这个帖子,对高手来说写的太详细,对初学者来说又有些晦涩难懂。
高不成,低不就。
LB342342
发表于 2018-10-21 09:51:02
真心想用,真心不好懂。{:smile:}
Gorgon_Meducer
发表于 2018-10-22 17:33:50
LB342342 发表于 2018-10-21 09:51
真心想用,真心不好懂。
其实你要相信我,这里我已经尽最大努力把内容写得让初学者好懂了。但看来效果并不尽如人意,
这里,我需要你的帮助,你能说出第一个让你觉得不好懂得地方么?我从那里开始尝试进行改进。
一步一步的,如果你不介意,我就可以借助你的帮助,把教程写得非常简单。其实你说用一个例子,
我讲真的, 我从头开始进行推导这个框架怎么来的,本身就是一个例子了……并且后面也的确提供
了例子——比如单级菜单的例子和两级菜单的例子。我想知道的是,这里缺失的是什么?
maimaige
发表于 2018-10-22 17:41:18
我先 留个名字 然后 好好 研究一下 啊
LB342342
发表于 2018-10-24 09:31:11
楼主| 发表于 前天 17:33 | 只看该作者
其实你要相信我,
****************************
是我没有静下心来理解,只想着拿来就往里套用。
现在在静静的看了。
就开头部分而言,前面的推理倒把我绕糊涂了,其实前面的就是铺垫,直接从这里开始看,到时号理解点,看不懂了,再往前面看。
因此,前面的默认模板就可以用极为简单的形式进行描述:
typedef struct __menu_itemmenu_item_t;
typedef struct __menu menu_t;
typedef fsm_rt_t menu_item_handler_t(menu_item_t *);
struct __menu_item {
menu_item_handler_t *fnHandle; //!< handler
menu_t *ptChild; //!< Child Menu
};
declare_menu_item_template(default_menu_item_t)
def_menu_item_template(default_menu_item_t)
//! depends on your application, you can add/remove/change following members
char *pchTitle; //!< Menu Title
char *pchDescription; //!< Description for this menu item
char chShortCutKey; //!< Shortcut Key value in current menu
end_def_menu_item_template(default_menu_item_t)
复制代码
再次谢谢你的耐心。
LB342342
发表于 2018-10-24 12:03:06
试着把代码放到.h和.c文件,然后编译,会发现许多没有定义的标识符,然后开始在文章里找标识符的出处。
对初学者来说,要是最后给一个最终版的.c和.h文件内容。就比较好用好懂了吧。
感觉有用的信息,要在里面找,然后整合到一起。
LB342342
发表于 2018-10-24 15:07:35
我试着在MDK的STM32一个项目里加入一个.h和一个.c文件编译:
.H:
#ifndef __MENU__
#define __MENU__
#include "stm32f1xx_hal.h"
#ifndef __FSM_RT_TYPE__
#define __FSM_RT_TYPE__
//! \name finit state machine state
//! @{
typedef enum {
fsm_rt_err = -1, //!< fsm error, error code can be get from other interface
fsm_rt_cpl = 0, //!< fsm complete
fsm_rt_on_going = 1, //!< fsm on-going
fsm_rt_wait_for_obj = 2, //!< fsm wait for object
fsm_rt_asyn = 3, //!< fsm asynchronose complete, you can check it later.
} fsm_rt_t;
//! @}
#endif
typedef struct __menu_itemmenu_item_t;
typedef struct __menu menu_t;
typedef fsm_rt_t menu_item_handler_t(menu_item_t *);
struct __menu_item {
menu_item_handler_t *fnHandle; //!< handler
menu_t *ptChild; //!< Child Menu
};
typedef struct __menu_engine_cb menu_engine_cb_t;
typedef fsm_rt_t menu_engine_t(menu_engine_cb_t *);
struct __menu {
menu_item_t *ptItems; //!< menu item list
uint8_t chCount; //!< menu item count
menu_t *ptParent; //!< parent menu;
menu_engine_t *fnEngine; //!< engine for process current menu
};
typedef struct __default_menu_item_tdefault_menu_item_t;
struct __default_menu_item_t {
//! inherit from base class menu_item_t
menu_item_t;
//..\User\0aa_menu\MENU.h(48): error:#3093: anonymous structs are only supported in --gnu mode, or when enabled with #pragma anon_unions
//! depends on your application, you can add/remove/change following members
char *pchTitle; //!< Menu Title
char *pchDescription; //!< Description for this menu item
char chShortCutKey; //!< Shortcut Key value in current menu
};
#endif
/////////////////////////////////
.C:
#include "MENU.h"
extern fsm_rt_t top_menu_engine(menu_engine_cb_t *ptThis);
extern fsm_rt_t top_menu_item_a_handler(menu_item_t *ptItem);
extern fsm_rt_t top_menu_item_b_handler(menu_item_t *ptItem);
extern fsm_rt_t top_menu_item_c_handler(menu_item_t *ptItem);
extern const menu_t c_tTopMenu;
default_menu_item_t c_tTopMenuItems[] = {
{
top_menu_item_a_handler,
NULL, //!< child menu
"Top Menu A",
"This is Top Menu A",
},
{
top_menu_item_b_handler,
NULL, //!< child menu
"Top Menu B",
"This is Top Menu B"
},
{
top_menu_item_c_handler,
NULL, //!< child menu
"Top Menu C",
"This is Top Menu C"
}
};
const menu_t c_tTopMenu = {
(menu_item_t *)c_tTopMenuItems, //!< menu item list
UBOUND(c_tTopMenuItems), //!< menu item count UBOUND未定义
..\User\0aa_menu\menu.c(34): error:#59: function call is not allowed in a constant expression
NULL, //!< top menu has no parent
top_menu_engine,
};
fsm_rt_t top_menu_item_a_handler(menu_item_t *ptItem)
{
return fsm_rt_cpl;
}
fsm_rt_t top_menu_item_b_handler(menu_item_t *ptItem)
{
return fsm_rt_cpl;
}
fsm_rt_t top_menu_item_c_handler(menu_item_t *ptItem)
{
return fsm_rt_cpl;
}
fsm_rt_t top_menu_engine(menu_engine_cb_t*ptThis)
{
return fsm_rt_cpl;
}
编译后,出现3个错误,上面红色部分。