我正在尝试通过从文本字段插入其元素来创建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;
}
}
答案 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()。布局管理器将忽略该代码。
修复布局问题后,所有其他建议仍然有效:
paintComponent()
而不是绘画()