go语言缺乏官方GUI的支持,这点有时候很不方便。
虽然网上有很多开源的实现,但都不太满意,不太好用。
网上开源的有哪些?参见《2019,Go GUI项目爆发的一年?》https://studygolang.com/articles/21525?fr=sidebar
近来出现了很多跨平台的Go GUI项目。
虽说用井喷之势形容有些过了,但是的确有加速的迹象。难道Go语言将要开辟出另一大块疆土?
忙中偷闲,整理了一份目前GUI/图形/图像相关的Go项目列表。见下。欢迎补充。
原生GUI绑定
dlgs是一个跨平台的显示对话框和输入框的Go代码库。
glfw是一个GLFW3绑定库。
go-mobile支持移动平台应用开发(Android和iOS)。(其中包含OpenGL ES 2.0和ES 3.0绑定库。)
go-sdl2是一个SDL2绑定库。
go-gtk是一个GTK2绑定库。
gotk3是一个GTK+3绑定库。
GXUI,Google员工出品,但已经停止维护很久了。
。。。。。。
突然想起来曾经很火的嵌入式GUI,UCGUI多么的小巧灵活,且是使用100%的标准C代码编写的,跨平台当然很好移植和使用。
官方还有模拟器 emWin(UCGUI)模拟器。在电脑上有模拟器啊,这是不是很赞。
且图形界面可以在电脑上拖拽设计,这点儿更赞。
为什么网上没有go语言的ucgui的绑定?于是就萌生了用go语言封装ucgui的想法。
那么既然是为go语言打造的简易GUI,跨平台是必须的吧,至少Windows,linux和嵌入式linux都要支持的吧。
这不,以下先让ucgui在windows上的移植跑起来,是第一步。
ucgui在linux上的移植,参见博文:https://blog.csdn.net/yyz_1987/article/details/78380007
后续计划,ucgui的go语言封装
UCGUI简介:
UCGUI是一种嵌入式应用中的图形支持系统。
它设计用于为任何使用LCD图形显示的应用提供高效的独立于处理器及LCD控制器的图形用户接口。
它适用单任务或是多任务系统环境, 并适用于任意LCD控制器和CPU下任何尺寸的真实显示或虚拟显示。
它的设计架构是模块化的,由不同的模块中的不同层组成,由一个LCD驱动层来包含所有对LCD的具体图形操作。
UCGUI可以在任何的CPU上运行,因为它是100%的标准C代码编写的。
UCGUI能够适应大多数的使用黑白或彩色LCD的应用,它提供非常好的允许处理灰度的颜色管理。
还提供一个可扩展的2D图形库及占用极少RAM的窗口管理体系。
在Windows上的移植:,移植好的demo放在的我的github上了,
地址:https://github.com/yongzhena
https://github.com/yongzhena/ucgui-windows.git
使用方法:
首先,windows上必须有GCC的环境。
推荐安装mingwgcc
我安装的是x86_64-810gcc-posix-seh-npMingw64v75.7z这个压缩包,直接解压。再配置环境变量即可。
跟移植相关的,都在ucgui/GUI_X文件夹中。
在ucgui/GUI文件夹中,有写好的makefile文件,直接make即可编译出libucgui.a库。
然后需要把这个库放到GUIDemo_windows文件夹里。
同时,里面有几个windows上需要依赖的库在里面。libGDI32.LIB,libWINMM.lib,
同时多了两个文件MainTask.c和WinMain.c,其中windows程序的入口在WinMain.c中。
这个里面也有一个makefile文件,可执行make命令,直接就生成了demo,test.exe可执行程序。
//LCDSIM.c #include <windows.h> #include <memory.h> #include <math.h> #include "LCD.h" #include "GUI.h" #include "LCDConf.h" unsigned int LCD_Buffer[LCD_YSIZE][LCD_XSIZE]; BITMAPINFO bmp; void LCDSIM_Init(void) { //初始化位图结构 ZeroMemory(&bmp, sizeof(BITMAPINFO)); bmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmp.bmiHeader.biWidth = LCD_XSIZE; //位图宽度 bmp.bmiHeader.biHeight = -LCD_YSIZE; //位图高度 //当图像是倒立显示的时候,把biHeight改为对应的负值 bmp.bmiHeader.biPlanes = 1; bmp.bmiHeader.biBitCount = 32; //一个像素32Bit bmp.bmiHeader.biCompression = BI_RGB; } void UpdataShow(HDC _hdc) { SetDIBitsToDevice(_hdc, 0, 0, //在屏幕中的起始坐标 LCD_XSIZE, LCD_YSIZE, //显示的屏幕的宽,高 0 , 0, //位图左下角的坐标 0, //DIB中的起始扫描线 LCD_YSIZE, // DIB扫描线数目 (BYTE*)LCD_Buffer, //位图数据区起始指针,是BYTE*类型 &bmp, //位图的BITMAPINFO指针 DIB_RGB_COLORS); //颜色使用类型 } void LCDSIM_SetPixelIndex(int x, int y, int Index, int LayerIndex) { #if 0 int R = (Index & 0xF800) >> 11; int G = (Index & 0x07E0) >> 5; int B = Index & 0x001F; LCD_Buffer[y][x] = R << 3 << 16 | G << 2 << 8 | B << 3; #endif #if (LCD_BITSPERPIXEL == 8) unsigned char R = 1.164 * (Index - 16); LCD_Buffer[y][x] = R << 16 | R << 8 | R ; #elif (LCD_BITSPERPIXEL == 16) && (LCD_FIXEDPALETTE == 565) LCD_Buffer[y][x] = ((Index & 0xF800) << 3 >> 11 << 16) | ((Index & 0x07E0) << 2 >> 5 << 8) | (Index & 0x1F)<<3; #else if (LCD_BITSPERPIXEL == 1) if (Index == 0) { LCD_Buffer[y][x] = 0x00000000; } else { LCD_Buffer[y][x] = 0x00FFFFFF; } #endif } void LCDSIM_FillRect(int x0, int y0, int x1, int y1, int Index, int LayerIndex) { } int LCDSIM_GetPixelIndex(int x, int y, int LayerIndex) { return LCD_Buffer[y][x]; } void LCDSIM_SetLUTEntry(U8 Pos, LCD_COLOR color, int LayerIndex) { } GUI_PID_STATE Touch_Status; void Touch_Pressed(int x, int y) //触摸按下 x,y 为按下是的鼠标在窗体中的坐标 { Touch_Status.Pressed = 1; Touch_Status.x = x; Touch_Status.y = y; GUI_TOUCH_StoreStateEx(&Touch_Status); } void Touch_Release(void) //触摸释放 { Touch_Status.Pressed = 0; Touch_Status.x = -1; Touch_Status.y = -1; GUI_TOUCH_StoreStateEx(&Touch_Status); }
//LCD_Win.c #if defined(_WIN32) || defined(WIN32) || defined(WIN64) #include <windows.h> #endif #include "LCD.h" #include "LCD_Private.h" /* include LCDConf.h */ #include "LCDSIM.h" #include "GUI_Private.h" #include "memory.h" /********************************************************************* * * Defines * ********************************************************************** */ #if LCD_BITSPERPIXEL <= 8 #define PIXELINDEX U8 #else #define PIXELINDEX WORD #endif #ifdef WIN32 #ifndef ASSERT #define ASSERT(Val) \ if (!(Val)) \ MessageBox(NULL,"...in file "__FILE__,"Assertion failed...",MB_OK); #endif #endif #ifdef LCD_ASSERT #undef LCD_ASSERT #endif #define LCD_ASSERT(v) ASSERT(v) #ifndef LCD_DISPLAY_INDEX #define LCD_DISPLAY_INDEX 0 #endif /********************************************************************* * * Macros for internal use */ #if 0 static int _CheckBound(unsigned int c) { unsigned int NumColors = LCD_BITSPERPIXEL > 8 ? (LCD_BITSPERPIXEL > 16) ? 0xffffffff : 0xffff : (1 << LCD_BITSPERPIXEL) - 1; if (c > NumColors) { GUI_DEBUG_ERROROUT("LCDWin::SETPIXEL: parameters out of bounds"); return 1; } return 0; } #define SETPIXEL(x, y, c) \ if (!_CheckBound(c)) { \ LCDSIM_SetPixelIndex(x, y, c, LCD_DISPLAY_INDEX); \ } #else #define SETPIXEL(x, y, c) LCDSIM_SetPixelIndex(x, y, c, LCD_DISPLAY_INDEX) #endif #define XORPIXEL(x, y) _XorPixel(x,y) /********************************************************************* * * Static code * ********************************************************************** */ /********************************************************************* * * _XorPixel */ static void _XorPixel(int x, int y) { unsigned int Index = LCD_L0_GetPixelIndex(x,y); LCDSIM_SetPixelIndex(x, y, LCD_NUM_COLORS-1-Index, LCD_DISPLAY_INDEX); } /********************************************************************* * * _DrawBitLine1BPP */ static void _DrawBitLine1BPP(int x, int y, U8 const*p, int Diff, int xsize, const LCD_PIXELINDEX*pTrans) { LCD_PIXELINDEX Index0, Index1; #if (GUI_USE_MEMDEV_1BPP_FOR_SCREEN == 1) const LCD_PIXELINDEX aTrans[2] = {0, 1}; if (!pTrans) { pTrans = aTrans; } #endif Index0 = *(pTrans + 0); Index1 = *(pTrans + 1); x+=Diff; switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS|LCD_DRAWMODE_XOR)) { case 0: /* Write mode */ do { LCDSIM_SetPixelIndex(x++,y, (*p & (0x80>>Diff)) ? Index1 : Index0, LCD_DISPLAY_INDEX); if (++Diff==8) { Diff=0; p++; } } while (--xsize); break; case LCD_DRAWMODE_TRANS: do { if (*p & (0x80>>Diff)) LCDSIM_SetPixelIndex(x,y, Index1, LCD_DISPLAY_INDEX); x++; if (++Diff==8) { Diff=0; p++; } } while (--xsize); break; case LCD_DRAWMODE_XOR | LCD_DRAWMODE_TRANS: case LCD_DRAWMODE_XOR: do { if (*p & (0x80>>Diff)) { int Pixel = LCDSIM_GetPixelIndex(x,y, LCD_DISPLAY_INDEX); LCDSIM_SetPixelIndex(x,y, LCD_NUM_COLORS-1-Pixel, LCD_DISPLAY_INDEX); } x++; if (++Diff==8) { Diff=0; p++; } } while (--xsize); break; } } /********************************************************************* * * _DrawBitLine2BPP */ #if (LCD_MAX_LOG_COLORS > 2) static void _DrawBitLine2BPP(int x, int y, U8 const * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) { LCD_PIXELINDEX Pixels = *p; int CurrentPixel = Diff; x += Diff; switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) { case 0: if (pTrans) { do { int Shift = (3 - CurrentPixel) << 1; int Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift; LCD_PIXELINDEX PixelIndex = *(pTrans + Index); SETPIXEL(x++, y, PixelIndex); if (++CurrentPixel == 4) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } else { do { int Shift = (3 - CurrentPixel) << 1; int Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift; SETPIXEL(x++, y, Index); if (++CurrentPixel == 4) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } break; case LCD_DRAWMODE_TRANS: if (pTrans) { do { int Shift = (3 - CurrentPixel) << 1; int Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift; if (Index) { LCD_PIXELINDEX PixelIndex = *(pTrans + Index); SETPIXEL(x, y, PixelIndex); } x++; if (++CurrentPixel == 4) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } else { do { int Shift = (3 - CurrentPixel) << 1; int Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift; if (Index) { SETPIXEL(x, y, Index); } x++; if (++CurrentPixel == 4) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } break; } } #endif /********************************************************************* * * _DrawBitLine4BPP */ #if (LCD_MAX_LOG_COLORS > 4) static void _DrawBitLine4BPP(int x, int y, U8 const * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) { LCD_PIXELINDEX Pixels = *p; int CurrentPixel = Diff; x += Diff; switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) { case 0: if (pTrans) { do { int Shift = (1 - CurrentPixel) << 2; int Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift; LCD_PIXELINDEX PixelIndex = *(pTrans + Index); SETPIXEL(x++, y, PixelIndex); if (++CurrentPixel == 2) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } else { do { int Shift = (1 - CurrentPixel) << 2; int Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift; SETPIXEL(x++, y, Index); if (++CurrentPixel == 2) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } break; case LCD_DRAWMODE_TRANS: if (pTrans) { do { int Shift = (1 - CurrentPixel) << 2; int Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift; if (Index) { LCD_PIXELINDEX PixelIndex = *(pTrans + Index); SETPIXEL(x, y, PixelIndex); } x++; if (++CurrentPixel == 2) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } else { do { int Shift = (1 - CurrentPixel) << 2; int Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift; if (Index) { SETPIXEL(x, y, Index); } x++; if (++CurrentPixel == 2) { CurrentPixel = 0; Pixels = *(++p); } } while (--xsize); } break; } } #endif /********************************************************************* * * _DrawBitLine8BPP */ #if (LCD_MAX_LOG_COLORS > 16) static void _DrawBitLine8BPP(int x, int y, U8 const*p, int xsize, const LCD_PIXELINDEX*pTrans) { LCD_PIXELINDEX pixel; if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS)==0) { if (pTrans) { for (;xsize > 0; xsize--,x++,p++) { pixel = *p; SETPIXEL(x, y, *(pTrans+pixel)); } } else { for (;xsize > 0; xsize--,x++,p++) { SETPIXEL(x, y, *p); } } } else { /* Handle transparent bitmap */ if (pTrans) { for (; xsize > 0; xsize--, x++, p++) { pixel = *p; if (pixel) { SETPIXEL(x+0, y, *(pTrans+pixel)); } } } else { for (; xsize > 0; xsize--, x++, p++) { pixel = *p; if (pixel) { SETPIXEL(x+0, y, pixel); } } } } } #endif /********************************************************************* * * _DrawBitLine16BPP */ #if (LCD_BITSPERPIXEL > 8) static void _DrawBitLine16BPP(int x, int y, U16 const * p, int xsize) { LCD_PIXELINDEX pixel; if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) { for (;xsize > 0; xsize--,x++,p++) { SETPIXEL(x, y, *p); } } else { /* Handle transparent bitmap */ for (; xsize > 0; xsize--, x++, p++) { pixel = *p; if (pixel) { SETPIXEL(x + 0, y, pixel); } } } } #endif /********************************************************************* * * _DrawBitLine24BPP */ #if (LCD_BITSPERPIXEL > 16) static void _DrawBitLine24BPP(int x, int y, U32 const * p, int xsize) { LCD_PIXELINDEX pixel; if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) { for (;xsize > 0; xsize--, x++, p++) { SETPIXEL(x, y, *p); } } else { /* Handle transparent bitmap */ for (; xsize > 0; xsize--, x++, p++) { pixel = *p; if (pixel) { SETPIXEL(x+0, y, pixel); } } } } #endif /********************************************************************* * * Exported code * ********************************************************************** */ /********************************************************************* * * LCD_L0_DrawPixel * * Purpose: Writes 1 pixel into the display. */ void LCD_L0_DrawPixel(int x, int y) { if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) { XORPIXEL(x, y); } else { SETPIXEL(x, y, LCD_COLORINDEX); } } /********************************************************************* * * LCD_L0_DrawHLine */ void LCD_L0_DrawHLine(int x0, int y, int x1) { if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) { for (;x0 <= x1; x0++) { XORPIXEL(x0, y); } } else { for (;x0 <= x1; x0++) { SETPIXEL(x0, y, LCD_COLORINDEX); } } } /********************************************************************* * * LCD_L0_DrawVLine */ void LCD_L0_DrawVLine(int x, int y0, int y1) { if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) { while (y0 <= y1) { XORPIXEL(x, y0); y0++; } } else { while (y0 <= y1) { SETPIXEL(x, y0, LCD_COLORINDEX); y0++; } } } /********************************************************************* * * LCD_L0_FillRect */ void LCD_L0_FillRect(int x0, int y0, int x1, int y1) { for (; y0 <= y1; y0++) { LCD_L0_DrawHLine(x0,y0, x1); } } /********************************************************************* * * LCD_L0_DrawBitmap */ void LCD_L0_DrawBitmap(int x0, int y0, int xsize, int ysize, int BitsPerPixel, int BytesPerLine, const U8* pData, int Diff, const LCD_PIXELINDEX* pTrans) { int i; /* Use DrawBitLineXBPP */ for (i=0; i<ysize; i++) { switch (BitsPerPixel) { case 1: _DrawBitLine1BPP(x0, i + y0, pData, Diff, xsize, pTrans); break; #if (LCD_MAX_LOG_COLORS > 2) case 2: _DrawBitLine2BPP(x0, i + y0, pData, Diff, xsize, pTrans); break; #endif #if (LCD_MAX_LOG_COLORS > 4) case 4: _DrawBitLine4BPP(x0, i + y0, pData, Diff, xsize, pTrans); break; #endif #if (LCD_MAX_LOG_COLORS > 16) case 8: _DrawBitLine8BPP(x0, i + y0, pData, xsize, pTrans); break; #endif #if (LCD_BITSPERPIXEL > 8) case 16: _DrawBitLine16BPP(x0, i + y0, (const U16 *)pData, xsize); break; #endif #if (LCD_BITSPERPIXEL > 16) case 24: _DrawBitLine24BPP(x0, i + y0, (const U32 *)pData, xsize); break; #endif } pData += BytesPerLine; } } /********************************************************************* * * LCD_L0_SetOrg * * Purpose: * Sets the original position of the virtual display. * Has no function at this point with the PC-driver. */ void LCD_L0_SetOrg(int x, int y) { //LCDSIM_SetOrg(x, y, LCD_DISPLAY_INDEX); } /********************************************************************* * * Support for verification * * Purpose: * The following routines are implemented, but have no functionility * at this point. The reason is that these functions are supposed * to supervise the hardware, which for obvious reasons can not be * done in a simulation. */ #if LCD_VERIFY int LCD_GetErrStat(void) { return 0; } void LCD_ClrErrStat(void) { } int LCD_GetErrCnt (void) { return 0; } #endif /********************************************************************* * * LCD_On * LCD_Off * * (Not supported in Simulation) */ void LCD_Off (void) {} void LCD_On (void) {} /********************************************************************* * * LCD_L0_SetLUTEntry */ void LCD_L0_SetLUTEntry(U8 Pos, LCD_COLOR color) { LCDSIM_SetLUTEntry(Pos, color, LCD_DISPLAY_INDEX); } /********************************************************************* * * LCD_L0_Init */ int LCD_L0_Init(void) { LCDSIM_Init(); //初始化LCDSIM return 0; } int LCD_L0_CheckInit(void) { return 0; } /********************************************************************* * * LCD_L0_ReInit * * Purpose: * This routine is supplied for compatibility and interchangability of * "C"-sources with embedded versions of the driver. It has no real * effect in the PC-version as there is simply no need to re-initialize * the LCD since it is just simulated anyhow. */ void LCD_L0_ReInit (void) {} unsigned LCD_L0_GetPixelIndex(int x, int y) { return LCDSIM_GetPixelIndex(x,y, LCD_DISPLAY_INDEX); } /********************************************************************* * * LCD_L0_XorPixel * * Purpose: * Inverts 1 pixel of the display. */ void LCD_L0_XorPixel(int x, int y) { XORPIXEL(x, y); } /********************************************************************* * * LCD_L0_SetPixelIndex * * Purpose: * Writes 1 pixel into the display. */ void LCD_L0_SetPixelIndex(int x, int y, int ColorIndex) { SETPIXEL(x, y, ColorIndex); } /********************************************************************* * * LCD_L0_GetDevFunc */ void * LCD_L0_GetDevFunc(int Index) { GUI_USE_PARA(Index); return NULL; } void LCDWin_c(void); void LCDWin_c(void) { } /* avoid empty object files */
//GUI_X_Win.c #include "GUI_X.h" #include <windows.h> /********************************************************************* * * GUI_X_Init() */ void GUI_X_Init(void) { } /********************************************************************* * * GUI_X_ExecIdle() */ void GUI_X_ExecIdle(void) { Sleep(1); }; /********************************************************************* * * Timing: * GUI_GetTime() * GUI_Delay(int) Some timing dependent routines of uC/GUI require a GetTime and delay funtion. Default time unit (tick), normally is 1 ms. */ int StartTime; //程序开始运行时的时间 该时间为从系统开启算起所经过的时间 单位为毫秒 int GUI_X_GetTime(void) { return (timeGetTime() - StartTime); } void GUI_X_Delay(int Period) { Sleep(Period); } /********************************************************************* * * Multitask interface for Win32 * * The folling section consisting of 4 routines is used to make * the GUI software thread safe with WIN32 */ static HANDLE hMutex; static int _EntranceCnt; // For debugging only ... Not required void GUI_X_InitOS(void) { StartTime = timeGetTime(); //需要添加winmm.lib库 //创建一个互斥量对象 hMutex = CreateMutex(NULL, 0, "GUI Simulation - Mutex"); } U32 GUI_X_GetTaskId(void) { return GetCurrentThreadId(); } void GUI_X_Lock(void) { WaitForSingleObject(hMutex, INFINITE); if (++_EntranceCnt > 1) { //SIM_ErrorOut("Error in GUITASK.c module ..."); } } void GUI_X_Unlock(void) { _EntranceCnt--; ReleaseMutex(hMutex); } /********************************************************************* * * Text output for Logging, warnings and errors Logging - required only for higher debug levels */ void GUI_X_Log (const char *s) { /*SIM_Log(s); */} void GUI_X_Warn (const char *s) { /*SIM_Warn(s); */} void GUI_X_ErrorOut(const char *s) { /*SIM_ErrorOut(s);*/ }