How to draw a grid of lines without using lv_chart

Description

I’m using a canvas (lv_canvas_create) so I can draw pixels to a canvas. It uses a static buffer to store the pixels. This way I can draw traces in real-time. I tried lv_chart but it updated way to slow. This works great in terms of update speed. I draw multiple traces at once. But, how can i draw a grid? I tried lv_line, but i didn’t manage to draw a grid with it. I used rectangle objects with a with of 0 for vertical lines and a height of 0 for vertical lines of the grid. That works as expected, but then always their will be a ‘crash’ (program doesn’t reacts anymore) when the mouse clicks some other lvgl object, like a drop down or so. That problem disappears when I only draw verticals or only horizontals. So, apparently, it only crashes when the rectangles (used as lines) cross.

The only way that I managed to draw the grid was by using the pixel method to draw the grid lines too. But then, the traces will ‘paint through’ these lines as well. So, after some time, the grid lines get ‘eaten up’.

How should I proceed? What is the best way to tackle this problem?

What platform are you using

Code is running on both linux and Windows using SDL2

What LVGL version are you using?

9.3.0

What do you want to achieve?

Draw a grid (lines, like divisions) and draw real time traces that don’t interfere with the grid lines while not using lv_chart

What have you tried so far?

a) Drawing everything on a canvas, b) drawing lines with lv_line and c) using a object to draw a rectangles with 0 width or height to simulate a horizontal and vertical line.

Code to reproduce

A code snipped:

void View::drawRectangle(lv_obj_t *canvas, int32_t x, int32_t y, int32_t width, int32_t height, lv_color_t color)
{
  lv_obj_t * rect1 = lv_obj_create(canvas);
  lv_obj_add_style(rect1, &style_views_rectangle, LV_STATE_DEFAULT | LV_PART_MAIN);
  lv_obj_set_pos(rect1, x, y);
  lv_obj_set_size(rect1, width, height);
  lv_obj_set_style_border_color(rect1, color, LV_STATE_DEFAULT | LV_PART_MAIN);
}

void View::drawGrid(lv_obj_t *canvas, int32_t x, int32_t y, int32_t width, int32_t height, lv_color_t color)
{
	float dx;
	float dy;
	int32_t i_x;
	int32_t i_y;

 	for (int32_t i = 0; i < NUMBER_OF_DIVISIONS; i++)
	{
		// Vertical lines
		dx = (float)width / (float)10;
		i_x = round(dx * i);
		drawRectangle(canvas, x + i_x, y, 1, height, color);

		// Horizontal lines
		dy = (float)height / (float)10;
		i_y = round(dy * i);
		drawRectangle(canvas, x, y + i_y, width, 1, color);
	}
}

I can add that all the code is executed from the same thread. I’m still in the dark what is happening. Also, drawing overlapping objects shouldn’t a problem? Am I right?

Found it after enabling logging. It said:

[Error] (17.661, +17661) lv_realloc: couldn’t reallocate memory lv_mem.c:153
[Error] (17.661, +0) lv_obj_add_style: Asserted at expression: obj->styles != NULL (Out of memory) lv_obj_style.c:127

So, I doubled the LV_MEM_SIZE from 64 to 128 * 1024. I also added a heap monitor to get some idea how much memory is used. After creating a 128 kb heap, it reports:

11:29:00 INFO …\src\Shared\mon_system.cpp:71: Heap: total: 89648, free: 43784, max: 64624, used: 52%

I’m only wondering if needing more then the ‘standard’ 64 Kb is normal or if I’m doing something wrong anyway. I’m using about 100 lv_obj_t objects.

Hey Peter,

100 objects is quite a lot.
Is there a reason you do not want to use the chart? It is pretty good at drawing those lines just for background purposes.

I read a lot in the forum from people that need real-time updates of high frequency data. And I learned that the lv_chart is not really designed for that. So, I never used it. But I’m happy with drawing on a canvas and using the lvgl functions to implement a proper GUI. It all works fine now I allocated enough memory for the heap.

I meant to say that you could use the chart widget for background purposes only, then draw the pixels on top with the canvas.

Ah, I understand. I must give that a thought. Thanks for the suggestion!