Firing a caught event - javafx-2

This question is so obvious, and I am sure that it is so easy to solve that I wonder why no simple and easy to understand answer hes been posted yet. I’ve found answers explaining how to create a *new event, changing the event direction, -bubble, etc. However, I have not found a Q/A regarding catch a signal and then bounce it off to the user class, and then to a class that the is user of that user class and so on and so forth.
Having said that, here is my question.
My class, ClassOne, receive the signal of a button and then has to pass that signal to ClassTwo, which in turn passes the signal to ClassThree, how that heck do I do this in JavaFx.
Please note that the class must not fire a new event, but the same event that has been caught.
Below is a grammatical explanation of what I am trying to do.
Any help, and I mean any input would be most appreciated.
public class MyBoxedButton extends HBox {
private Button btn;
MyBoxedButton(){
// Initialization of all the objects
btn = new Button();
//catch the event emitted by the button
btn.setOnAction((ActionEvent e) ->{
// fire/emit the same received event
?????
});
}
}
/*
This class catches the event emitted by MyBoxedButton and then passes it to ClassThree,
but this does not work, how then can I catch the event and then re-emit it.
*/
class ClassTwo(){
private MyBoxedButton mbb;
public ClassTwo(){
mbb = new MyBoxedButton();
//catch the event emitted by MyBoxedButton
????
// re-emit the caught event
????
}
}
/*
This class catches the event emitted by ClassTwo.
The exersice is ment to show how the messages flow
form one object to a next and then to a next, so on and so forth.
*/
class ClassThree(){
private ClassTwo c2;
public ClassThree(){
c2 = new ClassTwo();
//catch the event emitted by MyBoxedButton
????
// re-emit the caught event
????
}

As long as your wrapper classes also extend Node, fireEvent should do the trick, I think.
MyBoxedButton and ClassTwo will have to provide a way to register a listener.
I've written the SimpleEventHandlerProperty helper class, which makes this easier. Here is a code snippet from a sample class which uses SimpleEventHandlerProperty to allow to register an ActionEvent handler.
private final ObjectProperty<EventHandler<ActionEvent>> onNewSampleAction = new SimpleEventHandlerProperty<>(this,
"onNewSampleAction", ActionEvent.ACTION, this::setEventHandler);
public final EventHandler<ActionEvent> getOnNewSampleAction() {
return onNewSampleActionProperty().get();
}
public final void setOnNewSampleAction(EventHandler<ActionEvent> contentChanged) {
onNewSampleActionProperty().set(contentChanged);
}
public ObjectProperty<EventHandler<ActionEvent>> onNewSampleActionProperty() {
return onNewSampleAction;
}
Then ClassTwo and ClassThree can register a listener as required.
The helper class is available at Maven Central:
<dependency>
<groupId>org.drombler.commons</groupId>
<artifactId>drombler-commons-fx-core</artifactId>
<version>0.13</version>
</dependency>

Related

Controlling the event ElementTypeDuplicated

I am controlling the event "application.ControlledApplication.ElementTypeDuplicated" and this event raise after the name of the new type is imputed, but after that I would like to override the result of the dialog box ( ID: "IDD_SYMBOL_ATTRIB") that were raised before the event ElementTypeDuplicated. I already try to get a Object Args and override the result inside the method that is suubscribing the event ElementTypeDuplicated, but is not working. Is there a way of doing this?
Example:
public void OnElementTypeDuplicated(object o, ElementTypeDuplicatedEventArgs args)
{
//doing things
duplicatingTypeArgs.OverrideResult(0);
}
}
}
public void OnDialogDuplicatingELement(object o, DialogBoxShowingEventArgs args)
{
if (args.DialogId=="IDD_SYMBOL_ATTRIB")
{
duplicatingTypeArgs = args;
}
}
Haven't tested this yet, but how about implementing IUpdater with "Element.GetChangeTypeElementAddition" instead subscribing to the duplicating type event
You could subscribe to the DocumentChanged event before duplicating the symbol. That will provide you with the element ids of all newly created elements. An example of using that is provided by the place family instance sample.
After the duplication, unsubscribe again.
You can use the Idling event to be notified when the duplication has terminated.

IrrKlang Sound Library and Stop Event threads

I have a question about using external c++ library (irrKlang.dll) which is an audio playback engine. Now, the problem is that when I get a SoundStopped event out of it, and do an action in the main form, all kinds of stack related errors arise. Let me show the code:
namespace WindowsFormsApplication4
{
public class IsoundFinished : ISoundStopEventReceiver
{
public delegate void OnSoundStoppedEventHandler(object source, EventArgs e);
public event OnSoundStoppedEventHandler IStopped;
public void OnSoundStopped(ISound iSound, StopEventCause reason, object userData)
{
if (reason.ToString() == "SoundFinishedPlaying")
IStopped?.Invoke(this, EventArgs.Empty);
}
}
}
That is an extended class for me to do custom actions (for example - if sound finished, raise the event...) I am creating an instance of it, for the event action to get exposed in my main Form1 class:
IsoundFinished iStopReceiver = new IsoundFinished();
Now in my main form, I have this line in my Form1() method, just under my InitializeComponent():
iStopReceiver.IStopped += new soundFinished.OnSoundStoppedEventHandler(OnStopped);
It's for subscribing to the event handler. And finally - my OnStopped() method which is supposed to do stuff when the song ends it's playback - it's on the same Form1:
private void OnStopped(object sender, EventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action<object, EventArgs>(OnStopped), sender, e);
return;
}
btnStop1.PerformClick();
}
My Stop1 button method is (for those who work with the IrrKlang) ISound.Stop(); and few more lines of code, dealing with the display of playlist and so on. Although I have invoked it from the main UI thread - which should provide me with some degree of thread misalignment protection, all kinds of errors appear, mostly
Cannot evaluate expression because a native frame is on the top of the call stack.
Of course, if I do it without event handler, ISound.Stop(); drops the sound from the engine, like it should. I know something wrong is happening with the threads, but I can't figure out what's going on. If someone would give me few tips, I'd appreciate that a lot.
Well it seems I've solved it myself ! It's all about understanding how the threads are working in Visual C#. The problem was this : I was actually PAUSING the background thread where my audioengine was triggering the event - so 'till I performed an action after INVOKE in the main UI thread, background thread was paused along with the whole irrKlang engine. It was unable to purge itself properly, so it's call stack got clogged!
Using BEGININVOKE solved the problem, as it doesn't PAUSE the background task. It lets it run instead. Diagram on this answer gave me much needed piece of info I was looking for.
Maybe someone will need this answer too, glad I helped myself :P
private void OnStopped(object sender, EventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action<object, EventArgs>(OnStopped), sender, e);
return;
}
btnStop1.PerformClick();
}

C++ CLI Invoke issues

I have a MainForm class (as you'd expect, it is a form) that has a text box on it. I also have another class called 'Application_Server' That does a load of other stuff (not just form-background related, quite a lot of network based stuff etc.).
The Application_Server class runs in it's own thread, but needs to be able to update the controls on the form, for this question, we will stick with just the textbox.
The problem is that even though I am executing the command to set the text of the textBox control via 'Invoke' I am still getting the following exception during runtime:
Additional information: Cross-thread operation not valid: Control
'DebugTextBox' accessed from a thread other than the thread it was
created on.
What could be causing this? I am definitely invoking a delegate within MainForm.
Here are the relevant code segments (cut down for readability):
MainForm.h:
public ref class MainForm : public System::Windows::Forms::Form {
delegate void del_updateDebugText(String^ msg);
del_updateDebugText^ updateDebugText = gcnew del_updateDebugText(this, &MainForm::postDebugMessage);
private: void postDebugMessage(String^ message);
};
MainForm.cpp:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
if (this->DebugTextBox->InvokeRequired)
{
this->Invoke(updateDebugText, gcnew array<Object^> { message });
}
else
{
this->DebugTextBox->AppendText(message);
}
Monitor::Exit(DebugTextBox);
}
And finally, the code calling it:
void ServerAppManager::postDebugMessage(System::String^ message)
{
mainFormHandle->updateDebugText(message);
}
void ServerAppManager::applicationStep()
{
postDebugMessage("Starting\n");
// This is Run in seperate thread in MainForm.cpp
while (s_appState == ApplicationState::RUN)
{
postDebugMessage("Testing\n");
}
}
Thanks!
From background worker called bwSearch we do the call as following from the DoWork event handler:
private: System::Void bwSearch_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
//... logic
UpdateTxtOutput("Some message");
//... more logic
}
I have a RitchTextBox called txtOutput, also the windows form control containing this code is called frmMain, the UpdateTxtOutput is defined in three parts as follows:
delegate void UpdateTxtOutputDelegate(String^ text);
void UpdateTxtOutput(String^ text)
{
UpdateTxtOutputDelegate^ action = gcnew UpdateTxtOutputDelegate(this, &frmMain::Worker);
this->BeginInvoke(action, text);
}
void Worker(String^ text)
{
txtOutput->AppendText("\t" + text + "\n");
}
I managed to get it working by simplifying the method within the 'MainForm' class to:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
DebugTextBox->AppendText(message);
Monitor::Exit(DebugTextBox);
}
And then moving the 'Invoke' call to the method calling the delegate, not pretty but it works for now. I think the issue may have been caused by the form getting stuck inside an Invoke loop. I say this as I noticed that the form would lock up and stop responding after it hit the recursive Invoke statement.

Async Error-Handling in BackgroundWorker

How does one get a meaningful BackgroundWorker.Error when DoWork must call a delegate that might throw an exeption?
I'm implementing a static MsgBox class that exposes various ways of conveying custom messages to the user (using a custom message form).
One of the exposed methods, ShowProgress, instantiates a ProgressMessageBoxForm (derived from the custom MessageBoxForm) which displays a progress bar while some background operation is happening (letting user cancel the operation all the while). If running a background task on a modal form sounds awkward, consider a signature like this:
public static DialogResult ShowProgress(string title, string message, _
Action<AsyncProgressArgs> progressAction)
The idea is to encapsulate a background worker that delegates its "work" to any provided method (/handler), while allowing that method to "talk" back and report progress and cancellation... and ideally error status. Whether the form is modal or not has no relevance in this context, the ability to display progress of a running task in a progress bar on a cancellable modal form that also automatically closes unless a checkbox is un-checked so as to remain visible and displaying a success status upon completion, is a required feature.
Here's the AsyncProgressArgs class in question:
public class AsyncProgressArgs
{
private readonly Action<int, string> _update;
private readonly BackgroundWorker _worker;
private readonly DoWorkEventArgs _workEventArgs;
public AsyncProgressArgs(Action<int, string> updateProgress, BackgroundWorker worker, DoWorkEventArgs e)
{
_update = updateProgress;
_worker = worker;
_workEventArgs = e;
}
/// <summary>
/// Reports progress to underlying <see cref="BackgroundWorker"/>.
/// Increments <see cref="ProgressBar"/> value by specified <see cref="int"/> amount and
/// updates the progress <see cref="Label"/> with specified <see cref="string"/> caption.
/// </summary>
public Action<int, string> UpdateProgress { get { return _update; } }
/// <summary>
/// Verifies whether asynchronous action is pending cancellation,
/// in which case asynchronous operation gets cancelled.
/// </summary>
public void CheckCancelled()
{
_workEventArgs.Cancel = _worker.CancellationPending;
}
}
The BackgroundWorker's DoWork event handler then invokes the method that was passed to the custom messagebox
protected virtual void worker_DoWork(object sender, DoWorkEventArgs e)
{
// *** If RunWorkerCompletedEventArgs.Error caught exceptions,
// then this try/catch block wouldn't be needed:
// try
// {
_startHandler(this, new AsyncProgressArgs(UpdateProgressAsync, _worker, e));
// }
// catch(Exception exception)
// {
// if (MsgBox.Show(exception) == DialogResult.Retry)
// {
// BeginWork(_startHandler);
// }
// else
// {
// Hide();
// }
// }
}
Given a method such as this:
private void AsyncProgressAction(AsyncProgressArgs e)
{
// do some work:
Thread.Sleep(200);
// increment progress bar value and change status message:
e.UpdateProgress(10, "Operation #1 completed.");
// see if cancellation was requested:
e.CheckCancelled();
// do some work:
Thread.Sleep(500);
// increment progress bar value and change status message:
e.UpdateProgress(30, "Operation #2 completed.");
// see if cancellation was requested:
e.CheckCancelled();
// ...
// throw new Exception("This should be caught by the BackgroundWorker");
}
The calling code can look like this:
MsgBox.ShowProgress("Async Test", "Please wait while operation completes.", _
AsyncProgressAction);
Everything works as expected (the progress bar moves, the process can be cancelled), until an exception gets thrown in the action method. Normally the BackgroundWorker would catch it and store it in its Error property, but here this doesn't happen.
Thus, the code in the passed action method needs to handle its own exceptions and if it doesn't, it remains unhandled and the program dies a horrible death.
The question is, is it possible to have such a construct and still somehow be able to have a meaningful Error property when the process completes? I want to be able to Throw new Exception() anywhere in the action method and have it handled in the encapsulated worker.
Side note, I resorted to BackgroundWorker because with Task I couldn't get the progress bar to move until all the work was done, and I'd like to avoid dealing with Thread object instances directly.
EDIT
This is a non-issue, the compiled app does not blow up. Actually, I got confused by the debugger breaking on the exception being thrown in the delegate method. As pointed out in the comments below, execution/debugging can continue afterwards, and whatever error-handling logic is intended to run, will run. I was expecting BackgroundWorker to somehow catch the exception and the debugger to keep going, but it turns out the exception is caught and still the debugger breaks.
I should have read this before: Unhandled exceptions in BackgroundWorker
I should have read this before: Unhandled exceptions in BackgroundWorker.
This is a very, very long question with lots of context for a simple non-issue: the VS debugger stops and misleadingly says "Exception was unhandled by user code" as it would for an unhandled exception... when it actually means "BackgroundWorker task has thrown an exception and the debugger is letting you know about it because otherwise you would think the BackgroundWorker is swallowing it."
The exception can be F5'd / ignored to resume execution, the exception does end up in RunWorkerCompletedEventArgs.Error as expected, and the deployed app does not blow up in the user's face.
Posting this answer to remove this question from the (overflowing?) stack of unanswered questions...

How to update UI after a web service calling thread is finished

Questions about threads are in no shortage, I know, but I can't seem to find a "full" example of a thread doing http work and then coming back to update the UI.
I basically call a few web services upon app launch. I obviously don't want to freeze the UI so I would want to use a separate thread, right? I have found a bunch of examples online on how to get a new thread to perform some task. But I haven't yet found one that shows how to actually update the UI when the thread's task is done.
How do I know when the web service thread is done? Is there a callback method? Can I access the UI from this callback method if one exists.
Edit: (Here is some code)
//The activate method is called whenever my application gains focus.
public void activate(){
DoSomething wsThread = new DoSomething();
wsThread.start();
}
public void wsCallBack()
{
myTabScreen.add(new ButtonField("Callback called"));
}
public class DoSomething extends Thread
{
public void run()
{
try
{
wsCallBack();
}
catch(Exception e)
{
}
}
}
Very simple. But it never creates the button.
Any ideas?
Thanks a lot.
You can set up a "callback" system to notify the UI when the threads complete. Have a class that extends Thread and pass to it a reference of the class that should be called at the end. If you have a list of such classes that needs to be notified create a Vector on the Thread implementation to hold them. Override the run function and after doing everything you need to do simply call a method on the UI class (iterating through the vector if needed). So your classes may look like:
public class commThread extends Thread{
MyUIClass callbackObj;
public commThread(MyUIClass myUiClass){
callbackObj = myUiClass;
}
public void run(){
//do stuff
callbackObj.callback();
}
}
and your UI class:
public MyUIClass{
public void callback(){
//refresh the UI
}
}
Of course if you have multiple threads running at the same time and calling the same UI object make sure to synchronize the callback method.
Hope this helps!

Resources