JButton setIcon Ошибка обновления

В настоящее время я делаю java-программу с использованием netbeans на основе изменения изображения в кнопке....

На самом деле мое требование состоит в том, чтобы изменить значок изображения кнопки, когда я нажимаю другую кнопку (Say A).....

я вышел со следующей программой........

       // Following function is included inside the button's (Here A) ActionListener........
       public void change_image()
       {
             if(sex==0)
             {
                   ic=new ImageIcon("E:\\java_images\\female_profile.jpg");
                   sex=1;
             }
             else if(sex==1)
             {
                   ic = new ImageIcon("E:\\java_images\\male_profile.png");
                   sex=0;
             }

              // To resize the image into the size of the button... 
               labelicon.setImage(ic.getImage().getScaledInstance(image_btn.getWidth(),image_btn.getHeight(), Image.SCALE_DEFAULT));

             img_btn.setIcon(labelicon);

         }

Переменные, которые я включил,

           private int sex;    // 0  - female, 1 - male

           private ImageIcon ic,labelicon;  // variables meant for storing ImageIcons.....
           private JButton img_btn;  // the button at which the image is to  be displayed....

Теперь странное поведение, которое я наблюдал, это .......

Изображение отображается при нажатии кнопки, только когда я нажимаю кнопку свертывания. то есть, когда я нажимаю кнопку A, выполняется код, указанный в ActionListener. Но эффект смены изображения появляется только тогда, когда я сворачиваю окно и снова заставляю его появляться на экране.... Кто-нибудь может сказать, почему это происходит и как я могу устранить проблему??

Все, что я хочу, это изменить изображение в тот момент, когда я нажимаю кнопку A..... Ну... я не включил код для создания кнопки, так как это легко сделать с помощью построителя графического интерфейса netbeans Swing......


person Arjun K P    schedule 19.06.2012    source источник
comment
Пожалуйста, взгляните на этот пример   -  person nIcE cOw    schedule 19.06.2012


Ответы (3)


  1. загрузить Icon / ImageIcon как локальную переменную один раз, нет причин повторно загружать изображение из ActionListener

  2. в API есть описание, что Image#ScaledInstance довольно асинхронно

  3. иначе придется звонить

.

labelicon.getImage().flush();
img_btn.setIcon(labelicon);

РЕДАКТИРОВАТЬ

@akp написал, но .. как бы вы изменили размер изображения значка .. ??

введите здесь описание изображениявведите здесь описание изображениявведите здесь описание изображения

есть два или три других способа, как поместить Icon /ImageIcon и изменить размер с его родителем, JLabel может быть самым простым способом

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;

public class JButtonAndIcon {

    private static JLabel label = new JLabel();
    private static Random random = new Random();
    private static ImageIcon image1; // returns null don't worry about 
    private static ImageIcon image2; // returns null don't worry about 
    private static Timer backTtimer;
    private static int HEIGHT = 300, WEIGHT = 200;

    public static void main(String[] args) throws IOException {
        label.setPreferredSize(new Dimension(HEIGHT, WEIGHT));
        final JButton button = new JButton("Push");
        button.setBorderPainted(false);
        button.setBorder(null);
        button.setFocusable(false);
        button.setMargin(new Insets(0, 0, 0, 0));
        button.setContentAreaFilled(false);
        button.setLayout(new BorderLayout());
        button.add(label);
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (button.getIcon() == image1) {
                    label.setIcon(image2);
                } else {
                    label.setIcon(image1);
                }
            }
        });
        JFrame frame = new JFrame("Test");
        frame.add(button);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        startBackground();
        frame.setVisible(true);
    }

    private static void startBackground() {
        backTtimer = new javax.swing.Timer(750, updateBackground());
        backTtimer.start();
        backTtimer.setRepeats(true);
    }

    private static Action updateBackground() {
        return new AbstractAction("Background action") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                label.setIcon(new ImageIcon(getImage()));
            }
        };
    }

    public static BufferedImage getImage() {
        int w = label.getWidth();
        int h = label.getHeight();
        GradientPaint gp = new GradientPaint(0f, 0f, new Color(
                127 + random.nextInt(128),
                127 + random.nextInt(128),
                127 + random.nextInt(128)),
                w, w,
                new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
        BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bi.createGraphics();
        g2d.setPaint(gp);
        g2d.fillRect(0, 0, w, h);
        g2d.setColor(Color.BLACK);
        return bi;
    }
}
person mKorbel    schedule 19.06.2012
comment
но .. как бы вы изменили размер изображения значка .. ?? - person Arjun K P; 19.06.2012

Проблема здесь в том, что вы обновляете внутренности файла Icon. Метод setIcon будет думать, что это тот же значок, что и у кнопки. Я бы порекомендовал вам сделать два разных объекта Icon, чтобы использовать их для обновления значка. Это решит проблемы.


Пример (с двумя разными значками):

public static void main(String[] args) throws IOException {

    final ImageIcon redIcon = createImageIcon(10, 10, Color.RED);
    final ImageIcon blueIcon = createImageIcon(10, 10, Color.BLUE);

    final JButton button = new JButton("Push", blueIcon);
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (button.getIcon() == redIcon)
                button.setIcon(blueIcon);
            else
                button.setIcon(redIcon);
        }
    });

    JFrame frame = new JFrame("Test");
    frame.add(button);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
}

private static ImageIcon createImageIcon(int w, int h, Color color) {
    Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    Graphics g = image.getGraphics(); 
    g.setColor(color); 
    g.fillRect(0, 0, w, h); 
    g.dispose();
    return new ImageIcon(image);
}

Задний план:

Глядя на источник AbstractButton.setIcon, вы можете видеть, что он не узнает об обновлении, если ссылка «не обновлена»:

    .....
    if (defaultIcon != oldValue) {
        if (defaultIcon == null || oldValue == null ||
            defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
            defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
            revalidate();
        } 
        repaint();
    }

Примечание для @HarryJoy: вы действительно были правы, хотя и не знали почему... :) Извините! +1 еще раз!

person dacwe    schedule 19.06.2012
comment
но... мне было интересно, изменился ли значок... отражение этого изменения должно появиться в свойствах его объекта... - person Arjun K P; 19.06.2012
comment
Он изменяет объект значка, но вам нужно будет сообщить графическому интерфейсу, что его необходимо обновить, в отличие от любого другого вызова setIcon. - person dacwe; 19.06.2012
comment
Хм.. Я был прав. УРА!!!! \м/ :р . Но я получил минус :( В любом случае хорошее объяснение. :) - person Harry Joy; 19.06.2012

//Позвонить img_btn.revalidate() и img_btn.repaint()

Исправление, setIcon уже должен это делать. Лично я использую хакерский способ img_btn.setText("<HTML><BODY><IMG SRC=\"/path/to/img.jpg\"/></BODY</HTML>");.

person iracigt    schedule 19.06.2012
comment
-1 От этого толку не будет. setIcon уже делает это (проверьте источник). - person dacwe; 19.06.2012
comment
Нет, приятель, setIcon уже это делает (как сказал dacwe). Я только что опубликовал то же самое, но затем удалил, потому что это неправильно. - person Harry Joy; 19.06.2012
comment
@apk Похоже, но я не могу вспомнить, в каком каталоге находится ./. например. icon.jpg находится в той же папке, что и класс? это / корневой каталог или jar? Кто-нибудь знает? - person iracigt; 19.06.2012