首页 > 解决方案 > 为什么打印某些东西(在 Java 中)会改变是否显示 JFrame 的连续实例?

问题描述

我试图基本上 1)创建随机 DFA 和 2)使用 JFrame 一个接一个地显示它们。我已经研究出如何随机创建 DFA,让 GraphViz 负责将它们可视化并将它们保存在 .png 文件中,然后将它们显示在 JFrame 中。DFA 在一个循环中创建,在该循环中displayAutomaton调用一个函数,该函数负责创建 .png 并显示它。

for(int i = 2; i < 10; i++) {
        AutomatonConverter.displayAutomaton(createRandomDFA(i));
        while(AutomatonConverter.jFrameExists) System.out.println("this works");
    }

的代码displayAutomaton如下:

public static void displayAutomaton(Automaton A) {
    // Create the automaton-dependent file name
    String fileName = getAutomatonName(A);
    // Convert the Automaton and save it in a .png
    convertAutomaton(A, fileName);
    
    
    JFrame frame = new JFrame();
    // This static variable is used to determine whether the window
    // has been closed, so that the next iteration in the loop can start
    jFrameExists = true;
    ImageIcon icon = new ImageIcon(fileName);
    JLabel label = new JLabel(icon);
    frame.add(label);
    frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            jFrameExists = false;
            frame.dispose();
        }
    });
    frame.pack();
    frame.setVisible(true);
}

如您所见,我jFrameExists在主循环中使用静态变量来推断窗口是否已关闭,因为我想连续打开自动机的不同图像。为此,我重写了框架的 Window-Listener。这是奇怪的部分:正如您在上面看到的,在显示自动机之后,while 循环询问是否jFrameExists已设置为 false(再次发生,当窗口关闭时)。目前,所有这些都有效. 每个创建的自动机都显示在不同的 JFrame 中,一个接一个,每个新窗口仅在我关闭前一个窗口后打开,这正是我想要的 - 但我显然不想每次都打印“this works”,所以我试图删除这个简单的指令。但是,然后代码不再起作用 - 这样,只显示第一张图像,在我关闭它之后,什么也没有发生。

我尝试简单地在此处结束该行,断言 true ( while(AutomatonConverter.jFrameExists) assert true;),并创建空的 void 方法来放置此处 ( while(AutomatonConverter.jFrameExists) doNothing();),但没有任何工作正常 - 再次,这种方式只显示第一张图像,并且循环似乎不会继续下一个自动机。我只是想不通为什么。有人知道吗?

编辑:这是我的代码的通用版本,希望更容易理解(忽略 convertAutomaton 和 createRandomDFA 中的代码,为了完整起见,我只是添加了它):

    public class main {
    static boolean jFrameExists = false;

    public static void convertAutomaton(Automaton A, String fileName) {
        // Creates a png of the automaton A and saves it under the fileName
        GraphViz gv = new GraphViz();
    gv.addln(gv.start_graph());
    gv.addln("rankdir=LR;");
    String startName;
    String shape;
    
    if(A instanceof DFA) {
        
        // Create the starting node
        State q0 = ((DFA) A).getQ0();
        startName = "\"" + q0.getName() + "start\"";
        shape = A.getF().contains(q0) ? "doublecircle" : "circle";
        // Add the node itself...
        gv.addln("node [shape = " + shape + "]; \"" + q0.getName() +"\";");
        // ... and its corresponding entry arrow
        gv.addln("node [shape = point]; " + startName + ";");
        gv.addln(startName + " -> \"" + q0.getName() + "\"");
        
        // Create all accepting nodes
        for(State s : A.getF()) {
            if(!((DFA) A).getQ0().equals(s)) gv.addln("node [shape = doublecircle]; \"" + s.getName() +"\";");
        }
        
    } else {
        
        // Create all starting nodes
        for(State s : ((NFA) A).getQ0()) {
            startName = "\"" + s.getName() + "start\"";
            shape = A.getF().contains(s) ? "doublecircle" : "circle";
            // Add the node itself...
            gv.addln("node [shape = " + shape + "]; \"" + s.getName() +"\";");
            // ... and its corresponding entry arrow
            gv.addln("node [shape = point]; " + startName + ";");
            gv.addln(startName + " -> \"" + s.getName() + "\"");
        }
        
        
        // Create all accepting nodes
        for(State s : A.getF()) {
            if(!((NFA) A).getQ0().contains(s)) gv.addln("node [shape = doublecircle]; \"" + s.getName() +"\";");
        }
    }
    
    gv.addln("node [shape = circle];");
    
    // Create all transitions
    ArrayList<State> reachable;
    String sName, s2Name;
    for(State s : A.getStates()) {
        for(char c : Automaton.alphabet) {
            sName = "\"" + s.getName() + "\"";
            reachable = s.delta(c);
            for(State s2 : reachable) {
                s2Name = "\"" + s2.getName() + "\"";
                gv.addln(sName + " -> " + s2Name + " [ label = \"" + c + "\" ];");
            }
        }
    }
    
    gv.add(gv.end_graph());
    File out = new File(fileName);
    gv.writeGraphToFile(gv.getGraph(gv.getDotSource(), type), out );
}
    }

    public static void displayAutomaton(Automaton A) {
        String fileName = "automaton.png"
        convertAutomaton(A, fileName);
        JFrame frame = new JFrame();
        jFrameExists = true;
        ImageIcon icon = new ImageIcon(fileName);
        JLabel label = new JLabel(icon);
        frame.add(label);
        frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    jFrameExists = false;
                    frame.dispose();
            }
            });
        frame.pack();
        frame.setVisible(true);
    }

    public static Automaton createRandomDFA(int numberOfStates) {
       // Create the states
    ArrayList<State> states = new ArrayList<State>();
    for(int i = 0; i < length; i++) states.add(new State(Integer.toString(i)));
    
    // Create random transitions
    Random r = new Random();
    State rState;
    for(State s : states) for(char c : Automaton.alphabet) {
        rState = states.get(r.nextInt(length));
        s.addTransition(c, rState);
    }
    
    // Create random accepting states
    ArrayList<State> F = new ArrayList<State>();
    for(State s : states) {
        if(r.nextInt(length) == length - 1) F.add(s);
    }
    if(F.size() == 0) F.add(states.get(r.nextInt(length)));
    
    // Create random starting state
    State q0 = states.get(r.nextInt(length));
    
    return new DFA(states, q0, F);
}
    }

    public static void main(String[] args) {
        
        for(int i = 2; i < 10; i++) {
            displayAutomaton(createRandomDFA(i));
            while(jFrameExists) System.out.println("waiting until the window is closed");
        }
    }
}

基本上就是这样。我知道不在它自己的类中实现所有可视化内容并简单地关闭窗口而不是添加处理我想要的功能的按钮很奇怪,但从长远来看,我基本上不想可视化任何东西,这只是应该测试自动机是否正确创建。将来我会尝试更符合编码标准的不同方法,但我仍然很想知道为什么调用会有所作为System.out.println()

标签: javaswingjframedfasystem.out

解决方案


推荐阅读