1. 程式人生 > 其它 >【第3版emWin教程】第19章 emWin6.x的2D圖形庫之繪製圖形(含二維碼和條形碼)

【第3版emWin教程】第19章 emWin6.x的2D圖形庫之繪製圖形(含二維碼和條形碼)

教程不斷更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第19章 emWin6.x的2D圖形庫之繪製圖形(含二維碼和條形碼)

本期主要講解2D圖形庫的圖形繪製,包括繪製多邊形,繪製圓,繪製橢圓,繪製弧線,繪製線圖,繪製餅圖。本章節的例子不用在開發板上面做除錯,直接用emWin模擬器即可。

學習本章節,務必保證已經學習了第9章或者第10章以及第11章。本章節提供的模擬器演示程式碼都是可以在模擬器上面執行的,使用方法是將SWIPELIST_Demo.c檔案裡面的所有內容刪掉並將本章節提供的程式碼複製到SWIPELIST_Demo.c檔案即可執行。

19.1 初學者重要提示

19.2 繪製多邊形

19.3 繪製圓

19.4 顯示屏繪製的圓為什麼不圓

19.4 繪製橢圓

19.5 繪製弧線

19.6 繪製線圖

19.7 繪製餅圖

19.8 總結

19.1 初學者重要提示

  1. 2D函式的圖形繪製就是一些API函式,從應用上來講,基本沒有什麼難度,初學者多做練習,呼叫幾次就熟練了。
  2. 2D繪圖的所有API函式在emWin手冊中都有講解,下圖是中文版手冊裡面API函式的位置

下圖是英文版手冊裡面API函式的位置:

19.2 繪製多邊形

當前emWin支援的多邊形函式主要有以下5個:

下面我們通過如下三個例項來講解這幾個API函式的用法。

19.2.1 例子一

這個例子主要涉及到以下三個函式:

  • void GUI_DrawPolygon(const GUI_POINT * pPoint, int NumPoints, int x, int y)

根據使用者設定的座標點(x,y)位置,將點列表pPoint中的NumPoints個座標點連線,最終繪製出一個閉合的多邊形。

  • void GUI_EnlargePolygon(GUI_POINT * pDest, const GUI_POINT * pSrc, int NumPoints, int Len)

將點列表pSrc中的NumPoints個座標點按指定的畫素個數Len全方位擴充套件,並將最終結果賦值給新的點列表pDest,這個新的點列表就是擴充套件後的多邊形座標點。

  • void GUI_FillPolygon(const GUI_POINT * pPoint, int NumPoints, int x, int y)

根據使用者設定的座標點(x,y)位置,將點列表pPoint中的NumPoints個座標點連線,最終繪製出一個填充的多邊形。

下面是在模擬器上實際執行的例子:

#include "GUI.h"


/* 圖形的原始座標點 */
const GUI_POINT aPoints[] = {
{ 40, 20},
{ 0, 20},
{ 20, 0}
};

/* 用於儲存放大後的座標點 */
GUI_POINT aEnlargedPoints[GUI_COUNTOF(aPoints)];

void Sample(void) {
    int i;

    /* 清屏 */
    GUI_Clear();

    /* 設定繪圖模式 */
    GUI_SetDrawMode(GUI_DM_XOR);
    
    /* 繪製多邊形 */
    GUI_FillPolygon(aPoints,              /* 指向要顯示和填充的多邊形 */
                    GUI_COUNTOF(aPoints), /* 點列表中指定的點數量 */
                    140,                  /* 原點的X位置 */
                    110);                 /* 原點的Y位置 */

    for (i = 1; i < 10; i++) {
        GUI_EnlargePolygon(aEnlargedPoints,      /* 指向目標多邊形 */
                           aPoints,              /* 指向源多邊形 */
                           GUI_COUNTOF(aPoints), /* 點列表中指定的點數量 */
                           i * 5);               /* 擴充套件多邊形的長度 (畫素) */

        /* 繪製放大後的多邊形 */
        GUI_FillPolygon(aEnlargedPoints, GUI_COUNTOF(aPoints), 140, 110);
    }
}

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {

  /* emWin初始化 */
  GUI_Init();

  /* 呼叫測試函式 */
  Sample();

  while (1)
  {
      GUI_Delay(10);
  }
}

顯示效果如下:

19.2.2 例子二

  • void GUI_MagnifyPolygon(GUI_POINT * pDest, const GUI_POINT * pSrc, int NumPoints,

int Mag);

此函式可以按照使用者設定的放大係數Mag放大多邊形。另外請注意,擴充套件和放大多邊形之間的區別,比如呼叫函式GUI_EnlargePolygon()(引數Len= 1)是將多邊形的所有邊擴充套件1畫素,而呼叫GUI_MagnifyPolygon()(引數Mag= 1)則沒有效果。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"


/* 圖形的原始座標點 */
const GUI_POINT aPoints[] = {
{ 0, 20},
{ 40, 20},
{ 20, 0}
};

/* 用於儲存放大後的座標點 */
GUI_POINT aMagnifiedPoints[GUI_COUNTOF(aPoints)];

void Sample(void) {
    int Mag, y = 0, Count = 4;

    /* 清屏 */
    GUI_Clear();
    
    /* 設定前景色,即所繪製圖形的顏色 */
    GUI_SetColor(GUI_GREEN);

    for (Mag = 1; Mag <= 4; Mag *= 2, Count /= 2) {
        int i, x = 0;

        /* 放大多邊形 */
        GUI_MagnifyPolygon(aMagnifiedPoints, aPoints, GUI_COUNTOF(aPoints), Mag);

        /* 繪製填充的多邊形 */
        for (i = Count; i > 0; i--, x += 40 * Mag) {
            GUI_FillPolygon(aMagnifiedPoints, GUI_COUNTOF(aPoints), x, y);
        }

        y += 20 * Mag;
    }
}


/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {

  /* emWin初始化 */
  GUI_Init();

  /* 呼叫測試函式 */
  Sample();

  while (1)
  {
      GUI_Delay(10);
  }
}

實際顯示效果如下:

19.2.3 例子三

這個多邊形的例子是官方提供的,例子所在的位置如下:

顯示效果如下:

指出官方例子的所在位置和演示現象是為了方便使用者以後做專案來參考。

19.3 繪製圓

  • void GUI_DrawCircle(int x0, int y0, int r);

在當前視窗中的指定位置(x0, y0)繪製半徑為r的圓圈。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"

void ShowCircles(void) 
{
    int i;

    /* 繪製圓圈 */
    for (i=10; i<50; i += 3)
    GUI_DrawCircle(120, 60, i);
}

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {

  /* emWin初始化 */
  GUI_Init();

  /* 呼叫測試函式 */
  ShowCircles();

  while (1)
  {
      GUI_Delay(10);
  }
}

實際顯示效果如下:

19.4 顯示屏繪製的圓為什麼不圓

這個問題經常有初學者會問,比如這個帖子:http://bbs.armfly.com/read.php?tid=3899 。使用者在

顯示屏上面繪製圓圈,顯示出來的效果是這個樣子的:

給人的感覺是圓圈不夠圓,實際上是因為顯示屏的每個畫素點的長度和寬度不是1:1的,從而造成顯示出來的效果有點扁。

19.5 繪製橢圓

  • void GUI_DrawEllipse(int x0, int y0, int rx, int ry)

在當前視窗中的指定位置(x0,y0)繪製x軸方向半徑為rx,y軸方向半徑為ry的橢圓。

  • void GUI_FillEllipse(int x0, int y0, int rx, int ry)

在當前視窗中的指定位置(x0,y0)繪製x軸方向半徑為rx,y軸方向半徑為ry的填充的橢圓。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"


/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {

  /* emWin初始化 */
  GUI_Init();
  
  /* 繪製填充的橢圓 */
  GUI_SetColor(GUI_RED);   
  GUI_FillEllipse(100, 100, 50, 70);

  /* 繪製橢圓 */
  GUI_SetColor(GUI_GREEN);    
  GUI_DrawEllipse(100, 100, 60, 80);

   /* 繪製填充的橢圓 */
  GUI_SetColor(GUI_BLACK);    
  GUI_FillEllipse(100, 100, 10, 50);

  while (1)
  {
      GUI_Delay(10);
  }

}

實際現象效果如下:

19.6 繪製弧線

void GUI_DrawArc(int xCenter, int yCenter, int rx, int ry, int a0, int a1)

在當前視窗中的指定位置(xCenter,yCenter)繪製x軸方向半徑為rx,y軸方向半徑為ry,起始角度為a0,結束角度為a1的弧線。

注意,當前引數ry未使用,是以rx代替的,也就是說繪製的弧線是圓弧。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"
#include "math.h"
#include "stdio.h"


void DrawArcScale(void) 
{
    int x0 = 160;
    int y0 = 160;
    int i;
    char ac[4];
    
    /* 設定背景色為白色並清屏 */
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    
    /* 設定畫筆大小 */
    GUI_SetPenSize( 5 );

    /* 設定文字模式,字型和前景色 */
    GUI_SetTextMode(GUI_TM_TRANS);
    GUI_SetFont(&GUI_FontComic18B_ASCII);
    GUI_SetColor(GUI_BLACK);

    /* 繪製圓弧 */
    GUI_DrawArc( x0,y0,150, 150,-30, 210 );

    /* 在圓弧上面顯示刻度和相應刻度的數值 */
    for (i=0; i<= 23; i++) {
        float a = (-30+i*10)*3.1415926/180;
        int x = -141*cos(a)+x0;
        int y = -141*sin(a)+y0;

        if (i%2 == 0)
        GUI_SetPenSize( 5 );
        else
        GUI_SetPenSize( 4 );

        GUI_DrawPoint(x,y);
        if (i%2 == 0) {
            x = -123*cos(a)+x0;
            y = -130*sin(a)+y0;
            sprintf(ac, "%d", 10*i);
            GUI_SetTextAlign(GUI_TA_VCENTER);
            GUI_DispStringHCenterAt(ac,x,y);
        }
    }
}

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {

   /* 初始化emWin */
   GUI_Init();

   /* 繪製餅圖 */
   DrawArcScale();

   while (1)
   {
      GUI_Delay(10);
   }

}

實際顯示效果如下:

19.7 繪製曲線

void GUI_DrawGraph(I16 * paY, int NumPoints, int x0, int y0)

根據使用者設定的起始座標(x0,y0),依次將NumPoints個點座標

(x0+0, y0+*(paY +0)))

(x0+1, y0+*(paY +1)))

(x0+2, y0+*(paY +2)))

(x0+3, y0+*(paY +3)))

…………

(x0+NumPoints-2, y0+*(paY +NumPoints-2)))

(x0+NumPoints-1, y0+*(paY +NumPoints-1)))

連線起來繪製成曲線。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"
#include <stdlib.h>


I16 aY[200];

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  int i;

  /* 初始化emWin */
  GUI_Init();

  /* 獲取隨機數 */
  for (i = 0; i < GUI_COUNTOF(aY); i++) 
  {
     aY[i] = rand() % 50;
  }

  /* 繪製波形 */
  GUI_SetColor(GUI_YELLOW);
  GUI_DrawGraph(aY, GUI_COUNTOF(aY), 0, 0);

  while (1)
  {
      GUI_Delay(10);
  }

}

實際顯示效果如下:

19.8 繪製餅圖

void GUI_DrawPie(int x0, int y0, int r, int a0, int a1, int Type)

繪製圓形扇區。

在當前視窗中的指定位置(x0,y0)繪製以r為半徑,起始角度為a0,結束角度為a1的圓形扇區。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"


/* 變數 */
int i, a0, a1;
const unsigned aValues[] = { 100, 135, 190, 240, 340, 360};
const GUI_COLOR aColors[] = { GUI_BLUE, GUI_GREEN, GUI_RED,
                              GUI_CYAN, GUI_MAGENTA, GUI_YELLOW };


/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  int i;

  /* 初始化emWin */
  GUI_Init();

  /* 繪製餅圖 */
  for (i = 0; i < GUI_COUNTOF(aValues); i++) {
     a0 = (i == 0) ?0 :aValues[i - 1];
     a1 = aValues[i];
     GUI_SetColor(aColors[i]);
     GUI_DrawPie(100, 100, 50, a0, a1, 0);
  }

  while (1)
  {
      GUI_Delay(10);
  }

}

實際顯示效果如下:

19.9 繪製二維碼

GUI_HMEM GUI_QR_Create(const char * pText,

int PixelSize,

int EccLevel,

int Version);

  • 第1個引數是要顯示二維碼的字元,注意要是UTF-8編碼格式,漢字也支援。
  • 第2個引數是二維碼中單位點陣大小。
  • 第3個引數是ECC糾錯,支援的引數如下:

GUI_QR_ECLEVEL_L 大約 7% 的錯誤被糾正。

GUI_QR_ECLEVEL_M 大約15% 的錯誤被糾正。

GUI_QR_ECLEVEL_Q 大約25% 的錯誤被糾正。

GUI_QR_ECLEVEL_H 大約30% 的錯誤被糾正。

  • 第4個引數是二維碼一個畫素模組需要的大小,範圍1-40。如果設定為0的話,會自動計算。

下面是在模擬器上面實際執行的例子:

#include "GUI.h"


/*********************************************************************
*
*       MainTask
*/
void MainTask(void)
{
    GUI_HMEM hMem, hMem1, hMem2;
    GUI_Init();

    GUI_SetBkColor(GUI_BLUE);
    GUI_Clear();

    GUI_SetColor(GUI_WHITE);
    GUI_SetFont(&GUI_Font16_1);
    GUI_DispStringAt("http://www.armfly.com/", 2, 5);
    hMem = GUI_QR_Create("http://www.armfly.com/", 7, GUI_QR_ECLEVEL_L, 0);
    GUI_QR_Draw(hMem, 2, 30);

    GUI_DispStringAt("http://www.armbbs.cn/", 190, 5);
    hMem1 = GUI_QR_Create("http://www.armbbs.cn/", 5, GUI_QR_ECLEVEL_L, 0);
    GUI_QR_Draw(hMem1, 190, 30);

    GUI_DispStringAt("https://www.segger.com/", 330, 5);
    hMem2 = GUI_QR_Create("https://www.segger.com/", 3, GUI_QR_ECLEVEL_L, 0);
    GUI_QR_Draw(hMem2, 330, 30);

    while (1)
    {
        GUI_Delay(10);
    }
}

實際顯示效果如下:

19.10 繪製條形碼

int GUI_BARCODE_Draw( int xPos,

int yPos,

int ModuleSize,

int ySize,

int Type,

const char * sBarcode);

  • 第1個引數是條形碼x座標位置。
  • 第2個引數是條形碼y座標位置。
  • 第3個引數是繪製條形碼豎條時,最小的寬度。
  • 第4個引數是條形碼高度,高度至少要是第3個引數的3倍。
  • 第5個引數是條形碼型別,支援兩種型別

GUI_BARCODE_ITF 可以展示偶數個數字。

GUI_BARCODE_128 可以展示所有128個字元。

  • 第6個引數是要展示的內容

下面是在模擬器上面實際執行的例子:

#include "GUI.h"



/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  int i;

  /* 初始化emWin */
  GUI_Init();

  /* 繪製條形碼 */
  GUI_SetColor(GUI_BLACK);
GUI_SetBkColor(GUI_WHITE);
GUI_BARCODE_Draw(0, 0, 3, 60, GUI_BARCODE_ITF, "123456789");
GUI_BARCODE_Draw(0, 0, 2, 60, GUI_BARCODE_128, "armfly");

  while (1)
  {
      GUI_Delay(10);
  }

}

實際顯示效果如下:

19.11 總結

關於2D圖形庫的繪圖部分就跟大家講這麼多,還是那句話,多多練習,熟能生巧。