I want to draw a tree in Jframe, the tree view is available in the attachment,

As you see there are nodes connecting to each other.I know that I have to find the midpoint of the nodes at the same level or things like that.

What I want your help is which components Should I use?
the necessities are:
No third parties,just using swing,
a node can be clicked to add or remove node,when clicked a textbox will be opened and the user will enter name of node,and if the tree gets bigger and doesnt fit the window the window will be able to expand.

Some says that I must use JScrollpane for window.But I dont have a main idea!


Is there anyone who can help me?

Attachments Untitled-1.jpg 22.19 KB

Just use JLabels for the nodes and override paintComponent() on your panel to render the lines between them.

I have created a JFrame frame and a Jpanel panel,
then I added the panel to frame.

I have overriden paintComponent method in my panel.
Now,do I have to call paintComponent method on Jpanel object?
Because it shows nothing but the background.

paintComponent() is called automatically when your component needs to be rendered. If you haven't put anything on the panel then it's showing you exactly what is there: nothing.

no,of course I put my drawing function in paintComponent! but it doesnt show anything!

As far as I see,there is no probelm with Jpanel or Jframe,maybe my drawing method in overriden paintComponent method can be the problem.But I cannot debug,because debeugger does not enter paintComponent,although I put breakpoint inside it...

I am using eclipse 3.4.1,please help me..

I don't use Eclipse, but it's debugger should enter paintComponent() just fine.

I'd recommend starting with one of the basic drawing examples from the 2D tutorial that I linked above and then modifying the drawing code to draw the lines you want. Once you understand the rendering process of the components and the use of the Graphic2D class more clearly you'll be in better shape to apply that to your specific application needs.

I don't use Eclipse, but it's debugger should enter paintComponent() just fine.

I'd recommend starting with one of the basic drawing examples from the 2D tutorial that I linked above and then modifying the drawing code to draw the lines you want. Once you understand the rendering process of the components and the use of the Graphic2D class more clearly you'll be in better shape to apply that to your specific application needs.

Is there any way for panel to draw without overriding paintComponent method?Can I put my method just in Jpanel and then call it?

now,I found the problem,its not about the overriden method!

now there is something new,
You suggested me to use Jlabels ,but I used drawRectangle to draw nodes.Can these nodes(shapes) be clickable? Or do I have to use Jlabels?

Call it how? It needs a graphic context, which is supplied by the paintComponent() method when the component is rendered to the screen.

Edit: Cross-post. I'm referring to the previous question on calling the method yourself.

now,I found the problem,its not about the overriden method!

now there is something new,
You suggested me to use Jlabels ,but I used drawRectangle to draw nodes.Can these nodes(shapes) be clickable? Or do I have to use Jlabels?

Yes, you can simply draw the rectangles yourself, but then you will need to manage any interactions with them yourself as well. That would include things like keeping track of their bounds within the screen, determining mouse-over, rendering the text within them, etc. Using a JLabel saves you all of that work.

Yes, you can simply draw the rectangles yourself, but then you will need to manage any interactions with them yourself as well. That would include things like keeping track of their bounds within the screen, determining mouse-over, rendering the text within them, etc. Using a JLabel saves you all of that work.

thank you very much,I will try Jlabels...

Here's a small example that should give you plenty to play around with:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

public class PaintNodes extends JFrame {

    private NodeLabel node1;
    private NodeLabel node2;
    private JPanel paintPanel;

    public PaintNodes() {
        initComponents();
    }

    private void paintNodeConnections(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        // draw line between right connection point of node1
        // and the left connection point of node2
        Point p1 = node1.getConnectionPoint("RIGHT");
        Point p2 = node2.getConnectionPoint("LEFT");
        g2d.drawLine(p1.x, p1.y, p2.x, p2.y);
    }

    private void initComponents() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setMinimumSize(new Dimension(300, 300));

        // this just overrides the paintComponent() method 
        // of the created panel.
        paintPanel = new  JPanel() {
           public void paintComponent(Graphics g){
                super.paintComponent(g);
                paintNodeConnections(g);
            }
        };

        paintPanel.setLayout(null);

        node1 = new NodeLabel("Node 1");
        node1.setHorizontalAlignment(SwingConstants.CENTER);
        node1.setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
        paintPanel.add(node1);
        node1.setBounds(54, 52, 56, 28);

        node2 = new NodeLabel("Node 2");
        node2.setHorizontalAlignment(SwingConstants.CENTER);
        node2.setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
        paintPanel.add(node2);
        node2.setBounds(186, 52, 56, 28);

        getContentPane().add(paintPanel, BorderLayout.CENTER);

        pack();
    }

    /** Small class to add some additionial behavior for nodes */
    class NodeLabel extends JLabel {

        Map<String, Point> connectionPoints = new HashMap<String, Point>();

        public NodeLabel(String text) {
            super(text);
            addComponentListener(new java.awt.event.ComponentAdapter(){
                 public void componentResized(java.awt.event.ComponentEvent evt) {
                    mapConnectionPoints();
                }
                public void componentMoved(ComponentEvent e) {
                    mapConnectionPoints();
                }
                 
            });
        }
        
        // updates the mapped positions of the connection points
        // called whenever the component get's resized or moved
        private void mapConnectionPoints(){
            connectionPoints.clear();
            Point point = new Point(getX(),getY()+getHeight()/2);
            connectionPoints.put("LEFT", point);

            point = new Point(getX() + getWidth(), getY() + getHeight()/2);
            connectionPoints.put("RIGHT", point);

            point = new Point(getX() + getWidth()/2, getY());
            connectionPoints.put("TOP", point);

            point = new Point(getX() + getWidth()/2, getY() + getHeight());
            connectionPoints.put("BOTTOM", point);
        }

        public Point getConnectionPoint(String key) {
            return connectionPoints.get(key);
        }
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new PaintNodes().setVisible(true);
            }
        });
    }
}

(Sorry for the wraparound on a few lines, but I don't have time here to fix all that. Also, that connection point map really should use an enum for the key instead of a string, but I didn't want to obfuscate the example too much.)

This article has been dead for over six months. Start a new discussion instead.