JTable右alignment页眉

基本上,我有一个JTable包含右alignment单元格的列,但左alignment的标题看起来非常糟糕。 我想正确alignment这些列的标题,而不改变标题的“外观和感觉”。

谢谢

这是修改表的JTableHeaderTableCellRenderer的一种替代方法。 这个用法并不是严格必要的,但它最大限度地减less了对UI委托外观的影响。

典型用法:

 JTable table = new JTable(…); JTableHeader header = table.getTableHeader(); header.setDefaultRenderer(new HeaderRenderer(table)); 

自定义标题渲染器:

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

尝试这个:

 ((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer()) .setHorizontalAlignment(JLabel.RIGHT); 

上面显示的HeaderRenderer(2011 / sep / 21 by trashgod)结合了Heisenbug(2011 / sep / 21)的代码,只有在所有头部alignment的情况下才能正常工作。

如果您想要以不同的方式alignment不同的标头,则必须使用以下代码:

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

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

那是:
getTableCellRendererComponent设置alignment,而不是在HeaderRenderer构造函数中。

 DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) your_jtable.getTableHeader().getDefaultRenderer(); renderer.setHorizontalAlignment(0); 

0是中心。

 for (int i = 0 ; i < table.getColumnCount(); i++){ DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); renderer.setHorizontalAlignment(SwingConstants.RIGHT); table.getColumn(i).setHeaderRenderer(renderer); } 

关于包装默认表头的一件事情:不要拘泥于它们的引用。

如果您(或您的用户)在Windows 7上使用Windows经典主题,并且您的应用程序设置了默认系统LAF , 则 @trashgod发布的答案可能会对您造成问题。

它受到十年前发布的这个bug的影响(认真)。 如果您的表格正在显示,并且您将Windows首选项中的主题从Aero主题切换到Windows Classic,则会有一系列NPE。 您不应该坚持渲染器的引用,因为它可能会在某个时间点失效。 如错误报告的评论中所build议的那样,包装应该以dynamic的方式完成。 我从那里获取了代码,并创build了以下可运行示例:

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

只需运行该示例,然后select“ Yes两次,然后将其分开。 然后将I_WANT_THE_BUG_TO_HAPPEN静态成员更改为false并重复。 这个成员设置为true情况基本上与这里最高的答案相同。 这个例子中最重要的部分是dynamic包装的扩展JTableMyAlternativeJTable )。

这个问题目前被接受的答案被广泛使用,但它是不好的build议。 具有讽刺意味的是,在显示可sorting的表格(例如“ Window > IDE Tools > Notifications ,您可以丢失应用程序,包括Netbeans 8.0.2(本身是基于Java的)。 只需在Windows 7上将Windows主题从Aero切换到Windows Classic(通过right-click Desktop > Personalize > Change the visuals and sounds on your computerright-click Desktop > Personalize > Change the visuals and sounds on your computer )即可。

如果您使用Glazed Lists并调用ca.odell.glazedlists.swing.TableComparatorChooser.install ,则您也受到影响。 它注入自己的自定义渲染器来sorting箭头。

我偶然发现了这个问题 ,试图find一个我怀疑是相关的问题的解决scheme。

 DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) MSISDNTable.getTableHeader().getDefaultRenderer(); renderer.setHorizontalAlignment(JLabel.RIGHT); 

MSISDNTable是您的表

试试这个代码,

 JTableHeader jtableHeader = jtable.getTableHeader(); DefaultTableCellRenderer rend = (DefaultTableCellRenderer) jtable.getTableHeader().getDefaultRenderer(); rend.setHorizontalAlignment(JLabel.CENTER); jtableHeader.setDefaultRenderer(rend); 

我已经创build了一个基于pvbemmelen62的解决scheme,可以很容易地使用,例如:

 AlignHeaderRenderer.install(myTable, new int[] { SwingConstants.RIGHT, SwingConstants.RIGHT, SwingConstants.LEFT }); 

要么

 AlignHeaderRenderer.install(myTable, 0, SwingConstants.RIGHT); AlignHeaderRenderer.install(myTable, 1, SwingConstants.RIGHT); 

代码如下:

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

秘密就是使用虚拟表格中的渲染器来获得正确的L&F,并从实际表格的行渲染器复制alignment。 这样每个列都分开alignment。 这里是代码:

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

上面的代码没有保留对渲染器的引用,所以避免了上面提到的NPE错误。 它不需要任何命名的类,所以你可以把代码放在任何你需要的地方。

  ((DefaultTableCellRenderer)jTable2.getTableHeader().getDefaultRenderer()) .setHorizontalAlignment(JLabel.CENTER); 
 ((JLabel)mTabBOM.getTableHeader().getDefaultRenderer()).setHorizontalAlignment( JLabel.CENTER );