TouchGFX使用教程(五)


Graph控件是用於實現圖表以及需要繪製圖像的控件,該控件在TouchGFX Designer中沒有體現,但是可以在工程中自行添加,TouchGFX官方給的Demo中有針對於該部分的Demo,這些Demo可以給大家些幫助,下面針對於該控件給大家詳細的介紹下。

CanvasWidget

Canvas Widgets和Canvas Widget Renderer是TouchGFX的功能強大且用途廣泛的附加組件,它使用相對較少的內存就可以提供流暢,抗鋸齒的幾何形狀圖形,同時保持了高性能。但是,渲染幾何形狀必須被視爲相當昂貴的操作,並且如果不小心使用,很容易使微控制器資源緊張。

Canvas Widget Renderer(以下稱爲CWR)是一種通用的圖形API,可爲圖元提供優化的圖形,並自動消除大多數多餘的圖形。TouchGFX使用CWR繪製複雜的幾何形狀。幾何形狀由“畫布小部件”定義。TouchGFX隨附了許多受支持的Canvas Widget,但就像普通的Widget一樣,您可以製作自己的自定義Canvas Widget來滿足您的需求。當Canvas Widget定義要由CWR繪製的圖形的幾何形狀時,圖形內每個像素的實際顏色由關聯的Painter類定義。同樣,TouchGFX附帶了許多Painter,但是您可以根據自己的需要製作自己的自定義Painter。

TouchGFX中的其他小部件的大小會自動設置。例如,位圖小部件將自動獲取所包含位圖的寬度和高度。因此,足以setXY()在位圖小部件上使用以將位圖放置在顯示器上。
畫布小部件沒有默認大小,該默認大小可以自動確定並進行初始設置。必須不僅要注意位置,而且還要正確調整窗口小部件的大小,否則“畫布”窗口小部件的寬度和高度將爲零,並且在顯示器上不會繪製任何內容。

因此,不要setXY()使用setPosition()來放置和調整畫布小部件的大小,而要使用。另請參閱下面的“自定義畫布小部件”,以獲取有關如何創建和使用自定義畫布小部件的示例。

設置畫布小部件的位置和大小後,便可以在其中繪製幾何形狀。座標系將在小部件(而不是顯示)的左上角具有(0,0),X軸向右延伸,Y軸向下延伸。

Canvas窗口小部件在TouchGFX Designer中也受支持,它使用法簡單並具有自動內存分配功能。

CanvasWidget內存分配

TouchGFX Designer中的內存分配

將小部件添加到屏幕的畫布時,會自動生成一個內存緩衝區。緩衝區的大小基於具有以下公式的屏幕寬度(Width × 3)× 5。但是,這並非總是適用於所有情況的理想緩衝區大小。因此,可以覆蓋緩衝區大小,如下圖所示。
在這裏插入圖片描述

用戶代碼中的內存分配

內存可被分配和設置在target/main.cpp與simulator/main.cpp或可以設置和每畫面分配。

static const uint16_t CANVAS_BUFFER_SIZE = 3600;
static uint8_t canvasBuffer[CANVAS_BUFFER_SIZE]

定義內存緩衝區大小的靜態const,可以在main.cpp或的開頭定義實際的內存緩衝區ScreenView.hpp
然後,在任一main()的方法main.cpp或setupScreen()方法ScreenView.cpp中的以下行建立緩衝區可以被添加。

CanvasWidgetRenderer :: setupBuffer (canvasBuffer ,CANVAS_BUFFER_SIZE );

所需的CWR內存量取決於應用程序中要繪製的形狀的最大大小。但是,您可以保留少於最大形狀所需的內存。爲了處理這種情況,CWR將形狀的圖紙分成較小的幀緩衝區部分,從而導致稍長的渲染時間,因爲在這種情況下,有時不得不多次渲染形狀。在模擬器模式下運行時,可以更仔細地調查和微調內存消耗。只需將以下函數調用添加到main.cpp中:

CanvasWidgetRenderer :: setWriteMemoryUsageReport (true );

現在,每當繪製操作完成時,CWR都會報告(在控制檯中打印)需要多少內存。對於canvas_widget_example,它可能是“ CWR需要3604字節”(對於第一次繪製操作),然後是“ CWR需要7932字節(缺少4328個字節)”(對於第二次繪製操作)。即使CWR似乎沒有足夠的內存(在這種情況下,缺少4328字節),應用程序也可以正常運行。這是因爲CWR檢測到可用內存太少,無法在一次運行中完成複雜的繪製操作。取而代之的是,它將繪製操作分爲兩個單獨的繪製操作,形狀將被繪製得很好,但需要更多時間進行渲染。

因此,設置正確的內存緩衝區大小需要在內存和性能(渲染時間)之間進行權衡。好的起始值通常約爲3000,但是使用上述技術,通常可以確定更好的值。如果形狀太複雜而分配的內存緩衝區太小,則將不會繪製形狀的一部分(某些垂直像素線將被跳過),並且有可能根本沒有繪製。無論如何,渲染時間都會增加很多。

這意味着,如果您希望您的應用程序以最快的速度渲染CWR圖形,則需要分配請求的內存量。但是,如果可以使用較慢的渲染計時器,則可以減少內存緩衝區。

CWR座標系

TouchGFX中的座標系通常用於尋址像素,以在顯示器上定位位圖。位圖,文本和其他圖形元素都放置在座標系中,其中(0,0)是左上像素,x軸向右延伸,y軸向下延伸。在CWR中,僅能夠使用整數尋址像素是不夠的,儘管在特殊情況下這可能就足夠了,但通常這還遠遠不夠。爲了說明這一點,請考慮一個線寬爲1的圓,它必須恰好適合5 x 5像素的框。該圓的中心必須位於(2.5,2.5),半徑必須爲2,因此中心座標需要分數。同樣,如果圓應適合於6 x 6像素的框,則中心必須位於(3,3),半徑必須爲2.5,因此此處半徑必須爲分數。

這種尋址圖形座標的新方法意味着(0,0)的像素中心具有CWR座標(0.5,0.5)。因此,包含在屏幕左上角像素的框具有以下輪廓:(0,0)->(1,0)->(1,1)->(0,1)->(0 ,0)。
在這裏插入圖片描述
儘管起初看起來似乎很混亂,但很快就變得很自然。當位圖的座標系統處理像素時,畫布小部件的相同座標處理像素之前和上方的間隙。

點、線、面

當創建完畫圖的畫板後就可在其中創建圖像, TouchGFX的圖像不支持線性的曲率變化,換句話說就是隻能通過點去鏈接線,但是如何能做到曲率的線呢,這時我們可以通過貝塞爾算法,或者其他的曲率算法推算出每一個點的座標,或者是相隔固定點的座標,之後在界面上顯示出來。
官方提供了兩個demo 分別是TouchGFX Demo1 和TouchGFX Demo2,兩個demo中都有graph繪製方法的體現,但體現的方法不同,對用CanvasWidget繼承程度也不盡相同。
這裏我們講解個內容比較多的TouchGFX Demo1,我會在下一節提出代碼。

Demo

首先先看一下該部分代碼的調用的方法。

    primaryGraph.setXY(graphXOffset, graphYOffset);
    primaryGraph.setup(graphWidth, graphHeight, Color::getColorFrom24BitRGB(0x24, 0x73, 0xAC), graphBackground.getColor());
    primaryGraph.setDotShape(0, 30, 5);//設置折線上點的參數
    primaryGraph.setDotBackgroundShape(0, 30, 7);//設置折線上點的背景參數
    graphArea.add(primaryGraph);

在此可以看出graph作爲一個控件調用方法是一致的,都是先設置x,y的位置,也需要設置畫布的寬高,以及轉向點或者其他的設置。
這裏唯一的不一樣的地方是setup()函數,這個函數中除了寬高外還有顏色,顏色的含義則是畫筆的顏色,想要作畫除了畫布同樣還需要畫筆。至於化成什麼樣子則是我們掌握的,下面看下setup函數。

void Graph::setup(int newWidth, int newHeight, colortype lineColor, colortype backgroundColor)
{
    setWidth(newWidth);
    setHeight(newHeight);

    graphLinePainter.setColor(lineColor);
    graphAreaPainter.setColor(lineColor, 255);
    graphDotsPainter.setColor(lineColor);
    graphDotsBackgroundPainter.setColor(backgroundColor);

    graphLine.setLinkedGraph(graphArea);
    graphLine.setLinkedGraph(graphDots);
    graphLine.setLinkedGraph(graphDotsBackground);

    graphLine.setPosition(0, 0, getWidth(), getHeight());
    graphLine.setPainter(graphLinePainter);
    graphLine.setBuffer(graphBuffer, NUMBER_OF_POINTS);
    graphLine.setLineWidth(1);
    graphLine.setRange(-2, 216, 400, 0);

    graphArea.setPainter(graphAreaPainter);
    graphArea.setLineWidth(0);

    graphDots.setPainter(graphDotsPainter);
    graphDots.setLineWidth(7);
    graphDots.setDotShape(0, 90);

    graphDotsBackground.setPainter(graphDotsBackgroundPainter);
    graphDotsBackground.setLineWidth(9);
    graphDots.setDotShape(0, 30);

    add(graphArea);
    add(graphLine);
    add(graphDotsBackground);
    add(graphDots);
}

可以看出,整體採用的畫筆以及將其畫布放置在一起的過程。
除此之外還有些細節的這裏不將展示。需要可以參考官方的代碼,我將具體的部分放到這裏供大家快速定位。
在這裏插入圖片描述
GraphView.cpp中放的是使用方法,文件夾graph_widget文件夾中放的是控件的源碼,大家可以根據需要自己研究下該控件。

注意

本人在開發該部分控件時,會彈出buffer空間不足的提示框,原因則是在新建的工程中未添加畫布空間的buffer,所以纔會報錯,具體請參照本章內容。

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