I have a question that whether the C++ builder VCL Button Click function executes in main UI thread or a temporary new created thread? I wrote a test code that Button Click function exited when user close some dialog, and I found that the Button Click function is entered again even if the previous invoked dialog is presented.
The test code looks like below. My question is that Button can be clicked again and Click function is re-entered due to Application->ProcessMessages() in DoPollingFunc()?
void SomeForm::DoPollingFunc( void )
{
while( 1 )
{
Application->ProcessMessages();
if( polling some flag )
{
break;
}
if( timeout condition )
{
break;
}
}
}
void __fastcall SomeForm::ButtonClick(TObject* Sender)
{
DoPollingFunc();
}
I have a question that whether the C++ builder VCL Button Click function executes in main UI thread or a temporary new created thread?
It runs in whatever thread actually creates the button, which is typically the main UI thread, unless you write your own multi-threaded code to do something different.
I wrote a test code that Button Click function exited when user close some dialog, and I found that the Button Click function is entered again even if the previous invoked dialog is presented.
The OnClick event is triggered when a click message is received by the button control.
If the dialog is modal, it blocks your Form from receiving user input while the dialog is visible, so the OnClick can only be triggered if the dialog's internal message loop is receiving and dispatching a click message for that particular button. Which means the button click must be getting simulated by some piece of code while the dialog is visible.
If the dialog is not modal (such as TFindDialog), it does not block your Form from receiving user input while the dialog is visible, and the dialog operates within the main message loop, so the user can still interact with the button directly while the dialog is visible.
The code executes in the main VCL thread, unless you start, from the OnClick, some other thread to handle the response (and then sync back somehow).
It's not clear what you did with your test case. It is possible to have the OnClick execute multiple times if the button was clicked multiple times, but they will be sequential, not parallel.
If the call to Application->ProcessMessages(); picks up a button click message, then yes, SomeForm::ButtonClick will be called , which in turn will call DoPollingFunc. So your call stack will look like (most recent first):
TApplication::ProcessMessages
SomeForm::DoPollingFunc
SomeForm::ButtonClick
TApplication::ProcessMessages
SomeForm::DoPollingFunc
...
To avoid this happening you might want to use a static variable to detect re-entry. For example:
struct locker
{
bool &b;
locker(bool &b): b(b) {}
bool lock() { return b++; }
~locker() { b = false; }
};
void SomeForm::DoPollingFunc( void )
{
static bool reentry_flag = false;
locker reentry_lock(reentry_flag);
if ( reentry_lock.lock() )
return; // Already in this function at an earlier level
// ... main code here ...
}
Related
I am writing testcases in CAPL and want to activate each test case by using "Button" from Panel Designer.
The problem is that whenever I pressed the Button, it reacted as if it were pressed twice.
I just simply add a code like this to make that problem visible.
(The system variable of "#sysvar::Test_Cases::TC1" is linked to the Button in the Panel Editor)
on sysvar sysvar::Test_Cases::TC1
{
putValueToControl("Window","CAPL Output View",#sysvar::Test_Cases::TC1);
}
I expect to see only --> Value of #sysvar::Test_Cases::TC1 =1
But the output is like this:
Value of #sysvar::Test_Cases::TC1 =1
Value of #sysvar::Test_Cases::TC1 =0
on sysvar X{...} event procedure reacts to value change of X.So in case of button press (0->1) value will be set to one then on button release (1->0) value will be set to zero, so you change the value of X twice. This is why you are getting trigger twice.
To react only once on such button press event, and get notification only once, please use the keyword this and condition statement.
on sysvar sysvar::Test_Cases::TC1
{
if (this==1) /* Following block is called only once, on button press 0->1 */
{
putValueToControl("Window","CAPL Output View",#sysvar::Test_Cases::TC1);
}
}
I have several TextField's inside a window along with a Button, e.g. aButton.
The TextField's, Button, and window all have setImmediate(True).
When a TextField loses focus some validation code is executed and if it fails it calls:
aButton.setEnabled(False);
When incorrect data is entered into one TextField and then focus is lost the debugger shows that aButton.setEnabled(False) is called but aButton still looks enabled.
Two possible things can happen from here:
1.) If one modifies data in another TextField and exits that field (loses focus), the validation can be successful or not for that field but the system knows to call aButton.setEnabled(False) as the previous TextField is still invalid. This time though aButton is visually disabled.
2.) If one clicks on aButton which is visually enabled it produces this warning then visually becomes disabled:
Warning: Ignoring variable change for disabled component < class 'ui.button.Button'>, caption=OK
Currently using Vaadin 6.7.3
Are there any known work arounds to force aButton to visually become disabled immediately (force the client to update) after manually setting it to be disabled?
Sadly I have only Vaadin 7 at my disposal right now, but I checked this anyway. It works as you wanted it to work and I have to jump to the conclusion that this should be the same in Vaadin 6.7.3. This part is not really different in Vaadin7... Have you tried this feature in an isolated code (only a textbox and the button)?
VerticalLayout vlTestContent = new VerticalLayout();
final Button butChangeMe = new Button("Enabled");
final TextField tf = new TextField("Blur", "default value");
tf.addBlurListener(new BlurListener() {
private static final long serialVersionUID = 5544993392287938660L;
#Override
public void blur(BlurEvent event) {
butChangeMe.setCaption("Disabled");
butChangeMe.setEnabled(false);
}
});
Button but = new Button("Change button", new ClickListener() {
private static final long serialVersionUID = -2235317499126190105L;
#Override
public void buttonClick(ClickEvent event) {
butChangeMe.setCaption("Enabled");
butChangeMe.setEnabled(true);
}
});
vlTestContent.addComponent(butChangeMe);
vlTestContent.addComponent(tf);
vlTestContent.addComponent(but);
(The second button is just for fun)
button.setVisible(false) will always work. You need to be careful to not fire up a another event on the focus lost event that ends up setting the visibility of the button to true.
You can request a repaint of a component or the whole window, but the whole point of the framework is that you will never need to do that, because visually modified components will automatically repaint on each request.
Just to be curious, do you let your request to finish before trying to see if the browser updates? Or you look at your browser right after you pass the setVisible() line in your debugger ?
I think that your point nr 2 happens because you clicked on the button, and what happens in this order is: 1st your focus lost event runs (which probably disables your button), 2nd button click runs and somehow a repaint is requested for that button because a state change happened in the button but a repaint show the warning that it won't do anything with it because it is disabled (was just disable by the focus lost event)
As a side note. I think this UI won't make for a good user experience, it should be the other way arround, if a validation is ok, then show the button (or better, always show the button, but enable/disable instead) But it depends...
I am having a bit of a problem with an app I'm developing for BlackBerry.
I have a series of Item objects on the screen, each with a DefaultCommand tied to it. Example
below:
...
cmdBrowse = new Command(temp.id,Command.ITEM,0);
mainList.setDefaultCommand(cmdBrowse);
mainList.setItemCommandListener(icl);
...
Previously just clicking on the item with the confirm button would run the proper command. No problem there.
Then I added the handleKeyReleased method to capture the BlackBerry's back button as follows:
protected boolean handleKeyReleased(int keyCode, int gameAction) {
if(keyCode==1769472) {
/*code to deal with back button*/
return true;
} else {
return false;
}
}
Now when I click on the mainList Item with the confirm button, it brings up the list of commands first and I have to click again to actually run the command. Two clicks where it used to be one.
So, is there a way to either:
A. Keep the single click behaviour while still being able to capture the back button with handleKeyReleased
or
B. Capture the back button in a different way ?
I ended up overlooking one very simple thing. All I had to do was call the superclass's handleKeyReleased method and everything worked perfectly.
When a button is pressed on Screen A, I push Screen B. And when Back button is pressed on Screen B, I want Screen A to understand that to update Screen. Is there any way to handle this?
When Screen B is popped, it will have its onUiEngineAttached(boolean) function called, with the parameter set to false. If Screen B held a reference to Screen A, it could then trigger whatever updating is needed.
Another way is to setup your own Listener where Screen B would provide the event and Screen A would listen for the event. Again, you would probably fire the event from the onUiEngineAttached(boolean) function.
You could use a callback pattern. Check my another post for details. Upon any UI event on your Screen B (e.g. a button is pressed) the Screen B runs the callback passing any parameter if needed. Going this way your Screen A keeps its original/clean interface.
You can detect the device 'Back' btn press with this code:
protected boolean keyChar(char c, int status, int time) {
if (c == Characters.ESCAPE) {
// .. run callback here ..
close(); // actually close the Screen B
return true;
}
return super.keyChar(c, status, time);
}
Screen B is popped off of the stack, so it will get the onUiEngineAttached() callback. But you are interested in screen A, which will get a different callback - Screen.onExposed().
I think this can be done using YUI History manager.
I am using the Borland c++ builder. I have an application where I want the main form to be hidden until a button is pressed on a different form. i have set the Visible value on the mainform to false, but it still shows up when i run the program. anyone know what to do?
Have a look at the TApplication ShowMainForm property.
Here is an example based on the instructions in online help.
Set the main form Visible property to false.
On the menu select Project -> View Source to display the main project file.
Add the following code after the call to Application->CreateForm and before the call to Application->Run.
Application->ShowMainForm = false;
You should end up with something like this.
try
{
Application->Initialize();
Application->MainFormOnTaskBar = true;
Application->CreateForm(__classid(TMainForm), &MainForm);
// extra code to hide main form
Application->ShowMainForm = false;
Application->Run();
}
There is a demo that comes with C++Builder that does this It can be found in demos\cpp\apps\twoforms
"First" is the form with the button that shows "Second"
The button's OnClick event handler creates the new form with new, then calls ShowModal()
You can use just Show() if it isn't meant to be a modal form.