0

I've got scroll panel which contains ImageIcon. I want to add JLabel with absolute position in px. What I've got:Swing app image

The code:

public class HelloWorld {


    HelloWorld() {

        JFrame jfrm = new JFrame("Hello, World!");
        jfrm.setSize(640, 480);
        JPanel mapPanel = new JPanel();
        mapPanel.setLayout(null);
        mapPanel.setSize(600,400);
        jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ImageIcon imageIcon = new ImageIcon("src\\SwingExp\\img\\map.gif");
        JScrollPane scrollPane = new JScrollPane(new JLabel(imageIcon));
        scrollPane.setBounds(5,5,600,400);
        JLabel usaLabel = new JLabel("U.S.A.");
        usaLabel.setBounds(210,200,50,25);
        mapPanel.add(usaLabel);
        mapPanel.add(scrollPane);

        jfrm.add(mapPanel);
        jfrm.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new HelloWorld();
            }
        });
    }
}

But if I'll scroll a little, USA label will disappear from map: Swing app image

JLabel positions must be absolute, as you see. How to avoid this?

Tony
  • 3,605
  • 14
  • 52
  • 84

2 Answers2

3

Add the usaLabel to the label containing the icon, not the scrollpane:

ImageIcon imageIcon = new ImageIcon("src\\SwingExp\\img\\map.gif");
JLabel map = new JLabel( imageIcon );
JScrollPane scrollPane = new JScrollPane( map );
//JScrollPane scrollPane = new JScrollPane(new JLabel(imageIcon));
scrollPane.setBounds(5,5,600,400);
JLabel usaLabel = new JLabel("U.S.A.");
usaLabel.setBounds(210,200,50,25);
map.add( usaLabel );
//mapPanel.add(usaLabel);

Also stop using a null layout everywhere. There is no need for your mapPanel variable. Just add the scrollpane directly to the content pane of the frame. By default the scrollpane will be added to the CENTER and will take up all the space available in the frame.

camickr
  • 321,443
  • 19
  • 166
  • 288
2

I offer this as an alternate answer:

  • It uses an EmptyBorder for white (OK blue) space
  • The scroll pane returns a preferred size scaled by the width factor.
  • Scrolls to the end then seamlessly starts over.
  • America (Australia, New Zealand & ..everywhere else depicted) is always in view since the GUI displays one 'image width'. ;)

screen shot of world image scrolling in option pane

The source image was created for this answer.

world source image

Code

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.*;
import javax.imageio.ImageIO;

class HelloScrollingWorld {

    public JPanel gui = new JPanel(new BorderLayout());
    JScrollPane scrollPane;
    Timer timer = null;
    /**
     * The number of images we tile horizontally, must be >1 for scroll bar
     */
    int width = 2;
    /**
     * The equator (drawn in pale gray) is 44 px south of the vertical
     * center of the image.
     */
    int offset = 44;
    /**
     * Use this as padding on top and bottom.
     */
    int pad = 15;

    HelloScrollingWorld() {
        try {
            URL worldImage = new URL("https://i.stack.imgur.com/OEGTq.png");
            BufferedImage img = ImageIO.read(worldImage);
            initComponents(img);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private final void initComponents(final BufferedImage image) {
        JPanel multiimage = new JPanel(new GridLayout(1, 0, 0, 0));
        for (int ii = 0; ii < width; ii++) {
            multiimage.add(new JLabel(new ImageIcon(image)));
        }
        multiimage.setBackground(Color.BLUE.brighter());
        // add the white (or bright blue) space.
        multiimage.setBorder(new EmptyBorder(pad, 0, pad + offset, 0));
        scrollPane = new JScrollPane(
                multiimage,
                JScrollPane.VERTICAL_SCROLLBAR_NEVER,
                JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS) {

            /**
             * return the preferred size scaled by the width.
             */
            @Override
            public Dimension getPreferredSize() {
                Dimension d = super.getPreferredSize();

                return new Dimension(d.width / width, d.height);
            }
        };
        gui.add(scrollPane, BorderLayout.CENTER);
        ActionListener scrollListener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                scrollGui();
            }
        };
        timer = new Timer(15, scrollListener);
        timer.start();
    }

    public void stopTimer() {
        timer.stop();
    }

    public void scrollGui() {
        JScrollBar scrollBar = scrollPane.getHorizontalScrollBar();
        BoundedRangeModel model = scrollBar.getModel();
        int max = model.getMaximum() - scrollBar.getVisibleAmount();
        int now = model.getValue();
        if (now < max) {
            model.setValue(now + 1);
        } else {
            model.setValue(1);
        }
    }

    public JComponent getGui() {
        return gui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                HelloScrollingWorld hsw = new HelloScrollingWorld();

                JOptionPane.showMessageDialog(
                        null,
                        hsw.getGui(),
                        "Hello Scrolling Padded World",
                        JOptionPane.INFORMATION_MESSAGE);

                hsw.stopTimer();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433