[英]Scrollbar doesn't work on a JScrollPanel inside a JPane
我正在嘗試編寫一個具有JScrollPane的JPane,我想在其中實時添加面板。 我的意思是,我有一些組件,一個是Button,它向JScrollPane內部的主要組件(secundario)添加了另一個JPane。 問題是,當它添加了一些覆蓋范圍超過窗口大小的面板時,我放置的滾動條不會移動,因此我無法下去查看下面的面板(它應該是垂直滾動條)。 我將代碼留在這里:
舊代碼:
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; 問題是現在的尺寸和垂直滾動條在我添加一些面板占用的窗口大於窗口大小時不起作用。
碼:
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組件擴展。 首先擺脫這條線。
如果這不能完全解決您的問題,那么您將想要向我們展示您的“ 最小,完整和可驗證”示例 。
您聲明:
如果我刪除了這條線,那么它可以工作,但是水平的,也就是說,面板連續添加一行,然后出現水平滾動條。 我想垂直放置它們,並使用垂直滾動條,對不起,我沒有提到。
這是與您的問題有關的關鍵信息,解決方案是使用一個或多個布局管理器來幫助您解決此問題。 如果添加到secudario的所有組件都將具有相同的大小,請考慮為其提供GridLayout。 然后,我要做的是使用JPanel將GridLayout添加到另一個使用BorderLayout的JPanel並將其添加到BorderLayout.PAGE_START位置,然后將第二個JPanel添加到JScrollPane的視口中。 這樣可以防止使用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)將RowPanels添加到GridLayout中,然后將該JPanel放置到BorderLayout.PAGE_START位置中,就像我最初建議的那樣,將其放置到另一個使用BorderLayout的JPanel中。 然后,我重新驗證並重新繪制rowHolderPanel。 我還將RowPanel添加到了ArrayList中,因此我可以更輕松地提取其保存的數據。
這是我完整的最小,完整和可驗證的示例程序。 請注意,它比您的要小很多,因為它試圖消除所有與該問題無關的代碼(除了一些用於修飾結果的額外代碼):
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);
}
}
}
該代碼具有兩個非內部類,但是只有第一個是公共的並且具有main方法,因此兩個非內部類都可以存在於單個文件中。 因為現在人們可以更輕松地將此代碼復制並粘貼到他們的IDE中並進行測試,所以這使得mcve更好。
更好的解決方案是擺脫持有人JPanel和RowPanel,而改用JTable,但是我今晚沒有時間或精力進行此操作。
或者您可以使用secundario.setMinimumSize(maximumSize);
而不是secundario.setPreferredSize(maximumSize);
這樣,您將迫使布局縮小的大小不要超過maximumSize
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.