2

I am developing a GUI with a JTextArea to show certain messages. Two kind of messages might appear here: those written on purpose and intended for the user ("Task completed", "No file found", "Please wait"...) and those for the developer (information about exceptions, warnings, help messages...).

  • So far, I am considering two options to show information on the JTextArea: use the setText() method, or use System.out.print() and redirect the output stream to the JTextArea.

Which option is better? Why?

  • How can I implement a system to allow the user to select which kind
    of messages are to be showed on the JTextArea? Something like a JComboBox with different options, so the User can select if he/she wants to get just Application Messages, or messages related to the workflow (warnings, exceptions, etc.)
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
capovawi
  • 377
  • 8
  • 21
  • 1
    Have you considered using a logging library? A library like log4j or logback would allow you to write a custom appender to log to a JTextArea. Control over the logging level is also a base feature of the logging libraries. – mael Jul 24 '13 at 08:00
  • Since its related to logging, consider `append()`over `setText()`, `setText()` will simply `replace/override` the previous value of the component concern, whereas the former will add `more` to the previous value. You can try this behaviour, simply by changing `append()` with `setText()` in the working code mentioned in this [answer](http://stackoverflow.com/a/17763395/1057230) – nIcE cOw Jul 24 '13 at 08:43
  • Check my logback solution: http://stackoverflow.com/a/33657637/808901 – Rod Lima Nov 11 '15 at 18:49

2 Answers2

4
  1. I would just use setText(). Using System.out.println() and redirecting to the JTextArea would make things needlessly more complex.
  2. If you have a component that collects messages (which are then displayed by the JTextArea), you could change it so you do not only supply a message but also something like a Category. Depending on the content of the JComboBox, only messages of a certain Category would be displayed inside the JTextArea.

If I may suggest a somewhat different approach: maybe you're using something like Log4J or Logback inside your application to log messages. It might well be able to register a custom appender for your logging framework that redirects to the JTextArea. This approach might be a bit more work to get it running, but it could allow for greater flexibility - and not re-inventing a wheel that already exists.

My two cents on how to do this would be to have something like a FeedbackManager (I just made up the name, so feel free to make up a better name). This FeedbackManager would be a singleton, all classes that use it would refer to the same instance. Whenever you need to present a message to the user, post it to the FeedbackManager, including the Category (see above). When the FeedbackManager receives a Message, it should inform all its listeners that a new message was posted.

When instantiating the JTextArea, register an anonymous listener to the FeedbackManager; when the listener is called, it can check whether the message must be displayed based on the selection of the JComboBox, and if so, append it to the JTextArea.

mthmulders
  • 9,483
  • 4
  • 37
  • 54
  • I am not using any framework to log messages. Could you post some example for beginners of what you propose? I have no experience and that would be awesome ;) – capovawi Jul 24 '13 at 08:04
4

If you don't want use to an extra logging library (if the program is small, or if you have to save space (for example in an applet)...), you can always use the logging in JSE: java.util.logging. If so, you can use a Handler to write to the text component:

final class TextComponentHandler extends Handler {
  @Nonnull private final JTextArea text;
    TextComponentHandler(@Nonnull JTextArea text) {
      this.text = text;
    }
  @Override
  public void publish(LogRecord record) {
    if (isLoggable(record))
      synchronized(text) {
        text.append(getFormatter().format(record));
      }
  }
  @Override
  public void flush() {/**/}
  @Override
  public void close() throws SecurityException {/**/}
}

and add it with:

JTextArea textArea = new JTextArea() {
  @Override
  public void addNotify() {
    super.addNotify();
    for(Handler hh : logger.getHandlers())
      if (hh == h)
        return;
    logger.addHandler(h);
  }
  @Override
  public void removeNotify() {
    super.removeNotify();
    logger.removeHandler(h);
  }
};
Logger logger = Logger.getLogger("my.logger");
Handler h = new TextComponentHandler(textArea);
logger.addHandler(h);
chipukb
  • 213
  • 3
  • 7
  • I liked the approach or the intent, but How good this approach is, I can not comment on that, +1 I hope `addNotify()` can be used in this way – nIcE cOw Jul 25 '13 at 08:47
  • At least it is code that actually works, I use it in production – chipukb Jul 25 '13 at 12:49