简体   繁体   English

是否可以将JComponent及其所有子组件绘制到另一个组件?

[英]Is it possible to paint a JComponent and all its children to another component?

I have an extended JPanel class called GridPanel . 我有一个扩展的JPanel类,称为GridPanel It lets you drag and drop images into it from a JList . 它使您可以将图像从JList拖放到其中。 The GridPanel lets you drag the images around with the mouse and rearrange them as you want. GridPanel允许您用鼠标拖动图像并根据需要重新排列图像。 What I'm interested in is making a thumbnail view of the GridPanel component. 我感兴趣的是制作GridPanel组件的缩略图。

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 . 如果我理解正确,将JScrollPane的视图设置为GridPanel会使GridPanel成为GridPanel的子JViewPort ,而JViewPort成为JScrollPane的子级。 Currently GridPanel is already set to be the view of a JScrollPane and I'm pretty sure GridPanel can't have two parents. 当前, GridPanel已经设置为JScrollPane的视图,我很确定GridPanel不能有两个父级。 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 . 因此,我不能让两个组件共享同一视图,但实际上我只需要缩略图视图即可绘制GridPanel的缩放可视副本。

This leads to my question. 这引出了我的问题。 Is it possible to copy what GridPanel paints, but paint it on a completely separate component? 是否可以复制GridPanel绘制的内容,但将其绘制在完全独立的组件上?

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 . 我希望发生的事情是两个组件都显示同一组彩色的JLabels ,而不必重复这些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 截取渲染过程-覆盖paint(Graphics)方法
  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 将图像渲染到其他组件-覆盖paint(Graphics)方法

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: 在otherComponent中,您必须保存图像并在需要时绘制它:

@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: 您可以像这样重写paintComponent

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 . 假定gridPanel作为public重写paintComponent ,或者此类必须与GridPanel同一包中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM