在滚动窗格的左上方绘制箭头 [英] Draw arrow on top left of scrollpane

查看:60
本文介绍了在滚动窗格的左上方绘制箭头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在JScrollPane中有一个JPanel.在我的程序中,JPanel显示地图图像,并显示车辆的当前位置.我的程序接收车辆的位置和当前方向.我需要在地图上显示出来.

I have a JPanel within a JScrollPane. In my program, the JPanel shows an image of map and it shows the current location of a vehicle. My program receives the location and current direction of the vehicle. I need to show this on the map.

我在显示车辆方向时遇到问题.我想在地图可见区域的左上方显示一个箭头,以显示方向.以下是我尝试过的代码.但是当我向下滚动时会抛出异常.

I'm having a problem showing the direction of the vehicle. I want to show an arrow on the top left of the map's visible area to show the direction. The following is the code that I have tried. But it throws an exception when I scroll down.

Exception in thread "AWT-EventQueue-0" java.awt.image.RasterFormatException: Transformed height (-287) is less than or equal to 0.
    at java.awt.image.AffineTransformOp.createCompatibleDestImage(Unknown Source)
    at java.awt.image.AffineTransformOp.filter(Unknown Source)
    at Test.paintComponent(Test.java:62)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintToOffscreen(Unknown Source)


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

public class Test extends JPanel implements ActionListener {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setSize(300, 400);
        Test view = new Test();
        Dimension minimumSize = new Dimension(1000, 1000);

        view.setBorder(BorderFactory.createLineBorder(Color.BLUE));
        JScrollPane comp = new JScrollPane(view);
        comp.setBorder(BorderFactory.createLineBorder(Color.RED));
        f.getContentPane().add(comp, BorderLayout.CENTER);
        f.setVisible(true);
        view.setPreferredSize(minimumSize);
    }

    private BufferedImage i;
    private Random r = new Random();

    public Test() {
        try {
            i = ImageIO
                    .read(new URL("https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/br_next.png"));
            new Timer(1000, this).start();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

        Graphics2D g2d = (Graphics2D) g.create();
        AffineTransform transform = g2d.getTransform();

        transform.rotate(r.nextFloat() * Math.PI * 2, i.getWidth() / 2, i.getHeight() / 2);
        AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);

        Rectangle cb = g.getClipBounds();
        g2d.drawImage(op.filter(i, null), (int) cb.getX(), (int) cb.getY(), null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }

}

即使用户使用滚动条滚动,如何使箭头始终在左上角可见?

How can I make the arrow always visible on the top left corner even when the user scrolls using the scroll-bars?

推荐答案

JScrollPaneJViewport都经过高度优化,在绘制时,裁剪范围仅设置为实际需要更新的区域(引入的区域)

The JScrollPane and JViewport are both highly optimised, when painted, the clipping bounds is only set to the area that actually needs to be updated (the area which was introduced)

一个更好的主意可能是创建您自己的JViewport,您可以在其上绘制视口的内容

A better idea might be to create your own JViewport onto which you can paint over the viewport's content

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Test extends JPanel {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(300, 400);
                Test view = new Test();

                view.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                JScrollPane comp = new JScrollPane();
                ViewPortDirection vp = new ViewPortDirection();
                comp.setViewport(vp);
                comp.setViewportView(view);
                comp.setBorder(BorderFactory.createLineBorder(Color.RED));
                f.getContentPane().add(comp, BorderLayout.CENTER);
                f.setVisible(true);
            }
        });
    }

    public static class ViewPortDirection extends JViewport {

        private BufferedImage i;
        private Random r = new Random();

        public ViewPortDirection() {
            try {
                i = ImageIO.read(new URL("https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/br_next.png"));
                new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        repaint();
                    }
                }).start();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    repaint(0, 0, i.getWidth(), i.getHeight());
                }
            });
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);

            Graphics2D g2d = (Graphics2D) g.create();
            AffineTransform transform = AffineTransform.getRotateInstance(r.nextFloat() * Math.PI * 2, i.getWidth() / 2, i.getHeight() / 2);

            int x = 0;
            int y = 0;
            g2d.setTransform(transform);
            g2d.drawImage(i, x, y, this);
            g2d.dispose();
        }

    }

    public Test() {
        setBackground(Color.BLUE);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(1000, 1000);
    }

}

这篇关于在滚动窗格的左上方绘制箭头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆