自已实现一个UI库
[2014年写一个UI库时写的几个文章,公布出来]
几年前的一个嵌入式的UI开发,使自己有机会接触到了UI的一些底层知识,尽管之前也开发过非常多Windows下的信息应用系统,也做非常多的界面开发,但一直却对UI的一些运作却不了解。
BOSS决定使用UCGUI做为UI的基本库来开发UI界面的一些应用。用UCGUI的库来做开发。它已经有非常完好的基本构件,像窗口的管理,主要的控件,图片,文字处理等。只是听说UCGUI的授权费用也是不菲的。但我觉得它确实是一个物有所值的东西。
在使用中也还是遇到过一些问题,但这些基本都不会有什么大的影响,基本的是有源码,有一些小的BUG。也能够自己处理。满足不了的控件能够自己开发,也能够非常方便的在他的控件基础上做一些扩展。
使用它避免不了要去读了解它的一些底层代码,这样自己有机会对UI的动作有了一些主要的了解。近期也做些UI的事。想起UCGUI的代码架构还是值得学习的,所以自己从UI的基本原理上再次学习了一次,自己也花时间动手做了一些主要的代码实现。非常多基本原理都是从UCGUI上学习来的。再把这些主要的东西记下来,方便后来的学习者。
怎样自己动手写一个UI?在我自己没接触底层UI前,一直没想过,也认为它是一件比較复杂和难的事情。
它有多难?如今我认为假设会一门编程语言就能够写一个UI出来。这种基础就够了,我想能够试一试。
从画一个点開始
“像素”这个词我们一定已经非常熟悉了。如今买手机时大家非常观注的一个參数就是摄像头的成像像素是多少,由于图像的质量非常大成度就是它决定的。一个像素代表一个点。相同在显示器上也是一样,我们说的分辨率就是长宽多少个像素,在一个屏幕上显示有文字,有窗口。有图片及各种形状等等!看起来这是一个挺复杂的东西,但它却是由一个一个的点构成的。一个点代表一个像素,而这个点不同的像素值就代表不同的颜色。一个像素能够用8位,16位,32位来表示,位数越多。表示它能表示的颜色就越多显示的色彩也就越丰富了。
一个屏幕像是这种:
我们以左上角为原点,做一个坐标系。分别有X,Y方向。
像我如今的电脑的分辨率是1440x900,这样 X 最大取值是1440,Y最大取值是900。
假设我们要在一个屏幕上画一个点,给定一个点如:(500,500),仅仅要在坐标系里找到对应的位置就能够写一个像素值进去。屏幕就会显示出一个颜色点。
显示器有一个显存。要在屏幕上画出点,也就须要在对应的显存位置写入颜色值。显存又会映射到内存的一块连续的区域。这样我们仅仅要把值写入内存的区域。系统又会作I/O读写把更新显存的值。所心我们仅仅要关心写的内存的区域就好了。
操作显存
在Linux里有一个叫framebuffer的概念。叫“帧缓存”,事实上就是对显存当前值的缓存,Linux系统的显卡驱动都有实现,我们对framebuffer的读写就是对显存的读写。
在Linux里/dev文件夹里,应都有一个类似fbx(x表示一个数字)设备文件。打开它,再用mmap函数把framebuffer内存映射进我们的进程里就可认方便的对显示器操作了,这样我们能够画点,画线显示在显示器上面。
如以下的代码操作,打开fb0,并读取设置对应的參数:
static struct fb_var_screeninfo stVarInfo;
static struct fb_fix_screeninfo stfixInfo;
static unsigned char *pFrameBuffer = NULL;
char *file_name = "/dev/fb0";
int fbDev, s32Ret;
fbDev = open(file_name,O_RDWR,0);
if(fbDev < 0)
{
printf("open framebuff failed!\n");
return;
}
stVarInfo.bits_per_pixel = 16;
stVarInfo.activate = FB_ACTIVATE_NOW;
stVarInfo.xres = stVarInfo.xres_virtual = 1440;
stVarInfo.yres = stVarInfo.yres_virtual = 900;
s32Ret = ioctl(fbDev, FBIOPUT_VSCREENINFO, &stVarInfo);
if(s32Ret < 0)
{
printf("PUT_VSCREENINFO failed!%x\n",s32Ret);
return ;
}
if (ioctl(fbDev, FBIOGET_FSCREENINFO, &stfixInfo) < 0)
{
printf("Get fix screen info failed!\n");
return ;
}
pFrameBuffer = mmap(HI_NULL, stfixInfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fbDev, 0);
memset(pFrameBuffer,0x00,stfixInfo.smem_len);
在上面的代码中打开一个framebuffer,设置读取显示器的信息当中两个比較重要的结构:fb_var_screeninfo和fb_fix_screeninfo 。详细的能够搜索了解一下。
在mmap时,stfixInfo.smem_len就是显存在内存区域的大小。 memset的操作效果就是我们把显示器设成全黑色了,由于我们写入的每个点的像素值都是0x0。
在一个指定的点画点
显存的地址空间是一个线性的一维地址空间,我们的屏幕像上面的坐标系,是一个二维的了。给定一个点(x,y),这样我们就须要把它转换成对应的内存所在的地址。当知道一个屏幕的分辨率了,如1440 * 900,如今通过FBIOGET_FSCREENINFO知道了一些主要的信息,通过mmap知道了首地址。一个像素能够用8位。或16位,或32位,或很多其它的位表示。如我的板上的系统是16位,我用的LINUX系统是用32位的。以我板上的为例,用16位来表示一个像素点。也就是2个字节表示一个像素点。
那么屏幕上的点是这样确定的,想像你拿支笔从第一行画点,但把第一行画满后。再从第二行開始,持续的把整个屏画满,在屏上画点也是这样,假如是16位2个字节表示一个像素,分辨率是1400*900。所以给定的点(x,y)的地址为:
x * 2 + y * (1440 * 2),
假设用上一步代码里得到的信息来表示就是:
(x + stVarInfo.xoffset) * (stVarInfo.bits_per_pixel >> 3) + (y + stVarInfo.yoffset) * stfixInfo.line_length;
Xoffset,yoffset表示是否相对原点的偏移,bit_per_pixel表示一个像素用多少位表示。line_length表示一行占用多少字节。
画一个点(x,y)的地址确定了,这样写入一个值,对应的位置显示对应的颜色。
那么对应的画点函数例如以下:
void UI_SetPointPixel(int x, int y, int pixelValue)
{
int location = 0;
location = (x + stVarInfo.xoffset) * (stVarInfo.bits_per_pixel >> 3) + (y + stVarInfo.yoffset) * stfixInfo.line_length;
*(short *)(pFrameBuffer + location) = (short)pixelValue;
}
应为是16位的。所以注意上面的转换 (short *).
获取一个点的颜色
相同有时操作须要得到一个点的颜色,依据上面画点的函数。能够例如以下写出获取点的函数:
unsigned int fb_GetPointPixel(int x, int y)
{
int location = 0;
location = (x + stVarInfo.xoffset) * (stVarInfo.bits_per_pixel >> 3) + (y + stVarInfo.yoffset) * stfixInfo.line_length;
int PixelIndex = *(short*)(pShowScreen + location);
return PixelIndex;
}
主要的UI底层操作
我们工作用的操作UI上,有窗口。图片,视频等等,非常多东西,看起来非常复杂。但这种复杂北后,却是主要的像素点组成的,但再复杂的实现。都是在上面的画点函数。为基础的。为了方便我们开法。于是扩展了上面的画点函数,有画线段。矩形,圆等等。为了方便后面画更复杂的。我们实现画线和填充矩形函数:
void fb_DrawHLine(int x0, int y0, int x1)
{
U16 PixelColor = UI_GetDrawPixeColor();
for(; x0 <= x1; x0++)
{
UI_SetPointPixel(x0, y0, PixelColor);
}
}
void fb_DrawVLine(int x0, int y0, int y1)
{
U16 PixelColor = UI_GetDrawPixeColor();
for(; y0 <= y1; y0++)
{
UI_SetPointPixel(x0, y0, PixelColor);
}
}
void fb_DrawFillRect(int x0, int y0, int x1, int y1)
{
for(; y0<=y1; y0++)
{
UI_DrawHLine(x0, y0, x1);
}
}
分别实现画水平,垂直线。画填充的矩形。上面的 UI_GetDrawPixeColor 函数得到当前画点线的填充颜色值。
这样我们就有了主要的操作UI的工具了。
我们如今用上面的函数就能够画点,线。矩形,还是非常easy的。
2014-11-15
自已实现一个UI库的更多相关文章
- avalon新一代UI库发布
任何前端框架,尤其是国内的,想推广开,必须有一个UI库,光是一个核心库当光头司令是不行的.此外还有一个小圈子,供大家遇到问题时可以发问,一起完善.自从avalon嫁入"去哪儿网"后 ...
- 腾讯出品的一个超棒的 Android UI 库
腾讯出品的一个超棒的 Android UI 库 相信做 Android 久了大家都会有种体会,那就是 Android 开发相对于前端开发来说统一的 UI 开源库比较少.造成这种现象的原因一方面是大多数 ...
- ZanUI-WeApp -- 一个颜值高、好用、易扩展的微信小程序 UI 库
ZanUI-WeApp -- 一个颜值高.好用.易扩展的微信小程序 UI 库:https://cnodejs.org/topic/589d625a5c8036f7019e7a4a 微信小程序之官方UI ...
- 新建一个UI窗口-XproerUI(MFC)教程
版权所有 2009-2015 荆门泽优软件有限公司 保留所有权利 产品首页:http://www.ncmem.com/apps/xproerui/index.asp 在线文档(XproerUI):Xp ...
- Riot - 比 Facebook React 更轻量的 UI 库
Riot 是一个类似 Facebook React 的用户界面库,只有3.5KB,非常轻量.支持IE8+浏览器的自定义标签,虚拟 DOM,语法简洁.Riot 给前端开发人员提供了除 React 和 P ...
- 免费的Android UI库及组件推荐
短短数年时间Android平台就已经形成了一个庞大而活跃的开发者社区.许多社区开发的项目业已进入成熟阶段,甚至可以用于商业的软件生产中,且不用担心质量问题. 本文编译自androiduipattern ...
- [转] 国内外最全面和主流的JS框架与WEB UI库(强烈推荐)
国内外最全面和主流的JS框架与WEB UI库... 当下对于网站前段开发人员来说,很少有人不使用一些JS框架或者WEB UI库,因此这些可以有效提高网站前段开发速度,并且能够统一开发环境,对于不同 ...
- 重大发现: windows下C++ UI库 UI神器-SOUI(转载)
转载:http://www.cnblogs.com/setoutsoft/p/4996870.html 在Windows平台上开发客户端产品是一个非常痛苦的过程,特别是还要用C++的时候.尽管很多语言 ...
- 移动端和web端前端UI库—Frozen UI、WeUI、SUI Mobile
web http://www.pintuer.com/ 拼图 http://www.h-ui.net/ http://www.layui.com/ 很厉害的一个个人产品 http://amazeui ...
随机推荐
- win10下anaconda3环境配置
WINDOW系统设置环境变量:我的电脑右键-属性-高级系统设置-高级-环境变量中在path中加入你系统安装anaconda的目录下的scripts中: C:\Users\***\anaconda3\S ...
- PHP 数组相加 和 数组合并array_merge
$arr1 = array("a"=>"PHP","b"=>"java","python" ...
- my @unpacking_list = values %map_function; print "\n".@unpacking_list; 输出是3 把 @unpacking_list 当做一个数 输出了
my %map_function = ( 88 "OK_func" => "open_statement", 89 & ...
- A10. JVM 对象
[概述] 首先需要了解对象在内存中的存储布局,其次需要了解对对象的访问定位. [对象的内存布局] 在 HotSpot 虚拟机中,对象在内存中存储的布局可以分为 3 块区域:对象头(Header).实例 ...
- 查找BUG的方法
1)测试环境 1)代码调试 2)问题重现 3)思考问题所在 2)生产环境 1)思考 2)测试本地环境是否存在问题 3)打开日志查看 4)思考是否是数据原因 5)拷贝数据到本地进行重现 3)未知错误 1 ...
- PyTorch: 序列到序列模型(Seq2Seq)实现机器翻译实战
版权声明:博客文章都是作者辛苦整理的,转载请注明出处,谢谢!http://blog.csdn.net/m0_37306360/article/details/79318644简介在这个项目中,我们将使 ...
- javaScript中计算字符串MD5
进行HTTP网络通信的时候,调用API向服务器请求数据,有时为了防止API调用过程中被黑客恶意篡改,所请求参数需要进行MD5算法计算,得到摘要签名.服务端会根据请求参数,对签名进行验证,签名不合法的请 ...
- 启发式合并CSU - 1811
F - Tree Intersection CSU - 1811 Bobo has a tree with n vertices numbered by 1,2,…,n and (n-1) edges ...
- MySQL与MyBatis中的查询记录
1.时间段查询 MySQL:select * from table where ctime >= CURDATE() and ctime <DATE_SUB(CURDATE(),INTER ...
- error trying to exec 'cc1plus': execvp: 没有那个文件或目录
出现这个问题,有两种可能: 第一,你没有安装g++ 第二,你的gcc的版本和g++版本不相符合 安装gcc和g++及一些依赖包 sudo apt-get install build-essential ...