Graph editor - advice needed

  • Thread starter Dobieslaw Wroblewski
  • Start date
D

Dobieslaw Wroblewski

Hi,

I am writing a graph editor in Swing. It should give a user the possibities
of adding/removal of nodes and edges, a user should be also able to move the
nodes or groups of them.

I am placing the graph on a JPanel. I have two possibilities:

1.
draw all the graph's edges and nodes by myself in JPanel's paintComponent(),

2.
derive the node and edge classes from JComponent, write paintComponent() for
each, add them to the panel and let the Swing do the rest.

I want the code to be pretty simple, yet I would like the editor to be fast,
responsive and not flickering. Which strategy would you recommend?

DW.
 
C

Chris Smith

Dobieslaw said:
I am placing the graph on a JPanel. I have two possibilities:

1.
draw all the graph's edges and nodes by myself in JPanel's paintComponent(),

2.
derive the node and edge classes from JComponent, write paintComponent() for
each, add them to the panel and let the Swing do the rest.

I'd definitely opt for #1. Nodes and edges do not fit the general
description of a GUI component. They are layed out in completely
different ways; and their bounding axis-aligned rectangles are quite
likely to overlap. You'd probably end up fighting *against* the GUI
framework if you tried to shoehorn this application into it.

Flickering is not a problem. Swing components double buffer their
drawing by default.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
D

Dobieslaw Wroblewski

I'd definitely opt for #1.

Well, this is what I started to do, so thank you to confirm my choice :).

Flickering is not a problem. Swing components double buffer their
drawing by default.

Yes, I noticed that.

I've got another question - when the graph edition is finished, I want to
visualise some graph algorithm running on it.

I would like the graph edition (especially selection of nodes) to be enabled
while the algorithm goes, but on the other hand I would like to avoid
repainting the whole graph at each algorithm's step - only some algorithm
status drawings that show on top of the graph. The graph itself should be
repainted only if a user makes edits to it.

I thought of using JLayeredPane or something like the component used in the
tutorial example 'GlassPaneDemo', but on the other hand I want the mouse
events to reach the graph panel. How to do that best?

DW.
 
C

Chris Smith

Dobieslaw said:
I've got another question - when the graph edition is finished, I want to
visualise some graph algorithm running on it.

I would like the graph edition (especially selection of nodes) to be enabled
while the algorithm goes, but on the other hand I would like to avoid
repainting the whole graph at each algorithm's step - only some algorithm
status drawings that show on top of the graph. The graph itself should be
repainted only if a user makes edits to it.

The best way to minimize repainting effort is simply to use versions of
the repaint method that specify a smaller region to repaint. Then, in
your paintComponent method (or paint method, if you're writing in AWT),
you can use g.getClipBounds and only draw those elements of the graph
that appear within the clipping rectangle.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
D

Dobieslaw Wroblewski

The best way to minimize repainting effort is simply to use versions of
the repaint method that specify a smaller region to repaint. Then, in
your paintComponent method (or paint method, if you're writing in AWT),
you can use g.getClipBounds and only draw those elements of the graph
that appear within the clipping rectangle.

I know that, however the bounding rectangle of the graph algorithm related
drawings will be very big in most steps. I found an easier (and better, I
believe) solution. The GraphPane (derived from JPanel) has a BorderLayout,
and I add to its center as a child the AlgorithmPane (derived from
JComponent). The GraphPane takes all the mouse input, and it draws the graph
in its paintComponent() method. The AlgorithmPane gets no user inputs and
just paints the graph algorithm related figures in its paintComponent() - on
top of the surface of the GraphPane.
This seems to work nice, the AlgorithmPane lets the user input go through it
and it is automatically repainted whenever the GraphPane.repaint() is
called.

BTW.
I have not used the 'getClipBounds' optimisation yet, but on the other hand
I am wondering if this makes any sense. I suspect that 'r =
g.getClipBounds()' and then checking the intersection of r with the bounds
of all nodes and edges is very fast compared to repainting all of them, but
on the other hand calculating the bounds of every node is quite complicated
as a node has a variable-length label (so, the call to
Font.getStringBounds(...) is needed in order to estimate the bounds). I have
no idea of how the computation time of Font.getStringBounds(...) compares to
Graphics2D.draw(Ellipse2D.Float). If the complexity is similar (and this is
what I suspect), then the optimisation is not worth the effort :-/.

DW.
 
C

Chris Smith

Dobieslaw said:
Thanks a lot. Have you got any idea where to get the package
'org.apache.xerces.parsers.SAXParser' from? I could no find it using google
:-/.

PMFJI. but http://xml.apache.org/ will do it. Look for Xerces2-J.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Dobieslaw said:
I know that, however the bounding rectangle of the graph algorithm related
drawings will be very big in most steps. I found an easier (and better, I
believe) solution. The GraphPane (derived from JPanel) has a BorderLayout,
and I add to its center as a child the AlgorithmPane (derived from
JComponent). The GraphPane takes all the mouse input, and it draws the graph
in its paintComponent() method. The AlgorithmPane gets no user inputs and
just paints the graph algorithm related figures in its paintComponent() - on
top of the surface of the GraphPane.
This seems to work nice, the AlgorithmPane lets the user input go through it
and it is automatically repainted whenever the GraphPane.repaint() is
called.

It's equally true that, because AlgorithmPane is transparent, GraphPane
is automatically repainted every time AlgorithmPane is repainted. If
your goal is to make your code run faster, then you've failed.

It's interesting that you failed, but didn't notice. Perhaps the
optimizations you are performing are not so important after all. Did
you observe a real performance problem, or are you just assuming that
one will exist? If you're just assuming, then you should stop now and
come back when you have a real problem.
I have not used the 'getClipBounds' optimisation yet, but on the other hand
I am wondering if this makes any sense. I suspect that 'r =
g.getClipBounds()' and then checking the intersection of r with the bounds
of all nodes and edges is very fast compared to repainting all of them, but
on the other hand calculating the bounds of every node is quite complicated
as a node has a variable-length label (so, the call to
Font.getStringBounds(...) is needed in order to estimate the bounds).

If you're concerned about the time it takes to re-layout the component
every time, then the first thing to do is store all of that information
on the location and size of the graph components. For example, you
might keep a HashMap storing the bounds of each graph node and edge.
When you change anything that may affect the layout, such as adding or
removing nodes and edges, changing the font, etc, you'll need to
recalculate the layout. For example:

public class GraphPane extends JPanel
{
private Font font;

private HashMap<Node, Rectangle2D> nodeBounds = null;
private HashMap<Edge, Rectangle2D> edgeBounds = null;

...

protected void paintComponent(Graphics g)
{
super.paintComponent(g);

if ((nodeBounds == null) || (edgeBounds == null))
{
calculateLayout();
}

...
}

private void calculateLayout()
{
...
}

public void setFont(Font f)
{
this.font = f;
nodeBounds = edgeBounds = null;
repaint();
}

...
}

Of course, there are further optimizations you could make here based on
additional information about the layout algorithm. For example, you may
be able to avoid pieces of the layout work if you know they aren't
affected by a change. Once you get6 back to optimization of the
painting code, you could even use quadtrees to avoid walking the entire
list of nodes or edges when repainting, but I seriously doubt you'll get
enough of the graph on one computer screen to justify something that
complex.

So test, identify if there's a problem, and then apply small
optimizations as needed to solve that problem.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
D

Dobieslaw Wroblewski

It's equally true that, because AlgorithmPane is transparent, GraphPane
is automatically repainted every time AlgorithmPane is repainted. If
your goal is to make your code run faster, then you've failed.

Well, in fact I was afraid of it ;-). I hoped however that Swing may keep
somewhere the bitmap for the GraphPane and draw the AlgorithmPane on top of
the cached bitmap (well, in fact this is what I can do manually... ;-). But
I made some debugging and now I see you are right - AlgorithmPane.repaint()
makes the GraphPane repaint, too :-/.
The only advantage is that I have separated the code painting the graph and
painting the algorithm status, but this could be done in many other ways -
anyway I will have to reconsider everything - thanks for your help.

It's interesting that you failed, but didn't notice.

The application is pretty responsive on my machine (Pentium IV 1.8 GHz, 768
MB RAM, ATI Radeon 7500), even when there are more than 100 nodes in the
graph (and this is more than the maximum expected size of the graph, I
think). So, there is no problem on my machine, I just wonder how responsive
will the application be on slower computers, especially laptops (I might
need them e.g. for presentation).

If you're just assuming, then you should stop now and
come back when you have a real problem.

:)

I just cannot stop thinking the way as in the old days, when the graphics
operations were slow :).

If you're concerned about the time it takes to re-layout the component
every time, then the first thing to do is store all of that information
on the location and size of the graph components.

Yes, I thought of it, but according to your advice I will just go on with
what I have - it will not be a big deal to optimise the painting if this
becomes necessary.

Thanks a lot for your help.

DW.
 
D

Dobieslaw Wroblewski

If you are interested, I might send you the source - you will see if this is
responsive on your computer.

DW.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top