2014-03-19 25 views
3

我在显示放置在JScrollPane中的特定组件时遇到问题。我有水平的JScrollPane GridLayout(1,0),它包含可变数量的JPanels - 每个包含图像。这就像GIF图像中的帧预览。我使用按钮在这些JPanel之间移动(通过改变边界并保持所选的索引),但我不知道如何强制JScrollPane向我显示JPanel是否被选中(并且如果可能,将其居中)。如何强制JScrollPane中的组件显示

所以我想这个 enter image description here

力做到这一点:提前 enter image description here

谢谢!

编辑:scrollRectToVisible()方法

public class MiniatursPanel extends JPanel{ 


private int indexOfChosenFrame = 0; 
private ArrayList<JPanel> frames; 
private JScrollPane scrollPane; 
private JPanel innerPanel; 



public MiniatursPanel(){ 
    setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),BorderFactory.createLoweredBevelBorder())); 
    setPreferredSize(new Dimension(1200,170)); 
    setLayout(null);  
} 

public void initialize(){ 
    int width = GifImageStats.getInstance().getWidth(); 
    int height = GifImageStats.getInstance().getHeight(); 
    int numberOfFrames = GifImageStats.getInstance().getNumberOfFrames(); 

    frames = new ArrayList(numberOfFrames); 

    for (int i = 0; i < numberOfFrames; i++) { 
     JPanel frameBox = new JPanel(); 
     frameBox.setLayout(new FlowLayout(FlowLayout.CENTER)); 
     JButton button = new JButton(String.valueOf(i+1)); 
     button.setPreferredSize(new Dimension(2*width,2*height)); 
     button.setBackground(Color.white); 
     button.setFocusable(false); 
     frameBox.add(button); 
     frames.add(frameBox); 
    } 

    innerPanel = new JPanel(); 
    innerPanel.setLayout(new GridLayout(1,0,10,10)); 


    for (JPanel button : frames) { 
     innerPanel.add(button); 
    } 

    scrollPane = new JScrollPane(innerPanel); 
    scrollPane.setBounds(10, 10, 1180, 145); 
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 

    highlightFrame(frames.get(0)); 

    add(scrollPane); 
} 


public void nextFrame(){ 
    if (indexOfChosenFrame == frames.size() - 1) {   
     unhighlightFrame(frames.get(indexOfChosenFrame)); 
     indexOfChosenFrame = 0; 
     highlightFrame(frames.get(0)); 
    }else{ 
     unhighlightFrame(frames.get(indexOfChosenFrame)); 
     indexOfChosenFrame++; 
     highlightFrame(frames.get(indexOfChosenFrame)); 
    } 
} 

public void previousFrame(){ 
    if (indexOfChosenFrame == 0) {   
     unhighlightFrame(frames.get(0)); 
     indexOfChosenFrame = frames.size()-1; 
     highlightFrame(frames.get(indexOfChosenFrame)); 
    }else{ 
     unhighlightFrame(frames.get(indexOfChosenFrame)); 
     indexOfChosenFrame--; 
     highlightFrame(frames.get(indexOfChosenFrame)); 
    } 
} 

private void highlightFrame(JPanel frame){ 
    Rectangle rect = frame.getBounds(); 
    rect.setBounds(frame.getX()-550, frame.getY(), frame.getWidth()+1050, frame.getHeight()); 
    innerPanel.scrollRectToVisible(rect);  
    frame.setBorder(BorderFactory.createLineBorder(Color.red,2)); 
}   

private void unhighlightFrame(JPanel frame){ 
    frame.setBorder(null); 
} 

回答

3

几乎工作的代码这里的相关方法是JComponent#scrollRectToVisible(Rectangle)。必须在位于滚动窗格的视口中的组件上调用它。 (就你而言,这是带有网格布局的面板,其中包含其他子面板)。

传递给此方法的矩形可以是一个子面板的边界。在这种情况下,scoll窗格将执行必要的“最小”滚动操作,以使给定的矩形可见。如果你想确保各个子面板位于中心,那么你可以增加这个矩形的大小 - 也就是说,你可以定义一个矩形,使所需的子面板位于中心。

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.Rectangle; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.BorderFactory; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JSpinner; 
import javax.swing.SpinnerNumberModel; 
import javax.swing.SwingConstants; 
import javax.swing.SwingUtilities; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 


public class ScrollToVisible 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static void createAndShowGUI() 
    { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     int n = 20; 
     final JPanel panel = new JPanel(new GridLayout(1,0)); 
     final List<JComponent> components = new ArrayList<JComponent>(); 
     for (int i=0; i<n; i++) 
     { 
      JComponent component = new JLabel(String.valueOf(i), SwingConstants.CENTER); 
      component.setPreferredSize(new Dimension(100,100)); 
      component.setBorder(BorderFactory.createLineBorder(Color.BLACK)); 
      components.add(component); 
      panel.add(component); 
     } 
     final JScrollPane scrollPane = new JScrollPane(panel); 

     final JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0, n-1, 1)); 
     spinner.addChangeListener(new ChangeListener() 
     { 
      JComponent selectedComponent = components.get(0); 

      @Override 
      public void stateChanged(ChangeEvent e) 
      { 
       selectedComponent.setBorder(BorderFactory.createLineBorder(Color.BLACK)); 

       int index = (Integer)spinner.getValue(); 
       JComponent component = components.get(index); 
       Rectangle bounds = component.getBounds(); 

       // This would make the component "just" visible: 
       //panel.scrollRectToVisible(bounds); 

       // This will center the component: 
       int cx = bounds.x + bounds.width/2; 
       int w = scrollPane.getViewport().getWidth(); 
       Rectangle r = new Rectangle(cx-w/2, bounds.y, w, bounds.height); 
       panel.scrollRectToVisible(r); 


       selectedComponent = component; 
       selectedComponent.setBorder(BorderFactory.createLineBorder(Color.RED)); 

      } 
     }); 

     f.getContentPane().setLayout(new BorderLayout()); 
     f.getContentPane().add(scrollPane, BorderLayout.CENTER); 
     f.getContentPane().add(spinner, BorderLayout.NORTH); 


     f.setSize(800, 300); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

} 

编辑:你应该使用setLayout(null),你应该做手工调用setBounds,你应该很少使用setPreferredSize。而且......当你发布的代码已经非常接近https://stackoverflow.com/help/mcve(或者甚至是由另一篇文章的可运行示例创建的),那么你应该使其真的可以运行。这很烦人根据该重新插入样板代码,浪费一些时间与调试,直到你意识到initialize()完全不叫......

但是,更改代码:

private void highlightFrame(JPanel frame){ 
    Rectangle rect = frame.getBounds(); 

    int c = rect.x + rect.width/2; 
    int w = scrollPane.getViewport().getWidth(); 
    int x = c-w/2; 
    rect.setBounds(x, rect.y, w, rect.height); 

    innerPanel.scrollRectToVisible(rect);  
    frame.setBorder(BorderFactory.createLineBorder(Color.red,2)); 
}   

private void unhighlightFrame(JPanel frame){ 
    frame.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 
} 

最重要的是要确保组件的大小是正确的,方法是设置一个与“突出显示”边框大小相同的空白边框。

+0

谢谢!它几乎完美地工作。但最后两个组件不会显示,我不知道为什么。我也尝试手动更改矩形弹簧,因此它会更宽,并将其更向右移动,但没有成功。滚动条在结束之前停止一段。我也会在一段时间内将代码添加到原始文章中,这可能会有所帮助。 – user3437263

+0

@ user3437263添加**编辑** – Marco13

+0

非常感谢您的帮助和时间。它现在完美。问题真的出现在我设定为空的边界内。 :) – user3437263