2014-01-23 12 views
0

У меня есть окно просмотра, и я подключил к нему прослушиватель изменений. Всякий раз, когда я просматриваю свой видовой экран, мой слушатель изменения вызывается примерно четыре раза. Я не уверен, как этого избежать; Я только хочу, чтобы звонок был однажды?Почему viewel changelistener вызывается несколько раз

+0

Похоже, когда вы прокручиваете состояние 'ViewPort', меняются несколько раз, из-за чего у вас есть несколько вызовов метода stateChanged (ChangeEvent e)'. – alex2410

+1

где ваш код? – Lijo

+0

голосование закрывается как не по теме (не соответствует стандарту на SO) – mKorbel

ответ

2

Там нет никакого способа обойти это, JViewport будет срабатывать несколько stateChanged событий, потому что это предоставление уведомления об изменениях в ряд свойств ...

От JavaDocs ...

Добавляет ChangeListener к список, который уведомляется каждый , когда размер, позиция или размер области просмотра имеют размер .

На данный момент, это отчасти трудно знать, что предложить, как мы не знаем, что именно вы пытаетесь достичь, однако, если вы должны использовать ChangeListener, вы можете настроить коалесцирующий механизм. То есть, а затем реагировать на каждое событие, вы в основном ждать, пока достаточно долго задержки не произошло между событиями, прежде чем ответить на него ...

Например ...

public class DelayedChangeHandler implements ChangeListener { 

    private Timer timer; 
    private ChangeEvent last; 

    public DelayedChangeHandler() { 
     timer = new Timer(250, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       stableStateChanged(); 
      } 
     }); 
     timer.setRepeats(false); 
    } 

    @Override 
    public void stateChanged(ChangeEvent e) { 
     last = e; 
     timer.restart(); 
    } 

    protected void stableStateChanged() { 
     System.out.println("Finally..."); 
    } 

} 

В основном, это ChangeListener, который использует не повторяющийся javax.swing.Timer с небольшой задержкой. Каждый раз, когда вызывается stateChanged, таймер перезапускается. Наконец, когда таймеру разрешено «галочку», он вызывает stableStateChanged, указав, что прошло достаточно времени с момента последнего события.

Это предполагает, что вы не столько заботиться о том, что вызвало событие, только то, что это событие произошло ...

исполняемого примера ...

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class TestViewport { 

    public static void main(String[] args) { 
     new TestViewport(); 
    } 

    public TestViewport() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JPanel pane = new JPanel() { 
        @Override 
        public Dimension getPreferredSize() { 
         return new Dimension(1000, 1000); 
        } 
       }; 

       JScrollPane sp = new JScrollPane(pane); 
       sp.getViewport().addChangeListener(new DelayedChangeHandler()); 
       sp.getViewport().addPropertyChangeListener(new PropertyChangeListener() { 
        @Override 
        public void propertyChange(PropertyChangeEvent evt) { 
         System.out.println(evt.getPropertyName()); 
        } 
       }); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(sp); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class DelayedChangeHandler implements ChangeListener { 

     private Timer timer; 
     private ChangeEvent last; 

     public DelayedChangeHandler() { 
      timer = new Timer(250, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        stableStateChanged(); 
       } 
      }); 
      timer.setRepeats(false); 
     } 

     @Override 
     public void stateChanged(ChangeEvent e) { 
      last = e; 
      timer.restart(); 
     } 

     protected void stableStateChanged() { 
      System.out.println("Finally..."); 
     } 

    } 

} 
+0

+1 отличный ответ, стандартный для всех per_pixel. Слушатели – mKorbel

+0

Спасибо, ребята, побалуйте свои предложения, очень цените. То, что я делаю, запускает событие из списка изменений в моей scrollpane, чтобы нарисовать новые компоненты, когда пользователь прокручивается мимо определенной точки. Я не могу добавить все компоненты спереди, слишком большие, вызывая проблемы с памятью. – 3uPh0riC

+0

О, кстати, mKorbel, я ценю отзывы, действительно, но я не понимаю, что такое «голосование, чтобы закрыть вопрос». Мне просто нужна была какая-то помощь от умных парней и задал базовый вопрос, получил отличные ответы и не пробовал их, не зная, в чем дело. Для меня, чтобы пойти и создать runnable короткую версию программы-монстра, у меня здесь действительно будет много работы.Если вы находите мой вопрос глупым или имеете какие-то другие проблемы с ним, просто не отвечайте на него, есть другие ребята, более чем желающие помочь ручке, подобной мне. Спасибо – 3uPh0riC

2

Вы можете попробовать использовать AdjustmentListener для gettign события прокрутки один раз, попробуйте следующий:

import java.awt.event.AdjustmentEvent; 
import java.awt.event.AdjustmentListener; 
import java.io.UnsupportedEncodingException; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 

public class Example { 

    public static void main(String[] args) throws UnsupportedEncodingException { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     final JScrollPane pane = new JScrollPane(new JTextArea()); 
     pane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { 

      @Override 
      public void adjustmentValueChanged(AdjustmentEvent e) { 
       if(e.getValueIsAdjusting()){ 
        return; 
       } 
       System.out.println("vertical scrolled"); 
       System.out.println("bar value = " + e.getValue()); 
      } 
     }); 
     frame.setContentPane(pane); 
     frame.setSize(300, 200); 
     frame.setVisible(true); 
    } 
} 

Вот еще example.

+0

+1 теперь я не помню, почему я использую [ChangeListener вместо AdjustmentListener] (http://stackoverflow.com/a/8249353/714968), ??? был/был вопрос (ы) ??? – mKorbel

+0

@mKorbel Действительно, я не помню, когда я использовал этого слушателя в прошлом, но для этого вопроса кажется, что это будет работа. Возможно, ChangeListener для более широких изменений. – alex2410

+0

+1 Мне нравится эта идея. Но в моем тестировании это действительно вызвало много событий, приятных без изменений – MadProgrammer

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