GEOS-SC : Flex UI : Sections : How To Detect User Interaction

Introduction | Terminology | How To Write An Application | How To Detect User Interaction | How To Bring Everything Together


Most of the work done by applications is handled by Flex UI components and EventListeners. Each Flex UI object can use a corresponding EventListener to check for user interaction with that object. When a component registers an event, the EventListener will call its appropriate EventHandler to execute the appropriate response.

For example, an address book application may consist of a FlexTable to display an entry, a FlexList to display the stored names, and a FlexButton to dial the current entry.

Since each of these objects have EventListeners that check for events, the code to handle each event resides in the respective EventHandlers:

This example will create a notepad application that allows the user to input text and either: clear the text, save the text, or revert back to the previously saved text, by using the following Flex UI components:

To write a notepad application that clears, saves, and reverts text:

  1. Declare the class NotepadApp in the header file and add ActionPerformed().
  2. Register the application and build the user interface.
  3. Create a FlexHoriztonalPanel to hold the buttons.
  4. Attach a FlexTextArea to the frame.
  5. Add the helper function CreateButton() to generate the buttons in the application.
  6. Add the EventHandler ActionPerformed() to handle any button presses in the application.
  7. Add the code to save the file in ActionPerformed().
  8. Add the code to revert the file in ActionPerformed().
  9. Compile and run the application.


Declare the class NotepadApp in the header file and add the EventHandler ActionPerformed(). (resource | header | source)


class NotepadApp : public ActionListenerInterface, public AppBase {
public:

...

    // Override ActionPerformed to intercept button presses
    virtual void ActionPerformed(ActionEvent& event);    

...
    // Enumerate our buttons to tell them apart.
    enum {
        NOTEPADAPP_CLEAR_BUTTON         = 0,
        NOTEPADAPP_SAVE_BUTTON          = 1,
        NOTEPADAPP_REVERT_BUTTON        = 2,

        ...
    };
};

Since the application uses an EventListener to monitor the New, Save, and Revert buttons, add the class ActionListenerInterface to the list of base classes. An ActionListener is an EventListener that listens for button events.

ActionPerformed() is the EventHandler method that controls what happens when a button is pressed.

Enumerate FlexComponentID values corresponding to buttons created later; use these values to identify the buttons.


Register the application and build the user interface in the source file. (resource | header | source)


// Register the application.
class NotepadResidentApplication : public ResidentApplication 
{
 public:
    NotepadAppResidentApplication() : ResidentApplication(NOTEPADAPP_NAME) 
    {};
    virtual AppBase *CreateAppBase(void) 
    {
        return new NotepadApp;
    }
};
static NotepadAppResidentApplication notepadApp;

// Specify the name of the application.
static AppNameAttribute notepadAppName(¬epadApp, NOTEPADAPP_APP_TEXT);

// Call the constructor to initialize our variables.
NotepadApp::NotepadApp() : _notepadAppMainFrame(NULL),
                           _notepadAppButtonPanel(NULL),
                           _notepadAppTextDisplay(NULL),
                           _notepadAppUIBuilt(FALSE)  
{
}

// Build the application.
void
NotepadApp::SetAppContext(const TCHAR *context)
{
    // Call the helper function to build the UI.
    if (!_notepadAppUIBuilt) {
        if (AttachNotepadAppUI() == FAILURE) { 
            EC_WARN("Unable to build application."); 
            Exit();
        } else {
            _notepadAppUIBuilt = TRUE;
        }
    }
    // Pass context to the USE_IT macro to suppress compiler warnings.
    USE_IT(context);
}

Return a result in the helper function AttachNotepadAppUI() to make sure that the user interface was built successfully. The system will notify the programmer if it is unable to create the components of the user interface.


Create a FlexHorizontalPanel to hold the buttons for the application. (resource | header | source)


    // Create a panel to hold the buttons for the application
    // and attempt to add it.
    _notepadAppButtonPanel = 
        theUIFactory->CreateFlexHorizontalPanel(0,
                                                NOTEPADAPP_BUTTON_PANEL_GAP);
    if (NULL == _notepadAppButtonPanel) { 
        EC_WARN("Unable to build the button panel.");
        return FAILURE; 
    }
    if (_notepadAppMainFrame->Add(_notepadAppButtonPanel) != SUCCESS) {
        EC_WARN("Unable to add the button panel.");
        delete _notepadAppButtonPanel;
        return FAILURE;
    }


Use a FlexHorizontalPanel to group components of the user interface that need to be organized independently of the rest of the application. Since a FlexHorizontalPanel is created by theUIFactory it will be deleted when the application exits.


Add a FlexTextArea to allow user input. (resource | header | source)

    
    // Create the text display and attempt to add it to the application.
    _notepadAppTextDisplay = theUIFactory->CreateFlexTextArea(0);
    if (NULL == _notepadAppTextDisplay) { 
        EC_WARN("Unable to create text display.");
        return FAILURE; 
    }
    if (_notepadAppMainFrame->Add(_notepadAppTextDisplay) != SUCCESS) {
        EC_WARN("Unable to add the text display.");
        delete _notepadAppTextDisplay;
        return FAILURE;
    }


    // Set the attributes of the text display.
    _notepadAppTextDisplay->SetColumns(75);
    _notepadAppTextDisplay->SetRows(7);  
    _notepadAppTextDisplay->SetMaxChars(600);

}

It is important to set the maximum number of characters of the text display to ensure that the buffer will not be overrun later in the application.


Add the method CreateButton() to create buttons for the application. (resource | header | source)


Result
NotepadApp::CreateButton(const TCHAR *title, FlexComponentID buttonID)
{
    // Create a button and attempt to add it to the application.
    FlexButton *button = 
	theUIFactory->CreateFlexButton(0, title);
    if (NULL == button) { 
        EC_WARN("Unable to create a button.");
        return FAILURE; 
    }
    if (_notepadAppButtonPanel->Add(button) != SUCCESS) {
        EC_WARN("Unable to add a button.");
        delete button;
        return FAILURE;
    }

    // Make the application an action listener.
    if (button->AddActionListener(*this) != SUCCESS) {
        EC_WARN("Unable to add action listener.");
        return FAILURE;
    }

    // Set the id for the button and return SUCCESS.
    button->SetID(buttonID);
    return SUCCESS;
}

The helper function CreateButton() creates buttons for the user interface and returns a result, either SUCCESS or FAILURE. Use this helper function to create buttons to save repeating code, but keep track of each button as it is added. This example uses the buttonID enumerations stored in the header file to keep track of the created buttons.

The method AddActionListener() adds the button to the list of objects that the ActionListener monitors.


Add the method ActionPerformed() to handle button events. (resource | header | source)


void
NotepadApp::ActionPerformed(ActionEvent& event )
{
    // Create a file pointer for SAVE and REVERT, as well as a buffer for
    // the text string and an integer to keep track of the buffer size.
    File  *myFile = NULL;       
    TCHAR *textBuffer = NULL;
    int32 bufferSize = 0;

    // Get the ID of the button that called this function.
    FlexComponentID id = (event.GetSource())->GetID();
    switch(id) {

    // Check if CLEAR was clicked.
    case NOTEPADAPP_CLEAR_BUTTON: 
       _notepadAppTextDisplay->SetText(_TEXT(""));
       break;


Since the ActionPerformed() method handles all button events, use the method GetID() to get the ID for the button that generated the event. Use this ID to determine which object called ActionPerformed().

If the user pressed the New button use the method SetText() to clear all the text.


In the method ActionPreformed(), add code to save the file. (resource | header | source)


    case NOTEPADAPP_SAVE_BUTTON:
        
       // Set the size of the buffer to read.
       bufferSize = (_notepadAppTextDisplay->GetCharCount() + 1) * sizeof(TCHAR);;
       textBuffer = new TCHAR[bufferSize];

       // Get the contents of the buffer.
       _notepadAppTextDisplay->GetText(textBuffer, bufferSize);
		
       // Open the file CREATE and READ_WRITE.
       myFile = theFileStoreManager.Open(_TEXT("/int/tempfile"), 
                                         O_CREAT | O_RDWR );

       if (myFile != NULL) {
           // Write the contents of the buffer to the file.
           myFile->Write((uint8*)textBuffer, bufferSize);
           myFile->SetSize(bufferSize);
       } else {
           _notepadAppTextDisplay->SetText(NOTEPADAPP_ERROR);
       }           
       // Clean up.
       myFile->Close();
       delete [] textBuffer;
       myFile = NULL;
       break;

If the user pressed the Save button, save the buffer to a file. Be sure to close the file after writing to it.


In the method ActionPreformed(), add code to revert the file. (resource | header | source)


    case NOTEPADAPP_REVERT_BUTTON:
       // Open the file READ_ONLY and read the contents into the buffer.
       // Copy the contents of the buffer into the text area and close 
       // the file when done.
       myFile = theFileStoreManager.Open(_TEXT("/int/tempfile"), 
                                             O_RDONLY );
       if (myFile != NULL) {
           myFile->GetSize(&bufferSize);
           textBuffer = new TCHAR[bufferSize];

           if ((myFile->Read((uint8*)textBuffer, bufferSize) == bufferSize)){
               _notepadAppTextDisplay->SetText(textBuffer);	
           } else {
               _notepadAppTextDisplay->SetText(NOTEPADAPP_ERROR);	
           }

           myFile->Close();

       } else {
           _notepadAppTextDisplay->SetText(NOTEPADAPP_ERROR);	
       }
       // Clean up.
       delete [] textBuffer;
       myFile = NULL;
       break;
    }   
}

If the user pressed the Revert button, open the file and revert the buffer to the previously saved file.


Compile and run the application.


Introduction | Terminology | How To Write An Application | How To Add Detect User Interaction | How To Bring Everything Together