agregar java swing user-interface jtable jscrollpane

agregar - scrollbar java jframe



JTable que se puede desplazar horizontalmente Y crece para llenar el contenedor principal (1)

Tuve el mismo problema. La tabla solo hace que las columnas sean más grandes o más pequeñas en lugar de mostrar una barra de desplazamiento. A través de prueba y error, el truco que surgió es un ComponentListener que adjuntas al ScrollPane .

El truco consiste en desactivar el cambio de tamaño automático de la mesa una vez que el panel de desplazamiento es más pequeño que el tamaño preferido de la mesa. Tenga en cuenta que no debe establecer el tamaño preferido de la tabla directamente. Deje eso solo para que se calcule automáticamente. Si necesita ciertas columnas más grandes o más pequeñas, establezca su ancho a través del modelo de columna (por ejemplo, table.getColumnModel().getColumn(0).setMaxWidth(25) ).

Esta clase también incluye otro TableModelListener que realiza la misma lógica cuando las columnas se agregan a la tabla.

public final class ScrollingTableFix implements ComponentListener { private final JTable table; public ScrollingTableFix(JTable table, JScrollPane scrollPane) { assert table != null; this.table = table; table.getModel().addTableModelListener(new ColumnAddFix(table, scrollPane)); } public void componentHidden(final ComponentEvent event) {} public void componentMoved(final ComponentEvent event) {} public void componentResized(final ComponentEvent event) { // turn off resize and let the scroll bar appear once the component is smaller than the table if (event.getComponent().getWidth() < table.getPreferredSize().getWidth()) { table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } // otherwise resize new columns in the table else { table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } } public void componentShown(final ComponentEvent event) {} // similar behavior is needed when columns are added to the table private static final class ColumnAddFix implements TableModelListener { private final JTable table; private final JScrollPane scrollPane; ColumnAddFix(JTable table, JScrollPane scrollPane) { this.table = table; this.scrollPane = scrollPane; } @Override public void tableChanged(TableModelEvent e) { if (e.getFirstRow() == TableModelEvent.HEADER_ROW) { if (scrollPane.getViewport().getWidth() < table.getPreferredSize().getWidth()) { table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } else { table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } } } } }

Para usar esto, simplemente conecte todo de la siguiente manera:

JTable table = new JTable(); JScrollPane scroller = new JScrollPane(table); scroller.addComponentListener(new ScrollingTableFix(table, scroller));

Quiero poner una JTable en un JScrollPane y quiero que:

  • ser desplazable horizontal y verticalmente (solo si tiene contenido que lo hace más grande que el contenedor principal)
  • crecer automáticamente para llenar el contenedor primario si es necesario (en ambas direcciones)
  • solo tiene cualquiera / ambas barra (es) de desplazamiento cuando sea necesario

La JList comporta exactamente así, por cierto. Pero no he encontrado una manera fácil de lograr todos los objetivos simultáneamente con una JTable . La forma más fácil de lograr el primero es desactivar el cambio de tamaño automático, pero eso impide que ocurra el segundo. He encontrado una solución muy hacky que agrega un componente de escucha al contenedor padre de JScrollPane y cambia el tamaño de la tabla cuando se cambia el tamaño de ese contenedor. Sin embargo, he tenido que agregar algunos "factores fudge" (ver 4x comentarios) al método de cambio de tamaño, alterando mis controles de altura / ancho en pequeñas cantidades de píxeles debido a una inexactitud inherente, supongo. Sin estos factores de borrado, las barras de desplazamiento aparecen demasiado pronto (antes de que se necesiten), o el final de las celdas de la tabla larga se corta incluso con la barra de desplazamiento presente. La peor parte de estos factores extravagantes es que si cambias el aspecto de la GUI, entonces toda la solución deja de funcionar tan limpiamente (es decir, los factores de chocolate deberían cambiar). Que obviamente está muy lejos de ser ideal.

Tiene que haber una manera más limpia de lograr esto. ¿Alguien puede ayudar? Ejecute el código adjunto y arrastre el tamaño del marco completo para ver la actualización de la tabla. Este código utiliza el aspecto y la sensación de metal que parece funcionar en mi máquina con Windows 7 con los factores de chocolate elegidos, pero no me sorprendería si no funcionara tan limpiamente en otro sistema operativo.

import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ScrollPaneConstants; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; public class JTableScrollTest { private JFrame frame; private JPanel panel; private DefaultTableModel tableModel; private JTable table; private JScrollPane scrollPane; /** * Launch the application. */ public static void main(String[] args) { try { UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); } catch (Throwable e) { e.printStackTrace(); } EventQueue.invokeLater(new Runnable() { public void run() { try { JTableScrollTest window = new JTableScrollTest(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public JTableScrollTest() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); panel = new JPanel(); frame.getContentPane().add(panel, BorderLayout.CENTER); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); scrollPane = new JScrollPane(); panel.add(scrollPane); tableModel = new DefaultTableModel(new Object[]{"Stuff"},0); tableModel.addRow(new Object[]{"reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally long string"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"a"}); tableModel.addRow(new Object[]{"LAST ITEM"}); table = new JTable(tableModel); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); scrollPane.setViewportView(table); resizeTable(); panel.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { resizeTable(); } }); } public void resizeTable() { int width = 0; int height = 0; for (int row = 0; row < table.getRowCount(); row++) { TableCellRenderer renderer = table.getCellRenderer(row, 0); Component comp = table.prepareRenderer(renderer, row, 0); width = Math.max (comp.getPreferredSize().width, width); height += comp.getPreferredSize().height; } if (width > panel.getWidth() - 2) { // fudge factor width += 4; // fudge factor scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); } else { width = panel.getWidth(); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); } if (height > panel.getHeight() + 4) { // fudge factor height -= 26; // fudge factor scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); } else { height = panel.getHeight(); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); } table.setPreferredSize(new Dimension(width, height)); } }