Reputation: 1657
I'm writing a utility to help with testing a much larger system, and my UI doesn't show up at all if I run it through the system. It works fine when I run it myself. More details:
I apologize if this has been answered elsewhere. I did my best to search around, but all the questions I could find are about certain components failing to render, never a failure of the entire app to display.
Thanks!
Edits: Based on feedback, I've swapped in a demo program that's as small as possible. Here's the entire code:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class AceProbe
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JFrame frame = new JFrame("Visible?");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JLabel("Test"), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
});
}
}
Running this from the command line displays the window as expected. However, when the controller spawns the process, nothing displays. When spawned by the controller, I can debug into the process remotely using -agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address=8000
and verify that all of the threads are spawning as expected, and that no exceptions are thrown.
My intuition from here is that controller is in some odd graphics configuration and, since is parents the new java process, maybe Swing is not using the correct GraphicsDevice? I tried adding this code:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for(GraphicsDevice d : ge.getScreenDevices())
{
Log.println(d);
for (GraphicsConfiguration c : d.getConfigurations())
{
Log.println(c);
Log.println(c.getBounds());
}
}
The log contains this:
Win32GraphicsDevice[screen=0]
sun.awt.Win32GraphicsConfig@13f459d[dev=Win32GraphicsDevice[screen=0],pixfmt=0]
java.awt.Rectangle[x=0,y=0,width=1920,height=1080]
which seems to indicate there's only one device with one config, so I'm at a bit of a loss.
Upvotes: 3
Views: 821
Reputation: 1657
The solution is to split the app into 2 components (data gathering and ui/processing) and have them communicate via RMI.
It turns out that Windows services cannot spawn GUIs. I did some sc query
ing and discovered that controller.exe is a service. Since it parents the java process, java gets the same service permissions, which means no gui. There are some workarounds, but they exist for backwards compatibility and really should be avoided in new code.
It is important to reiterate that java didn't raise any exceptions. It seems like this situation should throw something to indicate that the java process doesn't have permission to create new windows, but the code runs "normally." The window just never appears.
Bottom line: if another process is launching your vm, and you get no errors but no ui, check to make sure your vm isn't launching as a service. If it is, you'll need to extract ui code into a separate process.
Upvotes: 2
Reputation: 109823
You have an issue with Concurency in Swing. Swing is single threaded, and all output to the Swing GUI must be done on EDT.
basically you can solve that by wrapping output to the GUI in invokeLater
or invokeAndWait
correct way would be invoke background task(s) from SwingWorker
or Runnable#Thread
(in Runnable
, output must be wrapped into invokeLater
or invokeAndWait
)
EDIT
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class SSCCE extends JFrame {
private static final long serialVersionUID = 1L;
public SSCCE() {
super("SSCCE");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(createContent());
pack();
centerFrameOnMonitor(0);
setVisible(true);
}
private JComponent createContent() {
JPanel ret = new JPanel();
JButton button = new JButton("I have a tooltip");
button.setToolTipText("I wonder where this tooltip is going to popup!");
ret.add(button);
return ret;
}
/**
* Centers this frame in the middle of the monitor with the monitorIndex specified. This method assumes that all monitors are laid out
* horizontally. The 0th index monitor would be the one furthest left.
* @param monitorIndex
*/
private void centerFrameOnMonitor(int monitorIndex) {
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = e.getScreenDevices();
if (monitorIndex < 0 || monitorIndex >= devices.length) {
throw new RuntimeException("Monitor Index out of bounds: " + monitorIndex);
}
Arrays.sort(devices, new Comparator<GraphicsDevice>() {
@Override
public int compare(GraphicsDevice a, GraphicsDevice b) {
return (int) (a.getDefaultConfiguration().getBounds().getX() - b.getDefaultConfiguration().getBounds().getX());
}
});
GraphicsConfiguration gc = devices[monitorIndex].getDefaultConfiguration();
Rectangle gcBounds = gc.getBounds();
Point p = new Point((int) (gcBounds.getX() + (gcBounds.getWidth() / 2 - this.getWidth() / 2)), (int) (gcBounds.getY() + (gcBounds.getHeight() / 2 - this.getHeight() / 2)));
this.setLocation(p);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SSCCE sSCCE = new SSCCE();
}
});
}
}
EDIT2:
Capabilities Test retuns
from HP Elite, WinXp, Java6, low profile GPU
Upvotes: 5