Basically, I have a JTable containing columns with right-aligned cells but left-aligned headers which looks really bad. I would like to right-align the headers of these columns without altering the "Look and Feel" of the headers.
Thanks
Here's an alternate approach to modifying the TableCellRenderer of a table's JTableHeader. It's not strictly necessary for this usage, but it minimizes the impact on the UI delegate's appearance.
Typical usage:
JTable table = new JTable(…);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new HeaderRenderer(table));
Custom header renderer:
private static class HeaderRenderer implements TableCellRenderer {
DefaultTableCellRenderer renderer;
public HeaderRenderer(JTable table) {
renderer = (DefaultTableCellRenderer)
table.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.CENTER);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {
return renderer.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
}
}
Try this:
((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(JLabel.RIGHT);
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) your_jtable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(0);
Where 0 is Centre.
The HeaderRenderer shown above (2011/sep/21 by trashgod) combined with code from Heisenbug (2011/sep/21) , will only work correctly if you have all headers aligned the same.
If you want to align different headers differently, then you will have to use the following code:
int[] alignments = new int[] { JLabel.LEFT, JLabel.RIGHT, JLabel.RIGHT };
for (int i = 0 ; i < jTable.getColumnCount(); i++){
jTable.getTableHeader().getColumnModel().getColumn(i)
.setHeaderRenderer(new HeaderRenderer(jTable, alignments[i]));
}
and
private static class HeaderRenderer implements TableCellRenderer {
DefaultTableCellRenderer renderer;
int horAlignment;
public HeaderRenderer(JTable table, int horizontalAlignment) {
horAlignment = horizontalAlignment;
renderer = (DefaultTableCellRenderer)table.getTableHeader()
.getDefaultRenderer();
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, col);
JLabel label = (JLabel)c;
label.setHorizontalAlignment(horAlignment);
return label;
}
}
That is:
Set the alignment in getTableCellRendererComponent , and not in the HeaderRenderer constructor.
A thing to remember about wrapping default table headers: do not hold on to a reference of them.
If you (or your users) are using a Windows Classic theme on Windows 7 and your application sets default system LAF, the answer posted by #trashgod may cause problems for you.
It is affected by this bug, posted a decade ago (seriously). If your table is showing and you switch the theme in Windows preferences from an Aero Theme to Windows Classic, there will be a barrage of NPEs. You are NOT supposed to hold on to a reference of a renderer as it may become invalid at some point in time. The wrapping should be done in a dynamic way, as suggested in the comments of the bug report. I took the code from there and created the following runnable example:
import java.awt.*;
import java.lang.ref.WeakReference;
import javax.swing.*;
import javax.swing.table.*;
public class TestFrame extends JFrame {
private static final boolean I_WANT_THE_BUG_TO_HAPPEN = true;
public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedLookAndFeelException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
int res = JOptionPane.showConfirmDialog(null, "Do you want to use the XP L&F?", "laffo", JOptionPane.YES_NO_OPTION);
if (res == JOptionPane.YES_OPTION) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
}
}
new TestFrame().setVisible(true);
}
});
}
public class MyModel extends AbstractTableModel {
public int getRowCount() {
return 10;
}
public int getColumnCount() {
return 10;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return "" + rowIndex + " X " + columnIndex;
}
}
public class MyJTable extends JTable {
/**
*
*/
private static final long serialVersionUID = -233098459210523146L;
public MyJTable(TableModel model) {
super(model);
}
public void doSomething() {
System.out.println("HEHE");
}
}
public class MyAlternativeJTable extends JTable {
private WeakReference<TableCellRenderer> wrappedHeaderRendererRef = null;
private TableCellRenderer wrapperHeaderRenderer = null;
public MyAlternativeJTable(TableModel model) {
super(model);
}
private class MyAlternativeTableColumn extends TableColumn {
MyAlternativeTableColumn(int modelIndex) {
super(modelIndex);
}
#Override
public TableCellRenderer getHeaderRenderer() {
TableCellRenderer defaultHeaderRenderer
= MyAlternativeJTable.this.getTableHeader().getDefaultRenderer();
if (wrappedHeaderRendererRef == null
|| wrappedHeaderRendererRef.get() != defaultHeaderRenderer) {
wrappedHeaderRendererRef
= new WeakReference<TableCellRenderer>(defaultHeaderRenderer);
wrapperHeaderRenderer
= new DecoratedHeaderRenderer(defaultHeaderRenderer);
}
return wrapperHeaderRenderer;
}
}
#Override
public void createDefaultColumnsFromModel() {
TableModel m = getModel();
if (m != null) {
// Remove any current columns
TableColumnModel cm = getColumnModel();
while (cm.getColumnCount() > 0) {
cm.removeColumn(cm.getColumn(0));
}
// Create new columns from the data model info
for (int i = 0; i < m.getColumnCount(); i++) {
TableColumn newColumn = new MyAlternativeTableColumn(i);
addColumn(newColumn);
}
}
}
}
private JPanel jContentPane = null;
private JScrollPane jScrollPane = null;
private JTable table1 = null;
private JScrollPane jScrollPane1 = null;
private JTable table2 = null;
/**
* This is the default constructor
*/
public TestFrame() {
super();
initialize();
int res = JOptionPane.showConfirmDialog(null, "Do you want to call updateUI() on the tables ?", "laffo", JOptionPane.YES_NO_OPTION);
if (res == JOptionPane.YES_OPTION) {
table2.updateUI();
table1.updateUI();
}
}
/**
* This method initializes this
*
* #return void
*/
private void initialize() {
this.setSize(753, 658);
this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
/**
* This method initializes jContentPane
*
* #return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.add(getJScrollPane(), null);
jContentPane.add(getJScrollPane1(), null);
}
return jContentPane;
}
/**
* This method initializes jScrollPane
*
* #return javax.swing.JScrollPane
*/
private JScrollPane getJScrollPane() {
if (jScrollPane == null) {
jScrollPane = new JScrollPane();
jScrollPane.setBounds(new java.awt.Rectangle(358, 0, 387, 618));
jScrollPane.setViewportView(getTable1());
}
return jScrollPane;
}
/**
* This method initializes table1
*
* #return javax.swing.JTable
*/
private JTable getTable1() {
if (table1 == null) {
table1 = new JTable(new MyModel());
}
return table1;
}
/**
* This method initializes jScrollPane1
*
* #return javax.swing.JScrollPane
*/
private JScrollPane getJScrollPane1() {
if (jScrollPane1 == null) {
jScrollPane1 = new JScrollPane();
jScrollPane1.setBounds(new java.awt.Rectangle(0, 0, 350, 618));
jScrollPane1.setViewportView(getTable2());
}
return jScrollPane1;
}
/**
* This method initializes table2
*
* #return javax.swing.JTable
*/
private JTable getTable2() {
if (table2 == null) {
if (I_WANT_THE_BUG_TO_HAPPEN) {
table2 = new MyJTable(new MyModel());
JTableHeader header = table2.getTableHeader();
TableCellRenderer render = new DecoratedHeaderRenderer(header.getDefaultRenderer());
header.setDefaultRenderer(render);
} else {
table2 = new MyAlternativeJTable(new MyModel());
}
}
return table2;
}
private class DecoratedHeaderRenderer implements TableCellRenderer {
public DecoratedHeaderRenderer(TableCellRenderer render) {
this.render = render;
}
private TableCellRenderer render;
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = render.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return c;
}
}
}
Simply run the example and choose Yes twice and watch it break apart. Then change the I_WANT_THE_BUG_TO_HAPPEN static member to false and repeat. The case with this member set to true is essentially the same as the most upvoted answer here. The most important part of this example is the extended JTable (MyAlternativeJTable) which does the wrapping dynamically.
The currently accepted answer to this question is widely used, but it is ill advised. You can reproduce it with lost of applications, including Netbeans 8.0.2 (which itself is Java based) while it is showing a sortable table, such as Window > IDE Tools > Notifications, where you'll also get the NPE reports, ironically. Just switch the Windows theme from Aero to Windows Classic (via right-click Desktop > Personalize > Change the visuals and sounds on your computer) on Windows 7.
If you are using Glazed Lists and call ca.odell.glazedlists.swing.TableComparatorChooser.install, you are also affected. It injects its own custom renderer for sorting arrows.
I stumbled upon this by coincidence while trying to find a solution for this question which I suspect is related.
for (int i = 0 ; i < table.getColumnCount(); i++){
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(SwingConstants.RIGHT);
table.getColumn(i).setHeaderRenderer(renderer);
}
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)
MSISDNTable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);
where MSISDNTable is your table
DefaultTableCellRenderer defaultHeaderRenderer = (DefaultTableCellRenderer) getTableHeader().getDefaultRenderer();
defaultHeaderRenderer.setHorizontalAlignment(JLabel.CENTER);
getTableHeader().setDefaultRenderer(defaultHeaderRenderer);
I have tested in JAVA8. working fine.
Try this code,
JTableHeader jtableHeader = jtable.getTableHeader();
DefaultTableCellRenderer rend = (DefaultTableCellRenderer) jtable.getTableHeader().getDefaultRenderer();
rend.setHorizontalAlignment(JLabel.CENTER);
jtableHeader.setDefaultRenderer(rend);
I have created a class based on the solution of pvbemmelen62, that can be used very easily, for example:
AlignHeaderRenderer.install(myTable, new int[] { SwingConstants.RIGHT,
SwingConstants.RIGHT, SwingConstants.LEFT });
or
AlignHeaderRenderer.install(myTable, 0, SwingConstants.RIGHT);
AlignHeaderRenderer.install(myTable, 1, SwingConstants.RIGHT);
Here's the code:
public class AlignHeaderRenderer implements TableCellRenderer {
private final TableCellRenderer renderer;
private final int alignment;
public static void install(final JTable table, final int[] alignments) {
for (int i = 0; i < alignments.length; ++i)
install(table, i, alignments[i]);
}
public static void install(final JTable table, final int row,
final int alignment) {
table.getTableHeader().getColumnModel().getColumn(row)
.setHeaderRenderer(new AlignHeaderRenderer(table, alignment));
}
private AlignHeaderRenderer(final JTable table, final int alignment) {
renderer = table.getTableHeader().getDefaultRenderer();
this.alignment = alignment;
}
#Override
public Component getTableCellRendererComponent(final JTable table,
final Object value, final boolean isSelected,
final boolean hasFocus, final int row, final int col) {
final Component c = renderer.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, col);
((JLabel) c).setHorizontalAlignment(alignment);
return c;
}
}
The secret is to use the renderer from a dummy table to get correct L&F, and copy the alignment from the real table's row renderer. That way each column in aligned separately. Here is the code:
table.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
Component c2 = dummy.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if (table.getRowCount() > 0) {
Component c3 = table.getCellRenderer(0, col).getTableCellRendererComponent(table, value, isSelected, hasFocus, 0, col);
if (c2 instanceof JLabel && c3 instanceof JLabel)
((JLabel)c2).setHorizontalAlignment(((JLabel)c3).getHorizontalAlignment());
}
return c2;
}
private final JTable dummy = new JTable();
});
The above code does not keep any references to renderers, so it avoids the NPE bug mentioned above. It does not require any named class, so you can just drop the code in wherever you need it.
((DefaultTableCellRenderer)jTable2.getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(JLabel.CENTER);
((JLabel)mTabBOM.getTableHeader().getDefaultRenderer()).setHorizontalAlignment( JLabel.CENTER );
Related
Here is my JTable mouse listener I've put it like this in table because I want it to sort directly.
myTable= new JTable();
myTable.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if( myTable.getRowCount()!= 0) {
TableRowSorter<TableModel> sorter = new TableRowSorter(myTable.getModel());
myTable.setRowSorter(sorter);
List<RowSorter.SortKey> date= new ArrayList<>();
int columnIndexToSort = 10;
datum.add(new RowSorter.SortKey(columnIndexToSort, SortOrder.DESCENDING));
sorter.setSortKeys(date);
sorter.sort();
}
myTable.repaint();
myTable.revalidate();
}
});
Here is the cell renderer which BTW, works nice but after sorting it doesn't repaint:
public class MyTableRenderer extends DefaultTableCellRenderer{
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row,int col) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
Object resault = table.getModel().getValueAt(row, 9);
int value= Integer.parseInt(resault.toString());
Color color = null;
if (value>= 5000) {
c.setBackground(new Color(144, 238, 144));
}else if (value< 5000 && value>=500) {
color = Color.ORANGE;
c.setBackground(color);
}else if (value>= 0 && value<500) {
c.setBackground( new Color(255, 76, 76));
}
c.setFont(c.getFont().deriveFont(Font.BOLD));
return c;
}
}
These are some of the things I've remembered to say about this particular problem if there is anything that is not understandable so I would get the answer please ask.
Object resault = table.getModel().getValueAt(row, 9);
The renderer shows the data in the view of the table. When you sort data the data in the TableModel is not changed, only the order of the data in the view.
So you should be using:
Object result = table.getValueAt(row, 9);
to get the data in the current view as it has been sorted.
I have a simple JTable that shows the details (in column format) of a row from another JTable. This works nicely. However, sometimes the text in a row is very long so the user ends up having to scroll across which isnt neat.
How can I wrap the text in a row and allow the row height to change to show all the text in it.
Here is the code:
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
int selectedRow = table.getSelectedRow();
DefaultTableModel newModel = new DefaultTableModel();
String rowName = "Row: " + selectedRow;
newModel.setColumnIdentifiers(new Object[]{rowName});
for (int i = 0; i < table.getModel().getColumnCount(); i++) {
newModel.addRow(new Object[]{table.getModel().getValueAt(selectedRow, i)});
}
JTable newTable = new JTable(newModel) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(140, 240);
}
};
newTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
newTable.setRowHeight(14, 30);
TableColumnAdjuster tcanewTable = new TableColumnAdjuster(newTable);
tcanewTable.setColumnHeaderIncluded(true);
tcanewTable.setColumnDataIncluded(true);
tcanewTable.setOnlyAdjustLarger( true );
tcanewTable.setDynamicAdjustment( true );
tcanewTable.adjustColumns();
// Apply any custom renderers and editors
JOptionPane.showMessageDialog(frame, new JScrollPane(newTable),
rowName, JOptionPane.PLAIN_MESSAGE);
}
}
});
You can accomplish this by using a JTextArea as a TableCellRenderer for that column in your table. For example:
static class WordWrapCellRenderer extends JTextArea implements TableCellRenderer {
WordWrapCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setText(value.toString());
setSize(table.getColumnModel().getColumn(column).getWidth(), getPreferredSize().height);
if (table.getRowHeight(row) != getPreferredSize().height) {
table.setRowHeight(row, getPreferredSize().height);
}
return this;
}
}
To use WordWrapCellRenderer in your table:
table.getColumnModel().getColumn(columnIndex).setCellRenderer(new WordWrapCellRenderer());
This is an update of the accepted answer.
It makes the renderer more efficient by limiting the number of getPreferredSize() calls.
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
/**
* The WordWrapRenderer can be used as a renderer for a JTable column. It will
* allow the text to wrap to a new line and adjust the table row height.
*
* Note. This renderer can only be used for a single column in the table.
*/
public class WordWrapRenderer extends JTextArea implements TableCellRenderer
{
WordWrapRenderer()
{
setLineWrap(true);
setWrapStyleWord(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
setText( (value == null) ? "" : value.toString() );
setSize(table.getColumnModel().getColumn(column).getWidth(), table.getRowHeight(row));
// Recalculate the preferred height now that the text and renderer width have been set.
int preferredHeight = getPreferredSize().height;
if (table.getRowHeight(row) != preferredHeight)
{
table.setRowHeight(row, preferredHeight);
}
return this;
}
private static void createAndShowGUI()
{
JTable table = new JTable(2, 3);
table.setValueAt("A", 0, 0);
table.setValueAt("This text should wrap by default", 0, 1);
table.getColumnModel().getColumn(1).setCellRenderer( new WordWrapRenderer() );
JFrame frame = new JFrame("TableBasic");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane( table ) );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
I want to create a JTable that I'll be able to select multiple, non-contiguous cells with ctrl+click combination. So far, when I select not contiguous cells from the same row it works fine.
But when I select cells from different row, I get this
Could somebofy please help me on this?
Here's my code
Class TestTimeTable
public class TestTimeTable extends JFrame{
private final int rows = 10;
private final int cols = 8;
private final String daysOfTheWeek[] = {"ΔΕΥΤΕΡΑ", "ΤΡΙΤΗ", "ΤΕΤΑΡΤΗ", "ΠΕΜΠΤΗ", "ΠΑΡΑΣΚΕΥΗ"};
private final JPanel jTablePanel;
private final JScrollPane scrollPane;
private final JTable timeTable;
private final Object[][] rowData;
public TestTimeTable(){
this.rowData = new Object[this.rows][this.cols];
this.timeTable = new JTable(this.rowData,this.daysOfTheWeek){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
this.timeTable.setRowHeight(200, 200);
this.timeTable.setFillsViewportHeight(true);
this.timeTable.setOpaque(true);
this.timeTable.setColumnSelectionAllowed(true);
this.timeTable.setRowSelectionAllowed(true);
this.timeTable.setCellSelectionEnabled(true);
this.timeTable.setDefaultRenderer(Object.class, new BoardTableCellRenderer());
this.scrollPane = new JScrollPane(this.timeTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.jTablePanel = new JPanel();
this.jTablePanel.add(this.scrollPane);
getContentPane().add(new JScrollPane(this.timeTable), BorderLayout.CENTER);
}
public void createAndShowUI(){
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] argas){
TestTimeTable tt = new TestTimeTable();
tt.createAndShowUI();
}
Class BoardTableCellRenderer
class BoardTableCellRenderer extends DefaultTableCellRenderer{
Component c;
private static final long serialVersionUID = 1L;
private final Color selectionBlue = new Color(131,166,198);
private final MatteBorder border = new MatteBorder(1, 1, 0, 0, Color.BLACK);
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (table.isCellSelected(row, column)){
c.setBackground(this.selectionBlue);
setBorder(this.border);
}
else {
c.setBackground(Color.WHITE);
}
return c;
}
}
Any opinion would be very helpful. Thank you in advance.
Well this seems to be a common problem with JTables, you can not select non-contiguous cells but you can show "fake" non-contiguous cells.
You can check my solution but is not perfect. In that solution the "shift" selections doesn't work.
The idea is to override isCellSelected(int row, int colum) and changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) of JTable.
So I store the individually selected cells and use them in isCellSelected.
Create these classes fom cell storage :
class Cell {
private int row;
private int column;
public Cell(int row, int column) {
this.row = row;
this.column = column;
}
public boolean is(int r, int c) {
return row == r && column == c;
}
}
class CellSelectionSet {
private ArrayList<Cell> cells = new ArrayList<TestTimeTable.Cell>();
public void add(int r, int c) {
if (!contains(r, c)) {
cells.add(new Cell(r, c));
}
}
public boolean containsOneOrLess() {
return cells.size() <= 1;
}
public boolean contains(int r, int c) {
for (Cell cell : cells) {
if (cell.is(r, c)) {
return true;
}
}
return false;
}
public void clear() {
cells.clear();
}
}
and at JTable you can use that :
this.timeTable = new JTable(this.rowData, this.daysOfTheWeek) {
CellSelectionSet cellSelectionSet = new CellSelectionSet();
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
#Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
super.changeSelection(rowIndex, columnIndex, toggle, extend);
if (toggle) {
cellSelectionSet.add(rowIndex, columnIndex);
} else {
if (extend) {
cellSelectionSet.add(rowIndex, columnIndex);
} else {
// reset
cellSelectionSet.clear();
cellSelectionSet.add(rowIndex, columnIndex);
}
}
}
#Override
public boolean isCellSelected(int row, int column) {
if (cellSelectionSet.containsOneOrLess()) {
// show the default
return super.isCellSelected(row, column);
}
return cellSelectionSet.contains(row, column);
}
};
I hope this helps you.
So I have the following class which defines basic parameters of an error
public class Error {
public String desc;
public int rowNumber;
public int colNumber;
public int fixNumber;
public Error(String desc,int row, int col, int fix){
this.desc = desc;
rowNumber = row++;
colNumber = col++;
fixNumber = fix;
}
...
My gui Class
public class Gui extends JFrame {
AbstractTableModel model;
JTable table;
public void start(AbstractTableModel model) {
this.model = model;
table=new JTable(model){
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < model.getColumnCount(); i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(120);
column.setMaxWidth(300);
column.setMinWidth(50);
column.setCellRenderer(new customCellRender());
}
JScrollPane pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(900,900));
add(pane);
setLayout(new FlowLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
I have attempted to make a cellRenderer but at the moment it does not have the intended effect. Because it colors all the cells.
#SuppressWarnings("serial")
public class customCellRender extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component c = null;
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(new java.awt.Color(255, 72, 72));
return c;
}
I then have a List which stores instances of the error class.What I cant figure out is how to ONLY change the color of the cells in my table based on the Error(rowNumber,colNumber). Considering that the errors are in a list structure, so I would have to iterate over and somehow pass each error column and row to the renderer. Is that possible ?
Your code colors all the cells because the component is reused, not recreated every time. Just add a
if (error) {
c.setBackground(errorBackground);
} else {
c.setBackground(table.getBackground);
}
A couple of points to make:
Don't create a new Color every time. It's expensive and you're using the same one anyway.
Use a Set for your errors to make contains quick, otherwise your rendering may become very slow with a large number of those.
I have a GUI designed as a Form in Netbeans 7.2. I have a JTable with the troublesome behavior. The table model is designed with Right-Click -> Properties -> Model and setting up 1 row and 12 columns with types Long and Double for editable number fields.
Now if I navigate to such a cell which contain e.g. "0.0" and just start typing "123" I get "0.0123" instead of "123". I would like it to work that if you just start typing you start with a blank value - and if the entry is "clicked" then you start editing the cell and whatever you type is inserted at the cursor location.
Can this be done easily?
I found https://stackoverflow.com/a/8493016/53897 to work.
The way to add the code, is to right-click the JTable in the Navigator, and choose "Code Customizer". In the line for new javax.swing.JTable() change the drop down box to "custom creation" and you can now edit that snippet including adding the {...#Override public void changeSelection(...)...} needed for this.
whats wrong with standard Swing JTable and DefaultTableModel
sure there are missing some ideas for productions code (make the things better)..., selectAll for Editor, cell alingment, background, foreground, stripping, font, Look and Feels etc... (most of custom Look and Feels doesn't works correctly with built-in Components pallette in Netbeans Swing Framework),
SwingX have got Components pallette for Netbeans, better and safest way, maybe you have look at ...
import java.awt.*;
import java.awt.event.*;
import java.text.NumberFormat;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;
public class EditorTest {
private JScrollPane getTableComponent() {
String[] colNames = {"Stock", "Price", "Shares", "Quantity", "Action", "Action", "Holder"
};
final Object[][] data = {{"MSFT", Double.valueOf(12.21), Integer.valueOf(10),
Integer.valueOf(0), "Buy", "Sell", "Bill"}, {"IBM", Double.valueOf(13.21), Integer.valueOf(12),
Integer.valueOf(0), "Buy", "Sell", "Tim"}, {"ORACLE", Double.valueOf(21.22), Integer.valueOf(11),
Integer.valueOf(0), "Buy", "Sell", "Tom"}
};
DefaultTableModel model = new DefaultTableModel(data, colNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int col) {
return data[0][col].getClass();
}
};
JTable table = new JTable(model);
TableColumnModel colModel = table.getColumnModel();
colModel.getColumn(1).setCellRenderer(new DoubleRenderer());
colModel.getColumn(3).setCellRenderer(new SpinnerRenderer());
colModel.getColumn(4).setCellRenderer(new ButtonRenderer());
colModel.getColumn(5).setCellRenderer(new ButtonRenderer());
colModel.getColumn(3).setCellEditor(new SpinnerEditor());
colModel.getColumn(4).setCellEditor(new ButtonEditorA(table));
colModel.getColumn(5).setCellEditor(new ButtonEditorA(table));
table.setCellSelectionEnabled(true);
Dimension d = table.getPreferredSize();
table.setPreferredScrollableViewportSize(d);
return new JScrollPane(table);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new EditorTest().getTableComponent());
f.pack();
f.setLocation(100, 100);
f.setVisible(true);
}
}
class SpinnerEditor extends AbstractCellEditor implements TableCellEditor {
private static final long serialVersionUID = 1L;
private SpinnerNumberModel model = new SpinnerNumberModel(0, 0, null, 1);
private JSpinner spinner = new JSpinner(model);
private int clickCountToStart = 1;
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
spinner.setValue(((Integer) value).intValue());
return spinner;
}
public Object getCellEditorValue() {
return (Integer) spinner.getValue();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}
#Override
public void cancelCellEditing() {
super.cancelCellEditing();
}
}
class ButtonEditorA extends AbstractCellEditor implements TableCellEditor, ActionListener {
private static final long serialVersionUID = 1L;
private JTable table;
private JButton button = new JButton();
private NumberFormat nf = NumberFormat.getCurrencyInstance();
private int clickCountToStart = 1;
public ButtonEditorA(JTable table) {
this.table = table;
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
int row = table.getEditingRow();
int col = table.getEditingColumn();
//System.out.printf("row = %d col = %d%n", row, col);
sb.append((String) table.getValueAt(row, 6));
sb.append(" has ");
sb.append(((col == 4) ? "bought " : "sold "));
sb.append(((Integer) table.getValueAt(row, 3)).toString());
sb.append(" shares of " + (String) table.getValueAt(row, 0));
sb.append(" at " + nf.format(((Double) table.getValueAt(row, 1)).doubleValue()));
stopCellEditing();
System.out.println(sb.toString());
}
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row, int column) {
button.setText(value.toString());
return button;
}
public Object getCellEditorValue() {
return button.getText();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
return super.stopCellEditing();
}
#Override
public void cancelCellEditing() {
super.cancelCellEditing();
}
}
class SpinnerRenderer implements TableCellRenderer {
private SpinnerNumberModel model = new SpinnerNumberModel(0, 0, null, 1);
private JSpinner spinner = new JSpinner(model);
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column) {
spinner.setValue(((Integer) value).intValue());
return spinner;
}
}
class ButtonRendererA implements TableCellRenderer {
private JButton button = new JButton();
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
button.setText(value.toString());
return button;
}
}
class DoubleRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
private NumberFormat nf = NumberFormat.getCurrencyInstance();
public DoubleRenderer() {
setHorizontalAlignment(RIGHT);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(nf.format(((Double) value).doubleValue()));
return this;
}
}