【问题标题】:Drawing between 2 images in 1 JPanel在 1 个 JPanel 中的 2 个图像之间绘图
【发布时间】:2011-09-30 09:27:17
【问题描述】:

我想在 2 JScrollPanes 之间画线(左侧的第一个滚动窗格,右侧的第二个)。这些JScrollPanes 包含图像。我想在这两个图像之间画线(使用一些图层,使用一些技巧等)。我尝试了不同的方法,但我失败了。可能吗? (如果没有,我将不得不在一张 JScrollPane 中制作 2 张图片,这不会很好)。

编辑

我想在 2 个图像之间绘制 - 通过组件 - 从图像中获取一些点并在它们之间画线。对于表述不当的问题,我深表歉意。

【问题讨论】:

  • 我相信您需要做的就是在玻璃板上作画。我会尽快编辑我的答案以反映这一点。

标签: java swing jscrollpane draw


【解决方案1】:

为了实现这一点,我相信您需要使用Glass PaneGlass Pane 位于JRootPane 中的所有内容之上并填充整个视图。这个特殊的位置允许两种不同的能力:

  • 拦截鼠标和键盘事件
  • 绘制整个用户界面

我相信您的问题已通过第二种功能解决。以下是一个示例实现,您可以稍后对其进行定制以满足您自己的需求。请注意,我遗漏了很多关于 Glass Pane 的细节,您需要自己研究。

代码

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GlassPaneDemo {
        private static BufferedImage bi;

        public static void main(String[] args){
            try {
                loadImages();

                SwingUtilities.invokeLater(new Runnable(){
                    @Override
                    public void run() {
                        createAndShowGUI();             
                    }
                });
            } catch (IOException e) {
                // handle exception
            }
        }

        private static void loadImages() throws IOException{
            bi = ImageIO.read(new File("src/resources/person.png"));
        }

        private static void createAndShowGUI(){
            final JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
            frame.setGlassPane(new CustomGlassPane());
            frame.getContentPane().add(getButtonPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.getGlassPane().setVisible(true);
            frame.setVisible(true);
        }

        private static final JPanel getButtonPanel(){
            @SuppressWarnings("serial")
            final JPanel panel = new JPanel(){
                @Override
                protected void paintComponent(Graphics g){
                    Graphics gCopy = g.create();

                    gCopy.setColor(Color.BLUE.darker());
                    gCopy.fillRect(0, 0, getWidth(), getHeight());

                    gCopy.dispose();
                }
            };

            final JLabel labelOne = new JLabel();
            labelOne.setIcon(new ImageIcon(bi));
            final JLabel labelTwo = new JLabel();
            labelTwo.setIcon(new ImageIcon(bi));
            panel.add(labelOne);
            panel.add(labelTwo);

            return panel;
        }

        @SuppressWarnings("serial")
        private static class CustomGlassPane extends JComponent{
            private Point p1;
            private Point p2;
            private boolean lineDrawn;

            public CustomGlassPane(){
                addMouseListener(new MouseAdapter(){
                    @Override
                    public void mouseClicked(MouseEvent e){
                        if(p1 == null || lineDrawn){
                            if(lineDrawn){
                                p1 = null;
                                p2 = null;
                                lineDrawn = false;
                            }
                            p1 = e.getPoint();
                        }else{
                            p2 = e.getPoint();
                            repaint(); // not optimal
                            lineDrawn = true;
                        }
                    }
                });

                // Block all other input events
                addMouseMotionListener(new MouseMotionAdapter(){});
                addKeyListener(new KeyAdapter(){});
                addComponentListener(new ComponentAdapter(){
                    @Override
                    public void componentShown(ComponentEvent e){
                        requestFocusInWindow();
                    }
                });
                setFocusTraversalKeysEnabled(false);
            }

            @Override
            protected void paintComponent(Graphics g){
                if(p1 != null && p2 != null){
                    Graphics2D g2 = (Graphics2D) g.create();

                    g2.setRenderingHint(
                            RenderingHints.KEY_ANTIALIASING, 
                            RenderingHints.VALUE_ANTIALIAS_ON);
                    g2.setColor(Color.RED);
                    g2.drawLine((int)p1.getX(), (int)p1.getY(), (int)p2.getX(), (int)p2.getY());

                    g2.dispose();
                }
            }
        }
  }

输出

解释

在本例中,我在每个JLabel 中单击了两个任意点,然后画了一条连接线。

【讨论】:

  • 如果这真的有效......那么我今天学到了一些新东西:D,我认为我们应该在我们的覆盖方法中调用drawChilderen 或类似的东西。 +1
  • 谢谢,但这仅适用于Component,分别连接Component。我需要通过JScrollPane 画线。我从图像中得到了一些点,我想把它们联系起来。此示例不适用于此。
  • @Equo,好的,感谢您的澄清,但请尽量提前明确您的要求!
  • @little bunny foo foo,谢谢,现在看来它可以工作了。几个小时前,当我在 oracle 教程页面上找到它时,我正在考虑这个问题,但我没有时间尝试。
  • 这不允许你画框外,还是我错了?
【解决方案2】:

你可以用这个 http://java-sl.com/connector.html 作为此类代码的示例。

【讨论】:

    【解决方案3】:

    这应该是很有可能的。您将需要创建一个知道两个垂直滚动条的自定义组件。它应该将自己作为AdjustmentListener 添加到每个滚动条中,以便检测更改并重新绘制两者之间的线条。

    见: addAdjustmentListener method in the API

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多