Java Swing: сделайте что-нибудь, когда компонент * закончит * изменение размера - PullRequest
8 голосов
/ 26 февраля 2010

Извиняюсь за несколько неясный вопрос - не мог придумать лучшего способа поставить его.

Я использую JXTaskPane (из API-интерфейса расширения Swing Labs) для отображения некоторой информации.

Пользователь может «щелкнуть» заголовок, чтобы развернуть панель. JXTaskPane находится в контейнере JPanel, который затем добавляется в JFrame, главное окно моего приложения.

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

panel.addComponentListener(new ComponentListener()
{   
    public void componentResized(ComponentEvent e)
    {
        Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
        reSizeFrame(newSize);
    }
}

private void reSizeFrame(Dimension newSize)
{   
    if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
    {
        containerPanel.setSize(newSize);
        appFrame.setSize(containerPanel.getSize());
        appFrame.pack();
    }
}

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

Как я могу определить, когда JXTaskpane завершил изменение размера? Я думал о двух подходах:

  • Поместите метод resizeFrame () в вызов SwingUtilities.invokeLate (..).

  • Включите вызов resizeFrame таймера, чтобы любые последующие вызовы ничего не делали, пока не сработает таймер. Это должно дать достаточно времени для изменения размера панели.

Как лучше всего двигаться вперед?

Кроме того - Это мое первое серьезное приложение с графическим интерфейсом Java после многих лет работы на стороне сервера. StackOverflow был очень полезным. Так что спасибо!

Ответы [ 3 ]

9 голосов
/ 01 марта 2010

Я знаю, что вы уже выбрали ответ, но переопределение метода рисования определенно не правильно, и, хотя вы можете взломать что-то на месте, оно не будет идеальным.

Глядя на источник для JXTaskPane и, в частности, обращаясь к setExpanded () (строка 387), вы можете видеть, что он вызывает JXCollapsiblePane.setCollapsed (...), а затем запускает событие изменения свойства для расширенного. Слушатель этого свойства не будет корректным, потому что он сработает до завершения анимации. Итак, если вы зайдете в JXCollapsiblePane и посмотрите на setCollapsed (...) (строка 470), вы увидите, что если он анимирован, он устанавливает параметры и запускает таймер. Мы хотим знать, когда заканчивается анимация, поэтому в этом файле посмотрите на аниматор (строка 620 и, в частности, 652-667), который показывает, что когда анимация заканчивается, она запускает изменение свойства для ANIMATION_STATE_KEY со значением «свернуто» "или" расширенный ". Это событие, которое вы на самом деле хотите. Однако у вас нет доступа к JXCollapsiblePane, поэтому вернитесь к JXTaskPane и найдите ANIMATION_STATE_KEY, и вы найдете строку 208, которая показывает, что JXTaskPane создает прослушиватель для JXCollapsiblePane.ANIMATION_STATE_KEY и обновляет его как собственное событие.

Поскольку у вас есть доступ к JXTaskPane, вы можете прослушивать это событие, выполняя ...

taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
  public void propertyChange(PropertyChangeEvent e) {
    if(e.getNewValue().equals("expanded") {
      ...
    }
    else if(e.getNewValue().equals("collapsed") {
      ...
    }
  }
}

должен получить ваше событие именно тогда, когда вы этого хотите.

Правильный способ прослушивания событий в Swing - через прослушиватели свойств. К сожалению, единственный способ выяснить, какие правильные свойства и значения, это просмотреть исходный код.

1 голос
/ 01 марта 2010

Я не знаком с JXTaskPane, но моя первая реакция - возможно, вы обрабатываете неправильное событие. Вы хотите изменить размер фрейма, когда пользователь нажимает на заголовок - так почему бы не обработать это событие (возможно, с помощью EventQueue.invokeLater (), чтобы изменить размер фрейма после изменения размера панели задач)?

Но если это не сработает, и вам нужно использовать подход, который вы описали выше, лучше использовать javax.swing.Timer. Установите его на 200 миллисекунд или около того и просто перезапускайте его каждый раз, когда запускается componentResized ().

1 голос
/ 26 февраля 2010

В качестве рекомендации вы пытались переопределить метод рисования, сначала вызывая super, а затем помещая код изменения размера в конец этого, если (и только если) размер значительно изменился.

...