简体   繁体   English

重绘方法不起作用

[英]Repaint method does not work

I'm trying creating an AVL tree by inserting its elements from text field, and then draw the tree by pressing on button "draw". 我正在尝试通过从文本字段插入其元素来创建AVL树,然后通过按“绘制”按钮来绘制树。 My problem is that when I store random elements in the tree in the main and run the program the paint method works fine and the tree painted on the frame, but when I use text field to insert the elements and call repaint method in the actionPerformed method for draw button it does not paint anything. 我的问题是,当我将随机元素存储在主树中并运行程序时,paint方法可以正常工作,并且树可以在框架上绘制,但是当我使用文本字段插入元素并在actionPerformed方法中调用repaint方法时对于绘制按钮,它不会绘制任何内容。 Can someone help me to know what is wrong in the actionPerformed method for draw button and why repaint method does not respond. 有人可以帮我知道绘制按钮的actionPerformed方法中出了什么问题以及为什么重新绘制方法没有响应。

This is my first panel which contains all components 这是我的第一个面板,其中包含所有组件

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;
}

} }

This is the demo class 这是演示班

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();
}}

This class is used to paint the tree on panel and it works fine. 此类用于在面板上绘制树,并且效果很好。 You do not need to go through it 您不需要通过它

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;
}
}

All JPanels require to be revalidated before being repainted, or else nothing would change. 所有JPanel都需要在重新粉刷之前重新验证,否则将保持不变。

Revalidating marks the panel as changed so it would be considered for repainting. 重新验证会将面板标记为已更改,因此可以考虑对其进行重新粉刷。

So here would be the code which does that: 因此,这将是执行此操作的代码:

treeCanvas.revalidate(); //revalidate first. 

treeCanvas.repaint(); //then repaint.

(they have to be revalidated because they are marked as valid right after being first painted, and revalidating it marks it as invalid so it can be repainted) (必须重新验证它们,因为它们在第一次绘制后就被标记为有效,并且重新验证它会将其标记为无效,以便可以重新绘制)

My problem is that when I store random elements in the tree in the main and run the program the paint method works fine and the tree painted on the frame 我的问题是,当我将随机元素存储在主树中并运行程序时,paint方法可以正常工作,而树在框架上绘制

I don't know how the code works. 我不知道代码是如何工作的。 All you do is: 您要做的就是:

TreeCanvas b =new TreeCanvas();
b.setRoot(t.getRoot());

So that creates a panel, but I don't see where you add the panel to the frame anywhere. 这样就创建了一个面板,但是我看不到将面板添加到框架的任何位置。

Anyway, I would say your problem is with layout managers. 无论如何,我会说您的问题出在布局管理器上。 All the classes you create extend JPanel which by default use a FlowLayout . 您创建的所有类都扩展了JPanel,默认情况下使用FlowLayout In some of the code you then just add components to the panel so the layout manager will then determine the size/location of the components based on the "preferred size" of the components. 然后,在某些代码中,您只需将组件添加到面板中,这样布局管理器便可以根据组件的“首选大小”来确定组件的大小/位置。

The problem is that your TreePanel class has a preferred size of 0, to there is nothing to paint. 问题是您的TreePanel类的首选大小为0,因此没有任何内容可以绘制。 You need to override the getPreferredSize() method of the class to return the size of the panel so the layout managers can work properly. 您需要重写该类的getPreferredSize()方法以返回面板的大小,以便布局管理器可以正常工作。 Do not attempt to be using setBounds() in your code. 不要尝试在代码中使用setBounds()。 The layout manager will ignore that code. 布局管理器将忽略该代码。

Once you fix the layout issue then all the other suggestions are still valid: 解决布局问题后,所有其他建议仍然有效:

  1. override paintComponent() not paint() 覆盖paintComponent()而不是paint()
  2. invoke revalidate() and repaint() after updating the tree 更新树后调用revalidate()和repaint()

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

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