1.2k views
in Embedded Wizard Studio by

I am displaying a menu dialog from the main application when a hardware button is pressed. This happens, but the dialog closses after a period of time. Here is a code snippet. 

 

/* The template just returns the given argument... */
var Application::MenuScreen menu = new Application::MenuScreen;

if( showMenu == true ) {
  SwitchToDialog( menu, null, null, null, null, null, null, null, null, null, false );
}
 
return aArg1;

 

by
Thanks, this was helpful.

1 Answer

0 votes
by

Hello,

I'm not sure whether I understand your question... are you wondering why your dialogs close automatically?

If this is the case please note that there is no automatism to hide any GUI components. If the dialog disappears, then there is some code executed to do this. Please verify your implementation of the splash screen (thread Implementing a splash screen). It contains a timer to close the current dialog. Have you followed the step 1 to ensure that the timer fires only once? I suppose, the timer fires periodically and so closes the actually shown dialog.

Best regards

Paul Banach

by
Thanks Paul, this was helpful.

Now it displays the menuScreen, but I cannot read tbe hardware button from this screen. I tried dimissing the MainScreen and using the PresentDialog function to display the MenuScreen instead of using the SwitchToDialog function. I still didn't have access to the hardware button. What am I missing?

I might add that I use a different keypad scan function for the MenuScreen. Using flags to control which keypad scan function is used.
by

Hello,

what do you mean with 'cannot read the hardware button from this screen'? Are you dispatching the hardware button events as keyboard events?

Best regards

Paul Banach

by

Hello,

 

No, I am updating a property from the device driver. Then I have a property observer fire an onEvent slot mehthod. Here is the code for my slot method; 

 

if( Application::Device.Button1 == 1 )
  btn1 = true;
else
  btn1 = false;
scanKeys();

Here is the devive driver code;

/* read PA1 */
if( EwBspGetButton1Level() ==  1 )
{
	/* user code */
	Button1Counter = 1;
} 
else	
{
	Button1Counter = 0;
}


#ifdef _ApplicationDeviceClass__UpdateButton1Property_
   ApplicationDeviceClass__UpdateButton1Property( DeviceObject, (XInt32)Button1Counter );
#endif

 

by
So the above method is not the best way to handle hardware buttons. I should have the device driver generate a keyboard event when a hardware button is pressed. And this event will be directed to the screen that has focus. So for instance, I have a three button keypad. I could use the USER1, USER2, USER3 keycodes to be sent with each hardware button. I am not using GPIO interrupts, should I? How do I send key events from the device driver?
by

I think I found the answer, your answer from another post. Use this function in the main loop.  

if ( Button_1_Pressed )
  events |= CoreRoot__DriveKeyboardHitting( rootObject, CoreKeyCodeUser1, 0, 1 );

if ( Button_1_ReLeased )
  events |= CoreRoot__DriveKeyboardHitting( rootObject, CoreKeyCodeUser1, 0, 0 );

 Does each GUI component (Screen) have to have it's own slot method?

 

 

by

Hello,

using a Device Property to 'signal a hardware button pressure' is not the ideal approach. Properties are more intended to store a setting or status value. Events (e.g. triggered by a sensor or a hardware button) are better processed as a System Event and the associated System Event Handler. In fact, by using the System Event you can feed the GUI application with events triggered by the hardware buttons.

We consider however the hardware buttons just as a kind of keyboard. Keyboard events, in turn, are better dispatched by using the method DriveKeyboardHitting(). From your preceding comments I think you already know this concept. Now, let me address your last question: Does each GUI component (Screen) have to have it's own slot method?

From technical point of view you can implement in each GUI component as many slot methods as you need. On the other hand, there is no obligation to implement slot methods. You do this only if you want some code to be executed in response to e.g. an event. For example, if you want an alert GUI component to react to a key event, then you add to this component a Key Press Handler. In this case you also add one or more slot methods which you connect with the Key Press Handler. If your application contains another GUI component (e.g. a menu) then you can add more Key Press Handler to this menu component and also add the necessary slot methods.

I'm not sure whether my answer addressed your question ... Maybe you can formulate it more precisely?

Best regards

Paul Banach

by

Regarding the usage of DriveKeyboardHitting() please see also the chapter main loop.

Best regards

Paul Banach

by

Well I used the DriveKeyboardHitting() function and it still is not working. What i mean by not working is when the main application screen is present, the program responds to a button push. This button press displays another screen. But twhen in this other screen, he code for the slot method does not react to the button press.  I have key event handlers for both screens and their corresponding slot methods. The following code is from the slot method of the main screen.

sender; /* the method is called from the sender object */
if ( showMenu == false )
{
  if ( MainKeyHandler.Code == Core::KeyCode.User1 )
    btn1 = true;
  else
    btn1 = false;

  if ( MainKeyHandler.Code == Core::KeyCode.User2)
    btn2 = true;
  else
    btn2 = false;

  if ( MainKeyHandler.Code == Core::KeyCode.User3 )
    btn3 = true;
  else
    btn3 = false;

  if ( btn1 == true ) {
    //menuAccess.menuLoop( 0 );
    showMenu = true;
    var Application::MenuScreen menu = new Application::MenuScreen;
    SwitchToDialog( menu, null, null, null, null, null, null, null, null, null, false );
  }
}

Code for the slot method for the other screen. When in this screen, the button increments a vetical list selection. 

sender; /* the method is called from the sender object */

// Which item is currently selected?
var int32 itemNo = VerticalList.SelectedItem;
// Create a new animation effect instance.
var Effects::Int32Effect effect = new Effects::Int32Effect;


if ( MenuKeyHandler.Code == Core::KeyCode.User1 )
  menubtn1 = true;
else
  menubtn1 = false;

if ( MenuKeyHandler.Code == Core::KeyCode.User2)
  menubtn2 = true;
else
  menubtn2 = false;

if ( MenuKeyHandler.Code == Core::KeyCode.User3 )
  menubtn3 = true;
else
  menubtn3 = false;


// Configure the animation duration and the timing (easing)
effect.CycleDuration = 250;  // milliseconds
effect.NoOfCycles    = 1;
effect.Timing        = Effects::Timing.Exp_InOut;

// When the user presses the 1st button, get the index of the next
// higher item
if ( menubtn1 == true ) {
  itemNo = itemNo + 1;
  if ( itemNo > 3 )
    itemNo = 0;
  Text1.String = string( itemNo );
}

// The upper or lower end of the list has been reached
//if (( itemNo < 0 ) || ( itemNo >= VerticalList.NoOfItems ))
//  return;

// Select the item ...
VerticalList.SelectedItem = itemNo;

// ... and eventually scroll the list, so the item is fully visible.
VerticalList.EnsureVisible( itemNo, true, null, null );

 

by

Hello,

it is difficult to say what is wrong. I would do following:

Step 1. To exclude that the problem is not related to the hardware buttons or implementation in the target system, test the behavior of the application within the Prototyper. When the Prototyper is running use the keyboard shortcuts Ctrl+1, Ctrl+2, Ctrl+3 to simulate the respective key codes User1, User2 and User3 (See also: Keyboard inputs in Prototyper.). Does it work in the Prototyper?

2. Set breakpoints in your Slot methods and again test it with Prototyper as explained in step 1. The integrated Debugger helps you to investigate whether the methods are invoked as expected or not. If a method is invoked, you can execute the method step by step and analyse the problem. Are the methods invoked?

3. If the method are not invoked, verify whether the slot methods are really connected to the Key Press Handler and the handler is configured to react to the particular key event (e.g. User1).

If none of the above steps help you to find the problem, you can reduce your application to an example demonstrating the problem and upload it to this forum. We can thereupon take a look at the application.

Best regards

Paul Banach

by

Thanks for the advice about the prototyper. Interesting, it works fine in the prototyper. I wonder if it is because I am checking the pin levels in the main loop instead of the device driver. Or that I am not doing any software debouncing. Strange that the button works fine in the main screen with the development board and keypad.

The code to check the pin levels in the main loop,

  /* receive keypad inputs */
  if ( EwBspGetButton1Level() == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser1, 0, 1 );
  if ( EwBspGetButton2Level() == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser2, 0, 1 );
  if ( EwBspGetButton3Level() == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser3, 0, 1 );

I'll try the following approach,

  /* receive keypad inputs */
  btn1 = DeviceDriver_GetButton1Level();
  if ( btn1 == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser1, 0, 1 );
  btn2 = DeviceDriver_GetButton2Level();
  if ( btn2 == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser2, 0, 1 );
  btn3 = DeviceDriver_GetButton3Level();
  if ( btn3 == 1 )
	events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser3, 0, 1 );

 

by

Hello,

one idea: in your actual implementation you invoke the function DriveKeyboardHitting() with 1 in its last parameter. This indicates the 'press' event. In practice, however, you should also signal the event when the button is released again. The simplest would be following adaptation: 

if ( EwBspGetButton1Level() == 1 )
{
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser1, 0, 1 );
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser1, 0, 0 );
}
if ( EwBspGetButton2Level() == 1 )
{
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser2, 0, 1 );
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser2, 0, 0 );
}
if ( EwBspGetButton3Level() == 1 )
{
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser3, 0, 1 );
  events |= CoreRoot__DriveKeyboardHitting( RootObject, CoreKeyCodeUser3, 0, 0 );
}

Without this adaptation, when you press the same harwdare button twice, the GUI framework will interpret the second press event as repeatition event. This repetition event will then be delivered to the Key Press Handler which has received the initial press event. This could explain why you don't get the event in the second screen.

Does it solve the issue?

The above adaptation is sufficient for most cases as long as you are not interested in processing events when the user presses and holds a key. In such case it would be reasonable to adapt the interface to the hardware buttons  so that it can detect the press and release events and report these individually.

Best regards

Paul Banach

 

by
Hello,

I haven't tried this yet, but will later this evening as I don't have the development board with me. But I have been prototyping other parts of the project. I have discovered the wonderful OOP feacture of EW! Our interface will probably have 13 - 15 screens. And there are certain aspects of each screen that will be the same. For instance the soft button icons and the keyboard event handler with the slot method. Well I created another bare minimum screen, and discovered that I could use the browser to find that component and just drop it on the unit and have another exact screen with the same functionality. It's well thought out. I commend you guys on a wonderful app!
by
Yes, this solved the issue, thank you. I did have to implement software debounce using the HAL_Delay method when checking the push buttons, but my app is working as it should!

On another note, I used a vertical list as my main menu. I am trying to make it look 3D like some of the examples. I see how it is done, by making the item rectangle color white and the BL and BR colors a shade of gray. But as soon as I go back to the screen with the vertical list, it's all white! Really don't understand why it does that. I am not doing something right.
by

Hello,

the color of a rectangle can be configured by 5 properties. The properties ColorTL .. ColorBR specify the colors for the particular corners. The property Color, in turn, overrides the corner properties permitting you to change the rectangle color at once:

Usually you use either the four properties (e.g. ColorTL) to specify the colors individiually for each corner or you use the property Color to specify the color for the entire rectangle. If you mix the both approaches, the property Color overrides the setting of the other properties. Please verify whether the property Color is modified (it appears bold in Inspector). If this is the case, restore the original value of the property Color.

Does it solve the issue?

Best regards

Paul Banach

by
The issue is solved, thanks!

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...