Using a different background color for odd and even rows is a commonly used trick to improve readability of large tables.
I want to use this effect in Swing's JTable. I started out by creating a custom table renderer, but this can only be used to paint actual cells, and I also want to add stripes to the "white" part of the table where there might be no cells. I can subclass JTable and override paintComponent(), but I would prefer an option where I can just change the table's rendering.
Is there a better way of doing this?
Edit: According to the answers so far this seems to be impossible without extending JTable. However, when I override JTable.paintComponent() it also only paints the area where there are rows. How can I paint the rest?
Use getCellRect( getRowCount() - 1, 0, true ).y to get the top y-coordinate of the empty space, and then paint some Rectangles and (Grid-)Lines with paintComponent( Graphics g ).
To make it much easier for you, here's a long (but complete) solution ;-)
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class StripedEvenInWhitePartsTable extends JTable
{
public StripedEvenInWhitePartsTable( String[][] data, String[] fields )
{
super( data, fields );
setFillsViewportHeight( true ); //to show the empty space of the table
}
#Override
public void paintComponent( Graphics g )
{
super.paintComponent( g );
paintEmptyRows( g );
}
public void paintEmptyRows( Graphics g )
{
Graphics newGraphics = g.create();
newGraphics.setColor( UIManager.getColor( "Table.gridColor" ) );
Rectangle rectOfLastRow = getCellRect( getRowCount() - 1, 0, true );
int firstNonExistentRowY = rectOfLastRow.y; //the top Y-coordinate of the first empty tablerow
if ( getVisibleRect().height > firstNonExistentRowY ) //only paint the grid if empty space is visible
{
//fill the rows alternating and paint the row-lines:
int rowYToDraw = (firstNonExistentRowY - 1) + getRowHeight(); //minus 1 otherwise the first empty row is one pixel to high
int actualRow = getRowCount() - 1; //to continue the stripes from the area with table-data
while ( rowYToDraw < getHeight() )
{
if ( actualRow % 2 == 0 )
{
newGraphics.setColor( Color.ORANGE ); //change this to another color (Color.YELLOW, anyone?) to show that only the free space is painted
newGraphics.fillRect( 0, rowYToDraw, getWidth(), getRowHeight() );
newGraphics.setColor( UIManager.getColor( "Table.gridColor" ) );
}
newGraphics.drawLine( 0, rowYToDraw, getWidth(), rowYToDraw );
rowYToDraw += getRowHeight();
actualRow++;
}
//paint the column-lines:
int x = 0;
for ( int i = 0; i < getColumnCount(); i++ )
{
TableColumn column = getColumnModel().getColumn( i );
x += column.getWidth(); //add the column width to the x-coordinate
newGraphics.drawLine( x - 1, firstNonExistentRowY, x - 1, getHeight() );
}
newGraphics.dispose();
} //if empty space is visible
} //paintEmptyRows
public Component prepareRenderer( TableCellRenderer renderer, int row, int column )
{
Component c = super.prepareRenderer( renderer, row, column );
if ( !isRowSelected( row ) )
{
c.setBackground( row % 2 == 0 ? getBackground() : Color.ORANGE );
}
return c;
}
public static void main( String[] argv )
{
String data[][] = { { "A0", "B0", "C0" }, { "A1", "B1", "C1" }, { "A2", "B2", "C2" }, { "A3", "B3", "C3" }, { "A4", "B4", "C4" } };
String fields[] = { "A", "B", "C" };
JFrame frame = new JFrame( "a JTable with striped empty space" );
StripedEvenInWhitePartsTable table = new StripedEvenInWhitePartsTable( data, fields );
JScrollPane pane = new JScrollPane( table );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( pane );
frame.setSize( 400, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
This example could be extended to:
fix the painted pseudogrid for variable RowHeights (I'm using the lowest height used in any row)
explain to the user why nothing happens if he clicks in the empty space to edit the cells (via tooltip)
add an extra row to the table model if the user clicks in the empty space (nooo! no Excel please!)
use the empty space to draw a reflection of the table (including all rendered data ( what for? ;-) )
The JXtable provided by swingx allow you to implements such rendering
Take a look at http://swinglabs.org/docs/components/JXTable/tutorial.jsp?step=3#RowHighlighting
Use Table Row Rendering concepts which is easier than dealing with individual renderers.
This approach only works for rendered cells. If you want to paint outside the bounds of the table, then you will need to override the paintComponent() method to add custom painting.
You can also use a custom TableCellRenderer which will pick the color for you, with a part of code like this inside:
if (isSelected) //color remains the same while selected
{
lFgColor = table.getSelectionForeground();
lBgColor = table.getSelectionBackground();
}
else
{
lFgColor = table.getForeground();
if (row%2 != 0) //once out of two rows, change color
lBgColor = table.getBackground();
else
{
//New look and feels like nimbus declare this property, try to use it
lBgColor = UIManager.getColor("Table.alternateRowColor");
if (lBgColor == null) //If not, choose your own color
lBgColor = UIManager.getColor("Table.light");
}
}
}
Edit: I missed the fact that you tried that already, and that you need to extend this color to the space without cells. To my knowledge, this is not possible with the current implementation of JTable or JXTable. The highlighters from JXTable are mostly sophisticated renderers, they still cater only to cells.
To extend the space, the only possibilities I see are:
draw it yourself, in your own component.
"hack" a way by adding a fake last column, with a custom JTableHeader which wouldn't display the last column header (and a renderer avoiding the grid for this last column). Also, the table resizing mode should be AUTO_RESIZE_LAST_COLUMN, in this case. This is a lot of conditions to make it work, and I'm not really sure it would work anyway.
Either use JXTable or if you are super-lazy ( or super time-short :-)) ) you can just use "Nimbus" look-and-feel, JTable looks there stripped by default :)
Related
I design a system by Java Swing. I have a tablet called sick and this tablet has a column called status which has two values,one is open and another is closed values. When the value of the column is open I want to change color to blue and when it is closed I want to change color to red (when the information is selected from the database).
What it appears you are looking to do is a form of Conditional Formatting against one or more specific cells within a JTable. This can be done by overriding the JTable's prepareRenderer() method with a custom Prepare Renderer method:
Here is a runnable code example that displays the above example form image:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class JTablePrepareRendererExample {
// Age Group colors
Color ageGroup1Color = Color.decode("#FCF3CF"); // Light Yellow
Color ageGroup2Color = Color.decode("#EBDEF0"); // Light Magenta
Color ageGroup3Color = Color.decode("#D4EFDF"); // Light Green
Color ageGroup4Color = Color.decode("#FAD7A0"); // Light Orange
Color ageGroup5Color = Color.decode("#D4AC0D"); // Gold
Color ageGroup6Color = Color.decode("#566573"); // Dark Gray
// Status Group Colors
Color openColor = Color.decode("#D4E6F1"); // Light Red
Color closeColor = Color.decode("#FADBD8"); // Light Blue
// Row Selection Color
Color selection = Color.decode("#7FB3D5"); // A lighter Blue
// Table Default Colors
Color cellsOrigBackColor = new JTable().getBackground();
Color cellsOrigForeColor = new JTable().getForeground();
public static void main(String[] args) {
// So we don't need statics...
new JTablePrepareRendererExample().startDemo(args);
}
private void startDemo(String[] args) {
initializeForm();
}
private void initializeForm() {
// Create a JFrame Form (with title).
JFrame frame = new JFrame("JTable Conditional Formatting");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Set its' Close Operation
frame.setAlwaysOnTop(true); // Set that form will be on top of all other applications.
frame.setSize(new Dimension(400, 250)); // Set the form size.
frame.setLayout(new BorderLayout()); // Set the form to utilize the Border Layout Manager.
// Table Column Names
Object[] columnNames = {"Name", "Age", "Alive", "Case Status"};
// Table Data...
Object data[][] = {
{"Tracey Johnson", 24, "Yes", "Unknown"},
{"Frank Thetank", 108, "Barely", "Closed"},
{"Denis Therman", 41, "Yes", "Open"},
{"Joe Blow", 60, "Yes", "Unknown"},
{"Fred Flintston", "#1", "No", "Closed"},
{"John Doe", 73, "Yes", "Open"},
{"James Brown", 87, "No", "Closed"} };
// Create a JTable Model and fill the table model with the above Object data...
DefaultTableModel model = new DefaultTableModel(data, columnNames);
// Declare a JTable and set the Table Model to that table.
JTable table = new JTable(model) {
private static final long serialVersionUID = 1L;
// Here is where all the cell formatting is done in this example
#Override
public Component prepareRenderer(TableCellRenderer renderer, int rowIndex, int columnIndex) {
Color cellBackColor = cellsOrigBackColor; // Original Cells Backgound color.
Color cellForeColor = cellsOrigForeColor; // Original Cells Foregound (text) color.
/* Acquire the current cell component being Rendered.
ALL cells get Rendered. */
JComponent component = (JComponent) super.prepareRenderer(renderer, rowIndex, columnIndex);
// The 'Age' Field Color Conditions...
// ===================================
// Get the 'Age' field value and convert to integer.
if (columnIndex == 1) {
String sAge = getValueAt(rowIndex, 1).toString();
int age = -1; // Age Default.
/* Make sure the data value in the current Age cell
being rendered is indeed a string representation
of a Integer (int) numerical value. */
if (sAge.matches("\\d+")) {
// Convert the table cell value to Integer
age = Integer.parseInt(sAge);
}
else {
/* If it's not a Integer type value then indicate
ERROR in cell and highlight RED */
cellBackColor = Color.RED;
component.setBackground(cellBackColor);
cellForeColor = properTextColor(cellBackColor);
component.setForeground(cellForeColor);
model.setValueAt("** ERROR **", rowIndex, 1);
return component;
}
if (age <= 25) {
cellBackColor = ageGroup1Color;
}
else if (age >= 26 && age <= 45) {
cellBackColor = ageGroup2Color;
}
else if (age >= 46 && age <= 65) {
cellBackColor = ageGroup3Color;
}
else if (age >= 66 && age <= 80) {
cellBackColor = ageGroup4Color;
}
else if (age >= 81 && age <= 95) {
cellBackColor = ageGroup5Color;
}
else if (age > 95) {
cellBackColor = ageGroup6Color;
}
else {
cellBackColor = cellsOrigBackColor;
}
}
// The 'Status' Field Color Conditions...
// ======================================
// Get the 'Status' field value
String status = getValueAt(rowIndex, 3).toString();
if (columnIndex == 3) {
if (status.equalsIgnoreCase("closed")) {
cellBackColor = closeColor;
}
else if (status.equalsIgnoreCase("open")) {
cellBackColor = openColor;
}
else {
cellBackColor = cellsOrigBackColor;
}
}
/* Set Age cell's determined Background color
based on any of the particular conditions
stipulated above. */
component.setBackground(cellBackColor);
/* Set cell's Text (foreground) Color based on
color and brightness of Cell's Background
color. */
cellForeColor = properTextColor(cellBackColor); // Helper method
component.setForeground(cellForeColor);
// If a row is selected, maintain the conditional formatting...
if (isRowSelected(rowIndex)) {
component.setBackground(selection);
} else {
component.setBackground(cellBackColor);
}
return component;
}
};
/* Set the table size, columns not selectable,
rows selectable via single selection */
table.setPreferredSize(new Dimension(400, 250));
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(true);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
/* Create a JScrollPane, set its size to Table and
add the Table to the JScrollPane ViewPort. */
JScrollPane sp = new JScrollPane();
sp.setPreferredSize(table.getPreferredSize());
sp.getViewport().add(table);
// Create a JPanel to hold JScrollPane (and JTable)
JPanel tablePanel = new JPanel();
tablePanel.add(sp); // Add ScrollPane to JPanel
/* Create another JPanel to hold a JLabel
and the JButtons 'Add' and 'Close' */
JPanel buttonsPanel = new JPanel();
// Set this JPanel to utilize a 'Flow Layout Manager'
buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); // Center any compnents in panel.
// Create a JLabel. Shown how to utilize HTML here for a JLabel.
JLabel doLabel = new JLabel("<html><pre><font color=blue>"
+ "Select a row and edit a cell. </font></pre>"
+ "</html>");
// Create the 'Add' JButton.
JButton addButton = new JButton("Add");
addButton.setToolTipText(" Add a Table Row "); // Set a ToolTip for 'Add' Button.
// Apply an Action Listener to 'Add' Button.
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.addRow(new Object[]{"", "0", "", ""});
}
});
// Create the 'Close' JButton.
JButton closeButton = new JButton("Close");
closeButton.setToolTipText(" Close Application "); // Set a ToolTip for 'Close' Button.
closeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}); // Apply an Action Listener to 'Close' Button.
buttonsPanel.add(doLabel); // Add JLabel to Buttons JPanel.
buttonsPanel.add(addButton); // Add 'Add' JButton to Buttons JPanel.
buttonsPanel.add(closeButton); // Add 'Close' JButton to Buttons JPanel.
frame.add(tablePanel, BorderLayout.NORTH); // Add The Table JPanel to top of JFrame Form.
frame.add(buttonsPanel, BorderLayout.SOUTH); // Add The Buttons JPanel to bottom of JFrame Form.
frame.pack(); // Pack the components on JFrame.
frame.setVisible(true); // Make the JFrame form visible.
frame.setLocationRelativeTo(null); // Make sure JFrame displays at center Screen.
}
/**
* Returns either the Color WHITE or the Color BLACK dependent upon the
* brightness of what the supplied background color might be. If the
* background color is too dark then WHITE is returned. If the background
* color is too bright then BLACK is returned.<br><br>
*
* #param currentBackgroundColor (Color Object) The background color text
* will reside on.<br>
*
* #return (Color Object) The color WHITE or the Color BLACK.
*/
public static Color properTextColor(Color currentBackgroundColor) {
double L; // Holds the brightness value for the supplied color
Color determinedColor; // Default
// Calculate color brightness from supplied color.
int r = currentBackgroundColor.getRed();
int g = currentBackgroundColor.getGreen();
int b = currentBackgroundColor.getBlue();
L = (int) Math.sqrt((r * r * .241) + (g * g * .691) + (b * b * .068));
// Return the required text color to suit the
// supplied background color.
if (L > 129) {
determinedColor = Color.decode("#000000"); // White
}
else {
determinedColor = Color.decode("#FFFFFF"); // Black
}
return determinedColor;
}
}
In the above example there are two specific data columns that have specific conditions checked on each column cell, the Age column and the Case Status column.
In the Age column, a specific age range determines the cell background color that will be displayed. You will notice that for the Fred Flintston row, the age value holds a ERROR message (highlighted in red) instead of a age value. If you look in the Object data array values you will see that the value supplied there ("#1") for Age is not a proper integer value. This yet another condition which is checked within the Renderer. The colors used for this column are declared within the class as member variables.
The Case Status Table column checks for three specific conditions:
If cell value contains a string value of "Open" then that cells
background color will be a light red.
If cell value contains a string value of "Closed" then that cells
background color will be a light blue.
If a cell value is anything other than "Open" or "Closed" then that
cells background color will be the original cell background color.
Even the Row Selection color is modified within this custom Renderer to a lighter, more comfortable blue (well, in my opinion).
Because the possibility of background color change is available so too must be the capability to change the text (cell foreground) color so that it will be legible within certain colors. By default the JTable cell text color is black, this makes text extremely hard to read if the cell's background color is changed to dark gray or even dark red. White text would be a better choice. For this reason I have also included a helper method named properTextColor() that will automatically supply a text color (either White or Black) that would be the easiest to see dependent upon the Background color supplied to the method. You can see this at work within the example application image provided specifically in Age column cells (rows: "Frank Thetank" and "Fred Flintston").
I have an SWT Table with multiple columns. In this example, let's say there are three columns. The cells of each column all contain an image followed by some text (example pictured below). However, as you can see there is no spacing between the 2 - 3 column lines and their cells.
Is there a built-in way to add a buffer zone to those cells so the icons don't appear right on the edge line? Such as an offset property of some kind? I don't see any property overtly listed in either Table or TableColumn.
If not, is there a workaround beyond just adding white space to the cell images?
Please let me know if there's anything I can do to make my question clearer.
Table:
I don't think there is a designated way to adjust the margin and spacing of image and text within a cell. Apart from adding transparent pixels to the image (as you already suggested), you can use a PaintListener to gain control over how a cell is rendered.
The example below draws image and text with adjustable margin and spacing:
Listener paintListener = new Listener() {
int leftMargin = 40;
int rightMargin = 10;
int imageSpacing = 200;
#Override
public void handleEvent( Event event ) {
TableItem item = ( TableItem )event.item;
Rectangle imageBounds = image.getBounds();
Point textExtent = event.gc.textExtent( item.getText() );
switch( event.type ) {
case SWT.MeasureItem: {
event.width += leftMargin + imageBounds.width + imageSpacing + textExtent.x + rightMargin;
event.height = Math.max( event.height, imageBounds.height + 2 );
event.height = Math.max( event.height, textExtent.y + 2 );
break;
}
case SWT.PaintItem: {
int x = event.x + leftMargin;
int imageOffset = ( event.height - imageBounds.height ) / 2;
event.gc.drawImage( image, x, event.y + imageOffset );
x += imageSpacing;
int textOffset = ( event.height - textExtent.y ) / 2;
event.gc.drawText( item.getText(), x, event.y + textOffset );
break;
}
case SWT.EraseItem: {
event.detail &= ~SWT.FOREGROUND;
}
}
}
};
table.addListener( SWT.MeasureItem, paintListener );
table.addListener( SWT.PaintItem, paintListener );
table.addListener( SWT.EraseItem, paintListener );
For a more thorough understanding of owner-drawn items in SWT please read the Custom Drawing Table and Tree Items article.
If you are using a JFace TableViewer, there is also an OwnerDrawLabelProvider as shown in this example:
http://www.vogella.com/tutorials/EclipseJFaceTableAdvanced/article.html#styledcelllabelprovider-and-ownerdrawlabelprovider
So I'm trying to make a small text preview with line numbers by inheriting from a JTextArea and overwriting paintComponent().
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JTextArea;
public class PreviewPane extends JTextArea {
public PreviewPane() {
setText( "first row\nsecond row\nthird row" );
}
#Override
protected void paintComponent( Graphics graphics ) {
Graphics2D g = (Graphics2D) graphics;
int emWidth = g.getFontMetrics().stringWidth( "m" );
int lineHeight = g.getFontMetrics().getHeight();
int baseLine = g.getFontMetrics().getAscent();
g.translate( 2 * emWidth, 0 );
super.paintComponent( g );
g.translate( -2 * emWidth, 0 );
g.setColor( getBackground() );
g.fillRect( 0, 0, 2 * emWidth - 1, getHeight() - 1 );
g.setColor( Color.LIGHT_GRAY );
g.drawLine( 2 * emWidth - 1, 0, 2 * emWidth - 1, getHeight() - 1 );
g.setColor( Color.BLACK );
// "guessed" value for antialiasing
g.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB );
for ( int i = 1; i <= 3; i++ ) {
g.drawString( String.valueOf( i ), getMargin().left, getMargin().top + baseLine + ( i - 1 ) * lineHeight );
}
}
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setBounds( 0, 0, 640, 480 );
frame.getContentPane().add( new PreviewPane(), BorderLayout.CENTER );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
}
In the marked line, I set the antialiasing hint to RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB. This will lead to the exact font rendering as the text area:
Omitting this line just uses the default:
But this will not work on every system. Querying the FontRenderContext or the originally assigned rendering hints from the graphics object just return Default antialiasing text mode, which cannot be the mode used for rendering the text area.
So my question is: How to obtain the actually used antialiasing mode from the text component/java system?
Note: I'm not trying to implement a fully fledged line numbering editor, so the "inefficiency" of this solution is irrelevant. Also, I came across this issue several times in the past years when directly rendering text in component's paint methods, so this is just an example.
Digging through the Java lib source reveals that font rendering of text area (and presumably the other text components as well) use internal class sun.swing.SwingUtilities2. This holds the desired information internally and queries it from the java.awt.Toolkit.
So the code to get text antialiasing information from the system is:
Toolkit tk = Toolkit.getDefaultToolkit();
Map map = (Map) tk.getDesktopProperty( sun.awt.SunToolkit.DESKTOPFONTHINTS );
g.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, map.get( RenderingHints.KEY_TEXT_ANTIALIASING ) );
The content of the map is (in my case)
{Text-specific antialiasing enable key=LCD HRGB antialiasing text mode, Text-specific LCD contrast key=120}
which is the exact information needed.
Note that sun.awt.SunToolkit.DESKTOPFONTHINTS is forbidden API and therefore should be replaced by "awt.font.desktophints".
I am new to Swing in Java and am trying to make a visual grid. I have some simple questions as to how to do the following. Here are some characteristics of the grid:
For each square of the grid, I should be having an equivalent index(i,j) using which I can identify the square and place a text.
Edit - (i,j) is the row/column value - the index of the square in the grid.
The diagonals of the squares should be drawn and each of the four divisions of the square should be having a different color.
Any suggestions as to how to do so.
Given row and column you will need to know the number of columns per row. With this information you can simply do (row * columns) + column which will return the index of the square.
For example, with 8 columns per row, a request for
row = 0, column = 4, will return 4
row = 1, column = 4, will return 12
row = 0, column = 0, will return 0
Rendering the sections of the square is more complex and can be achieved in at least two ways. You could use a Polygon which generates a triangle for each section or Shape and simply use Graphics2D#fill to fill it.
This will come down to how you physically render each square...
Take a look at 2D Graphics for more details and this for an example of both.
A Shape would be much easier to rotate and position and would only require you to have a single instance (or a single instance for each square based on your needs), where as you would require at least 4 Polygons or do some fun rotation...
Updated with simple example
All done with rotating triangles...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DividedSquare {
public static void main(String[] args) {
new DividedSquare();
}
public DividedSquare() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
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 {
private TriangleShape baseTriangle;
private Color[] colors;
public TestPane() {
colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA};
}
#Override
public void invalidate() {
super.invalidate();
baseTriangle = new TriangleShape(
new Point(0, 0),
new Point(getWidth(), 0),
new Point(getWidth() / 2, getHeight() / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text[] = new String[]{
"123.123",
"456.789",
"012.315",
"678.921"
};
FontMetrics fm = g2d.getFontMetrics();
double angel = 0;
for (int index = 0; index < 4; index++) {
g2d.setColor(colors[index]);
Path2D rotated = rotate(baseTriangle, angel);
g2d.fill(rotated);
Rectangle bounds = rotated.getBounds();
int x = bounds.x + ((bounds.width - fm.stringWidth(text[0])) / 2);
int y = bounds.y + (((bounds.height - fm.getHeight()) / 2) + fm.getAscent());
g2d.setColor(Color.WHITE);
g2d.drawString(text[index], x, y);
angel += 90;
}
g2d.setColor(Color.BLACK);
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.drawLine(getWidth(), 0, 0, getHeight());
g2d.dispose();
}
public Path2D rotate(TriangleShape shape, double angel) {
Rectangle bounds = shape.getBounds();
int x = bounds.width / 2;
int y = bounds.width / 2;
return new Path2D.Float(shape, AffineTransform.getRotateInstance(
Math.toRadians(angel),
x,
y));
}
}
public class TriangleShape extends Path2D.Double {
public TriangleShape(Point2D... points) {
moveTo(points[0].getX(), points[0].getY());
lineTo(points[1].getX(), points[1].getY());
lineTo(points[2].getX(), points[2].getY());
closePath();
}
}
}
Yes, see Making a robust, resizable Chess GUI for a GUI that uses a GridLayout to contain JButton objects. The buttons are held in an 8x8 array (the chessboard), while displayed in a 9 row x 9 column grid layout to accommodate the row (8-1) & column (A-H) identifiers of the board.
Buttons will accept an image that might represent the '4 color diagonal' and text. In the chess board I only use images (the chess pieces).
Edit 1
What is the actual difference between the 4 colored areas (besides the color). E.G. is there supposed to be different functionality depending on which of the diagonal areas the user clicks in?
Each of the 4 colored areas in the square has a value from a table based on some algorithm. The color depends upon the value. Currently, it is just used as an indicator. But the user needs to select an initial square in the grid where I place a mark that it is initial.
And the text. Should it be on top of the '4 color diagonal', beside it, below it..?
I also plan to place a text in each of the region indicating that value. Hence, there is one text field to be placed in each of the four partitions of the square.
Text field or label? A label can show text, but a text field makes it possible to copy the text or change it.
I need a text field because I need to change the text during the course of the algorithm.
By 'I' DYM the program, or the user? The program can change text in a label or text field, but the text field is user editable.
I mean the program
OK - Draw the design and text on an image. Use the image as a button icon. The user can select an initial square by clicking the button. If the text changes, generate a new image and set it to the button.
Edit 2
So do you mean that I have to create an image with 4 colors? Would that not be difficult. I would like to change the colors from the program itself. My algorithm would generate the values and at certain points of the algorithm, I would like to see the visualization.
Not if you generate the image at run-time.
How do I generate an image at run-time?
See the answer to Example images for code and mark-up Q&As The first set of Icons..
...
..As well as the Sprite sheet..
..were generated at run-time in Java code. Each set of images links to the question that includes the code that generated them.
I believe you're describing the SetGridLayout feature in swing. If you want a tutorial on how to set up such a window, you can find it here:
http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html
After reading your question a second time... I think you plan on drawing a grid...
I'd look into the Draw.java library
Maybe you can try to do this adding a jTable object, this object contains methods that can put values in every value i and j respectively like:
jTable1.setValueAt(Value, i, j);
this will allows you to change the value in every cell.
I currently have a JTable consisting of 7 columns and many rows of data.
How would I go about colour each cell in the 7th column? I want to colour according to the data inside the cell.
So if one of the cells in the 7th column was say below 0, then I want to colour red or if one of the cells in the 7th column was more than 0, then colour green etc.
Thank you
You can use a TableCellRenderer to create these custom styles for individual cells in the table. This tutorial explains in some detail. On that page is an example that uses a color renderer which may be the start that you need.
Override prepareRenderer() method when you initialize your table object, put your specific conditionals to change colors accordingly, then color changes will be reflected in your application as you defined. Suppose you have a global JTable variable table and let model be your DefaultTableModel instance:
table = new JTable( model )
{
public Component prepareRenderer ( TableCellRenderer r, int row, int col )
{
Component comp = super.prepareRenderer( r, row, col );
if ( col == 6 && !isCellSelected( row, col ) )
{
if ( table.getValueAt( row, col ) < 0 )
comp.setBackground( Color.RED );
else
comp.setBackground( Color.GREEN );
}
return comp;
}
};
The code above is checking for col == 6 because you want to colorize 7th column, which corresponds to column index 6 (it starts from 0). In the inner if statement, it is checking for cell values and changing cell background color accordingly.