I am trying to make a check where if the value of cell 3 is not blank, the whole row will be colored green, however this does nothing but, if I make no check of that, only checking to be sure nothing is selected (so that selecting gives the color to show that you did select) everything is drawn green.
if (!table.isRowSelected(row))
{
component.setBackground(getBackground());
if(table.getModel().getValueAt(row, 3).equals(""))
{
component.setBackground(Color.GREEN);
}
}
I tried to output the value and everything works properly, is there a problem here? A different way of doing this? thank you
I tried to output the value and everything works properly, is there a
problem here? A different way of doing this?
We would need some more code/info to answer this question properly:
How do you implement the TableCellRenderer? Is it by extending DefaultTableCellRenderer?
How do you set the TableCellRenderer to the JTable?
Is it 3 the correct model column index?
In any case I'd suggest you take a look to Using Custom Renderer section in How to Use Tables trail. Also you can see the example below and take this as start point:
import java.awt.Color;
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class Demo {
private void initGUI() {
DefaultTableModel model = new DefaultTableModel(new Object[]{"Manufacturer", "Model", "Country", "Price"}, 0);
model.addRow(new Object[]{"Fender", "Stratocaster", "Japan", ""});
model.addRow(new Object[]{"Gibson", "Les Paul", "USA", "$ 1599"});
model.addRow(new Object[]{"Jackson", "Soloist S3", "Japan","$ 1299"});
model.addRow(new Object[]{"Paul Reed Smith","Standard 24", "USA", ""});
JTable table = new JTable(model);
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(!isSelected){
Color background = table.getModel().getValueAt(row, 3).equals("") ? Color.GREEN : table.getBackground();
setBackground(background);
} else {
setBackground(table.getSelectionBackground());
}
return this;
}
});
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().initGUI();
}
});
}
}
Picture
A different way of doing this?
Check out Table Row Rendering for a different approach that doesn't require you to use a custom renderer.
This approach is easier because you don't need a custom renderer when you have different types of data in each table column.
Is your if statement correct? You have to check for non-blank cell
So, your if statement should look like this
if(!table.getModel().getValueAt(row, 3).equals(""))
Also to check value at cell#3, you have to use index 2 like this.
if(!table.getModel().getValueAt(row, 2).equals(""))
Related
How can I set the margin of a specific row in a JTable by its row number?
Please refer to the illustration below I made using excel.
Also, I want a thick border and an invisible border
JTable has a method setRowHeight(...) which will allow you to increase the height of specific rows.
Regarding the border you can check out Table Row Rendering. It demonstrates how to override the prepareRenderer(...) method of the JTable to use a custom Border.
This is an example of a JTable with custom row borders - for specific rows. These specific rows are determined by the data in the table rows.
The example uses a JTable with a custom renderer - CustomBorderRenderer class which extends javax.swing.table.DefaultTableCellRenderer. There are two classes in this example application: TableCellRendererTester.java and CustomBorderRenderer.java.
The following is the image of the table with custom border for a specific row - where the Year value is "2012". The source code for the two classes follow.
The Example Code:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class TableCellRendererTester {
private static final Object[] TABLE_COLUMNS = {"Book", "Author", "Year"};
private static final Object [][] TABLE_DATA = {
{"Book 1", "author 1", "1972"}, {"Book 2", "author 1", "1945"},
{"Book 3", "author 2", "2012"}, {"Book 4", "author 3", "1999"}
};
public static void main(String [] args) {
new TableCellRendererTester().createAndShowGUI();
}
public void createAndShowGUI() {
JFrame frame = new JFrame("Table Custom Row Border Tester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(getTablePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel getTablePanel() {
DefaultTableModel model = new DefaultTableModel(TABLE_DATA, TABLE_COLUMNS);
JTable table = new JTable(model);
table.setRowHeight(30);
CustomBorderRenderer renderer = new CustomBorderRenderer();
table.setDefaultRenderer(Object.class, renderer);
JScrollPane scrollpane = new JScrollPane(table);
scrollpane.setPreferredSize(new Dimension(400, 150));
scrollpane.setViewportView(table);
JPanel panel = new JPanel();
panel.add(scrollpane);
return panel;
}
}
The Renderer Class:
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.JComponent;
import javax.swing.BorderFactory;
import javax.swing.border.Border;
import javax.swing.table.TableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class CustomBorderRenderer extends DefaultTableCellRenderer {
private int prevRow;
private boolean customBorderFlag;
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
JComponent c = (JComponent) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
if (row != prevRow) {
// Row has changed.
// Store it so that all the columns can be rendered
// with the custom border - if condition is met.
customBorderFlag = false;
prevRow = row;
TableModel m = table.getModel();
String s = (String) m.getValueAt(row, 2);
// Check if the row needs to be rendered with a custom border.
if (s.equals("2012")) {
customBorderFlag = true;
}
}
if (customBorderFlag) {
// Set custom border for all column cells - for a row.
c.setBorder(getCustomBorder());
}
return c;
}
/*
* Returns a custom border with:
* 1. Thick border
* 2. A margin between cell content (text) and the border.
*/
private Border getCustomBorder() {
Border insideMargin = BorderFactory.createEmptyBorder(10, 10, 10, 10);
Border thickBorder = BorderFactory.createLineBorder(Color.BLACK, 3);
Border borderWithMargin =
BorderFactory.createCompoundBorder(thickBorder, insideMargin);
return borderWithMargin;
}
}
EDIT: Updated the image and the CustomBorderRenderer.java class to show the custom border with margin.
This is an example of a JList. I know how to set a border to the entire JList or the panel containing the JList. My question is that how can we create line borders between the cells?`
For example in the given picture the color of the line border between the first cell and the second is grey, while there is a white colored line border between all the other cells.
Please don't say that this is a JComboBox or a JTree (because of the second element and its two children); even if it is not a JList, I want my JList to have similar LineBorders between the cells.
My web search led me to this interface. Its method getListCellRendererComponent takes arguments like E value, int index, boolean isSelected, boolean cellHasFocus, while I want the LineBorder to appear between all the cells no matter what index they have and whether they are selected or not etc.
EDIT:-
The border is thicker in some places and fine in others.
You can achive that with help of ListCellRenderer. Here is simple example:
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class TestFrame extends JFrame{
public TestFrame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
init();
pack();
setVisible(true);
}
private void init() {
JList<String> list = new JList<>(new String[]{"1","2","3"});
list.setCellRenderer(getRenderer());
add(list);
}
private ListCellRenderer<? super String> getRenderer() {
return new DefaultListCellRenderer(){
#Override
public Component getListCellRendererComponent(JList<?> list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
JLabel listCellRendererComponent = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected,cellHasFocus);
listCellRendererComponent.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0,Color.BLACK));
return listCellRendererComponent;
}
};
}
public static void main(String... strings) {
new TestFrame();
}
}
Looks like:
Read more in tutorial.
EDIT: Just change LineBorder to MatteBorder(have changed code and image).
I'm have a custom table header renderer that will have the standard label and a button inside a JComponent.
The issue I'm having is with the label returned by the default renderer. The call to the default renderer provides the standard label. If I return that as is, it looks as expected. If I try to modify the background or border nothing changes. Modifying the foreground does have the intended effect, however. I do not want to view the sort icons, so I'm attempting to construct a JLabel that looks the same, minus the icons. That is not working correctly either. My JLabel is opaque.
JLabel l = (JLabel)table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
this.lbl.setBackground(l.getBackground());
return this.lbl;
I looked at the source for DefaultTableHeaderRenderer and I can't find anything special that the default class is doing.
I've also tried the following with no effect.
this.lbl.setOpaque(true);
this.lbl.setFont(UIManager.getFont("TableHeader.font"));
this.lbl.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
this.lbl.setBackground(UIManager.getColor("TableHeader.background"));
this.lbl.setForeground(UIManager.getColor("TableHeader.foreground"));
return this.lbl;
EDIT: Clarification. Both code snippets above are inside getTableCellRenderComponent() of my custom renderer. I've tried both ways and neither has worked.
Try using the UIManagers values directly.
TableHeader.background = DerivedColor(color=214,217,223 parent=control offsets=0.0,0.0,0.0,0 pColor=214,217,223
TableHeader.font = javax.swing.plaf.FontUIResource[family=SansSerif,name=sansserif,style=plain,size=12]
TableHeader.foreground = DerivedColor(color=0,0,0 parent=text offsets=0.0,0.0,0.0,0 pColor=0,0,0
TableHeader.opaque = true
Something like UIManager.getColor("TableHeader.background") for example
The border I think you'll find is actually painted by the UI delegate directly.
Updated with example
From the included image, it's obvious that using UIManager does provide some of the basic information need to get the values used by the header, but it does highlight that the renderer is doing some special painting to get the shading.
The second column is the default renderer and the third is cheeky. It is basically stealing the cell renderer directly from the table header...
package testcellrenderer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class TestCellRenderer {
public static void main(String[] args) {
new TestCellRenderer();
}
public TestCellRenderer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
DefaultTableModel model = new DefaultTableModel(
new Object[][]{{"Testing", "Testing", "Testing"}},
new Object[]{"Test A", "Test B", "Test C"}
);
JTable table = new JTable(model);
table.getColumn("Test A").setCellRenderer(new TestTableCellRenderer());
table.getColumn("Test C").setCellRenderer(table.getTableHeader().getDefaultRenderer());
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
}
protected class TestTableCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Color background = UIManager.getColor("TableHeader.background");
Color foreground = UIManager.getColor("TableHeader.foreground");
Font font = UIManager.getFont("TableHeader.font");
boolean opaque = UIManager.getBoolean("TableHeader.opaque");
setBackground(background);
setForeground(foreground);
setFont(font);
setOpaque(opaque);
return this;
}
}
}
I have defined cell editors for the two columns in my table in the following manner:
Java Code:
JComboBox combo = new JComboBox();
//code to add items to the combo box goes here.
JTextField textField = new JTextField();
textField.setHorizontalAlignment(JTextField.RIGHT);
TableColumn column = myJTable.getColumnModel().getColumn(0);
column.setCellEditor(new DefaultCellEditor(combo));
column = myJTable.getColumnModel().getColumn(1);
column.setCellEditor(new DefaultCellEditor(textField));
The problem I am facing is that when a focus is moved to a table cell, the cell doesn't become automatically editable. So, when the focus is moved to column 2 (that has a text field as an editor), the caret sign doesn't not appear unless the cell is double-clicked or the user starts typing. Similar is the case for column 1 (that has a combo box as an editor) as here the combo box doesn't appear unless the cell is clicked. These behaviors are counter-intuitive and undesirable for a user operating with the keyboard.:(
Please suggest pointers on how this could be resolved.
Thanks in advance.
This example overrides editCellAt() in a JTable having a DefaultCellEditor using JTextField.
You can bind the Space key to the startEditing action defined for JTable:
table.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "startEditing");
As commented above, you can use JComboBox both as renderer and editor. Below is a very basic example. It also shows DefaultCellEditor.setClickCountToStart() usage.
import java.awt.Component;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class ComboBoxEditorDemo {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("ComboBoxEditorDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable table = new JTable(
new Object[][] { { "1", "2" }, { "1", "2" } },
new Object[] {"Col1", "Col2" });
table.setRowHeight(24);
TableColumn column = table.getColumnModel().getColumn(1);
column.setCellRenderer(new MyComboBoxRenderer(new String[] { "1", "2", "3" }));
column.setCellEditor(new MyComboBoxEditor(new String[] { "1", "2", "3" }));
DefaultCellEditor editor = new DefaultCellEditor(new JTextField());
editor.setClickCountToStart(1);
column = table.getColumnModel().getColumn(0);
column.setCellEditor(editor);
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
static class MyComboBoxRenderer extends JComboBox implements
TableCellRenderer {
public MyComboBoxRenderer(String[] items) {
super(items);
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelectedItem(value);
return this;
}
}
static class MyComboBoxEditor extends DefaultCellEditor {
public MyComboBoxEditor(String[] items) {
super(new JComboBox(items));
}
}
}
I am trying to create colored headers and footers when printing a JTable. Specifically, I am looking at getPrintable() in javax.swing.JTable, but MessageFormat does not give me the option to specify the color of the header or footer.
How can I do it?
clarification
I am interested in setting the header/footers while printing. For example, notepad appends the filename as a header to what you print.
update
Seems like there is no standard way of doing this, can someone give me some workarounds? The only answer posted so far has nothing to do with printing(as in send to a printer, not displaying to screen) header/footers.
Copied from my comment: I am interested in the printing header/footer. For example, when you are printing a document from notepad, it appends the filename as a header (or perhaps its the footer, I do not remember exactly)
One solution I can think of is to use your own printable:
public class CustomTablePrintable implements Printable {
Printable tablePrintable;
public void setTablePrintable(Printable printable) {
tablePrintable = printable;
}
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) throws PrinterException {
if (pageIndex > 0) {
return NO_SUCH_PAGE;
}
tablePrintable.print(graphics, pageFormat, pageIndex);
Graphics2D g2d = (Graphics2D)graphics;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
// Draw header/footer here
graphics.drawString(header, posx, posy);
return PAGE_EXISTS;
}
}
When you call getPrintable from your JTable, inject it to a new instance to the custom printable and then use this with the PrinterJob.
You can now draw the header and footer as you wish, but you also lose some stuff:
You can't use MessageFormat to format the messages. I believe that you could easily add this functionality to your printable.
Header and footer aren't automatically positioned. You could have rough estimates for these though.
EDIT: I've looked at the Java Sources and there is the private class TablePrintable that does all the job. You can peak at the source code to see how the header and footer are printed. Then you can move this functionality to your Printable class.
This code is mainly from www.java2s.com with changes to show how to change the color. It is not the prettiest solution but hopefully will help you.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class MainClass {
public static void main(String args[]) {
String rows[][] = { { "A", "a" }, { "B", "b" }, { "E", "e" } };
String headers[] = { "Upper", "Lower" };
JFrame frame = new JFrame("Label Header");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable table = new JTable(rows, headers);
JScrollPane scrollPane = new JScrollPane(table);
Border headerBorder = UIManager.getBorder("TableHeader.cellBorder");
JLabel headerLabel1 = new JLabel(headers[0], JLabel.CENTER);
headerLabel1.setBorder(headerBorder);
// Here is where the color is changed.
headerLabel1.setBackground(new Color(255, 0, 0));
headerLabel1.setForeground(new Color(0, 0, 255));
// End of color change.
JLabel headerLabel2 = new JLabel(headers[1], JLabel.CENTER);
headerLabel2.setBorder(headerBorder);
TableCellRenderer renderer = new JComponentTableCellRenderer();
TableColumnModel columnModel = table.getColumnModel();
TableColumn column0 = columnModel.getColumn(0);
TableColumn column1 = columnModel.getColumn(1);
column0.setHeaderRenderer(renderer);
column0.setHeaderValue(headerLabel1);
column1.setHeaderRenderer(renderer);
column1.setHeaderValue(headerLabel2);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class JComponentTableCellRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
return (JComponent)value;
}
}
The most important bit is:
// Here is where the color is changed.
headerLabel1.setBackground(new Color(255, 0, 0));
headerLabel1.setForeground(new Color(0, 0, 255));
// End of color change.
HTH let me know how you got on with it :)
This is a little out of left-field, but you could use a library like iText to create a PDF document, and then send that to the printer. You'll get a much greater level of control over the appearance and presentation of the document, including the ability to manage how the rows of your table break over page boundaries, and you'll be able to set the page header and footer very readily.
You can print a PDF in Java following these instructions: http://www.juixe.com/techknow/index.php/2008/01/17/print-a-pdf-document-in-java/
It's easy:
JTable table = new JTable();
((DefaultTableCellRenderer)table.getTableHeader().getColumnModel().getColumn(4).getHeaderRenderer()).setForeground(Color.ORANGE);