2011-10-12 2 views
3

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

Проблема заключается в том, что пользователь изменяет размер окна, все на JPanel повторно перерисовывается. Это приводит к тому, что прямоугольники быстро меняют цвет.

В идеале, мне нужны цвета прямоугольников, чтобы оставаться неизменным во время изменения размера. В противном случае я мог бы также управлять решением, в котором JPanel перекрашивается только один раз после завершения изменения размера.

Есть ли у вас общие идеи о том, как я могу это реализовать? Я чувствую, что было бы намного проще, если бы был метод onStartResize и onFinishResize callback в ComponentListener.

Спасибо!

ответ

5

Этот пример может служить иллюстрацией нарушения, представленного @kleopatra. По мере изменения размера компонента механизм отправки событий помогает вам использовать repaint(). Если вы измените состояние своего рендеринга, скажем, в paintComponent(), вы увидите, что он быстро работает. В приведенном ниже примере нижняя строка мерцает при изменении размера, а верхняя строка остается неизменной.

Addendum: AnimationTest - родственный пример, который использует этот эффект для выполнения анимации в ComponentAdapter.

ResizeMe

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.GridLayout; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

/** @https://stackoverflow.com/questions/7735774 */ 
public class ResizeMe extends JPanel { 

    private static final int N = 4; 
    private static final int SIZE = 100; 
    private static final Random rnd = new Random(); 
    private final List<JLabel> list = new ArrayList<JLabel>(); 
    private boolean randomize; 

    public ResizeMe(boolean randomize) { 
     this.randomize = randomize; 
     this.setLayout(new GridLayout(1, 0)); 
     for (int i = 0; i < N; i++) { 
      JLabel label = new JLabel(); 
      label.setPreferredSize(new Dimension(SIZE, SIZE)); 
      label.setOpaque(true); 
      list.add(label); 
      this.add(label); 
     } 
     initColors(); 
     this.addComponentListener(new ComponentAdapter() { 

      @Override 
      public void componentResized(ComponentEvent e) { 
       System.out.println(e); 
      } 
     }); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (randomize) { 
      initColors(); 
     } 
    } 

    private void initColors() { 
     for (JLabel label : list) { 
      label.setBackground(new Color(rnd.nextInt())); 
     } 
    } 

    private static void display() { 
     JFrame f = new JFrame("ResizeMe"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setLayout(new GridLayout(0, 1)); 
     f.add(new ResizeMe(false), BorderLayout.NORTH); 
     f.add(new ResizeMe(true), BorderLayout.SOUTH); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       display(); 
      } 
     }); 
    } 
} 
+0

собирался дать пять (хороший скриншот :-) - пока я не увидел ваш код: изменение состояния в paintComponent ... tsssee. Нельзя, это может создать неприятные петли! – kleopatra

+0

Совершенно верно; это значит служить примером того, что делать не нужно. – trashgod

-1

Предполагаете, вы используете paintAll(Graphics g). Попробуйте создать метод с именем redoRectangles(), который случайным образом изменяет цвета прямоугольников. Назовите его при инициализации и событии мыши.

Если вы не используете paintAll, я понятия не имею.

+1

ошибочное предположение (за исключением OP получил картину _completely_ неправильно): никто _ever_ касается paintAll ... – kleopatra

3

Инициализировать массив цветов. При нажатии на прямоугольник пополняйте массив новыми случайными цветами. Если массив пуст, заполните его также случайными цветами. Храните массив вместе с прямоугольниками.

1

что право safiest путь implemnts ComponentListener, его метод componentResized(ComponentEvent e), внутри этого метода запуска javax.swing.Timer с небольшими Дили 350-500ms, если изменение размера все еще продолжают только Timer#restart(),

но This causes the rectangles to rapidly change color. указывают на другую проблему, как это возможно , потому что MouseListener не имеет ничего общего с изменением размера,

+0

пропустил проблему kleopatra

5

Возможно, вы неправильно ошиблись в рисовании логики (угадывая, конечно, не видя никакого кода :) Похоже, вы меняете цвет в методе paintComponent. Что нарушает общее правило: Не меняйте любое состояние компонента во время покраски.

Вместо этого подумайте о прямоугольнике, имеющем фиксированные цвета, до тех пор, пока они не будут нажаты, а затем измените цвет и перерисуйте. Изменение размера не входит в игру нигде.

+0

+1 я добавил [пример] (HTTP: //переполнение стека.com/questions/7735774/repaint-jpanel-only-after-window-resize-is-finished/7737098 # 7737098), который иллюстрирует нарушение. – trashgod

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