简体   繁体   English

使用Java Swing和AWT的完全相同的代码的不同输出

[英]Different Output for Exactly Same Code Using Java Swing and AWT

I am a newbie in swing and awt. 我是秋千和新手的新手。 I was implementing Huffman Tree in GUI. 我正在GUI中实现霍夫曼树。 But in the code I written the output is very strange in Ubuntu(JAVA 8). 但是在我编写的代码中,输出在Ubuntu(JAVA 8)中非常奇怪。 Sometimes it prints the tree (haphazardly though) sometimes the window remains blank. 有时它会打印树(尽管有可能),有时窗口仍为空白。 The function paintComponent is being called for different times for different run. 对于不同的运行,函数paintComponent的调用时间不同。 The code is same, no user input but for different run the result is different. 代码是相同的,没有用户输入,但是对于不同的运行,结果是不同的。 Please run the code for at least 5 times to see what I said. 请运行该代码至少5次,以查看我所说的内容。 Can anyone help me to get out of this problem? 谁能帮助我摆脱这个问题?
NB You can directly jump to the Huffman class. 注意:您可以直接跳到Huffman课程。

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.io.*;
import java.util.*;

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

class Node implements Comparable<Node> {
    private  char ch;
    private  int freq;
    private  Node left, right;
    private int x,y ;

    Node(char ch, int freq, Node l, Node r) {
        this.ch = ch;
        this.freq = freq;
        left = l;
        right = r;
    }

    public boolean isLeaf(){
        return (left == null) && (right == null);
    }

    public int compareTo(Node that) {
        return Integer.compare(this.freq,that.freq);
    }

    public Node getLeft(){
        return left;
    }

    public Node getRight(){
        return right;
    }

    public int getFreq(){
        return freq;
    }

    public char getCharacter(){
        return ch;
    }

    public void setPosition(int ht, int wd){
        x=wd; y=ht;
    }

    public int getX(){
        return x;
    }

    public int getY(){
        return y;
    }

    public String getString(){
        if(isLeaf()) return new String((Integer.toString(freq) + ' ' + ch));
        else return new String(Integer.toString(freq));
    }
}

public class Huffman extends JPanel{
    int height=0;
    String str;
    int[] freq = new int[256];
    Node root;
    Queue<Node> q = new LinkedList<Node>();

    static final private int LEFT = 5;
    static final private int RIGHT = 1300;
    static final private int TOP = 5;
    static final private int BOTTOM = 700;
    static final private int RADIUS = 15;

    public Huffman(){
        getStr();
        setFrequency();
        buildTree();
    }

    public void getStr(){
        //Scanner sc = new Scanner(System.in);
        //str = sc.nextLine();
        str = new String("What is happening?");
    }

    public void setFrequency(){
        for(int i=0;i<str.length();i++) freq[str.charAt(i)]++;
    }

    public void buildTree(){
        PriorityQueue<Node> PQueue = new PriorityQueue<Node>();
        for(int i=0;i<256;i++){
            if(freq[i]!=0){
                PQueue.add(new Node((char)i, freq[i], null, null));
            }
        }

        while(PQueue.size()>1){
            Node left, right;
            left = PQueue.poll();
            right = PQueue.poll();
            PQueue.add(new Node('\0',left.getFreq()+right.getFreq(),left,right));
            q.add(left);
            q.add(right);
        }
        root = PQueue.poll();
        q.add(root);
        setCoOrdinates(root,1,1);
    }

    public void setCoOrdinates(Node node, int wd, int ht){
        if(node == null) return;
        height = Math.max(height,ht);
        node.setPosition(wd,ht);
        setCoOrdinates(node.getLeft(),2*wd-1,ht+1);
        setCoOrdinates(node.getRight(),2*wd,ht+1);
    }

    public int getGraphicsX(int x, int y){
        return ((RIGHT-LEFT)/((int)Math.pow(2,y-1)+1))*x + LEFT;
    }

    public int getGraphicsY(int x, int y){
        return ((BOTTOM-TOP)/(height+1))*y + TOP;
    }

    @Override
    public void paintComponent(Graphics g){

        //this '*' is printing for multiple times
        System.out.println("*");

        while(q.isEmpty()==false){

            Node node = q.poll();

            int x = getGraphicsX(node.getX(),node.getY()), y = getGraphicsY(node.getX(),node.getY());

            String str = node.getString();

            g.drawOval(x-RADIUS,y-RADIUS,2*RADIUS,2*RADIUS);
            g.drawString(str,x,y+(RADIUS/2));

            if(node.isLeaf()==false){
                int leftX,leftY,rightX,rightY;

                leftX = getGraphicsX(node.getLeft().getX(), node.getLeft().getY());
                leftY = getGraphicsY(node.getLeft().getX(), node.getLeft().getY());

                rightX = getGraphicsX(node.getRight().getX(), node.getRight().getY());
                rightY = getGraphicsY(node.getRight().getX(), node.getRight().getY());

                g.drawLine(x, y+RADIUS, leftX, leftY-RADIUS);
                g.drawLine(x, y+RADIUS, rightX, rightY-RADIUS);

            }
        }
    }

    public static void main(String[] args) {

        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(RIGHT,BOTTOM);
        Huffman h = new Huffman();

        jFrame.add(h);
        jFrame.setVisible(true);

    }
}
@Override
public void paintComponent(Graphics g){
    ...
    while(q.isEmpty()==false){

        Node node = q.poll();

The problem is that you're modifying the queue inside paintComponent . 问题在于您正在修改paintComponent内的队列。 The UI system can call paintComponent any time that it wants to, for example dragging another window over the panel will cause repaints. UI系统可以在需要时随时调用paintComponent ,例如,在面板上拖动另一个窗口将导致重新绘制。

paintComponent should therefore be stateless and not modify the queue. 因此paintComponent应该是无状态的,并且不能修改队列。

If your use of poll is absolutely necessary, one simple solution is to copy the queue: 如果绝对需要使用poll ,则一种简单的解决方案是复制队列:

@Override
public void paintComponent(Graphics g){
    Queue<Node> q = new LinkedList<>(this.q);

Seems like you could also just iterate with a for-each loop. 似乎您也可以通过for-each循环进行迭代。


Few other things: 其他几件事:

  • Your code in main where you create the GUI needs to be wrapped inside a call to SwingUtilities.invokeLater : 您创建GUI的main代码需要包装在对SwingUtilities.invokeLater的调用中:

     public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // create the GUI here } }); } 

    This is because Swing is single-threaded and not thread-safe. 这是因为Swing是单线程而不是线程安全的。 See Initial Threads . 请参阅初始线程

  • You should call super.paintComponent , which paints the JPanel (background color, etc.): 您应该调用super.paintComponent ,它绘制JPanel (背景颜色等):

     @Override protected void paintComponent(Graphics g) { super.paintComponent(g); 
  • As shown in the previous code snippet, paintComponent is a protected method and there's no reason to make it public . 如前面的代码片段所示, paintComponent是一种protected方法,没有理由将其public

  • You shouldn't use setSize on a JFrame . 您不应该在JFrame上使用setSize If you want the frame to be a fixed size, you should override getPreferredSize() on the JPanel , then call pack() on the frame. 如果希望框架为固定大小,则应在JPanel上重写getPreferredSize() ,然后在框架上调用pack() The frame will size itself automatically around the panel inside it. 框架将自动围绕其内部面板调整大小。 (Example shown here .) The size of a JFrame includes eg title bar and borders so using setSize probably also interferes with your painting coordinates. 此处显示示例。) JFrame的大小包括例如标题栏和边框,因此使用setSize可能还会干扰您的绘画坐标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM