2015-07-23 6 views
1

У меня странная проблема. У меня есть JTabbedPane, у которого есть несколько JPanels, добавленных как дети.Изменение значка, не вызывающего перерисовку на JTabbedPane

Одна из этих панелей имеет ImageIcon вместе с меткой. Фактическое изображение, используемое этим ImageIcon, периодически изменяется на основе того, что происходит в связанной JPanel.

Вот пример того, что я имею в виду: enter image description here

Некоторые события на второй вкладке вызывают красный значок, чтобы изменить.

Когда эти события происходят изменить изображение, используя следующий метод: http://docs.oracle.com/javase/7/docs/api/javax/swing/ImageIcon.html#setImage(java.awt.Image)

Однако после того, как я установил изображение, вкладка фактическая не перекрашивать. Он перекрашивается только на другие события (например, мышь или клик).

Я бы подумал, что изменение изображения значков приведет к тому, что он вызовет перерисовку на все, что использует этот значок? Есть ли какой-то трюк, чтобы заставить это работать?

Возможно, я мог бы реализовать хакерское решение, создав собственный класс значков и передав ему JComponent, который будет перерисовываться при изменении изображения, однако это вызовет еще одну проблему перекраски всей JTabbedPane при каждом изменении значка ИЛИ вычисляя область, в которой значок занимает и перекрашивает это (что кажется большим количеством усилий).

EDIT:

Вот простое приложение, которое демонстрирует мою проблему. Предположим, что два изображения расположены в корневой директории 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); 
       } 
      } 
     }); 
    } 

} 

Сам вкладка не перекрашивается автоматически и требует другого события для запуска картины.

+3

Работает отлично для меня. Рассмотрите возможность предоставления [runnable example] (https://stackoverflow.com/help/mcve), который демонстрирует вашу проблему. Это не дамп кода, а пример того, что вы делаете, что подчеркивает проблему, с которой вы сталкиваетесь. Это приведет к меньшему путанице и лучшим ответам – MadProgrammer

+0

Используете ли вы методы SwingUtilities.invoke * для установки изображения? – KDM

+0

Он отлично работает здесь, возможно, что-то не так с L & F, который вы используете. Попробуйте использовать систему L & F, а не обычную для тестирования. – STaefi

ответ

2

Если это не окрашено, тогда позвоните по телефону 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 
     } 
+0

У меня есть такая версия, которая работает, но это значит, что мне нужно сохранить ссылку на везде, где используется значок, чего я надеялся избежать. – Fooble

+0

Думаю, это единственный вариант, спасибо. – Fooble

0

Используйте 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* является хорошей практикой.

 Смежные вопросы

  • Нет связанных вопросов^_^