1

I am writing a Java GUI library for practice, and I want to make a password field with a button to toggle that input being visible/invisible. The functionality is all there, but visually there are some problems.

I have a 512x512 icon (biggest size I could find) kept within a res/ folder on the same directory level as the src/ folder. (I am using IntelliJ as my IDE). The times I have gotten the icon to show up, it is FAR larger than the JTextField, and messes with the sizes of all other components on the view.

My question is how do I go about getting the icon to render at the correct size, despite the icon file being somewhat high-res.

package com.carvethsolutions.guilib.fields;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ToggleHiddenTextField extends JPanel {

private JButton toggle;

private HiddenTextField htf;

private boolean hidden;

public ToggleHiddenTextField() {
    htf = new HiddenTextField();
    htf.setBorder(null);
    hidden = true;

    toggle = new JButton(new ImageIcon("./visibility-button.png"));
    toggle.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (hidden) {
                htf.showInput();
            } else {
                htf.hideInput();
            }
            hidden = !hidden;
        }
    });

    this.setLayout(new GridLayout(1,2));
    this.add(htf);
    this.add(toggle);
    this.setBorder(BorderFactory.createLoweredBevelBorder());
}

}

enter image description here

This is what it currently looks like. How can I ensure the icon appears, and at the correct size?

UPDATE: This code get's a workable result. I can tweak the layout from here to get it perfect. Thank you everyone!

package com.carvethsolutions.guilib.fields;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class ToggleHiddenTextField extends JPanel {

private JButton toggle;

private HiddenTextField htf;

private boolean hidden;

public ToggleHiddenTextField() {
    htf = new HiddenTextField();
    htf.setBorder(null);
    hidden = true;

    try {
        Image image = ImageIO.read(getClass().getResource("/visibility-button.png"));
        image = image.getScaledInstance(htf.getPreferredSize().height, htf.getPreferredSize().height, Image.SCALE_AREA_AVERAGING);
        toggle = new JButton(new ImageIcon(image));
        toggle.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (hidden) {
                    htf.showInput();
                } else {
                    htf.hideInput();
                }
                hidden = !hidden;
            }
        });
    } catch (IOException e) {
        System.out.println("IOException : ");
        e.printStackTrace();
    }

    this.setLayout(new GridLayout(1,2));
    this.add(htf);
    this.add(toggle);
    this.setBorder(BorderFactory.createLoweredBevelBorder());
}

}

enter image description here

Dtroll MC
  • 303
  • 5
  • 14
  • You'll want to star by changing `toggle = new JButton(new ImageIcon("./visibility-button.png"));` to something more like `toggle = new JButton(new ImageIcon(getClass().getResource("/visibility-button.png")));` to retrieve the image, although I'd also recommend using `ImageIO` – MadProgrammer Apr 26 '18 at 20:19
  • There's also a number of ways to scale an image, for [example](https://stackoverflow.com/questions/11959758/java-maintaining-aspect-ratio-of-jpanel-background-image/11959928#11959928) and [example](https://stackoverflow.com/questions/14115950/quality-of-image-after-resize-very-low-java/14116752#14116752) - What size you use is up to you. Try a few common sizes (16x16, 24x24, 32x32) and see what works for you – MadProgrammer Apr 26 '18 at 20:20

1 Answers1

1
  1. Use ImageIO to read the file as a BufferedImage.
  2. Then you can scale the image to whatever size you want. This can be done by using the getScaledInstance() method of the BufferedImage. Or you can create a second BufferedImage at the size you want and then draw the first image to the scaled image.
  3. Create the Icon using the scaled image.
camickr
  • 321,443
  • 19
  • 166
  • 288
  • And what size would I want? The dimensions of the textfield within it's contained minus some padding? – Dtroll MC Apr 26 '18 at 20:14
  • You size the icon to whatever you want. The problem is that your layout doesn't make any sense. Why are you using a GridLayout? You are forcing the two components to be the same size. I would suggest you want to set the size to whatever you wish. Add the icon to the button and the button to the panel. Then the layout manager (maybe a FlowLayout) will just display the text field and the button at their preferred sizes. – camickr Apr 26 '18 at 20:22
  • The height of a text field is I think about 20 pixels. So you would probably only want your Icon to be 16 x 16 so the size of the button is similar to the size of the text field. `I have a 512x512 icon (biggest size I could find)` - in this case maybe you want a smaller icon to start with so you don't scale the Icon so much. – camickr Apr 26 '18 at 20:28
  • It just seems weird to hardcode the dimensions as actual pixels. – Dtroll MC Apr 27 '18 at 20:37
  • @DtrollMC, Swing determines the size of every component based on the properties of the component. In the case of a JButton you need to consider the text, icon, border etc. Swing doesn't know that you want to scale a large image smaller. – camickr Apr 27 '18 at 20:48
  • You might be able to use the [Stretch Icon](https://tips4java.wordpress.com/2012/03/31/stretch-icon/). It does dynamic scaling of an image. It might shrink the icon to the space available in the panel. – camickr Apr 27 '18 at 20:51