Java 重新绘制方法不起作用

Java 重新绘制方法不起作用,java,swing,graphics,awt,Java,Swing,Graphics,Awt,我正在尝试通过从文本字段插入其元素来创建一个AVL树,然后按draw按钮来绘制树。我的问题是,当我将随机元素存储在主目录树中并运行程序时,绘制方法工作正常,树绘制在框架上,但当我使用文本字段插入元素并调用actionPerformed方法中的repaint方法绘制按钮时,它不会绘制任何内容。 有人能帮我知道draw按钮的actionPerformed方法有什么问题,以及为什么repaint方法没有响应 这是我的第一个包含所有组件的面板 public class PanelComponents e

我正在尝试通过从文本字段插入其元素来创建一个AVL树,然后按draw按钮来绘制树。我的问题是,当我将随机元素存储在主目录树中并运行程序时,绘制方法工作正常,树绘制在框架上,但当我使用文本字段插入元素并调用actionPerformed方法中的repaint方法绘制按钮时,它不会绘制任何内容。 有人能帮我知道draw按钮的actionPerformed方法有什么问题,以及为什么repaint方法没有响应

这是我的第一个包含所有组件的面板

public class PanelComponents extends JPanel {

private JButton insertB;
private JButton drawB;

private JTextField insertTF;
private AvlTree<Integer> avl = new AvlTree<Integer>();// use AVL tree class
private TreeCanvas treeCanvas;

public PanelComponents() {

    setPreferredSize(new Dimension(780, 500));

    insertB = new JButton("insert");
    drawB = new JButton("draw");
    insertTF = new JTextField(7);
    createTreeCanvas();

    insertB.addActionListener(new ActionListener() {

        // here is the event handler
        public void actionPerformed(ActionEvent e) {
                int number = Integer.parseInt(insertTF.getText());
                avl.insert(number);
        }
    });

    drawB.addActionListener(new ActionListener() {

        // here is the event handler
        public void actionPerformed(ActionEvent e) {
            if (avl.isEmpty()) return;
            treeCanvas.setRoot(avl.getRoot());
            treeCanvas.repaint();


        }
    });
    add(insertTF);
    add(insertB);
    add(drawB);
}

private TreeCanvas createTreeCanvas() {
    if (treeCanvas == null) {
        treeCanvas = new TreeCanvas();
        treeCanvas.setBounds(5,5,680,230);
        add(treeCanvas);
    }
    return treeCanvas;
}
}

这是演示课

public class TreeDemo {
public TreeDemo(){
    /**
     * when I use this way of inserting the tree painted 
     */
    //      AvlTree<Integer> t = new AvlTree<Integer>();
   //       t.insert (new Integer(2));
   //       t.insert (new Integer(1));
   //       t.insert (new Integer(4));
   //       t.insert (new Integer(5));
   //       t.insert (new Integer(9));
   //       t.insert (new Integer(3));
   //       t.insert (new Integer(6));
   //       t.insert (new Integer(7));
   //       TreeCanvas b =new TreeCanvas();
   //       b.setRoot(t.getRoot());

            JFrame frame = new JFrame("AVL Tree");
            PanelComponents panel = new PanelComponents();
   //       frame.add(b);  
            frame.add(panel);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            frame.setSize(1000, 700);

}

  public static void main (String[] args){

      new TreeDemo();
}}
该类用于在面板上绘制树,效果良好。你不需要经历它

public class TreeCanvas extends JPanel {

private static final int NODE_WIDTH = 30;
private static final int ROW_GAP = 10;
private AvlNode<Integer> root;

public TreeCanvas() {
    root = null;
}

interface RenderNode {
    public void draw(Graphics g, AvlNode<Integer> parent, Point parentLoc,
            AvlNode<Integer> child, Point childLoc);
}

public void paint(Graphics g) {
    super.paint(g);
    int startX = getWidth() / 2;
    int startY = ROW_GAP + (NODE_WIDTH / 2);
    render(g, null, null, root, new Point(startX, startY), getWidth() / 2,
        new RenderNode() {public void draw(Graphics g, AvlNode<Integer> 
                    parent, Point parentLoc, AvlNode<Integer> child, Point childLoc) {
        if (parent != null) {
        g.setColor(Color.black);
        g.drawLine(parentLoc.x, parentLoc.y, childLoc.x,childLoc.y);
                    }
                }
            });
    render(g, null, null, root, new Point(startX, startY), getWidth() / 2,
        new RenderNode() {
       public void draw(Graphics g, AvlNode<Integer>parent,
                    point parentLoc, AvlNode<Integer> child, Point childLoc) {
                    child.draw(g, childLoc);
                }
            });
}

private void render(Graphics g, AvlNode<Integer> parent, Point parentLoc,
        AvlNode<Integer> child, Point childLoc, int spacing, RenderNode    
         callback) {

    if (child == null)
        return;

    callback.draw(g, parent, parentLoc, child, childLoc);
    int nextY = childLoc.y + (ROW_GAP + NODE_WIDTH);

    render(g, child, childLoc, child.getLeft(), new Point(childLoc.x
            - (spacing / 2), nextY), spacing / 2, callback);
    render(g, child, childLoc, child.getRight(), new Point(childLoc.x
            + (spacing / 2), nextY), spacing / 2, callback);
}

        public void setRoot(AvlNode<Integer> root){
    this.root = root;
}
}

所有JPanel在重新喷漆之前都需要重新验证,否则一切都不会改变

重新验证将面板标记为已更改,以便考虑重新喷漆

下面是实现这一点的代码:

treeCanvas.revalidate(); //revalidate first. 

treeCanvas.repaint(); //then repaint.
它们必须重新验证,因为它们在第一次喷漆后就被标记为有效,重新验证后会将其标记为无效,以便重新喷漆

我的问题是,当我将随机元素存储在主目录树中并运行程序时,绘制方法工作正常,树绘制在框架上

我不知道代码是怎么工作的。你所做的就是:

TreeCanvas b =new TreeCanvas();
b.setRoot(t.getRoot());
这样就创建了一个面板,但我看不到在哪里将面板添加到框架中

不管怎样,我想说你的问题是布局经理。您创建的所有类都扩展了默认使用FlowLayout的JPanel。在某些代码中,您只需将组件添加到面板中,这样布局管理器就会根据组件的首选大小确定组件的大小/位置

问题是您的TreePanel类的首选大小为0,因此没有任何可绘制的内容。您需要重写类的getPreferredSize方法以返回面板的大小,这样布局管理器才能正常工作。不要试图在代码中使用setBounds。布局管理器将忽略该代码

解决布局问题后,所有其他建议仍然有效:

替代绘制组件而不是绘制 在更新树后调用重新验证并重新绘制
不要在自定义绘画中使用绘画,请使用paintComponent。谢谢,我使用了paintComponent,但仍然存在相同的问题。您的渲染代码令人困惑,难以理解。但乍一看,您真的想要if父级吗!=无效的{一旦添加了TreeCanvas并因此已经有了父级,请检查?我的建议是添加简单的system.out.println语句,或使用调试器,以验证方法是否按照您期望的顺序被调用。如果是这样,则代码中存在逻辑错误。实际上,当我使用此代码时,我只是在该状态中放置了b而不是panelnt jframe.addpanel;我非常感谢您的帮助,我重写了getPreferredSize方法,现在它可以正常工作了。谢谢。@user3600270,实际上,当我使用此代码时,我只放了b而不是panel-我们会发布您使用的实际代码,所以我们不需要猜测您在做什么。我重写了getPreferredSize方法,现在它可以正常工作了,那么您应该接受答案,让人们知道问题已经解决。谢谢你的评论