Scrollbar doesn't work on a JScrollPanel inside a JPane

i am trying to code a JPane which has a JScrollPane where i want to add Panels in real time. I mean, I have some Components and one is a Button that adds another JPane to the main one (secundario) which is inside a JScrollPane. The problem is that when it adds some panels that cover more than the size of the window the scrollbar i put doesn't move, so i can't go down to see the panels below (it should be a vertical scrollbar). I'll leave the code here:

Old code:

    private JPanel panelModulos() {
    JPanel raiz = new JPanel();
    raiz.setLayout(new GridLayout(1, 1));
    raiz.setPreferredSize(new Dimension(490, 790));

    // Lo que guarda el contenedor
    secundario = new JPanel();
    secundario.setPreferredSize(maximumSize);

    // Deficicion del formato
    JLabel etModuloDir = etiqueta("Directorio");
    JLabel etModuloNombre = etiqueta("Nombre");
    JButton botAnModulo = boton("Añadir", "addModulo", 'A', icon("Iconos/addMod_opt.png"));
    JButton botElModulo = boton("Eliminar", "delModulo", 'E', icon("Iconos/delMod_opt.png"));
    JTextField txtNomMod = texto("", "Nombre", true, 25);
    JTextField txtDirMod = texto("", "Directorio", true, 25);
    txtDirMod.setMaximumSize(maximumSize);
    txtNomMod.setMaximumSize(maximumSize);

    // Contenedor de botones y etiquetas
    JPanel tercero = new JPanel();
    tercero.add(etModuloDir);
    tercero.add(txtDirMod);
    tercero.add(etModuloNombre);
    tercero.add(txtNomMod);
    tercero.add(botAnModulo);
    tercero.add(botElModulo);

    secundario.add(tercero);

    principal = new JScrollPane(secundario);
    principal.setPreferredSize(new Dimension(490, 790));
    principal.setVerticalScrollBar(principal.createVerticalScrollBar());
    principal.setWheelScrollingEnabled(true);
    principal.getVerticalScrollBar().setEnabled(true);
    principal.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    raiz.add(principal);

    return raiz;
}

UPDATE: OK so I reduced to the minimum my code so that you can run the program everywhere. It says PROBLEM in the window where my problem is, the rest windows work correctly. The function which controls that window is named panelModulos(); what I am trying to do is adding those components to a Panel and when I press the "Añadir" button it creates another JPanel with the same components and below (in colums) the old panel; the problem is the size now and the VERTICAL scrollbar which doesn't work when I add some panels that occupy more than the size of the window.

Code:

package problem;

import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.EventObject;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 * Clase mainApp
* <p>
 * Interfaz gráfica.
 * 
 * @author <a href="mailto:[email protected]">Berta García Sanz</a>
  * @author <a href="mailto:[email protected]">Héctor Mamolar Albitre</a>
 * 
 * @version 1.0
 *
 */

public class probMain implements ActionListener, ItemListener {

/*
 * Botones de la aplicación
 */
private JButton btnBBDDRep, btnEliminarAntena, btnEliminarPA, btnAnnadirPAf, btnAnnadirPA, btnAddRed,
        btnEliminarRed, btnEliminarPlanta, btnAnnadirEdif, btnEliminarEdif, rutaPA1, rutaPA2, cargarDatos,
        iniciarLocalizacion, terminarLocalizacion, conectar, iniciar, obtenerDatos, logs;

/*
 * Campos de la aplicación
 */
private JTextField txtUrlBBDDRep, txtDriverBBDDRep, txtUsuarioBBDDRep, finicial, ffinal, tuser, tclase, turl;
private JTextField txtDireccionI = texto("", " Dirección del edificio ", true, 20);
private JTextField txtTelefonoI = texto("", " Teléfono del edificio ", true, 20);
private JTextField txtX = texto("", " Posicion X de la antena ", true, 3);
private JTextField txtY = texto("", " Posicion Y de la antena ", true, 3);
private JTextField txtZ = texto("", " Posicion Z de la antena ", true, 3);
private JTextField txtDCC = texto("\\\\192.168.0.0\\publico", " Direccion de la carpeta compartida ", true, 17);
private JTextField txtAlcance = texto("", " AlcanceAntena ", true, 5);
private JTextField txtModelo = texto("", " ModeloAntena ", true, 5);
private JTextField txtAncho = texto("", " Ancho de planta del edificio ", true, 3);
private JTextField txtAlto = texto("", " Alto de planta del edificio ", true, 3);
private JTextField txtLargo = texto("", " Largo de planta del edificio ", true, 3);
private JTextField txtEPA2 = texto("", " Edificio del PA ", true, 10);
private JTextField txtPPA2 = texto("", " PPlanta del PA ", true, 4);
private JTextField txtEPA = texto("", " Edificio del PA ", true, 10);
private JTextField txtPPA = texto("", " Planta del PA ", true, 4);
private JTextField txtRed = texto("", " Red del PA ", true, 6);

/*
 * Áreas de texto de la aplicación
 */
private TextArea localizaciontexto = new TextArea(), areatexto = new TextArea();
private JCheckBox jchx;
private JComboBox<String> eList, pList, antList, antList2, antList3, edificiosList, edificiosList1, edificiosList2,
        edificiosList3, plantasList, plantasList2, plantasList3, PAList, PAList2, PAList3, PA1List;
private CheckboxGroup cbg1, cbg2, cbg3;
private Checkbox modEd, modPl, modPA, modAnt, jchxFiltro1, jchxFiltro3, jchxFiltro4;
private JPasswordField tpass, tpassClaveBBDDRep;
private JMenu men;
private JFrame cR, cE, cPA, cD;
private String edif = null;
private String planta = null;
private String fIni = null;
private String fFin = null;
static String password = "";
private Connection conexion, conexionRep, conexionMejora;
private String[] Edificios = { "" };
private String[] Plantas = { "" };
private String[] PuntosAcceso1 = { "" };
private String[] Antenas = { "" };
private File fichero1, fichero2;
private FileNameExtensionFilter filtroFicherotxt = new FileNameExtensionFilter("Archivos .txt", "txt");
private String rutPA1, rutPA2;

// TODO añadido yo
private JTextField txtFuera = texto("", "Fuera (0,1)", true, 2);
private JTextField txtRssiMin = texto("", "RSSI mínimo", true, 3);
private JTextField txtRssiMax = texto("", "RSSI máximo", true, 3);
private JTextField mejorabbddText;
private ArrayList<File> listFichDatos;
private ArrayList<File> listFichDisp;
private JTextField macDispConcreto;
private ArrayList<String> listDispConcretos;
private Thread capturas;
private Thread localizaciones;
private JComboBox<String> boxPuntosAcceso;
private ArrayList<String> listPAActivar;
private ArrayList<String> rutasModulos;
private ArrayList<String> parametros;
// Permite ir añadiendo elementos a la interfaz tras inicializarlo
private JPanel secundario;
private Dimension maximumSize;
private ArrayList<JPanel> panelesModulos;
private JScrollPane principal;

public static void main(String args[]) {
    probMain apli = new probMain(508, 808);
}

// -------------
// CONSTRUCTOR
// -------------

/**
 * Constructor de la clase
 * 
 * @param alt
 *            - Altura de la ventana del interfaz de la aplicación
 * @param anch
 *            - Anchura de la ventana del interfaz de la aplicación
 */
public probMain(int alt, int anch) {

    listFichDatos = new ArrayList<File>();
    listFichDisp = new ArrayList<File>();
    listDispConcretos = new ArrayList<String>();
    listPAActivar = new ArrayList<String>();

    panelesModulos = new ArrayList<JPanel>();

    try {

        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFrame f = new JFrame("Universidad de Burgos - Sistema de Localización GUI 2.0");
        f.setIconImage(new ImageIcon("Iconos/ubu.png").getImage());
        f.setSize(anch, alt);
        f.setJMenuBar(menu());
        f.setContentPane(tabpanel());
        f.setVisible(true);
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    } catch (ClassNotFoundException e) {
        JOptionPane.showMessageDialog(new JFrame(), e + "\n Clase No encontrada desempaquetando objeto",
                "Excepción java.lang", JOptionPane.WARNING_MESSAGE, null);
    } catch (InstantiationException e) {
        JOptionPane.showMessageDialog(new JFrame(), e + "\n Excepcion instanciando clase de Aspecto",
                "Excepción java.lang", JOptionPane.WARNING_MESSAGE, null);
    } catch (IllegalAccessException e) {
        JOptionPane.showMessageDialog(new JFrame(), e + "\n Acceso ilegal a clase de Aspecto",
                "Excepción java.lang", JOptionPane.WARNING_MESSAGE, null);
    } catch (UnsupportedLookAndFeelException e) {
        JOptionPane.showMessageDialog(new JFrame(), e + "\n Clase de Aspecto no soportada", "Excepción javax.swing",
                JOptionPane.WARNING_MESSAGE, null);
    }
}

// ---------------------
// UTILERIA de INTERFAZ
// ---------------------

/**
 * Creación de los componentes principales del menú.
 * 
 * @return JMenuBar Barra de menú de la aplicación
 */
private JMenuBar menu() {
    JMenuBar mBar = new JMenuBar();
    mBar.add(menuConf('Z', "Configuración"));
    mBar.add(menuTitulo('A', "Ayuda"));
    return (mBar);
}

/**
 * Metodo que crea un submenú del menú principal.
 * 
 * @param mnemonic
 *            Nemotécnico del submenú
 * @param nombre
 *            Nombre del submenú
 * @return JMenu Menú de ayuda
 */
private JMenu menuTitulo(char mnemonic, String nombre) {
    JMenu men = new JMenu(nombre);
    men.setMnemonic(mnemonic);
    men.add(objetoMenu("Acerca de...", 'c', "acerca"));
    return (men);
}

/**
 * Metodo que crea un submenú con tres componentes de configuración del menú
 * principal.
 * 
 * @param mnemonic
 *            Nemotécnico del submenú
 * @param nombre
 *            Nombre del submenú
 * @return JMenu Menú de configuración
 */
private JMenu menuConf(char mnemonic, String nombre) {
    men = new JMenu(nombre);
    men.setMnemonic(mnemonic);
    men.setEnabled(false);
    men.add(objetoMenu("Configuración Edificios", 'e', "confEdif"));
    men.add(objetoMenu("Configuración Puntos de Acceso y Red", 't', "confPA"));
    men.add(objetoMenu("Configuración Representación", 'r', "confRep"));
    return (men);
}

/**
 * Metodo que crea un objeto del menú.
 * 
 * @param nombre
 *            nombre del objeto a crear
 * @param mnemonic
 *            mnemonic
 * @param accion
 *            accion que realiza
 * @return JMenuItem objeto con el objeto implententado
 * 
 */
private JMenuItem objetoMenu(String nombre, char mnemonic, String accion) {
    JMenuItem mT = new JMenuItem(nombre, mnemonic);
    mT.setActionCommand(accion);
    mT.addActionListener(this);
    return (mT);
}

/**
 * Metodo que las pestañas de la ventana principal.
 * 
 * @return JTabbedPane Contenedor de pestañas de la interfaz
 */
private JTabbedPane tabpanel() {
    JTabbedPane jtp = new JTabbedPane();
    jtp.addTab("correct", panelConexion());
    jtp.addTab("correct", panelEscaneo());
    jtp.addTab("correct", panelObtenerDatos());
    jtp.addTab("PROBLEM", panelModulos());
    jtp.addTab("correct", panelLocalizarDisp());
    return (jtp);
}

// PANEL CONEXION BBDD
/**
 * Método que establece el formato deseado de la pestaña de configuración de
 * la base de datos.
 * 
 * @return JPanel Panel de conexión a la BBDD de localización
 */
private JPanel panelConexion() {

    JPanel raiz = new JPanel(new GridLayout(1, 1));
    return (raiz);
}

/**
 * Método que establece el formato deseado de la pestaña de escaneo de
 * redes.
 * 
 * @return JPanel Panel de escaneo de redes
 */
private JPanel panelEscaneo() {

    JPanel raiz = new JPanel(new GridLayout(2, 1));

    return (raiz);
}

/**
 * Método que establece el formato deseado de la pestaña de filtrado de
 * datos.
 * 
 * @return JPanel Panel de filtrado de datos
 */
private JPanel panelObtenerDatos() {

    JPanel raiz = new JPanel();

    return (raiz);
}

/**
 * Método que establece el formato deseado de la pestaña que añade módulos a
 * la aplicación.
 * 
 */
private JPanel panelModulos() {

    JPanel raiz = new JPanel();
    raiz.setLayout(new GridLayout(1, 1));

    // Deficicion del formato
    JLabel etModuloDir = etiqueta("Directorio");
    JLabel etModuloNombre = etiqueta("Nombre");
    JButton botAnModulo = boton("Añadir", "addModulo", 'A', icon("Iconos/addMod_opt.png"));
    JButton botElModulo = boton("Eliminar", "delModulo", 'E', icon("Iconos/delMod_opt.png"));
    JTextField txtNomMod = texto("", "Nombre", true, 25);
    JTextField txtDirMod = texto("", "Directorio", true, 25);
    // Lo que guarda el contenedor
    secundario = new JPanel();
    maximumSize = new Dimension(12, 12);

    etModuloDir.setMaximumSize(maximumSize);
    etModuloNombre.setMaximumSize(maximumSize);
    botAnModulo.setMaximumSize(maximumSize);
    botElModulo.setMaximumSize(maximumSize);
    txtNomMod.setMaximumSize(maximumSize);
    txtDirMod.setMaximumSize(maximumSize);

    GridLayout gridLay = new GridLayout(0, 6);
    BorderLayout borLay = new BorderLayout();

    // Contenedor de botones y etiquetas
    JPanel tercero = new JPanel();
    tercero.setMaximumSize(maximumSize);
    tercero.setLayout(gridLay);
    tercero.add(etModuloDir, BorderLayout.PAGE_START);
    tercero.add(txtDirMod, BorderLayout.PAGE_START);
    tercero.add(etModuloNombre, BorderLayout.PAGE_START);
    tercero.add(txtNomMod, BorderLayout.PAGE_START);
    tercero.add(botAnModulo, BorderLayout.PAGE_START);
    tercero.add(botElModulo, BorderLayout.PAGE_START);

    secundario.setLayout(borLay);
    secundario.add(tercero);

    principal = new JScrollPane(secundario, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    principal.setVerticalScrollBar(principal.createVerticalScrollBar());
    principal.setWheelScrollingEnabled(true);
    principal.getVerticalScrollBar().setEnabled(true);
    // principal.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    raiz.add(principal);

    return raiz;
}

/**
 * Método que establece el formato deseado de la pestaña de localización de
 * dispositivos.
 * 
 * @return JPanel Panel de localización
 */
private JPanel panelLocalizarDisp() {
    JPanel raiz = new JPanel(new FlowLayout(FlowLayout.LEFT));

    return (raiz);
}

/**
 * Método que establece las etiquetas de la interfaz.
 * 
 * @param texto
 *            Texto de la etiqueta
 * @return JLabel Etiqueta de la interfaz
 */
private JLabel etiqueta(String texto) {
    return (new JLabel(texto));
}

/**
 * Método que crea campo de texto.
 * 
 * @param texto
 *            Texto del campo
 * @param tooltip
 *            cadena con el tooltip
 * @param editable
 *            El campo es editable o no
 * @param columnas
 *            Tamaño del campo
 * @return JTextField Panel de escaneo de redes
 */
private JTextField texto(String texto, String tooltip, boolean editable, int columnas) {

    JTextField tf = new JTextField(texto, columnas);
    if (editable)
        tf.setEditable(true);
    else
        tf.setEditable(false);
    tf.setToolTipText(tooltip + texto);
    return (tf);
}

/**
 * Método que crea los botones de la interfaz.
 * 
 * @param nombre
 *            Nombre del botón
 * @param accion
 *            Acción del botón
 * @param memo
 *            Nemotécnico del botón
 * @param icon
 *            Icono asociado al botón
 * @return JPanel Panel de escaneo de redes
 */
private JButton boton(String nombre, String accion, char memo, Icon icon) {
    JButton b = new JButton(nombre, icon);
    b.setActionCommand(accion);
    b.setMnemonic(memo);
    b.addActionListener(this);
    return (b);
}

/**
 * Método que obtiene el icono.
 * 
 * @param ruta
 *            Ruta en la que se encuentra ubicado el icono
 * @return JPanel Panel de escaneo de redes
 */
private ImageIcon icon(String ruta) {
    return (new ImageIcon(ruta));
}

/**
 * Método que devuelve el panel de los que hay en la pestaña de módulos al
 * que se corresponde el objeto botón que se recibe como parámetro.
 * 
 * @param bot
 *            botón a buscar entre los paneles de los módulos de mejora.
 * @return panel correspondiente al botón.
 */
private Component getPanel(JButton bot) {
    for (JPanel panel : panelesModulos) {
        for (int i = 0; i < panel.getComponentCount(); ++i) {
            if (panel.getComponent(i).equals(bot)) {
                return panel;
            }
        }
    }
    return null;
}

/**
 * Añade un panel con sus correspondientes componentes a la pestaña de
 * módulos para que se introduzca otro.
 */
private void añadeFilaModulos() {
    JLabel etModuloDir = etiqueta("Directorio");
    JLabel etModuloNombre = etiqueta("Nombre");
    JButton botAnModulo = boton("Añadir", "addModulo", 'A', icon("Iconos/addMod_opt.png"));
    JButton botElModulo = boton("Eliminar", "delModulo", 'E', icon("Iconos/delMod_opt.png"));
    JTextField txtNomMod = texto("", "Nombre", true, 25);
    JTextField txtDirMod = texto("", "Directorio", true, 25);
    txtDirMod.setMaximumSize(maximumSize);
    txtNomMod.setMaximumSize(maximumSize);

    JPanel tercero = new JPanel();
    tercero.add(etModuloDir);
    tercero.add(txtDirMod);
    tercero.add(etModuloNombre);
    tercero.add(txtNomMod);
    tercero.add(botAnModulo);
    tercero.add(botElModulo);

    panelesModulos.add(tercero);
    secundario.add(tercero);
    secundario.revalidate();
    secundario.repaint();

    principal.revalidate();
    principal.repaint();
}

/**
 * Borra un panel y sus componentes y además los datos del módulo
 * correspondiente.
 * 
 * @param e
 *            evento ocurrido al pulsar el botón de eliminar un módulo.
 */
private void borraFilaModulos(EventObject e) {
    // Elimina el panel correspondiente
    secundario.remove(getPanel((JButton) e.getSource()));
    secundario.revalidate();
    secundario.repaint();

    principal.revalidate();
    principal.repaint();
}

// ---------
// OYENTES
// ---------
// Oyente de Botones
public void actionPerformed(ActionEvent e) {

    // Añade los datos del módulo a la base de datos y añade una nueva fila
    // para poner otro módulo.
    if (e.getActionCommand().equals("addModulo")) {
        añadeFilaModulos();
    }

    if (e.getActionCommand().equals("delModulo")) {
        borraFilaModulos(e);
    }

}

/**
 * Procedimiento para llenar los datos de una planta de un edificio dado
 * como parametro segun los datos de la base de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentran las plantas
 */
protected void rellenarPlantas(String idEdificio) {

}

/**
 * Procedimiento para llenar los datos de una planta de un edificio dado
 * como parametro segun los datos de la base de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentran las plantas
 */
protected void rellenarPlantas2(String idEdificio) {

}

/**
 * Procedimiento para llenar los datos de una planta de un edificio dado
 * como parametro segun los datos de la base de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentran las plantas
 */
protected void rellenarPlantas3(String idEdificio) {

}

/**
 * Procedimiento para llenar los datos de una planta de un edificio dado
 * como parametro segun los datos de la base de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentran las plantas
 */
protected void rellenarPlantas4(String idEdificio) {

}

/**
 * Procedimiento para rellenar los datos de un punto de acceso según la base
 * de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentra el punto de acceso.
 * @param idPlanta
 *            planta en la que se encuentra el punto de acceso.
 */
protected void rellenarPAC1(String idEdificio, String idPlanta) {

}

/**
 * Procedimiento para rellenar los datos de un punto de acceso según la base
 * de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentra el punto de acceso.
 * @param idPlanta
 *            planta en la que se encuentra el punto de acceso.
 */
protected void rellenarPAC2(String idEdificio, String idPlanta) {

}

/**
 * Procedimiento para rellenar los datos de un punto de acceso según la base
 * de datos.
 * 
 * @param idEdificio
 *            edificio donde se encuentra el punto de acceso.
 * @param idPlanta
 *            planta en la que se encuentra el punto de acceso.
 */
protected void rellenarPAC3(String idEdificio, String idPlanta) {

}

/**
 * Procedimiento que rellena los datos de una antena conectada a un punto de
 * acceso pasado como parámetro.
 * 
 * @param idPA
 *            identificador del punto de acceso.
 */
protected void rellenarAnt1(String idPA) {

}

/**
 * Procedimiento que rellena los datos de una antena conectada a un punto de
 * acceso pasado como parámetro.
 * 
 * @param idPA
 *            identificador del punto de acceso.
 */
protected void rellenarAnt2(String idPA) {

}

/**
 * Procedimiento que rellena los datos de una antena conectada a un punto de
 * acceso pasado como parámetro.
 * 
 */
protected void rellenarAnt3() {

}

/**
 * Procedimiento que rellena los datos de la red según la antena a la que
 * esté conectada que se pasa como parámetro.
 * 
 * @param idAntena
 *            identificador de la antena.
 */
protected void rellenarRed(String idAntena) {

}

/**
 * Rellena los datos del punto de acceso 1.
 * 
 * @param idEdificio
 *            identificador del edificio
 * @param idPlanta
 *            identificador de la planta
 */
protected void rellenarPA1(String idEdificio, String idPlanta) {

}

public void itemStateChanged(ItemEvent i) {
    if (i.getItemSelectable() == jchx) {
        if (i.getStateChange() == ItemEvent.SELECTED)
            jchx.setSelected(true);
        else
            jchx.setSelected(false);
    }
}

/**
 * Procedimiento que guarda la información obtenida en un fichero de texto
 * denominado HISTORIAL.txt.
 */
public void guardarInfo() {

}

}

Here are the images: https://www.dropbox.com/sh/082egfz7zk4l7kq/AABmX-EdDdHdlFbGbjsX6pZia?dl=0

Thanks for the help.

Upvotes: 1

Views: 196

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285415

This will mess you up:

secundario.setPreferredSize(maximumSize);

By setting the component's preferred size, you prevent it from actually calculating what should be its preferred size based on the components it holds, and this could prevent the secundario component from expanding. Get rid of this line first and foremost.

If this doesn't fully solve your problem, then you're going to want to show us your Minimal, Complete, and Verifiable example.


You state:

If i remove this line it works but horizontally, i mean, the panels add sequentially in a row and an horizontal scrollbar appears. I would like to have them vertically, with a vertical scrollbar, sorry that i didn't mention that.

This is key information that has bearing on your problem, and the solution is to use a layout manager or layout managers to help you with this. If all components added to secudario are going to be the same size, then consider giving it a GridLayout. What I've done is then add the GridLayout using JPanel to another JPanel that uses BorderLayout and add it to the BorderLayout.PAGE_START position, and then add that second JPanel to the JScrollPane's viewport. This prevents the Grids in the GridLayout using JPanel from spreading out.


One way to solve your problem is to create a JPanel that holds one row's worth of data, and that uses a sensible layout manager, and that has methods that allow outside classes to extract from it any information that it holds. For instance this class:

// holds a row of data
@SuppressWarnings("serial")
class RowPanel extends JPanel {
    private static final int COLS = 20;
    private JTextField txtDirMod = new JTextField(COLS);
    private JTextField txtNomMod = new JTextField(COLS);
    private ProbMain2 probMain2;
    private int minorStrut = 3;
    private int majorStrut = 6;

    // TODO: add tool tips, ...
    public RowPanel(ProbMain2 probMain2) {
        this.probMain2 = probMain2;
        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        setBorder(BorderFactory.createEmptyBorder(minorStrut, minorStrut, minorStrut, minorStrut));
        add(new JLabel("Directorio"));
        add(Box.createHorizontalStrut(minorStrut));
        add(txtDirMod);
        add(Box.createHorizontalStrut(majorStrut));
        add(new JLabel("Nombre"));
        add(Box.createHorizontalStrut(minorStrut));
        add(txtNomMod);
        add(Box.createHorizontalStrut(majorStrut));
        add(new JButton(new AnadirAction()));
        add(Box.createHorizontalStrut(minorStrut));
        add(new JButton(new EliminarAction()));
    }

    // to extract data held in the JPanel
    public String getDir() {
        return txtDirMod.getText();
    }

    public String getNom() {
        return txtNomMod.getText();
    }

    private class AnadirAction extends AbstractAction {
        public AnadirAction() {
            super("Anadir");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // add new RowPanel to the main GUI
            probMain2.addRowPanel();
        }
    }

    private class EliminarAction extends AbstractAction {
        public EliminarAction() {
            super("Eliminar");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // tell main GUI to remove *this* RowPanel object
            probMain2.removeRowPanel(RowPanel.this);
        }
    }
}

Has two JTextFields and two JButtons. The JButtons have Actions that call methods in the main class that tell the main class, probMain2, to add another RowPanel, or to remove this very same RowPanel object.

Within the main class, ProbMain2, I add the RowPanels to a GridLayout using JPanel, here called rowHolderPanel, and I place that JPanel into another JPanel that uses BorderLayout, to the BorderLayout.PAGE_START position, just as I recommended originally. I then revalidate and repaint the rowHolderPanel. I've also added the RowPanel to an ArrayList, so I can more easily extract the data it holds.

Here is my complete Minimal, Complete, and Verifiable example program. Notice that it's quite a bit smaller than yours as it tries to eliminate all code not relevant to the problem (except for a little extra code to prettify the results):

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

@SuppressWarnings("serial")
public class ProbMain2 extends JPanel {
    private static final int PREF_W = 800;
    private static final int PREF_H = 500;
    // holds the rows, has grid layout with variable number of rows and one column:
    private JPanel rowHolderPanel = new JPanel(new GridLayout(0, 1));
    private List<RowPanel> rowPanelList = new ArrayList<>();

    public ProbMain2() {
        // panel below holds the rowHOlderPanel at the PAGE_START position
        JPanel borderLayoutPanel = new JPanel(new BorderLayout());
        borderLayoutPanel.add(rowHolderPanel, BorderLayout.PAGE_START);
        JScrollPane scrollPane = new JScrollPane(borderLayoutPanel);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        addRowPanel();

        setLayout(new BorderLayout());
        add(scrollPane);
    }

    public void addRowPanel() {
        RowPanel rowPanel = new RowPanel(this);
        rowPanelList.add(rowPanel);
        rowHolderPanel.add(rowPanel);
        rowHolderPanel.revalidate();
        rowHolderPanel.repaint();
    }

    public void removeRowPanel(RowPanel row) {
        rowPanelList.remove(row);
        rowHolderPanel.remove(row);
        rowHolderPanel.revalidate();
        rowHolderPanel.repaint();
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

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

        JFrame frame = new JFrame("ProbMain2");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
            }
        });
    }

}


// holds a row of data
@SuppressWarnings("serial")
class RowPanel extends JPanel {
    private static final int COLS = 20;
    private JTextField txtDirMod = new JTextField(COLS);
    private JTextField txtNomMod = new JTextField(COLS);
    private ProbMain2 probMain2;
    private int minorStrut = 3;
    private int majorStrut = 6;

    // TODO: add tool tips, ...
    public RowPanel(ProbMain2 probMain2) {
        this.probMain2 = probMain2;
        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        setBorder(BorderFactory.createEmptyBorder(minorStrut, minorStrut, minorStrut, minorStrut));
        add(new JLabel("Directorio"));
        add(Box.createHorizontalStrut(minorStrut));
        add(txtDirMod);
        add(Box.createHorizontalStrut(majorStrut));
        add(new JLabel("Nombre"));
        add(Box.createHorizontalStrut(minorStrut));
        add(txtNomMod);
        add(Box.createHorizontalStrut(majorStrut));
        add(new JButton(new AnadirAction()));
        add(Box.createHorizontalStrut(minorStrut));
        add(new JButton(new EliminarAction()));
    }

    // to extract data held in the JPanel
    public String getDir() {
        return txtDirMod.getText();
    }

    public String getNom() {
        return txtNomMod.getText();
    }

    private class AnadirAction extends AbstractAction {
        public AnadirAction() {
            super("Anadir");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // add new RowPanel to the main GUI
            probMain2.addRowPanel();
        }
    }

    private class EliminarAction extends AbstractAction {
        public EliminarAction() {
            super("Eliminar");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // tell main GUI to remove *this* RowPanel object
            probMain2.removeRowPanel(RowPanel.this);
        }
    }
}

The code has two non-inner classes, but only the first one is public and has the main method, so both non-inner classes can exist in a single file. This makes for a better mcve since now folks can more easily copy and paste this code into their IDE and test it.

A better solution is to get rid of the holder JPanel and the RowPanel and instead use a JTable, but I don't have the time or energy tonight to do this.

Upvotes: 5

Sher Alam
Sher Alam

Reputation: 372

Or you could either use secundario.setMinimumSize(maximumSize); instead of secundario.setPreferredSize(maximumSize);
In this way you are forcing the layout to not reduce more than maximumSize.

Upvotes: 0

Related Questions