I'd like to have an application that creates a fixed set of Swing objects like instances of Font
and Color
in a well-defined/central/application-wide location, say GuiFonts.java
and GuiColors.java
, respectively.
In this way, my application can reference things like: GuiFonts.SMALL_FONT
and GuiColors.BACKGROUND
, and I can make changes in one place if I should later decide that "small font" means 8 point, instead of 10 point, or that the background should be #FFEF88
, instead of #AAAAFFF
, for example.
So, how should I write these defaults? In particular, how should I write them to ensure that they are correctly initialized with respect to Swing Event Dispatch Thread (EDT) visibility?
I believe it is correct to create and reference Swing GUI objects on the EDT, and only on the EDT - yes?
So, would something like this be sufficient, or is it somehow insufficient because the code would run on a class loader thread, and not the EDT? Or is it sufficient to run on a non-EDT thread so long as the references are static final
?
import java.awt.Font;
public class GuiFonts {
// not running on EDT, but is it correct anyhow?
public static final Font = new Font(Font.SANS_SERIF, Font.PLAIN, 16);
}
Or, should I ensure that the objects are created on the EDT, perhaps like this:
import java.awt.*;
import java.util.concurrent.*;
import javax.swing.*;
public class GuiFonts {
// intended to run on EDT, but is EDT running yet? In all cases?
public static final Font MEDIUM_FONT = new Callable<Font>() {
@Override
public Font call() {
final RunnableFuture<Font> future = new FutureTask<Font>(new Callable<Font>() {
@Override
public Font call() {
return new Font(Font.SANS_SERIF, Font.PLAIN, 16);
}
});
try {
SwingUtilities.invokeAndWait(future); // Could be invokeLater() because of the Future...
return future.get();
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}.call();
}
Granted, this is verbose, but a lot of it could be packaged into a routine that accepts a Callable
and submits it to the EDT:
public static final Font MEDIUM_FONT = runOnEDT(new Callable<Font>() {
@Override
public Font call() {
return new Font(Font.SANS_SERIF, Font.PLAIN, 16);
}
});
In addition to Swing EDT publication issues, this approach has an error-prone initialization ordering aspect to it if constants reference each other in several files: constants that are not initialized with be null
.
Note that such a routine like runOnEDT
should catch and log all exceptions, in particular, the logging should occur in a catch
clause and NOT in some UncaughtExceptionHandler
because an UncaughtExceptionHandler
is typically already installed on the EDT.
Or, is it preferable that static
initialization be abandoned all together. In favor of some lazy-loading scheme in which objects are represented by enum
constants, and some accessor creates the GUI objects on the Swing EDT upon first reference?