4

UPDATE: I'm using Netbeans and Matise and it's possible that it could be Matise causing the problems I describe below.

UPDATE 2: Thanks to those who offered constructive suggestions. After rewriting the code without Matise's help, the answer offered by ignis worked as he described. I'm still not sure how the code the Netbeans code generator interfered.

Though I've been programming in Java for awhile I've never done any GUI programming until now. I would like to control a certain part of my program externally (updating a jTextArea field with output from an external source) without requiring any user action to trigger the display of this output in the jTextArea.

Specifically, I want this output to begin displaying on startup and to start and stop depending on external conditions that have nothing to do with the GUI or what the user is doing. From what I understand so far you can trigger such events through action listeners, but these action listeners assume they are listening for user activity. If I must use action listeners, is there a way to trick the GUI into thinking user interaction has happened or is there a more straightforward way to achieve what I want to do?

Also, I'd really like to know more about best practices for separating GUI code from the application logic. From the docs I've come across, it seems that GUI development demands more of a messy integration of logic and user interface than, say, a web application where one can achieve complete separation. I'd be very interested in any leads in this area.

  • 1
    "I'm using Netbeans and Matise and it's possible that it could be Matise causing the problems.." Then dump the automagic IDE you apparently do not know how to use, and learn to code Java. – Andrew Thompson Jun 05 '11 at 07:18

3 Answers3

3

There is no need to use listeners. GUI objects are just like any other objects in the program, so actually

  1. you can use the listener pattern in any part of the program, even if it is unrelated to the GUI
  2. you can invoke methods of objects of the GUI whenever you want during the program execution, even if you do not attach any listeners to the objects in the GUI.

The main "rule" you must follow is that every method invocation performed on objects of the GUI must be run on the AWT Event Dispatch Thread (yes, that's true for Swing also).

http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html

So you must wrap code accessing the GUI objects, into either

javax.swing.SwingUtilities.invokeLater( new Runnable() { ... } )

or

javax.swing.SwingUtilities.invokeAndWait( new Runnable() { ... } )

http://download.oracle.com/javase/6/docs/api/javax/swing/SwingUtilities.html


About "separating GUI code from the application logic": google "MVC" or "model view controller". This is the "standard" way of separating these things. It consists in making the GUI code (the "view") just a "facade" for the contents (the "model"). Another part of the application (the "controller") creates and invokes the model and the view as needed (it "controls" program execution, or it should do that, so it is named "controller"), and connects them with each other.

http://download.oracle.com/javase/tutorial/uiswing/components/model.html

For example, a JFoo class in the javax.swing package, that defines a Swing component, acts as the view for one or more FooModel class or interface defined either under javax.swing or one of its subpackages. You program will be the "controller" which instantiates the view and an implementation of the model properly (which may be one of the default implementations found under those packages I mentioned, or a custom implementation defined among your custom packages in the program).

http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/package-summary.html

ignis
  • 8,692
  • 2
  • 23
  • 20
  • Thanks. I have tried to do some experimenting with SwingUtilities.invokeLater but it doesn't seem to work for me. What I've tried: GUIClass has method that does jTextArea.append called from within SwingUtilities.invokeLater (let's call that method GUIClass.updateLogWindow(String msg)) AppClass creates an instance of GUIClass, starts the gui with a GUIClass.launchUI method then tries to update a jTextArea field using GUIClass.updateLogWindow from GUIClass that updates. What happens: program starts, gui starts, but no text area updates. They are happening because I print them to the console. –  Jun 05 '11 at 06:03
  • I've edited my first reply for clarity's sake. What I mean by the last sentence is that when GUIClass.updateLogWindow is called, it does a jTextArea.append(msg) as well as printing the msg argument to the console. So, this method is firing, I know that it's actually appending the text to the text area, it's just not displaying. So, obviously I'm doing something wrong. –  Jun 05 '11 at 06:10
  • Does it work if you invoke textArea.repaint() after updating the text, inside the Runnable? I mean "public void run() { textArea.doWhatever(...); textArea.repaint(); }" – ignis Jun 05 '11 at 06:16
  • No, it doesn't. I know you're right about this. I think there must be something else causing this problem. I'm using Netbeans and their Matise gui builder and it generates a crazy amount of code. It's possible that something that Matise is doing is causing the problem. I'm going to try rewriting this without Matise and see if it works. I'll mark your answer as correct shortly, because it is for the question I specifically asked. But I'd like to see if someone else might know something if this actually is a Matise-specific problem. –  Jun 05 '11 at 06:24
  • @Ignis. +1 Really nice answer dude. I wish I could write that simply and clearly. – corlettk Jun 05 '11 at 06:59
  • @Fred: [Sun's Article: Painting in AWT and Swing](http://java.sun.com/products/jfc/tsc/articles/painting/) expands on what Ignis was saying about `repaint`. It's readable, and has decent examples. And yes it very well could be a Matise problem. Like I said earlier about painting within the nine dots... I'd have to see and run your (complete) code to be sure though, and that's "out of scope" really, isn't it? – corlettk Jun 05 '11 at 07:03
1

That's a really good question, IMHO... one I asked a couple of years ago on Sun's Java Forums (now basically defunct, thanx to Oracle, the half-witted pack of febrile fiscal fascists).

On the front of bringing order to kaos that is your typical "first cut" of an GUI, Google for Swing MVC. The first article I read on the topic was JavaWorld's "MVC meets Swing". I got lucky, because it explains the PROBLEMS as well as proposes sane solutions (with examples). Read through it, and google yourself for "extended reading" and hit us with any specific questions arrising from that.

On the "simulated user activity" front you've got nothing to worry about really... you need only observe your external conditions, say you detect that a local-file has been updated (for instance) and in turn "raise" a notification to registered listener(s)... the only difference being that in this case you're implementing both the "talker" and the "listener". Swings Listener interface may be re-used for the messaging (or not, at your distretion). Nothing tricky here.

"Raising" an "event" is totally straight forward. Basically you'd just invoke the "EventHappened" method on each of the listeners which is currently registered. The only tricky bit is dealing with "multithreaded-ness" innate to all non-trivial Swing apps... otherwise they'd run like three-legged-dogs, coz the EDT (google it) is constantly off doing everything, instead of just painting and message brokering (i.e. what it was designed for). (As said earlier by Ignis) The SwingUtilies class exposes a couple of handy invoke methods for "raising events" on the EDT.

There's nothing really special about Swing apps... Swing just has a pretty steep learning curve, that's all, especially multithreading... a topic which I had previously avoided like the plague, as "too complicated for a humble brain like mine". Needless to say that turned out to be a baseless fear. Even an old idiot like myself can understand it... it just takes longer, that's all.

Cheers. Keith.

corlettk
  • 13,288
  • 7
  • 38
  • 52
0

This doesn't exactly answer your question, but you might be interested in using Netbeans for Java GUI development. You can use GUI in Netbeans to do Java GUI development.

Here's a good place to get started - http://netbeans.org/kb/trails/matisse.html

Ashish Agarwal
  • 14,555
  • 31
  • 86
  • 125
  • 3
    Not a great recomendation, IMHO. Matisse generates some of the most unreadable (and therefore unmaintainable) code imaginable. It's all (damn) good if your problem fits within Mattisse's constraints, but if you need to paint outside the nine dots for ANY reason (now or in the future) you're stuck with sucking square lemons. – corlettk Jun 05 '11 at 05:42
  • I agree with corlettk. Matise makes it really easy to slap together elements, but the code is generates is ridiculous. I want to post the code here, but it's so verbose and complicated that I'm afraid it will just confuse people. –  Jun 05 '11 at 06:18