Search code examples
javaswingjtablestrikethrough

How to strikethrough text of a selected row(having checkbox in first column) of JTable?


I have a Jtable with a checkbox in first column. I want to strikethrough text of a row when the checkbox is selected. (eg same as we do in microsoft outlook when our task is complete.) I have tried using AttributeString, but not able to do it.

Can anyone please guide me to solve it?

String strStrike; 
AttributedString as; 

public void setTextStrikeThrough() {
    for(int r=0;r< taskcells.length;r++) {
        if (ttable.getValueAt(r,0).equals(Boolean.TRUE)) { 
            for(int c=2;c<7;c++) {
                strStrike+=taskcells[r][c-1]; 
            }//end inner for as=new
            AttributedString(strStrike); 
            as.addAttribute(TextAttribute.STRIKETHROUGH,
                TextAttribute.STRIKETHROUGH_ON);
            as.getIterator(); 
        }//end if 
    }//end for       
}

I am not getting exactly where to call this method. I want to strikethrough text of a row when checkbox of that row has been checked.


Solution

  • I don't know that an ActionListener will work well for a JCheckBox in a JTable since the check box isn't a real button but rather a rendering of a checkbox. Perhaps playing with the table model will help. For instance you can use HTML to display a strike through of Strings displayed in table cells. For instance below I create a custom TableModel that extends DefaultTableModel and holds rows with a Boolean object followed by objects of a TextWrapper class that I've created that changes its toString result depending on a boolean.

    e.g.,

    import java.util.Vector;
    import javax.swing.*;
    import javax.swing.table.DefaultTableModel;
    
    public class StrikeThroughRow {
       public static final Object[][] DATA = {{Boolean.TRUE, "Monday", "fe"},
          {Boolean.FALSE, "Tuesday", "fi"}, {Boolean.TRUE, "Wednesday", "fo"},
          {Boolean.FALSE, "Thursday", "fum"}, {Boolean.TRUE, "Friday", "foo"}};
    
       public StrikeThroughRow() {
    
       }
    
       private static void createAndShowUI() {
          JTable table = new JTable(new StrikeThroughModel(DATA));
          JScrollPane scrollpane = new JScrollPane(table);
    
          JFrame frame = new JFrame("StrikeThroughRow");
          frame.getContentPane().add(scrollpane);
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }
    }
    
    class StrikeThroughModel extends DefaultTableModel {
       public StrikeThroughModel(Object[][] data) {
          super(new String[]{"Check", "Work Day", "Giant Speak"}, 0);
          for (int i = 0; i < data.length; i++) {
             Vector<Object> rowVect = new Vector<Object>();
             rowVect.add(data[i][0]);
             if (data[i].length > 1) {
                for (int j = 1; j < data[i].length; j++) {
                   rowVect.add(new TextWrapper(data[i][j].toString(), (Boolean)data[i][0]));
                }
             }
             addRow(rowVect);
          }
       }
    
       @Override
       public Class<?> getColumnClass(int columnIndex) {
          if (columnIndex == 0) {
             return Boolean.class;
          }
          return super.getColumnClass(columnIndex);
       }
    
       @Override
       public void setValueAt(Object value, int row, int column) {
          if (column == 0) {
             for (int i = 1; i < getColumnCount(); i++) {
                TextWrapper textWrapper = (TextWrapper) getValueAt(row, i);
                textWrapper.setStrikeThrough((Boolean) value);
                fireTableCellUpdated(row, i);
             }
          }
          super.setValueAt(value, row, column);
       }
    }
    
    class TextWrapper {
       private String text;
       private boolean strikeThrough = false;
    
       public TextWrapper(String text) {
          this.text = text;
       }
    
       public TextWrapper(String text, boolean strikeThrough) {
          this(text);
          this.strikeThrough = strikeThrough;
       }
    
       @Override
       public String toString() {
          if (strikeThrough) {
             return "<html><strike>" + text + "</html></strike>"; 
          }
          return text;
       }
    
       public void setStrikeThrough(boolean strikeThrough) {
          this.strikeThrough = strikeThrough;
       }
    }
    

    I'm betting that there are better solutions including creating a custom renderer for your cells, but the code above offers a quick and dirty fix.