自已實現乙個UI庫

2021-07-03 14:28:17 字數 4560 閱讀 1125

[2023年寫乙個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表示一行占用多少位元組。

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底層操作

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的工具了。我們現在用上面的函式就可以畫點,線,矩形,還是很簡單的。

2014-11-15

自已實現乙個UI庫 實現Windows的乙個模擬器

實現windows的乙個模擬器 接上一節的實現的介面,在windows裡面寫乙個簡單的模擬器,在上面能操作上一節裡面的介面動作。開啟vs,建立乙個解決方案,把ui的 作了乙個單獨的lib庫,再建立乙個帶窗體的工程,ui的畫圖就畫在乙個窗體的客戶區dc中.首先定義乙個對dc的畫圖操作,對應上一節的ui...

如何實現乙個UI系統

如何為我的遊戲實現乙個ui系統,這個問題我想了很久,不過我現在可不像開始的時候那樣一點思路也沒有。如果你也被這個問題所困擾,我十分樂意與你分享這幾天來的學習成果。嘿嘿,我是不是有點得意忘形了?在開始之前,我要提醒你,學而不思則惘。在看這篇文章的時候,請時刻保持頭腦清醒,如果有什麼不太明白的話,請停下...

利用QtQuick實現UI的乙個Demo

利用qtquick實現ui的乙個demo demo主頁面 二級頁面分類電影集合,可滑動動態載入 第 介面,具體的電影資訊 2,介面的設計。這個demo介面設計很簡單,分為 介面,第一級介面是主頁,顯示電影型別。使用者選擇某乙個分類,進入第二級介面,攤開顯示該分類下的電影集合,當然這些電影相關資訊是已...