java - 滚动条在 JPanel 内的 JScrollPane 上不起作用

标签 java swing scrollbar jscrollpane

我正在尝试编写一个 JPane,它有一个 JScrollPane,我想在其中实时添加面板。我的意思是,我有一些组件,其中一个是 Button,它将另一个 JPane 添加到 JScrollPane 内的主要组件 (secundario)。问题是,当它添加一些覆盖超过窗口大小的面板时,我放置的滚动条不会移动,所以我无法向下查看下面的面板(它应该是一个垂直滚动条)。我会把代码留在这里:

旧代码:

    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;
}

更新: 好的,所以我将我的代码减少到最少,以便您可以在任何地方运行该程序。它在我的问题所在的窗口中显示问题,其余窗口工作正常。 控制该窗口的函数名为 panelModulos();我想做的是将这些组件添加到一个面板中,当我按下“Añadir”按钮时,它会创建另一个具有相同组件的 JPanel,并在旧面板下方(按列);问题是现在的大小和 VERTICAL 滚动条,当我添加一些占据超过窗口大小的面板时,它不起作用。

代码:

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:bgs0010@alu.ubu.es">Berta García Sanz</a>
  * @author <a href="mailto:hma0002@alu.ubu.es">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() {

}

图片如下:https://www.dropbox.com/sh/082egfz7zk4l7kq/AABmX-EdDdHdlFbGbjsX6pZia?dl=0

感谢您的帮助。

最佳答案

这会让你一团糟:

secundario.setPreferredSize(maximumSize);

通过设置组件的首选大小,您可以防止它根据它所持有的组件实际计算出它的首选大小,这可能会阻止 secundario 组件扩展。首先摆脱这一行。

如果这不能完全解决您的问题,那么您将要向我们展示您的 Minimal, Complete, and Verifiable example .


你声明:

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.

这是与您的问题有关的关键信息,解决方案是使用一个或多个布局管理器来帮助您解决这个问题。如果添加到 secudario 的所有组件都将具有相同的大小,那么考虑给它一个 GridLayout。我所做的是将使用 JPanel 的 GridLayout 添加到另一个使用 BorderLayout 的 JPanel 并将其添加到 BorderLayout.PAGE_START 位置,然后将第二个 JPanel 添加到 JScrollPane 的视口(viewport)。这可以防止使用 JPanel 的 GridLayout 中的网格散开。


解决您的问题的一种方法是创建一个 JPanel,它包含一行数据,使用合理的布局管理器,并且具有允许外部类从中提取它包含的任何信息的方法。比如这个类:

// 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);
        }
    }
}

有两个 JTextField 和两个 JButton。 JButton 具有调用主类中的方法的操作,这些方法告诉主类 probMain2 添加另一个 RowPanel,或者删除这个完全相同的 RowPanel 对象。

在主类 ProbMain2 中,我使用 JPanel(此处称为 rowHolderPanel)将 RowPanel 添加到 GridLayout,然后将该 JPanel 放入另一个使用 BorderLayout 的 JPanel 中的 BorderLayout.PAGE_START 位置,正如我最初推荐的那样。然后我重新验证并重新绘制 rowHolderPanel。我还将 RowPanel 添加到 ArrayList,因此我可以更轻松地提取它包含的数据。

这是我的完整 Minimal, Complete, and Verifiable example程序。请注意,它比您的要小得多,因为它试图消除与问题无关的所有代码(除了一些额外的代码来美化结果):

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);
        }
    }
}

该代码有两个非内部类,但只有第一个是公共(public)的并且有 main 方法,所以两个非内部类可以存在于一个文件中。这使得更好的mcve因为现在人们可以更轻松地将此代码复制并粘贴到他们的 IDE 中并进行测试。

更好的解决方案是去掉 holder JPanel 和 RowPanel,改用 JTable,但我今晚没有时间或精力这样做。

关于java - 滚动条在 JPanel 内的 JScrollPane 上不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34230247/

相关文章:

java - 在 Java 的 HashSets 上使用方法 retainAll 的时间和空间复杂度是多少?

java发布表单并在重定向后获取响应 header

java - jbutton 更改文本字段的文本

java - ImageIcon 无法设置为 JButton?

css - Antiscroll native 滚动条在 IE 和 Firefox 中可见

Java流程控制问题

java - Android - 如何从字符串中删除最后两行?

java - 当我删除 frame.add(Component) 时,组件必须是有效的对等体

rshiny - 在改变 inputId 时将垂直滚动条重置到顶部

android - 如何在 Android 中将可拖动的滚动条添加到 ScrollView / ListView ?