重绘方法不起作用

时间:2014-07-01 12:10:32

标签: java swing graphics awt

我正在尝试通过从文本字段插入其元素来创建AVL树,然后通过按下“绘制”按钮来绘制树。我的问题是,当我在main中的树中存储随机元素并运行程序时,paint方法工作正常,并且框架上绘制了树,但是当我使用文本字段插入元素并在actionPerformed方法中调用repaint方法时对于绘制按钮,它不会绘制任何东西。 有人可以帮我理解actionPerformed方法中绘制按钮的错误以及重绘方法没有响应的原因。

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

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

2 个答案:

答案 0 :(得分:0)

所有JPanel都需要在重新绘制之前重新验证,否则什么都不会改变。

重新验证会将面板标记为已更改,因此会将其视为重新绘制。

所以这就是执行该操作的代码:

treeCanvas.revalidate(); //revalidate first. 

treeCanvas.repaint(); //then repaint.

(它们必须重新验证,因为它们在第一次绘制后被标记为有效,并且重新验证它会将其标记为无效,因此可以重新绘制)

答案 1 :(得分:0)

  

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

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

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

这样就创建了一个面板,但我看不到你在任何地方将面板添加到框架的位置。

无论如何,我会说你的问题是布局管理员。您创建的所有类都扩展了JPanel,默认情况下使用FlowLayout。在某些代码中,您只需将组件添加到面板,然后布局管理器将根据组件的“首选大小”确定组件的大小/位置。

问题是您的TreePanel类的首选大小为0,因此无需绘制任何内容。您需要覆盖类的getPreferredSize()方法以返回面板的大小,以便布局管理器可以正常工作。不要尝试在代码中使用setBounds()。布局管理器将忽略该代码。

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

  1. 覆盖paintComponent()而不是绘画()
  2. 在更新树
  3. 后调用revalidate()和repaint()