I have an extended JPanel class called GridPanel. It lets you drag and drop images into it from a JList. The GridPanel lets you drag the images around with the mouse and rearrange them as you want. What I'm interested in is making a thumbnail view of the GridPanel component.

If I understand correctly, setting a JScrollPane's view to be GridPanel makes GridPanel a child of a JViewPort, which becomes a child of the JScrollPane. Currently GridPanel is already set to be the view of a JScrollPane and I'm pretty sure GridPanel can't have two parents. So I can't have two components share the same view, but I really only need the thumbnail view to paint a scaled visual copy of GridPanel.

This leads to my question. Is it possible to copy what GridPanel paints, but paint it on a completely separate component?

This is an example of what I've tried, in case I'm not being understood.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class TestMain {
public static void main(String[] a) {
    Color[] colors = new Color[]{Color.green, Color.red, Color.blue, Color.yellow};


    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationByPlatform(true);
    JPanel content = new JPanel();
    frame.setContentPane(content);
    content.setLayout(new FlowLayout());
    //using variable names to try and help relate to my question
    final JPanel gridPanel = new JPanel();
    gridPanel.setPreferredSize(new Dimension(200,200));
    gridPanel.setLayout(new GridLayout(2, 2));
    JLabel label;
    for (Color c: colors){
        label = new JLabel();
        label.setOpaque(true);
        label.setBackground(c);
        gridPanel.add(label);
    }

    JScrollPane gridScroll = new JScrollPane(gridPanel);

    final JScrollPane thumbnailScroll = new JScrollPane();
    thumbnailScroll.setPreferredSize(new Dimension(200,200));

    JButton tryThumbnailView = new JButton("Activate Thumbnail");
    tryThumbnailView.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent arg0) {
            thumbnailScroll.setViewportView(gridPanel);
            frame.repaint();

        }
    });
    content.add(tryThumbnailView);

    content.add(gridScroll);
    content.add(thumbnailScroll);

    frame.pack();
    frame.setVisible(true);
    }
}

What I would like to have happen is for both components to show the same set of colored JLabels, without duplicating those JLabels.

有帮助吗?

解决方案

All you have to do is "get rendering result" of one component and reuse it. That takes:

  1. intercept rendering process - override paint(Graphics) method
  2. create own image to render to
  3. render your image to original graphics
  4. render your image to other component - override paint(Graphics) method

First three steps can be done like this:

@Override
public void paint(Graphics originalGraphics) {
  GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsConfiguration c = e.getDefaultScreenDevice().getDefaultConfiguration();
  //create own image to paint to
  BufferedImage image = c.createCompatibleImage(getWidth(), getHeight());
  Graphics2D reusableGraphics = image.createGraphics();
  //let it paint into our graphics
  super.paint(reusableGraphics);
  // draw image on this component
  originalGraphics.drawImage(image, 0, 0, null);
  // draw image on other component
  otherComponent.setMirrorImage(image);
}

In otherComponent you have to save image and paint it when required:

@Override
public void paint(Graphics g) {
  if (mirroredImage == null) {
    super.paintAll(g);
  } else {
    g.drawImage(mirroredImage, 0, 0, getWidth() * 3 / 4, getHeight() * 3 / 4, null);
  }
}
public void setMirrorImage(BufferedImage mirroredImage) {
  this.mirroredImage = mirroredImage;
  repaint();
}

You can take a look here for full example

其他提示

You can override paintComponent like this:

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.scale(scaleFactor, scaleFactor);
    gridPanel.paintComponenet(g);
}

This assumes that gridPanel either overrides paintComponent as public or this class has to be in the same package as GridPanel.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top