javaswingjtabletablecellrenderer

Cannot align in a cell the text on the left and Icon on the right


I am trying to achieve a very simple thing, I tried different options but none seems to work. I have a simple JTable, in a column I use JLabel in order to show the text and the icon. I just want to have the text to be on the left of the cell and the Icon to the right.

if I use this snippet:

label.setHorizontalTextPosition(SwingConstants.LEFT);
label.setHorizontalAlignment(SwingConstants.RIGHT);

I just get the icon on the right as I want, but the text is immediately on the left of the icon. So I am setting the icon and text gap.

I am setting it like this:

int width = getWidth();
label.setSize(width, getHeight());
AffineTransform affinetransform = new AffineTransform();     
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);     
int textwidth = (int)(label.getFont().getStringBounds(label.getText(), frc).getWidth());

label.setIconTextGap(width - textwidth - label.getIcon().getIconWidth());

Debugging it, it seems to do what is supposed to do, but I got this result:

Text with unnecessary ellipses on the left...

I tried to add a bit of tolerance (subtracting textwidth 2 times) this is the result:

Icon showing but in an expected wrong position but text still have unnecessary ellipses

By the way, the text is shown if I reduce the gap again, but of course, I do not get things aligned as I want.

What I simply would like to achieve is a renderer similar to the editor component which is a combo box as you can see below:

As you can see this what I want to achieve in terms of alignment

This is not a priority task for me but I would really like to understand how to manage this.

EDIT:

I also tried to use a Container (also a JPanel) in order to add 2 JLabels and manage the text and the icon better as suggested by @MadProgrammer, but using the code below the cell is empty, only the background is visible

public java.awt.Component getTreeTableCellRendererComponent(TreeTable treeTable, Object value, boolean selected, boolean hasFocus, int row, int column) {
    Container container = new Container();
    JLabel label = new JLabel();
    JLabel icon = new JLabel();
    label.setText("XXX");
    icon.setIcon(myIcon);
    if (row % 2 == 0) {
        container.setBackground(new java.awt.Color(220, 245, 230));
    }
    else {
        container.setBackground(new java.awt.Color(240, 255, 240));
    }

    label.repaint();
    icon.repaint();
                
    container.add(label, BorderLayout.WEST);
    container.add(icon, BorderLayout.CENTER);                       
    container.revalidate();
    container.doLayout();
    container.setVisible(true);     
    container.repaint();
                
    return container;
}
                

the code above runs without throwing exceptions..


Solution

  • Had this old code lying around demonstrating the concept of using a panel as a renderer. The first 3 characters will be displayed on the left and the remainder on the right:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    
    public class TableRendererPanel
    {
        static class MultiLabelRenderer implements TableCellRenderer
        {
            private JPanel panel;
            private JLabel red;
            private JLabel blue;
    
        public MultiLabelRenderer()
        {
            red = new JLabel();
            red.setForeground(Color.RED);
            blue = new JLabel();
            blue.setForeground(Color.BLUE);
    
            panel = new JPanel();
            panel.setLayout( new BoxLayout(panel, BoxLayout.X_AXIS) );
            panel.add(red);
            panel.add(Box.createHorizontalGlue());
            panel.add(blue);
        }
    
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column)
        {
            panel.setBackground( isSelected ? table.getSelectionBackground() : table.getBackground() );
    
            if (value == null || value.toString().isEmpty())
            {
                red.setText(" ");
                blue.setText(" ");
                return panel;
            }
    
            //  Set the text for the two labels
    
            String text = value.toString();
            red.setText( text.substring(0, 3) );
            blue.setText( text.substring(3) );
    
            return panel;
        }
    }
    
    public static void createAndShowGUI()
    
        {
            JTable table = new JTable(5, 3);
          table.setPreferredScrollableViewportSize(table.getPreferredSize());
            table.getColumnModel().getColumn(0).setCellRenderer( new MultiLabelRenderer());
            JScrollPane scrollPane = new JScrollPane( table );
    
            table.setValueAt("abcde", 0, 0);
            table.setValueAt("123456789", 1, 0);
    
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
            frame.add( scrollPane );
            frame.pack();
            frame.setLocationRelativeTo( null );
            frame.setVisible(true);
        }
    
        public static void main(String[] args) throws Exception
        {
            java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
        }
    
    }