2012-04-26 19 views
8

Tengo un pequeño problema al utilizar JScrollPane en mi aplicación Java.Tamaño JScrollPane que contiene JPanel cuando aparecen barras de desplazamiento

Tengo un JScrollPane que contiene un JPanel. Este JPanel se actualiza dinámicamente con botones (ordenados verticalmente) que pueden ser de cualquier ancho. El JPanel ajusta automáticamente su ancho al componente más grande JButton que se encuentra dentro.

Ahora, cuando aparece la barra de desplazamiento vertical, se quita algo de espacio en el lado derecho de mi JPanel, lo que hace que los botones más grandes no aparezcan por completo. No quiero usar una barra de desplazamiento horizontal además de mostrar todo el botón.

¿Hay alguna manera de cambiar el tamaño de mi JPanel cuando aparece una barra de desplazamiento, por lo que aparece muy bien al lado de mis botones? ¿O hay alguna otra forma de que la barra de desplazamiento aparezca junto a mi JPanel?

¡Gracias de antemano!

EDIT: Aquí hay una demostración de mi problema. Cuando cambia el tamaño de la ventana a una altura menor, se cubre una pequeña parte de los botones del lado derecho.

import java.awt.BorderLayout; 
import java.awt.EventQueue; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import java.awt.GridLayout; 

/** 
* @author Dylan Kiss 
*/ 

public class Demo { 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        JFrame myFrame = new JFrame("Demo"); 
        JPanel sideBar = new JPanel(); 
        JPanel centerPanel = new JPanel(); 
        centerPanel.add(new JLabel("This is the center panel.")); 

        JPanel buttonContainer = new JPanel(); 
        JButton myButton = null; 

        for (int i = 0; i < 20; i++) { 
         buttonContainer.setLayout(new GridLayout(20, 1, 0, 0)); 
         myButton = new JButton("This is my button nr. " + i); 
         buttonContainer.add(myButton); 
        } 

        sideBar.setLayout(new BorderLayout(0, 0)); 

        JScrollPane scrollPane = new JScrollPane(buttonContainer); 

        sideBar.add(scrollPane); 

        myFrame.getContentPane().add(sideBar, BorderLayout.WEST); 
        myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER); 

        myFrame.setLocationByPlatform(true); 
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        myFrame.pack(); 
        myFrame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 
+1

Podría dar SSCCE? – StanislavL

+0

Es parte de un gran proyecto. Trataré de proporcionar una breve demostración del problema. – dylan202

+1

@StanislavL para usuarios nuevos, supongo que es mejor vincular lo que es [SSCCE] (http://sscce.org/). :) – COD3BOY

Respuesta

6

Aquí es un simple, no es bonito, solución:

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 

EDIT: pensé que podría no hacer el trabajo, en su caso. Aquí es una solución mejor a pesar de que tiene un buen montón de repetitivo:

private class ButtonContainerHost extends JPanel implements Scrollable { 
    private static final long serialVersionUID = 1L; 

    private final JPanel buttonContainer; 

    public ButtonContainerHost(JPanel buttonContainer) { 
     super(new BorderLayout()); 
     this.buttonContainer = buttonContainer; 
     add(buttonContainer); 
    } 

    @Override 
    public Dimension getPreferredScrollableViewportSize() { 
     Dimension preferredSize = buttonContainer.getPreferredSize(); 
     if (getParent() instanceof JViewport) { 
      preferredSize.width += ((JScrollPane) getParent().getParent()).getVerticalScrollBar() 
        .getPreferredSize().width; 
     } 
     return preferredSize; 
    } 

    @Override 
    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 
     return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width * 9/10, 1) 
       : Math.max(visibleRect.height * 9/10, 1); 
    } 

    @Override 
    public boolean getScrollableTracksViewportHeight() { 
     if (getParent() instanceof JViewport) { 
      JViewport viewport = (JViewport) getParent(); 
      return getPreferredSize().height < viewport.getHeight(); 
     } 
     return false; 
    } 

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

    @Override 
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 
     return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width/10, 1) 
       : Math.max(visibleRect.height/10, 1); 
    } 
} 

Implementa desplazable para obtener el control total del movimiento en sentido vertical, hace un truco de fantasía con el seguimiento de la altura de la vista para asegurarse de que los botones se expanden cuando el espacio está disponible y agrega el ancho de la barra de desplazamiento vertical al ancho preferido en todo momento. Podría expandirse cuando la barra de desplazamiento vertical esté visible, pero eso se ve mal de todos modos. Utilizar de esta manera:

scrollPane = new JScrollPane(new ButtonContainerHost(buttonContainer)); 

Se ve a mí como se requiere esta solución debido a un posible error en javax.swing.ScrollPaneLayout:

if (canScroll && (viewSize.height > extentSize.height)) { 
    prefWidth += vsb.getPreferredSize().width; 
} 

Aquí EXTENTSIZE se establece en el tamaño preferido de la viewport y viewSize se configuran en viewport.getViewSize(). Esto no parece correcto, AFAIK el tamaño de la vista dentro de la ventana siempre debe ser igual al tamaño preferido. Me parece que el tamaño de la vista debe compararse con el tamaño real de la ventana gráfica en lugar de su tamaño preferido.

+0

Prefiero mostrar solo la barra de desplazamiento cuando sea necesario:/ – dylan202

+0

Gracias por esta bonita solución. Funciona perfectamente como yo quiero. – dylan202

0

Puede cambiar el tamaño del JPanel llamando a setPreferredSize cuando se necesite cambiar el tamaño del JPanel.

buttonContainer.setPreferredSize(Dimension d); 
2

Una simple solución para satisfacer sus exigencias en cuanto a

Is there a way to resize my JPanel when a scrollbar appears, so it 
appears nicely next to my buttons? 

es el uso de EmptyBorder, esto le permitirá lograr lo que se siente como, debería ocurrir, como se muestra en la siguiente imagen:

SCROLLBAR SETTING

acabo de agregar esta línea escrita a continuación después de esta línea JPanel buttonContainer = new JPanel();

AÑADIDO LÍNEA

buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); 

Aquí está el código con esa línea añadido:

import java.awt.BorderLayout; 
import java.awt.EventQueue; 

import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import java.awt.GridLayout; 

/** 
* @author Dylan Kiss 
*/ 

public class Demo 
{ 
    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       try 
       { 
        JFrame myFrame = new JFrame("Demo"); 
        JPanel sideBar = new JPanel(); 
        JPanel centerPanel = new JPanel(); 
        centerPanel.add(new JLabel("This is the center panel.")); 

        JPanel buttonContainer = new JPanel(); 
        buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); 
        JButton myButton = null; 

        for (int i = 0; i < 20; i++) 
        { 
         buttonContainer.setLayout(new GridLayout(20, 1, 0, 0)); 
         myButton = new JButton("This is my button nr. " + i); 
         buttonContainer.add(myButton); 
        } 

        sideBar.setLayout(new BorderLayout(0, 0)); 

        JScrollPane scrollPane = new JScrollPane(buttonContainer);  

        sideBar.add(scrollPane); 

        myFrame.getContentPane().add(sideBar, BorderLayout.WEST); 
        myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER); 

        myFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
        myFrame.pack(); 
        myFrame.setLocationByPlatform(true); 
        myFrame.setVisible(true); 
       } 
       catch (Exception e) 
       { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 
Cuestiones relacionadas