问题
As a succession to this post I'm running into an infinite loop that causes my computer to crash. Or, well, not quite: it seems to cause the Java window (JFrame) to keep getting focus/getting iconified and normalized infinitely. As such do not try to run the code as is. The program won't allow you to shut it down, nor can you do so via task manager.
I have given a complete code example, that you can run - as is often advised. As it's a stripped-down version of an actual program, some code may seem redundant (especially the methods in the middle). The methods that are of importance are: the topmost (the constructor), and the two last ones. I'm guessing something is going wrong with the constructor and/or the refresh
method.
As Thomas pointed out here, I put all the code in the constructor in a Runnable block, but I guess I did something wrong there.
Of importance is that in the real program, this class doesn't have a main method but I call the Class from another Class, like so:
if(getInstance() == null) {
initOverview(0);
}
The two last window listeners are set so that when a user re-opens the window, its contents are updated.
I've been looking into the documentation, but I can't figure out where my error is. Am I using the Runnable example wrong? Or is it because of the Window Listener and the setExtendedState (to ensure the "opening" of the window) that trigger each other? If so, how could I solve this?
ANOTHER WARNING: DO NOT EXECUTE THIS CODE, IT WILL MAKE YOUR COMPUTER FLIP OUT
import javax.swing.*;
import java.awt.Color;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.awt.BorderLayout;
import java.awt.GridLayout;
public class OverviewTest extends JFrame {
private static final long serialVersionUID = 1L;
private static OverviewTest instance = null;
private static JLabel labelTextOverview;
private static JTabbedPane tabbedPane;
private static JPanel mapPane;
private OverviewTest() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setTitle("Game - Overview");
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setResizable(true);
setBounds(100, 100, 960, 720);
JPanel contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
contentPane.add(tabbedPane);
/* TAB 1: Entity Overview */
labelTextOverview = new JLabel();
labelTextOverview.setText(entityOverviewHTML());
JScrollPane scrollPaneEntityOverview = new JScrollPane(labelTextOverview);
tabbedPane.addTab("Entity overview", null, scrollPaneEntityOverview, null);
/* TAB 2: Map */
mapPane = new JPanel();
mapPane.setLayout(new GridLayout(6, 6, 2, 2));
fillMap();
tabbedPane.addTab("Map", null, mapPane, null);
/* TAB 3: Rules */
JLabel labelRules = new JLabel();
labelRules.setText(rulesHTML());
JScrollPane scrollPaneRules = new JScrollPane(labelRules);
tabbedPane.addTab("Rules", null, scrollPaneRules, null);
// Immediately show window on creation
setVisible(true);
setExtendedState(JFrame.ICONIFIED);
setExtendedState(JFrame.NORMAL);
// Add window listener so that contents get refreshed on window active/focus
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
setVisible(false);
}
@Override
public void windowActivated(WindowEvent e){
refresh(tabbedPane.getSelectedIndex());
}
@Override
public void windowDeiconified(WindowEvent e){
refresh(tabbedPane.getSelectedIndex());
}
});
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
if(getInstance() == null) {
initOverview(0);
}
}
private String rulesHTML() {
StringBuilder sbRules = new StringBuilder();
sbRules.append("<html><body style='padding: 12px;'>");
sbRules.append("<h2>Some text for Rules</h2>");
sbRules.append("<h3>Lorem ipsum</h3>");
sbRules.append("</body></html>");
return sbRules.toString();
}
private static void fillMap() {
mapPane.removeAll();
for (int i = 0; i < 36; i++) {
JLabel textTile = new JLabel(fillTile(i));
JScrollPane tile = new JScrollPane(textTile);
tile.setBorder(BorderFactory.createLineBorder(Color.BLACK));
mapPane.add(tile);
}
}
private static String fillTile(int i) {
StringBuilder sbTile = new StringBuilder();
sbTile.append("<html>");
sbTile.append("some text");
sbTile.append("</html>");
return sbTile.toString();
}
/**
* Reset UI components to system default
*/
public static void initOverview(int index) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
System.err.println(e);
}
instance = new OverviewTest();
tabbedPane.setSelectedIndex(index);
}
public static OverviewTest getInstance() {
return instance;
}
private static String entityOverviewHTML() {
StringBuilder sb = new StringBuilder();
sb.append("<html><body style='padding: 12px;'>");
sb.append("<h2>Some text for Rules</h2>");
sb.append("<h3>Lorem ipsum</h3>");
// Normally a loop that runs over getEntityInfo();
sb.append(getEntityInfo());
sb.append("</body></html>");
return sb.toString();
}
private static StringBuilder getEntityInfo() {
StringBuilder sbInfo = new StringBuilder();
sbInfo.append("this is not a drill, but a test");
return sbInfo;
}
private static void bringToFront() {
getInstance().setVisible(true);
getInstance().setExtendedState(JFrame.ICONIFIED);
getInstance().setExtendedState(JFrame.NORMAL);
}
public static void refresh(int index) {
labelTextOverview.setText(entityOverviewHTML());
fillMap();
tabbedPane.setSelectedIndex(index);
getInstance().repaint();
bringToFront();
}
}
回答1:
I'm not entirely sure why you are invoking both
getInstance().setExtendedState(JFrame.ICONIFIED);
getInstance().setExtendedState(JFrame.NORMAL);
but if you remove the first, i.e. simply:
getInstance().setExtendedState(JFrame.NORMAL);
then it just opens the window once, without the infinite looping you describe.
The reason your code causes an infinite loop is that it minimizes and then unminimizes the frame, which results in the windowActivated
method being run: this invokes the refresh
method, which invokes the bringToFront
method, which minimizes and unminimizes the frame etc.
To actually bring the window to the front, the following works for me, based upon this question:
private static void bringToFront() {
getInstance().setVisible(true);
getInstance().setExtendedState(JFrame.NORMAL);
getInstance().toFront();
getInstance().repaint();
}
来源:https://stackoverflow.com/questions/34632187/infinite-disappear-reappear-loop-in-jframe-java