本文记录了我学习MiniGui开发过程中遇到的一些有意思问题与解决方法,会随着我学习的深入慢慢的更新下去。文章中窗口指的是通过CreateMainWindow创建的窗口,控件是指CreateWindow或CreateWindowEx创建的控件。
方法一:窗口创建时,在界面的窗口过程函数里添加MSG_ERASEBKGND监听,什么也不画就是透明背景,这种方法有一个缺陷,就是透明背景只能和创建窗口的时候一样,改变控件的形状或位置,原来控件的形状或位置还留在原来的地方,不能透明
case MSG_ERASEBKGND: {
return 0;
}
方法二:使用mlshadow引擎
1、在配置的时候使能videomlshadow,真实引擎可以使用fbcon或qvfb,这里使用qvfb
./configure --enable-qvfbial --enable-videoqvfb --enable-videomlshadow
2、配置MiniGUI.cfg,把gal_engine的值换成mlshadow,mlshadow的real_engine换成qvfb就可以了。def_bgcolor是背景色,double_buffer可以取值enable/disable,表示刷屏时是否使用双缓冲。
MLShadow 引擎是实现了在机顶盒、PMP等产品的方案中提供多个显示层,以完成类似硬件提供的图形层叠加功能,自动实现层之间的透明、半透明的显示。
[system]
# GAL engine and default options
gal_engine=mlshadow
defaultmode=800x480-32bpp
[qvfb]
defaultmode=800x480-32bpp
display=0
[mlshadow]
real_engine=qvfb
defaultmode=800x480-32bpp
def_bgcolor=0x00FF00
double_buffer=enable
3、MiniGUI 提供了对 MLShadow 引擎当中虚拟图形层的操作函数,以实现对不同图形层的控制
BOOL mlsSetSlaveScreenInfo (HDC dc_mls, DWORD mask, int offset_x, int offset_y,
DWORD blend_flags, gal_pixel color_key, int alpha, int z_order);
此函数能够通过给定的 dc_mls 参数,找到对应的图形层,设置该图形层相对真实图形层的偏移量、混合标记、透明色、透明值以及叠加属性。
#下面是参数说明
• dc_mls 是图形层所对应的 DC 句柄。
• mask 用于判断是设置某一个或者某些属性,其他属性的值传入无效。例如:当 mask = MLS_INFOMASK_OFFSET
时只对 offset_x 和 offset_y 进行设置,当为 MLS_INFOMASK_ALL 时,设置所有属性。mask 的取值范围如下:
o MLS_INFOMASK_OFFSET 仅设置显示层偏移量
o MLS_INFOMASK_BLEND 仅设置显示层混合标志
o MLS_INFOMASK_ZORDER 仅设置显示层叠加顺序
o MLS_INFOMASK_ENABLE 仅设置显示层是否可见
o MLS_INFOMASK_ALL 设置所有信息
• offset_x 和 offset_y 设置给定显示层在主屏上的偏移量。
• blend_flags 则表示该显示层是透明的还是带有 alpha 通道的,flags 可以取下列值:
o MLS_BLENDMODE_COLORKEY 表示进行混合时,去掉透明色
o MLS_BLENDMODE_ALPHA 表示进行混合时,是进行 ALPHA 混合
• color_key 指定透明色
• alpha 指定 ALPHA 通道值
• z_order 则指定叠加的顺序,z_order 值越大,则该显示层越靠外。
BOOL mlsGetSlaveScreenInfo (HDC dc_mls, DWORD mask, int *offset_x, int *offset_y,
DWORD *blend_flags, gal_pixel *color_key, int *alpha, int *z_order);
此函数获取由参数 dc_mls 指定的显示层的混合叠加信息,参数 mask 指定是获取所有信息还是部分信息,它的取值在函数mlsSetSlaveScreenInfo 的参数说明里面已经说明过了。
BOOL mlsEnableSlaveScreen (HDC dc_mls, BOOL enable);
此函数设置显示层 dc_mls 是否可见,即是否参加图形层的混合叠加操作。 enable 为 TRUE 时,为可见;为 FALSE 时,不可见。
使用CreateWindowEx函数创建,并传入WS_EX_TRANSPARENT风格
CreateWindowEx(CTRL_STATIC, "静态文本",
WS_CHILD | SS_GROUPBOX | WS_VISIBLE, WS_EX_TRANSPARENT, 0, 0, 0,
rect.right, rect.bottom, hwnd, 0);
不是使用MoveWindow函数,控件的父窗口必须使用双缓冲风格
HWND parent = GetParent(hwnd);
if (IsMainWindow(parent)) {
//首先获取父窗口的坐标与控件的坐标
RECT parentRect, clientRect;
GetWindowRect(hwnd, &parentRect);
//获取双缓冲的设备环境上下文
HDC parentHdc = GetSecondaryDC(parent);
/**
* 在系统内存中建立一个类似显示内存的区域,slideHdc是滑动层,showHdc是显示层
* 所有的动画都在slideHdc画,画完之后,把显示的数据复制到showHdc中
* 然后再由showHdc把显示的数据送到屏幕上,这样可以避免屏幕闪烁问题
*/
HDC slideHdc = CreateCompatibleDCEx(parentHdc, clientRect.right,
clientRect.bottom);
HDC showHdc = CreateCompatibleDCEx(parentHdc, clientRect.right,
clientRect.bottom);
SetSecondaryDC(parent, parentHdc, ON_UPDSECDC_DONOTHING);
//设置背景图片与透明度
FillBoxWithBitmap(slideHdc, 0, 0, clientRect.right,
clientRect.bottom, &slideTextData->bmp_bg);
SetMemDCAlpha(slideHdc, MEMDC_FLAG_SRCALPHA, 32);
//每帧动画的间隔事件
unsigned int time = 25000;
//每帧动画控件的高度,随着时间而增大,最大到原本控件的高度
int currentHeight = 30;
int parentY = parentRect.bottom - currentHeight;
while (clientRect.bottom > currentHeight) {
/**
* 把主窗口该移动控件处的背景填充到showHdc层中,相当于还原showHdc层,
* 如果不这样做,每次移动的图层会叠加,导致显示的越来越黑
*/
BitBlt(parentHdc, parentRect.left, parentRect.top,
clientRect.right, clientRect.bottom, showHdc, 0, 0, 0);
//把slideHdc层中移动的画面复制到showHdc层中
BitBlt(slideHdc, 0, 0, clientRect.right, currentHeight, showHdc,
0, clientRect.bottom - currentHeight, 0);
//把showHdc层中的画面显示到屏幕上
BitBlt(showHdc, 0, clientRect.bottom - currentHeight,
clientRect.right, currentHeight,
HDC_SCREEN, parentRect.left, parentY, 0);
//每帧动画移动30的距离
currentHeight = currentHeight + 30;
parentY = parentRect.bottom - currentHeight;
usleep(time);
}
//释放申请的设备环境上下文
SetSecondaryDC(parent, parentHdc, ON_UPDSECDC_DEFAULT);
DeleteMemDC(slideHdc);
DeleteMemDC(showHdc);
}
1、查看编译libminigui-gpl的时候,是否指定了–disable-cursor,如果指定了是没有鼠标显示的
2、查看MiniGUI.cfg,cursorpath的路径下是否有鼠标图片,cursornumber是否大于0
3、查看窗口的过程函数MSG_ERASEBKGND下是否返回了return 0并且什么也没有画,没有填充背景,这样是不显示鼠标的
4、查看MiniGUI.cfg的输入引擎是否支持鼠标,如
# IAL engine
ial_engine=console
mdev=/dev/input/mouse0
mtype=IMPS2
5、查看创建窗口是否获取了鼠标
CreateInfo.hCursor = GetSystemCursor(0);
6、查看创建自定义控件是否获取了鼠标
MyClass.hCursor = GetSystemCursor(0);
使用SetNotificationCallback为静态框或按钮设置监听事件之后,点击了控件却没有收到事件
1、静态框创建的时候需要指定SS_NOTIFY风格
2、按钮创建的时候需要指定BS_NOTIFY风格
3、如果创建的静态框或按钮的父窗口不是窗口,是控件的话,使用SetNotificationCallback是监听不到事件的,消息传递到了父控件那里
1、使用自定义控件之前需要注册自定义控件
RegisterWindowClass(&MyClass)
程序结束之后需要销毁
UnregisterWindowClass("xxxxxxxxxxxxxxx");
2、查看自定义控件的属性
//最多只能有15个字符,多了就不显示了
MyClass.spClassName = "xxxxxxxxxxxxxxx";
因为在/libminigui-gpl-3.0.12/src/include/ctrlclass.h有定义宏
#define MAXLEN_CLASSNAME 15
使用MoveWindow函数或者快速更换显示图片时屏幕闪烁,查看创建窗口的时候是否使用了双缓冲机制,在移动的时候会刷新窗口背景,没有使用双缓冲,会直接在屏幕上画图,所以看到闪烁,如果使用双缓冲,则会在创建的缓冲中画好图之后再显示在屏幕上
CreateInfo.dwExStyle = WS_EX_AUTOSECONDARYDC;
1、gal_engine更换成shadow可以使用MiniGui的UI旋转功能。首先使能shadow,使用该引擎也会把屏幕点击事件旋转了,不用担心只是画面旋转而点击事件没有旋转
./configure --enable-qvfbial --enable-videoqvfb --enable-videoshadow
2、配置MiniGUI.cfg,shadow的real_engine可为pc_xvfb、qvfb、fbcon等,这里使用qvfb,rotate_screen的值可以为normal ,cw , ccw , hflip , vflip,cw是顺时针旋转90度
[system]
# GAL engine and default options
gal_engine=shadow
#旋转之后的分辨率
defaultmode=800x480-16bpp
[qvfb]
#屏幕原始分辨率
defaultmode=480x800-16bpp
display=0
[shadow]
real_engine=qvfb
#旋转之后的分辨率
defaultmode=800x480-16bpp
rotate_screen=cw