0

I have a problem with my program. Every time when I change my screen resolution, my image starts to move out of position. Any suggestions on how to make my image stay in the same location even though I change to any other resolution?

p2 = new JPanel();
p2.setLayout(new FlowLayout());      
ImageIcon img2 = new ImageIcon("C:\\Drum\\Invisible4.png");             
jbtn2 = new JLabel(img2);
p2.add(jbtn2);                      
add(jbtn2);
jbtn2.setSize(jbtn2.getPreferredSize());
jbtn2.setLocation(140, 380);
James Dunn
  • 8,064
  • 13
  • 53
  • 87
jat
  • 9
  • 6
  • Don't try and position it manually, instead, use a layout manager...like `GridBagLayout` or `BorderLayout`. The real question is, where do you actually want it – MadProgrammer Jul 25 '13 at 02:05
  • how to use the layout manager? Im creating a drum program. I need to put the drum cymbal and tom at a specific location so that it look like a drum set. the above code is just displaying one drum image. – jat Jul 25 '13 at 02:09
  • Okay, does it need to scale? So when the size of the window changes, do the images need to scale in proportion? – MadProgrammer Jul 25 '13 at 02:10
  • yes it need to scale in proportion too – jat Jul 25 '13 at 02:13
  • See [this answer](http://stackoverflow.com/a/10862262/418556) for possible tips. – Andrew Thompson Jul 25 '13 at 02:14
  • As does [this one](http://stackoverflow.com/questions/11959758/java-maintaining-aspect-ratio-of-jpanel-background-image/11959928#11959928) – MadProgrammer Jul 25 '13 at 02:16
  • I heard that I can use dynamic resolution. Any one has tips abt it? – jat Jul 25 '13 at 03:35

3 Answers3

1

I prefer to always try and work within boundaries of the framework where I can, it makes life generally easier in the long run.

Swing has begin designed to work with LayoutManagers, this means that the way that Swing updates it's components and communicates these changes is based on the use of the LayoutManagers (more or less).

The following example uses pieces from Java: maintaining aspect ratio of JPanel background image to scale the images and a PropertionalLayoutManager which is designed to try and scale not only the size, but also the position of the components based on the size of the parent container.

The PropertionalLayoutManager demonstrated here will try and layout the components around the center of the parent container. You can change this, but it looks weird - IMHO

enter image description hereenter image description here

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager2;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.WeakHashMap;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Drums {

    protected static BufferedImage SYMBOL;
    protected static BufferedImage DRUM;

    public static void main(String[] args) {
        new Drums();
    }

    public Drums() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new PropertionalLayoutManager(400, 400));
            add(new Symbol(), new PropertionalConstraint(0f, 0));
            add(new Symbol(), new PropertionalConstraint(0.67f, 0));
            add(new Symbol(), new PropertionalConstraint(0f, 0.4675f));
            add(new Symbol(), new PropertionalConstraint(0.67f, 0.4675f));
            add(new Drum(), new PropertionalConstraint(0.205f, 0.1f));
            add(new Drum(), new PropertionalConstraint(0.5f, 0.1f));
            add(new Drum(), new PropertionalConstraint(0f, 0.33f));
            add(new Drum(), new PropertionalConstraint(0.705f, 0.33f));
        }
    }

    public class PropertionalConstraint {

        private float x;
        private float y;

        public PropertionalConstraint(float x, float y) {
            this.x = x;
            this.y = y;
        }

        public float getX() {
            return x;
        }

        public float getY() {
            return y;
        }
    }

    public class PropertionalLayoutManager implements LayoutManager2 {

        private Map<Component, PropertionalConstraint> constraints;
        private Dimension defaultSize;

        public PropertionalLayoutManager(int defaultWidth, int defaultHeight) {
            constraints = new WeakHashMap<>(25);
            defaultSize = new Dimension(defaultWidth, defaultHeight);
        }

        @Override
        public void addLayoutComponent(Component comp, Object constraint) {
            if (constraint instanceof PropertionalConstraint) {
                constraints.put(comp, ((PropertionalConstraint) constraint));
            }
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return preferredLayoutSize(target);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
            constraints.remove(comp);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {

            return defaultSize;

        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        @Override
        public void layoutContainer(Container parent) {

            int width = parent.getWidth();
            int height = parent.getHeight();

            double dScaleWidth = getScaleFactor(defaultSize.width, width);
            double dScaleHeight = getScaleFactor(defaultSize.height, height);

            double scaleSize = Math.min(dScaleHeight, dScaleWidth);
            int minRange = Math.min(width, height);

            if (width > 0 && height > 0) {

                int maxY = 0;
                int maxX = 0;

                for (Component comp : parent.getComponents()) {
                    PropertionalConstraint p = constraints.get(comp);
                    if (p != null) {
                        Dimension prefSize = comp.getPreferredSize();

                        prefSize.width *= scaleSize;
                        prefSize.height *= scaleSize;

                        int x = Math.round(minRange * p.getX());
                        int y = Math.round(minRange * p.getY());

                        comp.setBounds(x, y, prefSize.width, prefSize.height);

                        maxX = Math.max(maxX, x + prefSize.width);
                        maxY = Math.max(maxY, y + prefSize.height);
                    } else {
                        comp.setBounds(0, 0, 0, 0);
                    }
                }

                for (Component comp : parent.getComponents()) {
                    System.out.println("maxX = " + maxX);
                    System.out.println("maxY = " + maxY);
                    if (comp.getWidth() > 0 && comp.getHeight() > 0) {
                        int x = ((width - maxX) / 2) + comp.getX();
                        int y = ((height - maxY) / 2) + comp.getY();
                        comp.setLocation(x, y);
                    }                    
                }

            } else {

                for (Component comp : parent.getComponents()) {
                    comp.setBounds(0, 0, 0, 0);
                }

            }

        }
    }

    public abstract class AbstractKitPiecePane extends JPanel {

        private BufferedImage scaled;

        public AbstractKitPiecePane() {
            setOpaque(false);
        }

        public abstract BufferedImage getKitImage();

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(getKitImage().getWidth(), getKitImage().getHeight());
        }

        @Override
        public void invalidate() {
            super.invalidate();
            if (getWidth() > 0 && getHeight() > 0) {
                scaled = getScaledInstanceToFit(getKitImage(), getSize());
            } else {
                scaled = null;
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (scaled != null) {
                int x = (getWidth() - scaled.getWidth()) / 2;
                int y = (getHeight() - scaled.getHeight()) / 2;
                g.drawImage(scaled, x, y, this);
            }
        }
    }

    public class Drum extends AbstractKitPiecePane {

        @Override
        public BufferedImage getKitImage() {
            return DRUM;
        }
    }

    public class Symbol extends AbstractKitPiecePane {

        @Override
        public BufferedImage getKitImage() {
            return SYMBOL;
        }
    }

    protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {

        BufferedImage imgScale = img;

        int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
        int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

        if (dScaleFactor <= 1.0d) {

            imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        } else {

            imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        }

        return imgScale;

    }

    protected static BufferedImage getScaledDownInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint) {

//        System.out.println("Scale down...");
        int type = (img.getTransparency() == Transparency.OPAQUE)
                ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;

        if (targetHeight > 0 || targetWidth > 0) {
            int w, h;
            w = img.getWidth();
            h = img.getHeight();

            do {

                if (w > targetWidth) {
                    w /= 2;
                    if (w < targetWidth) {
                        w = targetWidth;
                    }
                }

                if (h > targetHeight) {
                    h /= 2;
                    if (h < targetHeight) {
                        h = targetHeight;
                    }
                }

                BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;

            } while (w != targetWidth || h != targetHeight);
        } else {
            ret = new BufferedImage(1, 1, type);
        }

        return ret;
    }

    protected static BufferedImage getScaledUpInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint) {

        int type = BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;
        int w, h;
        w = img.getWidth();
        h = img.getHeight();

        do {
            if (w < targetWidth) {
                w *= 2;
                if (w > targetWidth) {
                    w = targetWidth;
                }
            }

            if (h < targetHeight) {
                h *= 2;
                if (h > targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
            tmp = null;
        } while (w != targetWidth || h != targetHeight);

        return ret;
    }

    public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
        double scaleFactor = getScaleFactorToFit(img, size);
        return getScaledInstance(img, scaleFactor);
    }

    public static double getScaleFactorToFit(BufferedImage img, Dimension size) {
        double dScale = 1;

        if (img != null) {
            int imageWidth = img.getWidth();
            int imageHeight = img.getHeight();
            dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
        }

        return dScale;
    }

    public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
        double dScale = 1d;

        if (original != null && toFit != null) {
            double dScaleWidth = getScaleFactor(original.width, toFit.width);
            double dScaleHeight = getScaleFactor(original.height, toFit.height);
            dScale = Math.min(dScaleHeight, dScaleWidth);
        }

        return dScale;
    }

    public static double getScaleFactor(int iMasterSize, int iTargetSize) {
        double dScale = 1;
        if (iMasterSize > iTargetSize) {
            dScale = (double) iTargetSize / (double) iMasterSize;
        } else {
            dScale = (double) iTargetSize / (double) iMasterSize;
        }

        return dScale;
    }

    static {

        try {
            SYMBOL = ImageIO.read(new File("Symbol.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        try {
            DRUM = ImageIO.read(new File("Drum.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }
}

And the images used within the program, for your enjoyment. They live in the same directory the program is run from

enter image description hereenter image description here

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I try run the program but it display me this error: javax.imageio.IIOException: Can't read input file! at javax.imageio.ImageIO.read(ImageIO.java:1301) at test.(test.java:405) javax.imageio.IIOException: Can't read input file! at javax.imageio.ImageIO.read(ImageIO.java:1301) at test.(test.java:410) Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException – jat Jul 25 '13 at 03:51
  • Of course, you need to supply you own images of the symbols and drums :P – MadProgrammer Jul 25 '13 at 03:53
  • @mKorbel Yeah, couldn't find any :P – MadProgrammer Jul 25 '13 at 06:12
  • Thanks for the working code. Any idea where i can insert the mouseListener to the following image – jat Jul 25 '13 at 06:58
  • The best way would be to attach it to the component itself. If you wanted to use a single listener on the top level panel, you could use `getComponentAt(Point)` in your mouse listener to find the component that was clicked – MadProgrammer Jul 25 '13 at 07:01
0

create a percentage/ratio of the "normal" screen size to what it currently is and multiply that by the pos. Example if the screen size you are working with was 400x600

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
double widthRat = width/600
double heightRat = height/400

then

jbtn2.setLocation(140*widthRat, 380*heightRat);

that way say the screen size was doubled to 1200x800 widthRat would = 2 and double the position. This is kind of a sloppy example but gives the idea

RustyH
  • 473
  • 7
  • 22
  • IMHO, you be better of designing a proportional layout manager that was capable of defining a size and position of the components based on there preferred sizes and the size of the actual container. This way you don't need to add a multitude of listeners to keep it all updated as you'd be working within the Swing framework – MadProgrammer Jul 25 '13 at 02:20
  • True i wasn't really thinking about increasing size on demand. – RustyH Jul 25 '13 at 02:26
0

I prefer to use Absolute layout. And here are the codes which should work for you.

Toolkit toolkit=Toolkit.getDefaultToolkit();
JPanel1.setSize(toolkit.getScreenSize().width, toolkit.getScreenSize().height);
int w=toolkit.getScreenSize().width;
int h=toolkit.getScreenSize().height;
JPanel1.setBounds(0, 0, w, h);

This code will fetch the current resolution of your computer...

sudipta.dey
  • 178
  • 1
  • 2
  • 13