1

I'm running into the problem I've always had with Swing time and time again. Swing doesn't play nice with the programmer handling their own asynchronous operations.

In front of me now, I have the quintessential problem that is often blasted with answers of the sort "Have Swing's EDT handle async tasks" or "Use invoke later".

Normally, that would be the way to go if I was building the entire application from the ground up. However, I'm not. What I currently have is a program (that I should not modify in any way) that runs in its own thread and fires off asynchronous update events of its own design. I want to use Swing to make a UI wrapper for it, to display the application in a panel while providing buttons to interact with the underlying program.

Now, I don't really want to lose my hair over this. I'm not going to tackle this problem head-on for hours at a time with no progress. If an acceptable answer to this question doesn't arise, I will simply use an OpenGL wrapper (that's right "simply").


Questions

  • Is there conventional method for wrapping a multi-threaded application of this nature in Java Swing?

  • Does that method allow for passive viewing of a changing model? (no UI mouse or keyboard events, but it still updates)

  • If there isn't a conventional way, is there a hack, bodge, or otherwise duct tape solution to what I'm trying to do?


Answers which fail to identify that the asynchronous portion of the application is in another program and suggest modifying that program will be deemed nonconstructive and will be flagged as off-topic.

If you need additional information, make a comment and I'll disclose as much as possible.

Axoren
  • 623
  • 1
  • 8
  • 22
  • *"Is there conventional method for wrapping a multi-threaded application of this nature in Java Swing?"* - `SwingWorker` or `SwingUtilties.invokeLater` come to mind – MadProgrammer Jan 11 '16 at 22:59
  • *"Does that method allow for passive viewing of a changing model? (no UI mouse or keyboard events, but it still updates)"* - Yes, neither `SwingWorker` or `SwingUtilities.invokeLater` will care about the user interaction against the model, they will (if you design to do so) only care about the events which your other program is generating. Sending updates back to your program will also need to be carefully considered, as you don't want to block the EDT while doing it (no context, so assuming), but because the other program seems to be event driven, your "watchers" should be able to cope – MadProgrammer Jan 11 '16 at 23:01
  • @MadProgrammer `SwingUtilities.invokeLater(...)` will have to be called from the thread that spawned the frame, wouldn't it? – Axoren Jan 11 '16 at 23:10
  • @MadProgrammer And what I meant by passive viewing was that if I were to look at the UI and the model would self-update, would a change to the UI occur? Contingent on your response to my previous comment, I'll already have the answer. I was unaware that invokeLater could be called from other threads if it can be. – Axoren Jan 11 '16 at 23:12
  • No, `SwingUtilities.invokeLater` can be (and typically is) called from ANY other thread other then the EDT (although you can call it from within the EDT as well), the point is, the `run` method of the `Runnable` supplied to it will be called within the EDT, making it safe to update the UI from. If your program was monitoring the changes to the other program (in a different thread other then the EDT - I don't know if you need to poll it or it provides a callback some how), you would sync the update back to the EDT. Would it be simultaneous? No, but it should be relatively quick – MadProgrammer Jan 11 '16 at 23:15
  • Is there a reason that invokeLater is not a synchronous method in Java 7 (the documentation does not list it as synchronous)? If it's called really quickly, are there any race conditions? – Axoren Jan 11 '16 at 23:35
  • 1
    That would come down to the `EventQueue`, as the `Runnable` is popped onto the queue from `invokeLater` – MadProgrammer Jan 11 '16 at 23:46

1 Answers1

3

Use SwingWorker for this. Start the process in your implementation of doInBackground(). Give the worker a reference to the listener that will receive "asynchronous update events" from the process. In the listener, invoke publish() as warranted to allow "passive viewing of a changing model." Your implementation of process() will be called on the EDT at a sustainable rate. Several examples may be seen here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I'm going to further investigate this solution. It looks like the better of the two (making a worker vs. making sporadic invokeLater calls). – Axoren Jan 12 '16 at 01:10
  • `SwingWorker` greatly simplifies synchronizing access to shared data. Can you elaborate on how "asynchronous update events" are generated? – trashgod Jan 12 '16 at 03:26
  • An asynchronous allegory for Observer/Observable style, where an Observer creates an notify thread per observer. – Axoren Jan 12 '16 at 04:34
  • It sounds like your `doInBackground()` can start the process, sleep in a loop on `isCancelled()`, and finally terminate the process. – trashgod Jan 12 '16 at 10:59