2

I have a JTable in which the final column displays a custom cell renderer (a JButton). Is it possible to reduce the width of the JButton within it's column so that it is only large enough to display it's text? I would rather not reduce the size of the column itself unless that is the only solution. Methods which I have tried and have failed were to:

  • Set an empty border
  • Set prefered size
  • Add a margin

Code for the custom renderer can be seen below:

import java.awt.Component;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class ButtonColumnRenderer extends JButton implements TableCellRenderer {

    public ButtonColumnRenderer(){
      //  this.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
      //  this.setPreferredSize(new Dimension(10,10));
      //  this.setMargin(new Insets(20,20,20,20));
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
        return this;
    }
}

The custom render component can be used as follows:

    import javax.swing.*;
    import javax.swing.table.*;

    public static void main(String[] args){
        //setup data + column headers
        String[] columns = {"Text Column", "Button Column"};
        Object[][] data = new Object[3][2];
        for(int i = 0; i < 3; i++){
            Object[] rowOfData = {"text" + i, "button" + i};
            data[i] = rowOfData;
        }   

        //Setup table
        DefaultTableModel model = new DefaultTableModel(data, columns);
        JTable table = new JTable(model);
        TableColumn column =  table.getColumnModel().getColumn(table.getModel().getColumnCount() - 1);
        column.setCellRenderer(new ButtonColumnRenderer(table.getModel().getRowCount()));

        //Display table on frame
        JFrame frame = new JFrame();
        frame.add(table);
        frame.pack();
        frame.setVisible(true);
    }

UPDATE: I have managed to reduce the size of component using a matteborder the same color as the background, however the issue with this is that there is no 'one size fits all' for the border (i.e. the component still stretches with the Table it is within). Any help setting a constant size for the render component would be much appreciated.

Hungry
  • 1,645
  • 1
  • 16
  • 26
  • 1) See also [`AbstractButton.setMargin(Insets)`](http://docs.oracle.com/javase/8/docs/api/javax/swing/AbstractButton.html#setMargin-java.awt.Insets-) 2) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal, Complete, Verifiable Example). – Andrew Thompson Aug 26 '14 at 08:43
  • Hi Andrew, unfortunately setting a margin had little effect on the appearance of the render components (I have updated the SO code incase I did something wrong). Sorry if you thought the code was a little long winded, I have been called out in the past for providing too little information. – Hungry Aug 26 '14 at 09:01
  • *"Sorry if you thought the code was a little long winded"* It's not, and I never wrote anything like that. It is not Complete, Verifiable, nor an Example. Read the link. – Andrew Thompson Aug 26 '14 at 09:03
  • Ah Ok, sorry Im pretty new to SO. So you're after code to set up the JTable? – Hungry Aug 26 '14 at 09:08
  • *"So you're after code to set up the JTable?"* It's not what I'm after that is important. It's your problem, after all. Whatever interest I have in this is purely academic. An MCVE of a run-time problem should compile and run (and show the problem). So it must include imports & a `main(String[])`.. – Andrew Thompson Aug 26 '14 at 09:10
  • Have updated the code to include a minimal main method. – Hungry Aug 26 '14 at 09:24

2 Answers2

1

IIUC, your problem is that the button fills up the column. Because of the resize mode you are using is giving the column more space, when the table is resized - your button gets more space to fill.

If you use a container (in this case, a JComponent), you may treat the problem as a "standard" layout problem, without dealing with renderers nor tables:

public class ButtonColumnRenderer extends JComponent implements TableCellRenderer {

    private final JButton button;

    public ButtonColumnRenderer(){
        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        button = new JButton();
        add(Box.createHorizontalGlue());
        add(button);
        add(Box.createHorizontalGlue());
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
        button.setText(String.valueOf(value));
        return this;
    }
}

My choice here was to use a BoxLayout. Feel free to use you favorite substance.

Asaf
  • 2,480
  • 4
  • 25
  • 33
0

The TableCellRenderer's component is reused hence the most customizing work should happen in getTableCellRenderComponent. (For other readers: normally one can derive one's TableCellRenderer from DefaultTableCellRenderer, but that uses a JLabel. That has the advantage that a call tosuper.getTableCellRenderer` sets visual effects for selection and focus.)

public ButtonColumnRenderer(){
}

public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column){
  //  this.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
  //  this.setPreferredSize(new Dimension(10,10));
  //  this.setMargin(new Insets(20,20,20,20));
    this.setBorder(BorderFactory.createMatteBorder(1, 50, 1, 50,
        isSelected ? Color.RED : Color.GRAY));
    this.setSize(new Dimension(120, 10));
    return this;
}
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Hi Joop, thanks for the response. Setting a matteborder to the component in the `getTableCellRenderComponent` method does affect the appearence of the button, however due to the reasons stated in the 'update' this is unsatisfactory. Unfortunately setting the size in the `getTableCellRenderComponent` method directly still has little effect, as the jbutton just expands to fill the cell (I tried `setSize`, `setPreferredSize` and `setMaximumSize`). I'm beggining to think that I may just have to set the column width manually. – Hungry Aug 28 '14 at 12:27