2024-11-24 02:43 PM
Hi
I am using the TouchGFX keyboard to input data into fields on a number of settings screens. Since the screens are small, I cannot afford the option of Cancel and Enter buttons as used in the demo. Instead I have added 2 buttons to the keyboard for Enter and Cancel. The former leaves the buffer intact, while the latter clears it before returning. However, the function that contains the keyboard container continues executing while the keyboard is in use. The result is that the data is never entered into the field.
One workaround I have used is to add an 'Add/Edit' flex button that loads the keyboard and writes the returned buffer to the model. Flex buttons over the data fields, that are made visible at the time the keyboard container is loaded, then cause the screen to reload, which then draws and displays the data from the model. It works, but it is too clunky.
I have tried using a while loop to pause while the keyboard is visible, but this does nothing.
Has anyone any suggestions on how to pause the code until the user has finished entering data via the keyboard? I'm probably missing something extremely obvious.
Solved! Go to Solution.
2024-11-26 05:34 AM
Hello @Kenbit ,
I have made an example where I change the behavior of the CapsLock button to print the current text to the MainView.
You could do the same but instead of printing it to a textArea like I did, you could sent it to the model since this is something you were trying to achieve.
Once you have your data in the model, you can anything you want with it.
Regards,
2024-11-25 05:15 AM
Hello @Kenbit ,
Which keyboard are you using?
I do not understand this sentence "the function that contains the keyboard container continues executing while the keyboard is in use". What is the function that "contains" the keyboard? Isn't it supposed to keep running for it to properly work?
You say that you don't have much space so you removed the buttons and added other ones. They seems to do the same thing, I assume you replaced them with smaller buttons then. Can't you simply resize the buttons provided?
Also, if you can't resize the provided buttons, can't you just call whichever function the initial buttons were calling?
"how to pause the code until the user has finished entering data via the keyboard?"
This seems like the wrong way of doing it. One doesn't not want to pause code, otherwise, wouldn't your application freeze and the user won't be able to enter text?
Can you share a project with an example of the issue you are facing?
Regards,
2024-11-25 10:41 AM
Hi Gaetan
Thanks for getting back to me.
Sometimes defining the problem becomes part of the problem.
The project is running on the STM32F429 DISC1 board. It uses FreeRTOS
I am using an amended form of the customKeyboard example in one of the TouchGFX demo projects. However, I have shortened the space bar and edited the keyboard to include an OK (tick) button and a cancel button.
These are part of the keyboard, not external buttons like in the demo project. I am taking this approach as my display is 320*240, as is the keyboard.
The code snippet shows what I want to do. However, lines 14 onwards are all executed while the keyboard is visible, so nothing is copied into the text area. I want this function to wait until the keyboard is cleared and the buffer contains the entered text. Waiting for the keyboard to clear and the buffer filled would not be an issue as the RTOS scheduler could switch to other tasks if needed.
Code is greatly abridged to save space. There are multiple text fields.
void SettingsScreenView::FlexDatafieldClicked()
{
/* Show the keyboard*/
keyboard.setVisible (true);
keyboard.invalidate();
/*keyboard is displayed and allows text entry*/
/*clicking on enter key (part of keyboard)*/
/*This is the code that should ideally run AFTER keyboard is hidden */
/* Copy keyboard buffer into datafield buffer*/
if (strlen(returnBuffer) != 0)
{
Unicode::strncpy(textAreaDatafieldBuffer, keyboard.getBuffer(), TEXTAREADATAFIELD_SIZE);
}
/*Convert Unicode textbuffer to char buffer*/
/* then save data to model via presenter*/
int i = 0;
do
{
txtBuf[i] = (char) textAreaDatafieldBuffer[i];
i++;
} while (textAreaDatafieldBuffer[i] != 0);
memset(txtBuf, '\0', TEXTAREADATAFIELD_SIZE);
presenter->saveDatafield(txtBuf);
textAreaDatafield.invalidate();
keyboard.clearBuffer();
}
The code below works, but this is an awkward fix, making the user see nothing returned from the keyboard until they click on the text area to be populated. Again there are lots of settings fields and this will be confusing.
/* This is the somewhat inelligant workaround*/
/*First an 'AddEdit' Flex button is used to open the keyboard*/
void SettingsScreenView::AddEditClicked()
{
keyboard.setVisible (true);
keyboard.invalidate();
/* a flex button (Alpha 0) is activated over the Datafield textarea*/
flexButtonDatafield.setVisible(true);
flexButtonDatafield.invalidate();
/*AddEdit button is hidden*/
Add_Edit_Button.setVisible(false);
Add_Edit_Button.invalidate();
/*text area */
textAreaDatafield.setVisible(true);
textAreaDatafield.invalidate();
}
/*Once keyboard entry is complete and keyboard is hidden*/
/*the flex button over the target field is clicked*/
/*Now the keyboard bufffer, which is still intact WILL copy into the data field*/
void SettingsScreenView::Edit1Clicked()
{
Unicode::strncpy(textAreaMem1Buffer, keyboard.getBuffer(), TEXTAREAMEM1_SIZE);
//Convert Unicode textbuffer to char buffer for saving in Model
int i = 0;
do
{
txtBuf[i] = (char) textAreaMem1Buffer[i];
i++;
} while (textAreaMem1Buffer[i] != 0);
presenter->saveDatafield(txtBuf, 1);
memset(txtBuf, '\0', TEXTAREAMEM1_SIZE);
keyboard.clearBuffer();
}
Is there a way to conveniently pause the first example until the keyboard entry is complete? The keyboard is an object of class CustomKeyboard, which is made visible via a flex button on the screen and normally hidden by the external buttons. The second method above emulates this external button idea, but hides the keyboard from within the keyboard code. Would a semaphore work here? I am also using the keyboard from other screens.
I hope this gives enough clarity.
Regards
Ken
2024-11-25 10:57 AM
To expand on the above, at the end of the Edit1Clicked() function, the screen must be refreshed. Even if the AddEdit flex button is made visible, it is no longer able to bring up the keyboard. This is not a major issue as screen refresh is not noticeable.
2024-11-26 12:20 AM - edited 2024-11-26 12:20 AM
you should really wrap your head around the concepts. touchgfx (like every gui) is more an event style system. so while-loops and pausing something are red flags and most of the time not the correct solution.
and sorry but the description of your problem is not ideal and it's hard to get what you are trying to achieve
you have no space for ok/cancel buttons? but you added them to the keyboard?!
When is your keyboard entry complete? after 1 char? after 5 chars? or when the user presses ok?
i just looked at https://www.youtube.com/watch?v=Tkz9099a7a4 how this keyboard is meant to be used. as far as i understand your ok/cancel button are part of the keyboard keys and not extra buttons. so in the keyboard eventhandler you need to disinguish which button was pressed. if it was ok than you need to check if your requirements(eg. 5 chars entered) are already met.
in the solution in the video there are extra buttons with their own event handler which is only called if exactly this button was pressed so you don't need to differentiate which button you pressed
another tip: if you have many widgets/elements you can combine them in containers. so you can just hide the one container if needed (i don't think you will need this here)
2024-11-26 01:53 AM
Hi Funky
I think you misunderstand. I am not new to the concepts. I have been at this for many years and am fully aware of event-driven code and, as in this case, RTOSs. I too have seen the YouTube videos, but they fall short of what I require. However, they are based on larger displays. The screen I will be using is 320*240, which happens to be the size of the keyboard container and a keyboard smaller than this would be too small to be usable anyway. This is why I incorporated the extra buttons in the keyboard, both of which work exactly as expected. As with any keyboard, entry is complete when the Enter button is pressed. The keyboard is set up to accept up to 100 characters, which are displayed in a scrollable container at the top. I currently have a fully-functioning project utilising the keyboard. It is used across a number of screens for data entry. Each screen has a number of text areas where the data is to be copied, some of which can accept all 100 characters and are also scrollable. So, a comprehensive project .. and working. The issue is a matter of user-friendliness. As stated, the first code block is what would be ideal, but not currently working and I do have some idea why. I just want some ideas of a more elegant workaround. The second block of code does work, but is not as intuitive as I would like.
It is not unreasonable for an individual screen to wait until keyboard entry is complete before copying the buffer into a text field and no user would expect to type data into a keyboard and then find that, on pressing return, the system had moved on without them. All screens in TouchGFX wait for user-input or until they receive instructions via the presenter. This may block this individual task, but the scheduler will certainly switch to other running tasks and there are a number in this project, including several I2C comms activities, rotary encoders and DSP tasks.
The keyboard class is s subclass of the Container class. I assume it must be running in a separate task, if it I am leaning towards using a semaphore, allowing the task to take block itself until the keyboard gives the semaphore. But where to give the semaphore (presumably on pressing enter). The possible issue with this is then an increase in complexity, with multiple screens possibly needing this same approach.
Any suggestions on how best to approach this would be appreciated.
Thanks
2024-11-26 02:01 AM
Sorry, brain was working faster than the typing.
The keyboard class is a subclass of the Container class. I assume it must be running in a separate task. I am leaning towards using a semaphore, allowing the task to take the semaphore, blocking itself until the keyboard task gives the semaphore. But where to give the semaphore (presumably on pressing enter)? The issue with this is then an increase in complexity, with multiple screens having to use this same approach.
2024-11-26 02:01 AM
@GaetanGodart wrote:"how to pause the code until the user has finished entering data via the keyboard?"
This seems like the wrong way of doing it. One doesn't not want to pause code, ,
Perhaps what @Kenbit is looking for is to make this modal ?
2024-11-26 02:01 AM
i don't get what you mean with "the system moves on"
when you/the user presses [ENTER] you have to generate an event/a message/whatever which copies the Textbuffer and sends it to the e.g. model, copies the text to another text window or whatever you want to do with it.
no need to wait or something like that
2024-11-26 02:07 AM
i dont't think the keyboard runs in its own task. it's party of the touchgfx gui task all running in the same task. just waiting for touch events and showing the gui
if you have multiple screens which needs the keyboard data (you can't show all screens at once) you have to propagate the data entered by the keyboard to the model and if you switch screens, that screen has to get the data from the model and show it.