繁体   English   中英

更改图标不会导致JTabbedPane上的重新绘制

[英]Changing Icon not causing repaint on JTabbedPane

我有一个奇怪的问题。 我有一个JTabbedPane,其中添加了几个JPanels作为子级。

这些面板之一具有一个ImageIcon和一个标签。 该ImageIcon使用的实际Image会根据关联的JPanel中发生的情况定期更改。

这是我的意思的示例: 在此处输入图片说明

第二个选项卡中的某些事件导致红色图标更改。

当这些事件发生时,我使用以下方法更改Image: http : //docs.oracle.com/javase/7/docs/api/javax/swing/ImageIcon.html#setImage(java.awt.Image)

但是,在设置图像之后,实际的选项卡不会重新绘制。 它仅在其他事件(例如,鼠标悬停或单击)上重绘。

我本以为更改图标图像会导致它在使用该图标的任何东西上触发重绘? 有一些技巧可以使它起作用吗?

我可能可以通过创建一个自定义图标类并将其传递给JComponent来实现一个hacky解决方案,该JComponent会在更改图像时重新绘制,但是这将带来另一个问题,即每次图标更改或计算区域时都重新绘制整个JTabbedPane图标正在占据并重新粉刷(看起来很费力)。

编辑:

这是一个演示我的问题的简单应用程序。 假设两个图像位于src根目录中,分别为Image1.png和Image2.png。

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 JTabbedPaneTest {

    JFrame jFrame;

    JTabbedPane jTabbedPane;
    ImageIcon testIcon;

    BufferedImage image1;
    BufferedImage image2;

    Timer timer;

    public JTabbedPaneTest() throws IOException {

        jFrame = new JFrame();
        jFrame.setMinimumSize(new Dimension(300, 300));

        image1 = ImageIO.read(getClass().getResource("/Image1.png"));
        image2 = ImageIO.read(getClass().getResource("/Image2.png"));

        testIcon = new ImageIcon(image1);

        jTabbedPane = new JTabbedPane();
        jTabbedPane.addTab("Tab 1", testIcon, new JPanel());
        jTabbedPane.addTab("Tab 2", new JPanel());

        jFrame.add(jTabbedPane, BorderLayout.CENTER);

        timer = new Timer(0, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Changing image...");
                if(testIcon.getImage() == image1){
                    testIcon.setImage(image2);
                }
                else {
                    testIcon.setImage(image1);
                }
            }
        });

        timer.setRepeats(true);
        timer.setDelay(1000);
        timer.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTabbedPaneTest application = new JTabbedPaneTest();
                    application.jFrame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.err.println(e.getClass().getSimpleName() + " : " + e.getMessage());
                    System.exit(1);
                }
            }
        });
    }

}

该选项卡本身不会自动重新绘制,并且需要另一个事件来触发绘制。

如果未绘制,则在更改图标后调用repaint()

    public void actionPerformed(ActionEvent e) {
            System.out.println("Changing image...");
            if (testIcon.getImage() == image1) {
                testIcon.setImage(image2);
            } else {
                testIcon.setImage(image1);
            }
            jTabbedPane.repaint();//calling repaint after icon change
        }

使用JTabbedPane#setIconAt设置新图标。 修改后的源代码在下面起作用。

package ant.test;
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 JTabbedPaneTest {

    JFrame jFrame;

    JTabbedPane jTabbedPane;
    ImageIcon testIcon1;
    ImageIcon testIcon2;

    BufferedImage image1;
    BufferedImage image2;

    Timer timer;

    public JTabbedPaneTest() throws IOException {

        jFrame = new JFrame();
        jFrame.setMinimumSize(new Dimension(300, 300));

        image1 = ImageIO.read(getClass().getResource("/Image1.png"));
        image2 = ImageIO.read(getClass().getResource("/Image2.png"));

        testIcon1 = new ImageIcon(image1);
        testIcon2 = new ImageIcon(image2);

        jTabbedPane = new JTabbedPane();
        jTabbedPane.addTab("Tab 1", testIcon1, new JPanel());
        jTabbedPane.addTab("Tab 2", new JPanel());

        jFrame.add(jTabbedPane, BorderLayout.CENTER);

        timer = new Timer(0, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Changing image...");
                if(jTabbedPane.getIconAt(0) == testIcon1){
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override public void run() {
                            jTabbedPane.setIconAt(0, testIcon2);
                        }
                    });
                }
                else {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override public void run() {
                            jTabbedPane.setIconAt(0, testIcon1);
                        }
                    });
                }
            }
        });

        timer.setRepeats(true);
        timer.setDelay(1000);
        timer.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTabbedPaneTest application = new JTabbedPaneTest();
                    application.jFrame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.err.println(e.getClass().getSimpleName() + " : " + e.getMessage());
                    System.exit(1);
                }
            }
        });
    }

}

顺便说一句,使用SwingUtilities#invoke*方法是一种好习惯。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM