Leandro Lima
Leandro Lima

Reputation: 1170

JPanel and JScrollPane with only vertical scroll

I'm interested in create a container that receive buttons dynamically. When it reaches the container width the buttons are put in bellow the first line of buttons and a vertical scrollbar must to be showed. Although it can't show the horizontal scrollbar, the container could be resizable horizontally. As an example: enter image description here

Clicking on jbutton1 you add new buttons according with panel size. In this picture it's not possible to see the vertical scrollbar and this is the problem.

The code I used is the bellow one:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ScrollPanelTest;

import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JScrollBar;

/**
 *
 * @author leandro.lima
 */
public class ScrollPane extends javax.swing.JFrame {

    public int count = 1;
    private WrapLayout layout = new WrapLayout(FlowLayout.LEADING, 5, 5);

    /**
     * Creates new form ScrollPane
     */
    public ScrollPane() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jPanel1 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jPanel1.setBackground(new java.awt.Color(255, 255, 255));
        jPanel1.setMinimumSize(new java.awt.Dimension(0, 0));
        jPanel1.setPreferredSize(new java.awt.Dimension(0, 0));
        java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout();
        flowLayout1.setAlignOnBaseline(true);
        jPanel1.setLayout(flowLayout1);
        jScrollPane1.setViewportView(jPanel1);
        jPanel1.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jButton1)
                .addContainerGap(327, Short.MAX_VALUE))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jScrollPane1))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(163, Short.MAX_VALUE)
                .addComponent(jButton1))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(jScrollPane1)
                    .addGap(34, 34, 34)))
        );

        pack();
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        final JButton button = new JButton();
        button.setPreferredSize(new Dimension(100, 100));
        button.setSize(new Dimension(100, 100));

        button.setAction(new AbstractAction("<html><center><h4>Button " + (count++) + "</h4><br>Remove me</center></html>") {
            @Override
            public void actionPerformed(ActionEvent ae) {
                jPanel1.remove(button);
                jPanel1.getRootPane().repaint();
                getContentPane().repaint();
            }
        });
        
        jPanel1.add(button);
        jPanel1.getRootPane().repaint();
        getContentPane().repaint();
    }                                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {

        }
        //</editor-fold>

        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ScrollPane().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration                   
}

Obs: I couldn't find a way to repaint the panel when buttons are add, if you know, please show me too.

Thanks!

Upvotes: 0

Views: 1053

Answers (1)

camickr
camickr

Reputation: 324207

    jPanel1.setLayout(flowLayout1);
    jScrollPane1.setViewportView(jPanel1);

You are using a FlowLayout in the panel. A FlowLayout does NOT recalculate the preferred size of a panel. Since the preferred size never changes, the vertical scrollbar will never appear.

That is why you need to use the WrapLayout on your panel.

You define a WrapLayout variable but you never actually use the WrapLayout on the panel.

Also, I have no idea why you are using a GroupLayout for something so simple. The default layout manager for a frame is a BorderLayout. Just create the scrollpane with the panel and add the scrollpane to the BorderLayout.CENTER. Then you add the other panel containing the button to the BorderLayout.PAGE_END. Its two lines of code. Learn you to create your own GUI's and don't rely on the complex code generate by the IDE.

I couldn't find a way to repaint the panel when buttons are add, if you know, please show me too.

When you add (or remove) components from a visible GUI then the basic code is:

panel.add(...);
panel.revalidate();
panel.repaint();

Upvotes: 3

Related Questions