java – 在某些情况下不会显示Swing应用程序
作者:互联网
我正在编写一个实用程序来帮助测试更大的系统,如果我在系统中运行它,我的UI根本就不显示.我自己运行时工作正常.更多细节:
>我正在测试的系统有许多进程,由控制器管理.部署后,controller.exe会生成并终止子进程,包括我的java应用程序.当由控制器启动时,我的应用程序运行良好(工作,生成日志等)但Swing UI根本不渲染.
>我可以从命令行自己启动我的应用程序,UI显示就好了.根据Process Explorer,Path,Command Line和Current Directory都与从控制器启动应用程序时观察到的值相同.
>当应用程序无法访问时,单击Process Explorer中的“Bring to Front”会弹出一个对话框. “这个过程找不到可见的窗户.”单击手动生成的进程上的相同按钮可将Swing UI按预期方式显示在前面.
>我在Windows XP中测试它.控制器进程在SYSTEM下运行.我使用“at 09:45 /interactive cmd.exe” trick为我的手动启动生成一个命令提示符作为SYSTEM. Process Explorer验证两个方法(手动/控制器)将java进程生成为SYSTEM.
>这两个过程之间唯一明显的区别是父母.系统进程作为controller.exe的子进程生成,而我的手动执行是cmd.exe的子进程.
>我使用jdwp远程调试到隐形进程,一切看起来都很正常. UI代码执行,不会抛出异常,我的JLists甚至会填充他们监视的数据.据我所知,一切正常;我只是看不到任何一个.
如果在其他地方已经回答,我道歉.我尽力搜索,但我能找到的所有问题都是关于某些组件无法渲染,而不是整个应用程序无法显示.
谢谢!
编辑:
根据反馈,我换了一个尽可能小的演示程序.这是整个代码:
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);
}
});
}
}
从命令行运行它会按预期显示窗口.但是,当控制器生成进程时,不会显示任何内容.当由控制器生成时,我可以使用-agentlib远程调试进程:jdwp = transport = dt_socket,suspend = y,server = y,address = 8000并验证所有线程是否按预期生成,并且没有异常被扔了.
我的直觉来自于控制器处于一些奇怪的图形配置中,并且由于父进程是新的java进程,也许Swing没有使用正确的GraphicsDevice?我尝试添加此代码:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for(GraphicsDevice d : ge.getScreenDevices())
{
Log.println(d);
for (GraphicsConfiguration c : d.getConfigurations())
{
Log.println(c);
Log.println(c.getBounds());
}
}
日志包含:
Win32GraphicsDevice[screen=0]
sun.awt.Win32GraphicsConfig@13f459d[dev=Win32GraphicsDevice[screen=0],pixfmt=0]
java.awt.Rectangle[x=0,y=0,width=1920,height=1080]
这似乎表明只有一个设备有一个配置,所以我有点不知所措.
解决方法:
你有一个Concurency in Swing问题.Swing是单线程的,所有输出到Swing GUI必须在EDT上完成.
>基本上你可以通过在invokeLater或invokeAndWait中将输出包装到GUI来解决这个问题
>正确的方法是从SwingWorker或Runnable #Thread调用后台任务(在Runnable中,输出必须包装到invokeLater或invokeAndWait中)
编辑
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:
功能测试返回
来自HP Elite,WinXp,Java6,低调GPU
标签:java,swing,windows-xp 来源: https://codeday.me/bug/20190729/1574309.html