3

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.

mKorbel
  • 108,320
  • 17
  • 126
  • 296
bsm
  • 1,603
  • 11
  • 28
  • 40
  • Where are you stuck? `AttributedString` should be the way to go. – miku Mar 11 '11 at 19:10
  • I am not getting exactly how to use it for JTable. – bsm Mar 11 '11 at 19:27
  • Maybe include some lines of code in your question, that illustrate your problem. – miku Mar 11 '11 at 19:28
  • Well, I meant (and wrote) in the question. It's not difficult to edit your question and place formatted code inside it. Please keep that in mind, in case you post another question on this site. Thanks. – miku Mar 11 '11 at 19:43
  • Yes..Thanks.. I found difficult to format the code in this comment reply section,otherwise we can see the preview of our question while posting, so in that case,its easy to format our code.Here I couldnt see preview,thats why not able to edit it.At the same time, we both were editing the main question with proper formatted code.Thanks. – bsm Mar 11 '11 at 19:48

3 Answers3

5

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.

Hovercraft Full Of Eels
  • 276,051
  • 23
  • 238
  • 346
  • Thanks..But why its giving me this error in setValueAt(..)method??:"java.lang.ClassCastException: java.lang.String cannot be cast to practiceproblems.TextWrapper" at TextWrapper textWrapper = (TextWrapper) getValueAt(row, i); line.I have used same as you mentioned but using AbstractTableModel. – bsm Mar 16 '11 at 17:43
  • Ohh its because getValueAt(r,i) returns Object..But I am still not able to do it while using AbstractTableModel.Only using trial and error method..Can anyone please explain me with AbstractTableModel? – bsm Mar 22 '11 at 12:45
  • Why not use DefaultTableModel instead? – Hovercraft Full Of Eels Mar 22 '11 at 14:57
5

Here is how you can create a "strike through font":

Map attributes = component.getFont().getAttributes();
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
component.setFont( new Font(attributes) );

One way to apply the font is to use the Table Row Rendering approach. Take a look at the background color example. Instead of setting the background of the renderer you can set the Font.

Otherwise you would need to create a custom renderer for the columns in your table to use the appropriate Font.

camickr
  • 308,339
  • 18
  • 152
  • 272
4

Add a listener to the checkbox which will add/remove the from the label. Here is an example of box and label maybe helpful:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class check {
  public static void main(String args[]) {

    JFrame frame = new JFrame("for bsm");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JCheckBox box = new JCheckBox("check me");

    final JLabel label = new JLabel("<html>text</html>");
    label.setFont(new Font("helvetica", Font.PLAIN, 12));
    label.setForeground(new Color(50, 50, 25));

    ActionListener actionListener = new ActionListener() {
      public void actionPerformed(ActionEvent actionEvent) {
        AbstractButton abstractButton = (AbstractButton) actionEvent.getSource();
        if(abstractButton.getModel().isSelected())
            label.setText(label.getText().replace("<html>", "<html><strike>").replace("</html>", "</strike></html>"));
        else
            label.setText(label.getText().replace("<html><strike>", "<html>").replace("</strike></html>", "</html>"));
      }
    };

    box.addActionListener(actionListener);

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(10, 10));
    panel.add(label, BorderLayout.NORTH);
    panel.add(box, BorderLayout.SOUTH);
    panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

    frame.add(panel);
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}
Vladp
  • 4,003
  • 3
  • 30
  • 66