I'm creating a JDialog
window with a JTable
on it and I'm trying to make it some "responsive" for different screen sizes. Due the window and the table size may change, I set by percentages the columns width.
No problems at this point. Everything looks good the first time the table gets shown. Once the table gets reloaded (due a modification or something), the columns sizes look different, the table and window still the same size though. This happens just the first time gets reloaded and then everything keeps the same size every next reload.
I used a JOptionPane
message dialog to show the table width every time it gets loaded and I found the problem. The first time the table gets loaded is using a different size (the JScrollPane
preferred size) and then the next times uses the one it should be due the resize operations.
The real question is why?
I already tried to move the JDialog
resizing code to different places on the initComponents()
method (creating a global Dimension variable), but the same still happening. If I remove the resizing JDialog
code everything works great but that's the coward way lol.
This is the code I'm using, at least what I think is relevant.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
public class Test extends JDialog {
private javax.swing.JButton bUpdate;
private javax.swing.JPanel jPanel1;
private javax.swing.JTable tabla;
private javax.swing.JScrollPane tablaSP;
public Test(Dimension d){
initComponents();
int w = (int) (Math.round(d.getWidth())/2);
int h = (int) (Math.round(d.getHeight())/2);
setSize(w, h);
setLocationRelativeTo(null);
bUpdate.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
cargarProductos();
}
});
cargarProductos();
}
private void cargarProductos(){
try{
String atr[] = {"Código", "Proveedor", "Nombre", "Clasificación", "Descripción", "Tipo", "P. Compra", "P. Venta"};
DefaultTableModel model = new DefaultTableModel(null, atr){
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
//Filling table model
tabla.setModel(model);
int tw = tablaSP.getWidth();
TableColumnModel cm=tabla.getColumnModel();
cm.getColumn(0).setPreferredWidth((int) (tw*.10));
cm.getColumn(1).setPreferredWidth((int) (tw*.15));
cm.getColumn(2).setPreferredWidth((int) (tw*.15));
cm.getColumn(3).setPreferredWidth((int) (tw*.10));
cm.getColumn(4).setPreferredWidth((int) (tw*.19));
cm.getColumn(5).setPreferredWidth((int) (tw*.10));
cm.getColumn(6).setPreferredWidth((int) (tw*.10));
cm.getColumn(7).setPreferredWidth((int) (tw*.10));
tabla.setAutoCreateRowSorter(true);
JOptionPane.showMessageDialog(null, tw, "Table width", JOptionPane.PLAIN_MESSAGE);
}catch(Exception e){
JOptionPane.showMessageDialog(this, e.getMessage(), "Error llenando tabla de productos", JOptionPane.PLAIN_MESSAGE);
}
}
public static void main(String[]args){
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Windows".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch(Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
}
EventQueue.invokeLater(new Runnable() {
public void run() {
Test dialog = new Test(new Dimension (Toolkit.getDefaultToolkit().getScreenSize()));
dialog.setVisible(true);
}
});
}
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
bUpdate = new javax.swing.JButton();
tablaSP = new javax.swing.JScrollPane();
tabla = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
setSize(new java.awt.Dimension(0, 0));
bUpdate.setText("Update");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(bUpdate, javax.swing.GroupLayout.DEFAULT_SIZE, 83, Short.MAX_VALUE)
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(bUpdate)
.addContainerGap(242, Short.MAX_VALUE))
);
tabla.setModel(new javax.swing.table.DefaultTableModel(
new Object[][]{ {},{},{},{} },
new String[]{}
));
tablaSP.setViewportView(tabla);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(tablaSP)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(tablaSP, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addContainerGap())
);
pack();
}
}
I want it to be a JDialog
because I need it as a modal Window, but I also need to make it bigger and some "responsive" due the content table may be huge.
The original issue is that you call initComponents
to early, namely before you have applied the dimensions you want it to have. As such the call of pack
in the initComponents
components method reduces your panel to the minimum size.
Afterwards you changed the size of the dialog (by calling setSize(w,h)
),
but that didn't directly affect the involved components. However when the dialog was set to visible
the components were automatically adjusted to fit the defined size. That did not apply to your column size as you did not define a ComponentListener
that would have triggered this (see 2nd example below).
This caused a click on the update
button to consider the adjusted size of the component for the first time and thus they were applied to the columns.
To fix your issue with the different sizes change your method calls in the constructor to
(complete example of the constructor further below):
int w = (int) (Math.round(d.getWidth()) / 2);
int h = (int) (Math.round(d.getHeight()) / 2);
setPreferredSize(new Dimension(w, h));
initComponents();
You might want to remove the setSize(new java.awt.Dimension(0, 0));
from your initComponents()
methods.
If you want to maintain the column size when the user manually resizes the Dialog consider adding a ComponentListener
, for another example check this answer
.
This could also be used as an alternative solution with your original code, but it might be cleaner to define the sizes correctly in the first place.
public Test(Dimension d) {
int w = (int) (Math.round(d.getWidth()) / 2);
int h = (int) (Math.round(d.getHeight()) / 2);
setPreferredSize(new Dimension(w, h));
initComponents();
setLocationRelativeTo(null);
bUpdate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cargarProductos();
}
});
this.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
cargarProductos();
}
});
}