Adding user data to windows

From SEGGER Wiki
Revision as of 11:55, 27 April 2020 by Florian (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The following tutorial explains how user data can be set for windows and widgets in emWin. User data are additional bytes that are allocated upon creation of a window or widget. They allow the user to store additional data that is associated with the window. The user data is typically processed by the window.

Button increasing a counter. The child window has access to the counter variable.

Objective of this tutorial

This tutorial gives an in-depth description on how user data can be set for windows and widgets in emWin and how this data can be used. The goal is an application that consists of a parent window, that has a BUTTON widget and another window as child windows. When the button is clicked, a counter variable located in the parent window is incremented. A pointer to the counter variable has been passed to the child window, so that both the parent and the child window will be able to display the counter value.

Tutorial

Prerequirements

Before the step of adding user data is done, we set up the base structure of our application. For that we need a MainTask() that creates the parent window, and the callback routines for the parent and child window. The counter variable is located in the parent window callback and is increased upon a button click.

#include "DIALOG.h"
#include <stdio.h>

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _cbChild
*/
static void _cbChild(WM_MESSAGE * pMsg) {
  char acBuffer[64];
  
  switch(pMsg->MsgId) {
  case WM_PAINT:
    GUI_SetBkColor(GUI_RED);
    GUI_Clear();
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbParent
*/
static void _cbParent(WM_MESSAGE * pMsg) {
  static int       Counter;
  static WM_HWIN   hChild;
  WM_HWIN          hItem;
  int              Id, NCode;
  char             acBuffer[64];

  switch(pMsg->MsgId) {
  case WM_CREATE:
    hItem = BUTTON_CreateEx(10, 30, 100, 20, pMsg->hWin, WM_CF_SHOW, 0, GUI_ID_BUTTON0);
    BUTTON_SetText(hItem, "Increase Counter");
    //
    // Create child window with the size of an int pointer as extra bytes.
    //
    hChild = WM_CreateWindowAsChild(10, 70, 150, 100, pMsg->hWin, WM_CF_SHOW, _cbChild, 0);
    break;
  case WM_PAINT:
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    //
    // Display counter.
    //
    GUI_SetColor(GUI_BLACK);
    GUI_SetFont(&GUI_Font16B_1);
    sprintf(acBuffer, "Counter: %d", Counter);
    GUI_DispStringAt(acBuffer, 10, 10);
    break;
  case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);
    NCode = pMsg->Data.v;
    switch(Id) {
    case GUI_ID_BUTTON0:
      switch(NCode) {
      case WM_NOTIFICATION_RELEASED:
        //
        // Increase counter when button is pressed and redraw window.
        //
        Counter++;
        WM_InvalidateWindow(pMsg->hWin);
        //
        // Also redraw the child window.
        //
        WM_InvalidateWindow(hChild);
        break;
      }
      break;
    }
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  GUI_Init();
  //
  // Create parent window.
  //
  WM_CreateWindow(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_CF_SHOW, _cbParent, 0);

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

Add user data to window

To add user data to the child window, we need to set a number of bytes that will be allocated upon the window's creation. Therefore, we edit the last parameter of WM_CreateWindowAsChild() to the size of a pointer to an integer.

//
// Create child window with the size of an int pointer as extra bytes.
//
hChild = WM_CreateWindowAsChild(10, 70, 150, 100, pMsg->hWin, WM_CF_SHOW, _cbChild, sizeof(int *));

Next, we add a static int pointer variable.

static int * pCounter;

Right after creating the child window, we use this pointer to store the address of the counter.

//
// Save the address of the counter in a pointer variable.
//
pCounter = &Counter;

Once we prepared the user data we want to attach to the window, we can add the data using WM_SetUserData(). We pass the handle of the target window as first parameter, which is the child window. Secondly, the address of the pointer is given and lastly, the byte size of the pointer variable.

//
// Set the user data to child window.
// The address of the pointer is the source of the user data.
//
WM_SetUserData(hChild, &pCounter, sizeof(int *));

Retrieve user data

To retrieve user data, we need to react on a WM_USER_DATA message in the window that received user data. Therefore, we add the code below to the _cbChild() callback.

case WM_USER_DATA:
  //
  // Get user data of this window and save it at the address of our pointer.
  //
  WM_GetUserData(pMsg->hWin, &pCounter, sizeof(int *));
  break;

We use the routine WM_GetUserData() to receive user data from the window. Again, we need to define a static int pointer to save the user data in that variable.

static int * pCounter;

Once the user data is retrieved, we can process it in the WM_PAINT case of the window. A buffer for output of the counter value also needs to be added.

char acBuffer[64];
...
//
// Check if pointer is valid.
//
if (pCounter) {
  GUI_SetColor(GUI_WHITE);
  sprintf(acBuffer, "Counter: %d", *pCounter);
  GUI_DispStringAt(acBuffer, 10, 10);
}

If we now run our application, the behavior is just as described in the introduction.

User data for widgets

The procedure of adding user data to widgets is exactly the same as described above. Alternatively to WM_SetUserData()/WM_GetUserData(), the equivalent of the corresponding widget can be called (<WIDGET>_SetUserData()), such as BUTTON_SetUserData().

Downloads

You can download the source code of this example here.