If you have ever had to create a program that uses lots of buttons, you know what a pain it can be to have to create, style, and position each one. That is why button matrixes were created.
The button matrix groups all the buttons together. This makes it easy to apply styles to the entire group and means it takes less memory to create and use the buttons.
Today, I will show you how to create and edit your own button matrix. We will do that by walking through some example code, which creates a button matrix for a simple calculator.
The Screen
To get the code to work with your screen, you will need to add your screen setup code to the beginning of it. If you want more information, you can try How to get a LVGL Micropython screen to work.
Here is the code
import lvgl
matrix = lvgl.btnmatrix(lvgl.scr_act())
MAP = ['7','8','9','+','\n',
'4','5','6','-','\n',
'1','2','3','=','\n',
'0',lvgl.SYMBOL.REFRESH,
None]
matrix.set_map(MAP)
matrix.set_btn_width(12,3)
matrix.set_btn_width(13,1)
matrix.set_size(320,150)
matrix.align(lvgl.ALIGN.BOTTOM_MID,0,0)
matrix.set_btn_ctrl(3,lvgl.btnmatrix.CTRL.CHECKABLE)
matrix.set_btn_ctrl(7,lvgl.btnmatrix.CTRL.CHECKABLE)
matrix.set_btn_ctrl(11,lvgl.btnmatrix.CTRL.CHECKABLE)
matrix.set_one_checked(True)
label = lvgl.label(lvgl.scr_act())
label.align(lvgl.ALIGN.TOP_MID,0,20)
label.set_text('')
def update_button(data):
btn_matx = data.get_target()
btn_id = btn_matx.get_selected_btn()
btn_text = btn_matx.get_btn_text(btn_id)
if btn_text == lvgl.SYMBOL.REFRESH:
label.set_text('')
elif btn_text == '=':
try:
label.set_text(str(eval(label.get_text())))
except:
pass
else:
label.set_text(label.get_text() + btn_text)
matrix.add_event_cb(update_button,lvgl.EVENT.VALUE_CHANGED,None)
Understanding the Code
Now that you have seen the code, lets walk through it to figure out how it works.
The Setup
To begin, we need to import the LVGL module. Around here is a good place to put your screen setup code.
import lvgl
Creating the Button Matrix
We will start by creating an empty button matrix.
matrix = lvgl.btnmatrix(lvgl.scr_act())
Next ,we will create a list of names for the buttons in our button matrix.
MAP = ['7','8','9','+','\n',
'4','5','6','-','\n',
'1','2','3','=','\n',
'0',lvgl.SYMBOL.REFRESH,
None]
How the List Works
For the most part the list above is just a bunch of text, but there are three special types of items in the list.
First there is the text ‘\n’, whenever a button matrix sees this it starts a new row of buttons. Without this command all the buttons in a button matrix would be squeezed into one row.
Secondly, there is the code lvgl.SYMBOL.REFRESH. A buttons label can be any kind of string. LVGL considers words and numbers as strings but it also considers symbols as strings. lvgl.SYMBOL.REFRESH is one of the special symbols available to LVGL.
Thirdly, The None at the end of the list is part of the background code. I will not bore you with why it’s there, but you should always put a None at the end of you list of buttons.
Now that we have created our list of button labels, we need to add it to the button matrix.
matrix.set_map(MAP)
The last row has only two buttons in it: ‘0’ and REFRESH SYMBOL. Normally the buttons would be the same size, but for this example we want the the 0 button to be three times bigger that the REFRESH button.
First we tell the matrix that button 12,the zero button, should have a relative size of three.
matrix.set_btn_width(12,3)
Then we tell the matrix that button 13,the REFRESH button, should have a relative size of one. Because both buttons are in the same row that makes the zero button three times bigger than the REFRESH button.
matrix.set_btn_width(13,1)
We are also going to set the size of the the button matrix and align it to the bottom of the screen to make it look nicer.
matrix.set_size(320,150)
matrix.align(lvgl.ALIGN.BOTTOM_MID,0,0)
Next we want the ‘+’, ‘-‘, and ‘=’ buttons to be checkable. If you tap a checkable button it turns on and if tap it again, it will turn of. So we set the the ctrl checkable on each of those buttons.
matrix.set_btn_ctrl(3,lvgl.btnmatrix.CTRL.CHECKABLE)
matrix.set_btn_ctrl(7,lvgl.btnmatrix.CTRL.CHECKABLE)
matrix.set_btn_ctrl(11,lvgl.btnmatrix.CTRL.CHECKABLE)
Then we will turn one_check on. The feature just makes sure that only one button can be checked at the same time.
matrix.set_one_checked(True)
The Label
We are going to create a label that will display the buttons we have pressed. To start we create an empty label object.
label = lvgl.label(lvgl.scr_act())
Then we align it to the middle of the top of the screen.
label.align(lvgl.ALIGN.TOP_MID,0,20)
Then we will set the text so the default is blank.
label.set_text('')
The LVGL Event Handler
Event handlers are functions that are run when ever something important happens. We need to create one that runs when the button matrix is clicked.
To begin we create a new function.
def update_button(data):
After that we get the object that called this function.
btn_matx = data.get_target()
Then we use that object to figure out what button was pressed.
btn_id = btn_matx.get_selected_btn()
The computer gave us the id of the button pressed but the actual text of the button is more useful so we will retrieve that to.
btn_text = btn_matx.get_btn_text(btn_id)
Next we use a IF statement to process which button was pressed. We start by checking if the button is the refresh button.
if btn_text == lvgl.SYMBOL.REFRESH:
If it was we delete all the text from the label we made earlier.
label.set_text('')
Then we check if the button was the ‘=’ button.
elif btn_text == '=':
If it was we then get the label’s text (it is supposed to contain a math equation) and try to calculate the result. After that we set the label’s text to the result.
We do all this in try except blocks so that any errors that occurs in the calculation don’t crash the hole program.
try:
label.set_text(str(eval(label.get_text())))
except:
pass
Lastly if the button pressed was not any of the previous buttons, we add the button’s text the the label.
else:
label.set_text(label.get_text() + btn_text)
Connecting the Handler
The only thing left to do is connect the function, we just made, to the button matrix. We will connect them so whenever a button is pressed(value changed) it calls our function.
matrix.add_event_cb(update_button,lvgl.EVENT.VALUE_CHANGED,None)
What It Outputs
Once you run the code, you should see a number keyboard. If you hit any of the numbers, the +, or the – buttons, the symbol you pressed will be added to a label above the keyboard. If you click the equal button, It will try to calculate the equation in the label and put the result back into the label.
Button matrixes are great if you need lots of buttons but don’t have lots of memory on your board. They also allow you to style all the buttons at once.
Button matrixes are so often used to create keyboards, that LVGL has a widget called the keyboard that is just a button matrix with some settings changed. If you want you can learn more about keyboards at Micropython LVGL Keyboard Examples.