2012-09-30 31 views
1

當我的JScrollPane中有超過50個組件時,每當用戶決定轉到下一頁時,JScrollPane中的前10個組件都被清除。Java JScrollPane在不更改視口的情況下刪除組件

此功能正常工作並且是可取的,但是當組件被移除時,視口/滾動被改變。每次清除組件時,滾動窗格的視圖都會跳回。

我想要的是保持視口在完全相同的位置,同時從JScrollPane中刪除第一個組件。

目前,我有一個解決辦法,但它不是優雅,但它發現用戶上次是,它是波濤洶涌,並跳轉到滾動窗格不看的權利:

if (middlePanel.getComponents().length > 50) 
{ 
    Component currentScroll = scrollPane.getViewport().getView(); 
    for (int counter = 0; counter < memeAnchors.size(); counter++) 
    { 
     middlePanel.remove(counter); 
    } 
    scrollPane.setViewportView(currentScroll); 
    scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getValue() - 800); 
} 

是什麼我甚至想做甚麼?

在此先感謝大家,

回答

1

好的,我說謊沒有迴應。

其中一種方法如下所示在我的SSCCE中。注意使用Scrollable。解釋是在評論中:

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.LayoutManager; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.*; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

@SuppressWarnings("serial") 
public class Sscce extends JPanel { 
    private static final int INITIAL_ROW_COUNT = 100; 
    public static final int INCREMENTAL_ADD_ROW_COUNT = 10; 
    private static final int MIN_VERT_PERCENT = 4; 
    private static final int TIMER_DELAY = 250; 
    private ViewportViewPanel viewportViewPanel = new ViewportViewPanel(
     new GridLayout(0, 1)); 
    private JScrollPane scrollPane = new JScrollPane(viewportViewPanel); 
    private BoundedRangeModel vertModel; 
    private Timer vertChangeTimer; 
    private int viewportViewPanelIndex = 0; 
    public Component firstViewedComp; 

    public Sscce() { 
     setLayout(new BorderLayout()); 
     add(scrollPane); 

     for (viewportViewPanelIndex = 0; viewportViewPanelIndex < INITIAL_ROW_COUNT; viewportViewPanelIndex++) { 
     viewportViewPanel.add(new ViewablePanel(viewportViewPanelIndex)); 
     } 

     vertModel = scrollPane.getVerticalScrollBar().getModel(); 
     vertModel.addChangeListener(new VertModelChangeListener()); 
    } 

    private class VertModelChangeListener implements ChangeListener { 

     @Override 
     public void stateChanged(ChangeEvent cEvt) { 
     // if timer is running, get out of here 
     if (vertChangeTimer != null && vertChangeTimer.isRunning()) { 
      return; 
     } 

     // if haven't set firstViewedComp back to null (done in Timer) get out of here 
     if (firstViewedComp != null) { 
      return; 
     } 

     // check to see if near bottom 
     int diff = vertModel.getMaximum() - vertModel.getValue() 
       - vertModel.getExtent(); 
     int normalizedDiff = (100 * diff)/vertModel.getMaximum(); 

     // if not near bottom, get out of here 
     if (normalizedDiff >= MIN_VERT_PERCENT) { 
      return; 
     } 

     // create and start timer 
     vertChangeTimer = new Timer(TIMER_DELAY, new VertChangeTimerListener()); 
     vertChangeTimer.setRepeats(false); 
     vertChangeTimer.start(); 

     // get viewport and its rectangle 
     JViewport viewport = scrollPane.getViewport(); 
     Rectangle viewRect = viewport.getViewRect(); 

     // find first component that is inside of viewport's rectangle 
     Component[] components = viewportViewPanel.getComponents(); 
     for (Component component : components) { 
      if (viewRect.contains(component.getBounds())) { 
       if (firstViewedComp == null) { 
        firstViewedComp = component; // first component found 
        break; 
       } 
      } 
     } 

     // delete 10 components at start 
     // add 10 components add end 
     for (int i = 0; i < INCREMENTAL_ADD_ROW_COUNT; i++) { 
      viewportViewPanel.remove(components[i]); 
      viewportViewPanel.add(new ViewablePanel(viewportViewPanelIndex)); 
      viewportViewPanelIndex++; 
     } 

     // redo laying out components and repainting the container 
     viewportViewPanel.revalidate(); 
     viewportViewPanel.repaint(); 

     // scroll back to first viewed component, but give a little delay to allow 
     // layout out above to complete. So queue it on the event queue via invokeLater 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       viewportViewPanel.scrollRectToVisible(firstViewedComp 
        .getBounds()); 
      } 
     }); 

     } 
    } 

    // the timer listener. it just nulls out the first viewed component 
    private class VertChangeTimerListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
     firstViewedComp = null; 
     } 
    } 

    private static void createAndShowGui() { 
     Sscce mainPanel = new Sscce(); 

     JFrame frame = new JFrame("Sscce"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

// JPanel that is held by the JScrollPane's JViewport and that holds the smaller 
// JPanels. Note that it implements Scrollable 
@SuppressWarnings("serial") 
class ViewportViewPanel extends JPanel implements Scrollable { 
    private static final int BLOCK = 8; 

    public ViewportViewPanel(LayoutManager layout) { 
     super(layout); 
    } 

    @Override 
    public Dimension getPreferredScrollableViewportSize() { 
     int scrollWidth = ViewablePanel.PREF_W; 
     int scrollHeight = ViewablePanel.PREF_H * BLOCK; 
     return new Dimension(scrollWidth, scrollHeight); 
    } 

    @Override 
    public int getScrollableBlockIncrement(Rectangle visibleRectangle, 
     int orientation, int direction) { 
     if (orientation == SwingConstants.VERTICAL) { 
     return ViewablePanel.PREF_H * (3 * BLOCK)/4; 
     } 
     return 0; 
    } 

    @Override 
    public boolean getScrollableTracksViewportHeight() { 
     return false; 
    } 

    @Override 
    public boolean getScrollableTracksViewportWidth() { 
     return true; 
    } 

    @Override 
    public int getScrollableUnitIncrement(Rectangle visibleRect, 
     int orientation, int direction) { 
     if (orientation == SwingConstants.VERTICAL) { 
     return ViewablePanel.PREF_H; 
     } 
     return 1; 
    } 

} 

// small JPanel. Many of these are held in a single GridLayout column 
// by the JPanel above. 
@SuppressWarnings("serial") 
class ViewablePanel extends JPanel { 
    public static final int PREF_W = 400; 
    public static final int PREF_H = 50; 
    private int index; 

    public ViewablePanel(int index) { 
     this.setIndex(index); 
     String title = "index " + index; 
     setBorder(BorderFactory.createTitledBorder(title)); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    public int getIndex() { 
     return index; 
    } 

    public void setIndex(int index) { 
     this.index = index; 
    } 

} 
+0

感謝您的回答,比我希望的複雜一點,但我絕對可以用這個。謝謝你的幫助。 – Cristian

+0

@克里斯蒂安:不客氣。祝你好運。 –

相關問題