Fondamentalement, j'ai une table JTable contenant des colonnes avec des cellules alignées à droite mais des en-têtes alignés à gauche qui semblent vraiment mauvaises. Je voudrais aligner à droite les en-têtes de ces colonnes sans modifier le "Look and Feel" des en-têtes.
Merci
Voici une autre approche pour modifier la TableCellRenderer
d'un JTableHeader
d'une table. Ce n'est pas strictement nécessaire pour cet usage, mais cela minimise l'impact sur l'apparence du délégué de l'interface utilisateur.
Utilisation typique:
JTable table = new JTable(…);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new HeaderRenderer(table));
Rendu d'en-tête personnalisé:
private static class HeaderRenderer implements TableCellRenderer {
DefaultTableCellRenderer renderer;
public HeaderRenderer(JTable table) {
renderer = (DefaultTableCellRenderer)
table.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.CENTER);
}
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {
return renderer.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
}
}
Essaye ça:
((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(JLabel.RIGHT);
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) your_jtable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(0);
Où 0
est le centre.
Le HeaderRenderer présenté ci-dessus (2011/sep/21 de trashgod), associé au code de Heisenbug (2011/sep/21), ne fonctionnera correctement que si tous les en-têtes sont alignés de la même manière.
Si vous souhaitez aligner différents en-têtes différemment, vous devrez utiliser le code suivant:
int[] alignments = new int[] { JLabel.LEFT, JLabel.RIGHT, JLabel.RIGHT };
for (int i = 0 ; i < jTable.getColumnCount(); i++){
jTable.getTableHeader().getColumnModel().getColumn(i)
.setHeaderRenderer(new HeaderRenderer(jTable, alignments[i]));
}
et
private static class HeaderRenderer implements TableCellRenderer {
DefaultTableCellRenderer renderer;
int horAlignment;
public HeaderRenderer(JTable table, int horizontalAlignment) {
horAlignment = horizontalAlignment;
renderer = (DefaultTableCellRenderer)table.getTableHeader()
.getDefaultRenderer();
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, col);
JLabel label = (JLabel)c;
label.setHorizontalAlignment(horAlignment);
return label;
}
}
C'est:
Définissez l’alignement sur getTableCellRendererComponent
et non dans le constructeur HeaderRenderer
.
for (int i = 0 ; i < table.getColumnCount(); i++){
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(SwingConstants.RIGHT);
table.getColumn(i).setHeaderRenderer(renderer);
}
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)
MSISDNTable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);
où MSISDNTable
est votre table
Une chose à retenir sur le wrapping des en-têtes de table par défaut: ne vous en tenez pas à une référence.
Si vous (ou vos utilisateurs) utilisez un thème Windows Classic sous Windows 7 et que votre application définit le système par défaut LAF , la réponse publiée par @trashgod peut vous causer des problèmes.
Il est affecté par ce bug , publié il y a une décennie (sérieusement). Si votre table est affichée et que vous basculez le thème dans les préférences Windows d'un thème Aero vers Windows Classic, il y aura un déluge de NPE. Vous n'êtes PAS censé conserver la référence d'un moteur de rendu, car celle-ci pourrait devenir invalide à un moment donné. Le wrapping doit être effectué de manière dynamique, comme suggéré dans les commentaires du rapport de bogue. J'ai pris le code à partir de là et créé l'exemple suivant:
import Java.awt.*;
import Java.lang.ref.WeakReference;
import javax.swing.*;
import javax.swing.table.*;
public class TestFrame extends JFrame {
private static final boolean I_WANT_THE_BUG_TO_HAPPEN = true;
public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int res = JOptionPane.showConfirmDialog(null, "Do you want to use the XP L&F?", "laffo", JOptionPane.YES_NO_OPTION);
if (res == JOptionPane.YES_OPTION) {
try {
UIManager.setLookAndFeel("com.Sun.Java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
}
}
new TestFrame().setVisible(true);
}
});
}
public class MyModel extends AbstractTableModel {
public int getRowCount() {
return 10;
}
public int getColumnCount() {
return 10;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return "" + rowIndex + " X " + columnIndex;
}
}
public class MyJTable extends JTable {
/**
*
*/
private static final long serialVersionUID = -233098459210523146L;
public MyJTable(TableModel model) {
super(model);
}
public void doSomething() {
System.out.println("HEHE");
}
}
public class MyAlternativeJTable extends JTable {
private WeakReference<TableCellRenderer> wrappedHeaderRendererRef = null;
private TableCellRenderer wrapperHeaderRenderer = null;
public MyAlternativeJTable(TableModel model) {
super(model);
}
private class MyAlternativeTableColumn extends TableColumn {
MyAlternativeTableColumn(int modelIndex) {
super(modelIndex);
}
@Override
public TableCellRenderer getHeaderRenderer() {
TableCellRenderer defaultHeaderRenderer
= MyAlternativeJTable.this.getTableHeader().getDefaultRenderer();
if (wrappedHeaderRendererRef == null
|| wrappedHeaderRendererRef.get() != defaultHeaderRenderer) {
wrappedHeaderRendererRef
= new WeakReference<TableCellRenderer>(defaultHeaderRenderer);
wrapperHeaderRenderer
= new DecoratedHeaderRenderer(defaultHeaderRenderer);
}
return wrapperHeaderRenderer;
}
}
@Override
public void createDefaultColumnsFromModel() {
TableModel m = getModel();
if (m != null) {
// Remove any current columns
TableColumnModel cm = getColumnModel();
while (cm.getColumnCount() > 0) {
cm.removeColumn(cm.getColumn(0));
}
// Create new columns from the data model info
for (int i = 0; i < m.getColumnCount(); i++) {
TableColumn newColumn = new MyAlternativeTableColumn(i);
addColumn(newColumn);
}
}
}
}
private JPanel jContentPane = null;
private JScrollPane jScrollPane = null;
private JTable table1 = null;
private JScrollPane jScrollPane1 = null;
private JTable table2 = null;
/**
* This is the default constructor
*/
public TestFrame() {
super();
initialize();
int res = JOptionPane.showConfirmDialog(null, "Do you want to call updateUI() on the tables ?", "laffo", JOptionPane.YES_NO_OPTION);
if (res == JOptionPane.YES_OPTION) {
table2.updateUI();
table1.updateUI();
}
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(753, 658);
this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.add(getJScrollPane(), null);
jContentPane.add(getJScrollPane1(), null);
}
return jContentPane;
}
/**
* This method initializes jScrollPane
*
* @return javax.swing.JScrollPane
*/
private JScrollPane getJScrollPane() {
if (jScrollPane == null) {
jScrollPane = new JScrollPane();
jScrollPane.setBounds(new Java.awt.Rectangle(358, 0, 387, 618));
jScrollPane.setViewportView(getTable1());
}
return jScrollPane;
}
/**
* This method initializes table1
*
* @return javax.swing.JTable
*/
private JTable getTable1() {
if (table1 == null) {
table1 = new JTable(new MyModel());
}
return table1;
}
/**
* This method initializes jScrollPane1
*
* @return javax.swing.JScrollPane
*/
private JScrollPane getJScrollPane1() {
if (jScrollPane1 == null) {
jScrollPane1 = new JScrollPane();
jScrollPane1.setBounds(new Java.awt.Rectangle(0, 0, 350, 618));
jScrollPane1.setViewportView(getTable2());
}
return jScrollPane1;
}
/**
* This method initializes table2
*
* @return javax.swing.JTable
*/
private JTable getTable2() {
if (table2 == null) {
if (I_WANT_THE_BUG_TO_HAPPEN) {
table2 = new MyJTable(new MyModel());
JTableHeader header = table2.getTableHeader();
TableCellRenderer render = new DecoratedHeaderRenderer(header.getDefaultRenderer());
header.setDefaultRenderer(render);
} else {
table2 = new MyAlternativeJTable(new MyModel());
}
}
return table2;
}
private class DecoratedHeaderRenderer implements TableCellRenderer {
public DecoratedHeaderRenderer(TableCellRenderer render) {
this.render = render;
}
private TableCellRenderer render;
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = render.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return c;
}
}
}
Il suffit d'exécuter l'exemple, de choisir Yes
deux fois et de le regarder se séparer. Puis changez le membre statique I_WANT_THE_BUG_TO_HAPPEN
en false
et recommencez. Le cas où ce membre est défini sur true
est essentiellement le même que la réponse la plus votée ici. La partie la plus importante de cet exemple est la JTable
étendue (MyAlternativeJTable
), qui effectue le wrapping de manière dynamique.
La réponse actuellement acceptée à cette question est largement utilisée, mais elle est déconseillée. Vous pouvez le reproduire avec une perte d'applications, y compris Netbeans 8.0.2 (qui est lui-même basé sur Java) tout en affichant une table triable, telle que Window > IDE Tools > Notifications
, où vous obtiendrez également les rapports NPE, ironiquement. Il suffit de basculer le thème Windows d’Aero vers Windows Classic (via right-click Desktop > Personalize > Change the visuals and sounds on your computer
) sous Windows 7.
Si vous utilisez des listes émaillées et appelez ca.odell.glazedlists.swing.TableComparatorChooser.install
, vous êtes également concerné. Il injecte son propre moteur de rendu personnalisé pour le tri des flèches.
Je suis tombé sur cela par hasard en essayant de trouver une solution pour cette question dont je soupçonne qu’elle est liée.
Le secret consiste à utiliser le moteur de rendu d'une table fictive pour obtenir les valeurs correctes, puis de copier l'alignement à partir du moteur de rendu de ligne de la table réelle. Ainsi, chaque colonne est alignée séparément. Voici le code:
table.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
Component c2 = dummy.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if (table.getRowCount() > 0) {
Component c3 = table.getCellRenderer(0, col).getTableCellRendererComponent(table, value, isSelected, hasFocus, 0, col);
if (c2 instanceof JLabel && c3 instanceof JLabel)
((JLabel)c2).setHorizontalAlignment(((JLabel)c3).getHorizontalAlignment());
}
return c2;
}
private final JTable dummy = new JTable();
});
Le code ci-dessus ne conserve aucune référence aux moteurs de rendu, il évite donc le bogue NPE mentionné ci-dessus. Il ne nécessite aucune classe nommée, vous pouvez donc simplement insérer le code là où vous en avez besoin.
Essayez ce code,
JTableHeader jtableHeader = jtable.getTableHeader();
DefaultTableCellRenderer rend = (DefaultTableCellRenderer) jtable.getTableHeader().getDefaultRenderer();
rend.setHorizontalAlignment(JLabel.CENTER);
jtableHeader.setDefaultRenderer(rend);
J'ai créé une classe basée sur la solution de pvbemmelen62, qui peut être utilisée très facilement, par exemple:
AlignHeaderRenderer.install(myTable, new int[] { SwingConstants.RIGHT,
SwingConstants.RIGHT, SwingConstants.LEFT });
ou
AlignHeaderRenderer.install(myTable, 0, SwingConstants.RIGHT);
AlignHeaderRenderer.install(myTable, 1, SwingConstants.RIGHT);
Voici le code:
public class AlignHeaderRenderer implements TableCellRenderer {
private final TableCellRenderer renderer;
private final int alignment;
public static void install(final JTable table, final int[] alignments) {
for (int i = 0; i < alignments.length; ++i)
install(table, i, alignments[i]);
}
public static void install(final JTable table, final int row,
final int alignment) {
table.getTableHeader().getColumnModel().getColumn(row)
.setHeaderRenderer(new AlignHeaderRenderer(table, alignment));
}
private AlignHeaderRenderer(final JTable table, final int alignment) {
renderer = table.getTableHeader().getDefaultRenderer();
this.alignment = alignment;
}
@Override
public Component getTableCellRendererComponent(final JTable table,
final Object value, final boolean isSelected,
final boolean hasFocus, final int row, final int col) {
final Component c = renderer.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, col);
((JLabel) c).setHorizontalAlignment(alignment);
return c;
}
}