0

I want to dispose the text inserted into a JTable cell in a particular way. Infact now if I write into a cell, the text will be all on the same line, while I would like to see it in two lines.

Maybe I would be clearer with a graphic description. See, I would like the second one:

enter image description here

My Table code here:

public class TablePanel extends JPanel
{
private JTable table;
public Tabella()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 
table = new JTable(new MyTableModel());
table.setFillsViewportHeight(true);     
table.setPreferredScrollableViewportSize(new Dimension(500, 100));
JScrollPane jps = new JScrollPane(table);
add(jps);
add(new JScrollPane(table));
table.setCellSelectionEnabled(true);
table.setRowHeight(30);
TableColumn tcol;
    for (int i=0; i<table.getColumnCount(); i++)
    {
        tcol = table.getColumnModel().getColumn(i);
        tcol.setCellRenderer(new CustomTableCellRenderer());
    }

table.addMouseListener(
    new MouseAdapter(){
    public void mouseClicked(MouseEvent e) {
        int row = table.rowAtPoint(new Point(e.getX(), e.getY()));
        int col = table.columnAtPoint(new Point(e.getX(), e.getY()));

        if (col>0) {
        if (e.getClickCount() > 1) {
        if (row == 5 | row == 6) 
            {
                JOptionPane.showMessageDialog(null, "Impossible to set lesson.");

                return;
            }
        else {
            table.getColumnName(col);
            String day = table.getColumnName(col);
            String hour = (String) table.getValueAt(row, 0);
            InsertLesson cell = new InsertLesson(day, hour);
            cel.setVisible(true);

             }
            }
          }
        }
}
);
}
private class MyTableModel extends AbstractTableModel {
private String[] columns = {"","Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
private String[][] data = {{"8:30 - 9:30","","","","","",""},
    {"9:30 - 10:30","","","","","",""},
    {"10:30 - 11:30","","","","","",""},
    {"11:30 - 12:30","","","","","",""},
    {"12:30 - 13:30","","","","","",""},
    {"13:30 - 14:30","","","","","",""},
    {"14:30 - 15:30","","","","","",""},
    {"15:30 - 16:30","","","","","",""},
    {"16:30 - 17:30","","","","","",""}};

public int getColumnCount() {
    return columns.length;
}

public int getRowCount() {
    return data.length;
}

public String getColumnName(int col) {
    return columns[col];
}

public Object getValueAt(int row, int col) {
    return data[row][col];
}
}
public class CustomTableCellRenderer extends DefaultTableCellRenderer{
  public Component getTableCellRendererComponent (JTable table, 
Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
  Component cell = super.getTableCellRendererComponent(
   table, obj, isSelected, hasFocus, row, column);
  if (isSelected) {
  cell.setBackground(Color.lightGray);
  } 
  else {
  if (row % 2 == 0) {
  cell.setBackground(new Color (245,245,250));
  }
  else {
  cell.setBackground(new Color(250,250,240));
  }
  }

  return cell;
  }
  }
}   

Thanks to the user Kiheru, a solution has been found: we have to:

1) centre the format of the string that will be inserted into the cell;

2) centre the "space" of the cell itself;

We can do these action by:

1) insert html centring text code in the string that has to be inserted into the cell (html code is automatically recognized);

2) centre the cell itself with the command setHorizontalAlignment(JLabel.CENTER);.

This question might be useful for everyone has this problem.

Bernheart
  • 607
  • 1
  • 8
  • 17

2 Answers2

1

It's possible to have multiline labels (DefaultTableCellRenderer extends JLabel) using html as the label text:

"<html>Math,<br>Class1</html>"

Note that you may need to adjust the row heights as described here.

Update: Centering the label text was wanted as well, in addition to the line breaking.

That needs a setHorizontalAlignment(JLabel.CENTER) call on the cell renderer to center the text block. Also, the text lines were wanted centered relative to each other, so the html code ended up to like (actual code has more formatting):

<html><div style="text-align:center">Math,<br>Class1</div></html>
Community
  • 1
  • 1
kiheru
  • 6,588
  • 25
  • 31
  • I think that I would insert a JLabel into ever cell, isn't it? – Bernheart Sep 13 '13 at 10:44
  • @Bernheart No, don't do that. `JTable` is designed to reuse the renderers, and what you have is quite capable of html. What exactly is the right spot to generate the html depends on your application design, but it's possible to (at least) 1 Insert the data as html to your model (simple, but not always appropriate), or 2: in your `getTableCellRendererComponent()` generate the html from the "Math, Class1" string (it's parameter `obj` in that method). – kiheru Sep 13 '13 at 10:50
  • @Bernheart A renderer isn't like a normal component, it is used to "stamp" the result onto the table. So, there only ever one instance of the renderer in use... – MadProgrammer Sep 13 '13 at 10:51
  • @kiheru mmm I can't extend `JLabel` with `DefaultTableCellRenderer` because `CustomTableCellRenderer extends DefaultTableCellRenderer` yet. I don't know if the two facts are connected, but I've tried as you written and I only see on my table cell an error that say: `java.swing.JLabel[,0,0,0x0, invalid,alignmentX=0.0,Y=0.0,border..` etc.. is too long for being see in a cell – Bernheart Sep 13 '13 at 11:11
  • 1
    @Bernheart You don't need to extend it, because it already *does*. All you need to do it is to format the contents as html. For a quick demonstration, try inserting "Math,
    Class1" in you table model. That should result in a two line cell with no changes in your actual code at all.
    – kiheru Sep 13 '13 at 11:17
  • Thanks! You're right. too bad I don't know html. So let me ask: if I want to put the text ever in the center of the cell (Justified text) in bold case, what have I to do? Again, thank you – Bernheart Sep 13 '13 at 11:31
  • 1
    @Bernheart There's more than one way to skin the cat, and I'm no html expert, but I think `"
    Math,
    Class1
    "` would work. You're welcome :-)
    – kiheru Sep 13 '13 at 11:49
  • mmm we are closer to solution, but the text isn't into the center of cell! – Bernheart Sep 13 '13 at 11:57
  • @Bernheart Ok, just took a look at my table code where I needed centering: call `setHorizontalAlignment(JLabel.CENTER)` for your cell renderer. That should take care of it. – kiheru Sep 13 '13 at 12:01
  • Yes it works! Only the southern text begins in alignment with the upper one. so the upper is centred, but the southern not. I know I could appear boring... but that is the situation! – Bernheart Sep 13 '13 at 13:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/37340/discussion-between-kiheru-and-bernheart) – kiheru Sep 13 '13 at 13:52
0

I'm not sure where I got this from, but I accomplished this with a TextAreaRenderer

public class TextAreaRenderer extends JTextArea implements TableCellRenderer {

    private final DefaultTableCellRenderer adaptee = new DefaultTableCellRenderer();
    /** map from table to map of rows to map of column heights */
    private final Map cellSizes = new HashMap();


    public TextAreaRenderer() {
        setLineWrap(true);
        setWrapStyleWord(true);
    }

    public Component getTableCellRendererComponent(
            JTable table, Object obj, boolean isSelected,
            boolean hasFocus, int row, int column) {

        // set the colours, etc. using the standard for that platform
        adaptee.getTableCellRendererComponent(table, obj,
                isSelected, hasFocus, row, column);
        setForeground(adaptee.getForeground());
        setBackground(adaptee.getBackground());
        setBorder(adaptee.getBorder());
        setFont(adaptee.getFont());
        setText(adaptee.getText());


        // This line was very important to get it working with JDK1.4
        TableColumnModel columnModel = table.getColumnModel();
        setSize(columnModel.getColumn(column).getWidth(), 100000);
        int height_wanted = (int) getPreferredSize().getHeight();
        addSize(table, row, column, height_wanted);
        height_wanted = findTotalMaximumRowSize(table, row);
        if (height_wanted != table.getRowHeight(row)) {
            table.setRowHeight(row, height_wanted);
        }
        return this;
    }

    @SuppressWarnings("unchecked")
    private void addSize(JTable table, int row, int column, int height) {
        Map rows = (Map) cellSizes.get(table);
        if (rows == null) {
            cellSizes.put(table, rows = new HashMap());
        }
        Map rowheights = (Map) rows.get(new Integer(row));
        if (rowheights == null) {
            rows.put(new Integer(row), rowheights = new HashMap());
        }
        rowheights.put(new Integer(column), new Integer(height));
    }

    /**
     * Look through all columns and get the renderer.  If it is
     * also a TextAreaRenderer, we look at the maximum height in
     * its hash table for this row.
     */
    private int findTotalMaximumRowSize(JTable table, int row) {
        int maximum_height = 0;
        Enumeration columns = table.getColumnModel().getColumns();
        while (columns.hasMoreElements()) {
            TableColumn tc = (TableColumn) columns.nextElement();
            TableCellRenderer cellRenderer = tc.getCellRenderer();
            if (cellRenderer instanceof TextAreaRenderer) {
                TextAreaRenderer tar = (TextAreaRenderer) cellRenderer;
                maximum_height = Math.max(maximum_height,
                        tar.findMaximumRowSize(table, row));
            }
        }
        return maximum_height;
    }

    private int findMaximumRowSize(JTable table, int row) {
        Map rows = (Map) cellSizes.get(table);
        if (rows == null) {
            return 0;
        }
        Map rowheights = (Map) rows.get(new Integer(row));
        if (rowheights == null) {
            return 0;
        }
        int maximum_height = 0;
        for (Iterator it = rowheights.entrySet().iterator();
                it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            int cellHeight = ((Integer) entry.getValue()).intValue();
            maximum_height = Math.max(maximum_height, cellHeight);
        }
        return maximum_height;
    }
}

Then you just use it like this (mine was for a "Notes" column):

table.getColumn("Notes").setCellRenderer(new TextAreaRenderer());

Whenever a \n appears, it will wrap the text. I also used this to accomplish the need for "merged cells" (you just have to be methodical about how you wrap the newlines). It's not perfect for the merged cells requirement, but it gets the job done.

ryvantage
  • 13,064
  • 15
  • 63
  • 112