基本上,我有一个JTable包含具有右对齐单元格但左对齐标题的列看起来非常糟糕。我想右对齐这些列的标题而不改变标题的“外观和感觉”。
由于
答案 0 :(得分:42)
以下是修改表格JTableHeader
的TableCellRenderer
的替代方法。这种用法并不是绝对必要的,但它最大限度地减少了对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);
}
}
答案 1 :(得分:36)
试试这个:
((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(JLabel.RIGHT);
答案 2 :(得分:5)
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) your_jtable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(0);
其中0
是中心。
答案 3 :(得分:4)
上面显示的HeaderRenderer(2011 / sep / 21 by trashgod)与Heisenbug(2011 / sep / 21)中的代码相结合,只有在所有标题对齐相同的情况下才能正常工作。
如果要以不同方式对齐不同的标题,则必须使用以下代码:
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
中设置对齐,而不是在HeaderRenderer
构造函数中设置。
答案 4 :(得分:2)
for (int i = 0 ; i < table.getColumnCount(); i++){
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(SwingConstants.RIGHT);
table.getColumn(i).setHeaderRenderer(renderer);
}
答案 5 :(得分:2)
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)
MSISDNTable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);
其中MSISDNTable
是您的表格
答案 6 :(得分:2)
要记住包装默认表头的事情:不要抓住它们的引用。
如果您(或您的用户)在Windows 7和您的应用程序sets default system LAF上使用Windows经典主题,则@trashgod发布的the answer可能会给您带来问题。
受十年前(严重)发布的this bug影响。如果您的表格正在显示,并且您将Windows首选项中的主题从Aero主题切换到Windows Classic,则会有一连串的NPE。您不应该保留渲染器的引用,因为它可能在某个时间点变为无效。包装应该以动态方式完成,如错误报告的注释中所示。我从那里获取代码并创建了以下可运行的示例:
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;
}
}
}
只需运行示例并选择Yes
两次,然后将其分开。然后将I_WANT_THE_BUG_TO_HAPPEN
静态成员更改为false
并重复。此成员设置为true
的情况与此处最受欢迎的答案基本相同。这个例子最重要的部分是扩展的JTable
(MyAlternativeJTable
),它动态地进行包装。
这个问题目前被接受的答案被广泛使用,但不建议。你可以通过丢失应用程序来重现它,包括Netbeans 8.0.2(它本身是基于Java的),同时显示一个可排序的表,例如Window > IDE Tools > Notifications
,你也可以获得NPE报告,具有讽刺意味。只需在Windows 7上将Windows主题从Aero切换到Windows Classic(通过right-click Desktop > Personalize > Change the visuals and sounds on your computer
)。
如果您使用的是Glazed Lists并致电ca.odell.glazedlists.swing.TableComparatorChooser.install
,您也会受到影响。它会为注释箭头注入自己的自定义渲染器。
我在试图找到this question的解决方案时巧妙地偶然发现了这一点,我怀疑这个解决方案是相关的。
答案 7 :(得分:1)
DefaultTableCellRenderer defaultHeaderRenderer = (DefaultTableCellRenderer) getTableHeader().getDefaultRenderer();
defaultHeaderRenderer.setHorizontalAlignment(JLabel.CENTER);
getTableHeader().setDefaultRenderer(defaultHeaderRenderer);
我已经在JAVA8中进行了测试。工作正常。
答案 8 :(得分:0)
试试这段代码,
JTableHeader jtableHeader = jtable.getTableHeader();
DefaultTableCellRenderer rend = (DefaultTableCellRenderer) jtable.getTableHeader().getDefaultRenderer();
rend.setHorizontalAlignment(JLabel.CENTER);
jtableHeader.setDefaultRenderer(rend);
答案 9 :(得分:0)
我已经基于pvbemmelen62的解决方案创建了一个类,可以很容易地使用,例如:
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;
}
}
答案 10 :(得分:0)
秘诀是使用虚拟表中的渲染器来获得正确的L&amp; F,并从真实表的行渲染器中复制对齐。这样每个列分别对齐。这是代码:
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错误。它不需要任何命名类,因此您可以将代码放在任何需要的地方。
答案 11 :(得分:-1)
((DefaultTableCellRenderer)jTable2.getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(JLabel.CENTER);
答案 12 :(得分:-2)
((JLabel)mTabBOM.getTableHeader().getDefaultRenderer()).setHorizontalAlignment( JLabel.CENTER );