1

I have tried to draw a diagram in Swing with a large number (thousands) of JLabels inside a large number of nestled JPanels, all with different layouts.

I made the whole diagram zoomable, zooming one step i use setPrefferedSize() on all of the components in the diagram.

It is also interactive, by clicking at one of the JLabels, the program zooms in on that JLabel. Each JLabel has a tooltip and changes color when hovered over.

The problem is that when the diagram is too large, the zoom is far to slow. There is a for-loop that has to go trough all of the JComponents in the diagram and change their prefered size. Then I have to call .revalidate() on the JComponents parent.

So my questions are:

  1. Instead of using the nestled JPanels with different layouts for the structure, should I only use one JPanel with null Layout and use setBounds() on all of the JLabels to position and zoom in on them? Will it be lighter for the computer?

  2. Should I use another GUI? It has to support the following:

    • Draw rectangular labels with tooltips, can add a mouseListener.
    • Zoomable, can scale the whole diagram
    • Can draw text in the diagram.
    • Scrollable, can add the diagram to a JScrollPane (important when zooming in)
user1506145
  • 5,176
  • 11
  • 46
  • 75
  • Well, I think your application will suffer serious performance problem. Tooooo many components. – Mohayemin Jul 18 '12 at 07:59
  • The scrolling works fine and is super-fast, its just that the zoom is to slow. I dont think using setPreffered size is that good. – user1506145 Jul 18 '12 at 08:04
  • Yes, but the links on the questions refering to JXLayer are dead http://stackoverflow.com/questions/2955000/zoom-a-jpanel-and-all-of-its-components I couldn't find any tutorial on the internet. – user1506145 Jul 18 '12 at 08:19
  • null layout is _never_ a solution, as well as setPref _never_ is the solution. Whatever you do manually in locating/sizing, should be factored out into a LayoutManager. For guidance, have a look into the JUNG project (http://jung.sourceforge.net/) - they have a bunch of highly specialized managers for visualizing networks – kleopatra Jul 18 '12 at 09:00

1 Answers1

2

You could forget the individual JLabels and just draw your text items in the paintComponent method of the main JPanel.
You can use drawString to draw the items of text.
Also, you can keep a "zoom level" value and draw the strings at different positions/sizes depending on that zoom level.

If I were you I'd knock up a quick example of this to draw a few thousand strings, and see if that's fast enough on your target spec client machine.

EDIT: Something like this:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

/**
 * TestPaintComponentZooming
 * 
 * @author davidf
 */
public class TestPaintComponentZooming {
    private JFrame f;
    private JPanel panel;
    private double zoom = 1.0;

    public static void main(String[] args) {
        TestPaintComponentZooming t = new TestPaintComponentZooming();
        t.init();
    }

    public TestPaintComponentZooming() {
    }

    public void init() {
        JButton b = new JButton();
        b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 10));
        panel = new _JPanel();
        panel.add(b);
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "Center");
        f.add(getCheckBoxPanel(), "South");
        f.setLocation(200, 200);
        f.setSize(400, 400);
        f.validate();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        JButton zoomIn = new JButton("Zoom in");
        zoomIn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                zoomAndRepaint(0.1);
            }
        });
        JButton zoomOut = new JButton("Zoom out");
        zoomOut.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                zoomAndRepaint(-0.1);
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(zoomIn);
        panel2.add(zoomOut);
        return panel2;
    }

    /**
     * zoomAndRepaint
     */
    protected void zoomAndRepaint(double d) {
        zoom += d;
        f.repaint();
    }

    private class _JPanel extends JPanel {

        public _JPanel() {
            super(null);
        }

        /**
         * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
         */
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);


            g.setFont(new Font("Arial", Font.PLAIN, (int) (zoom * 10 + 2)));
            for (int x=0; x < 100; x++) {
                for (int y=0; y < 100; y++) {
                    g.drawString("Hello " + x + "," + y, (int) (x * 60 * zoom), (int) (y * 10 * zoom));                    
                }
            }
        }
    }
}
davidfrancis
  • 3,734
  • 2
  • 24
  • 21
  • I managed to do it, is it more lightweight to use a JPanel than a JLabel? How to scale it when I want to zoom? – user1506145 Jul 18 '12 at 08:27
  • Also if override paintComponent I the backgroundcolor is reseted. – user1506145 Jul 18 '12 at 08:38
  • See my answer EDIT for some sample code - not sure about the background colour, you can probably just paint that yourself! – davidfrancis Jul 18 '12 at 08:50
  • For background colour, it gets painted OK [by the JPanel UI ie ComponentUI.update]. Just set a background colour in the _JPanel constructor in the example code and it works fine – davidfrancis Jul 18 '12 at 08:55
  • In this case you have 10 000 texts drawed in a JPanel. But what if I want to hover over the text and make it show a tooltip? And besides I also tested to paint out 10000 JLabels and there is not much difference in speed. – user1506145 Jul 18 '12 at 10:18
  • Yes you'd have to do all the extra bits like hit testing and tooltips yourself. Best thing would be to post your original code that you're having problems with - you could edit your question and include a self contained example – davidfrancis Jul 18 '12 at 11:09