zcu102_14_Zynq在Standalone下使用uGUI

uGUI的基本工作原理是將GUI組件的像素通過數據修改或者替換的方法疊加在原始圖像數據上

uGUI的使用非常簡單,將下載的ugui.h和ugui.c文件導入PS工程中即可以使用,通過官網手冊和代碼註釋可以查看詳細用法

下載

官網下載uGUI的最新版本

在網頁的下方可以找到使用手冊,源代碼和示例程序
在這裏插入圖片描述

導入PS工程

可以通過複製粘貼的方式將下載的源碼文件ugui.h和ugui.c文件導入PS工程

將ugui.h中的#include "system.h"改爲#include "stdint.h"

定義像素點繪製函數

爲了讓uGUI正常工作,還應當在程序中自定義像素點繪製函數,並且在uGUI的初始化函數UG_Init()中通過參數指定繪製函數,否則uGUI不能工作

目前使用的像素點繪製函數如下:

//自定義像素點(x, y)的填充函數
static void pix_set(UG_S16 x, UG_S16 y, UG_COLOR c)
{
	//計算當前像素點在圖像緩衝中的偏移
    //LINE_WIDTH爲當前圖像一行數據佔用的字節數目
    //PIX_BYTES爲當前圖像中一個像素點佔用的字節數目
	u32 pix_addr;
	pix_addr = y*LINE_WIDTH+x*PIX_BYTES;

	//取得配置顏色的RGB通道數值
	u8 r, g, b;
	r = (c >> 16) & 0xFF;
	g = (c >> 8) & 0xFF;
	b = c & 0xFF;

    //下方的透明度算法正確,但是uGUI底層接口調用時會在刷新GUI時出現閃爍
#ifdef GUI_ALPHA//如果有透明度要求
	//當前像素點值
	u8 ro, go, bo;
	ro = *(frame_ptr_ping+pix_addr);
	go = *(frame_ptr_ping+pix_addr+1);
	bo = *(frame_ptr_ping+pix_addr+2);

	//當前像素點值與GUI像素點值融合
	r = (u8)((float)r*GUI_ALPHA+(float)ro*(1.0F-GUI_ALPHA)+0.5F);
	g = (u8)((float)g*GUI_ALPHA+(float)go*(1.0F-GUI_ALPHA)+0.5F);
	b = (u8)((float)b*GUI_ALPHA+(float)bo*(1.0F-GUI_ALPHA)+0.5F);
#endif

    //當前圖像使用ping/pong雙緩衝,一個緩衝繪製GUI的同時,另一個緩衝接收原始數據
	//配置像素點的RGB值
	if (frame_flag == 0)
	{
		//刷新ping緩衝
		*(frame_ptr_ping+pix_addr) = r;
		*(frame_ptr_ping+pix_addr+1) = g;
		*(frame_ptr_ping+pix_addr+2) = b;
	}
	else
	{
		//刷新pong緩衝
		*(frame_ptr_pong+pix_addr) = r;
		*(frame_ptr_pong+pix_addr+1) = g;
		*(frame_ptr_pong+pix_addr+2) = b;
	}
}

刷新GUI圖像

uGUI使用函數UG_Update()刷新GUI圖像,在刷新GUI之前必須保證原始圖像不再更改,否則原始圖像的更改將會覆蓋GUI圖像

每次刷新GUI圖像之前,即使Window顯示或者隱藏狀態不變,也必須用UG_WindowShow()函數或者UG_WindowHide()函數更新全部Window的顯示狀態

定製GUI

爲了更好的匹配項目需求,大多數情況下需要對uGUI接口函數進行定製

而且uGUI的授權允許對其源碼進行修改

由於項目需要,目前對以下三個功能進行了定製修改

BMP圖像繪製

uGUI的源碼沒有RGB888像素格式的BMP圖像繪製功能,作爲最普遍的像素格式,需要自行添加至uGUI中

首先添加BMP_BPP_24的宏定義,作爲RGB888的格式定義

在ugui.h中找到BMP_BPP_32的宏定義(其中BPP表示Bits Per Pixel),在其下方添加:

#define BMP_BPP_24 (1<<6)

在ugui.c中找到UG_DrawBMP()函數,將函數內容修改爲以下代碼,注意下方代碼不繪製BMP圖像中的白色,將白色作爲透明色實現

//xp指繪圖起點x座標,yp指繪圖起點y座標
void UG_DrawBMP( UG_S16 xp, UG_S16 yp, UG_BMP* bmp )
{
   UG_S16 x,y,xs;
   UG_U8 r,g,b;

   UG_U16 tmp;
   UG_COLOR c;

   if ( bmp->p == NULL ) return;

   /* Only support 16 BPP so far */
   if ((bmp->bpp == BMP_BPP_16) && (bmp->colors == BMP_RGB565))//uGUI原有的BMP繪製功能
   {
	  UG_U16* p;
      p = (UG_U16*)bmp->p;
      xs = xp;//用xs暫存形參數值
      for(y=0;y<bmp->height;y++)
      {
         xp = xs;//每行繪圖的列起點
         for(x=0;x<bmp->width;x++)
         {
            tmp = *p++;
            /* Convert RGB565 to RGB888 */
            r = (tmp>>11)&0x1F;
            r<<=3;
            g = (tmp>>5)&0x3F;
            g<<=2;
            b = (tmp)&0x1F;
            b<<=3;
            c = ((UG_COLOR)r<<16) | ((UG_COLOR)g<<8) | (UG_COLOR)b;
            UG_DrawPixel( xp++ , yp , c );
         }
         yp++;
      }
   }
   else if ((bmp->bpp == BMP_BPP_24) && (bmp->colors == BMP_RGB888))//自定義
   {
	   UG_U8* p;
	   p = (UG_U8*)(bmp->p);
	   xs = xp;//用xs暫存形參數值
	   for (y = 0; y < bmp->height; ++y)
	   {
		   xp = xs;//每行繪圖的列起點

		   for (x = 0; x < bmp->width; ++x)
		   {
			   b = *p;
			   g = *(p+1);
			   r = *(p+2);

			   c = ((UG_COLOR)r<<16) | ((UG_COLOR)g<<8) | (UG_COLOR)b;

			   if ((r != 0xFF) || (g != 0xFF) || (b != 0xFF))
			   {
				   //白色不繪製,作爲透明顯示
				   //非白色才繪製
				   UG_DrawPixel(xp, yp, c);
			   }

			   //更新指針
			   p += 3;

			   //更新繪圖列座標
			   ++xp;
		   }

		   ++yp;//更新繪圖行座標
	   }
   }
   else
   {
      return;
   }
}

Window背景透明

uGUI中的Window是所有GUI組件的容器,但是Window背景不透明

如果需要Window背景透明,有2種方法:

  1. 每個GUI組件使用單個Window,Window設置爲無邊框和標題欄,並且GUI組件佔滿Window。由於uGUI中只有Window可以在建立後移動位置,這種方法可以實現GUI組件移動的效果。
  2. 修改ugui.c中的_UG_WindowUpdate()函數,去掉函數中繪製背景的代碼

根據上述第2種方法修改後的_UG_WindowUpdate()函數如下:

void _UG_WindowUpdate( UG_WINDOW* wnd )
{
   UG_U16 i,objcnt;
   UG_OBJECT* obj;
   UG_S16 xs,ys,xe,ye;

   xs = wnd->xs;
   ys = wnd->ys;
   xe = wnd->xe;
   ye = wnd->ye;

   wnd->state &= ~WND_STATE_UPDATE;
   /* Is the window visible? */
   if ( wnd->state & WND_STATE_VISIBLE )
   {
//      /* 3D style? */
//      if ( (wnd->style & WND_STYLE_3D) && !(wnd->state & WND_STATE_REDRAW_TITLE) )
//      {
//         _UG_DrawObjectFrame(xs,ys,xe,ye,(UG_COLOR*)pal_window);
//         xs+=3;
//         ys+=3;
//         xe-=3;
//         ye-=3;
//      }
//      /* Show title bar? */
//      if ( wnd->style & WND_STYLE_SHOW_TITLE )
//      {
//         _UG_WindowDrawTitle( wnd );
//         ys += wnd->title.height+1;
//         if ( wnd->state & WND_STATE_REDRAW_TITLE )
//         {
//            wnd->state &= ~WND_STATE_REDRAW_TITLE;
//            return;
//         }
//      }
//      /* Draw window area? */
//      UG_FillFrame(xs,ys,xe,ye,wnd->bc);

      /* Force each object to be updated! */
      objcnt = wnd->objcnt;
      for(i=0; i<objcnt; i++)
      {
         obj = (UG_OBJECT*)&wnd->objlst[i];
         if ( !(obj->state & OBJ_STATE_FREE) && (obj->state & OBJ_STATE_VALID) && (obj->state & OBJ_STATE_VISIBLE) ) obj->state |= (OBJ_STATE_UPDATE | OBJ_STATE_REDRAW);
      }
   }
   else
   {
//      UG_FillFrame(wnd->xs,wnd->xs,wnd->xe,wnd->ye,gui->desktop_color);
   }
}

添加中文顯示

uGUI源碼不支持中文顯示

在uGUI顯示中文有2種方法:

  1. 將中文內容作爲BMP圖像顯示,根據需要自行定義BMP圖像的三種組件Button, TextBox和Image
  2. 使用點陣取模軟件將需要顯示的中文字體加入代碼,替換uGUI中現有字體

2種方法中前者簡單方便,後者靈活度高適用於大規模的GUI顯示

對於本人而言,使用uGUI還是用第1種方法更合適,如果必須進行大規模的GUI顯示,uGUI本身已經不適用,還是用Linux+Qt更合適

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章