I would like a different way to create a multi-colored JLabel.
(Multi-colored = parts of the text in different foreground-colors)
The only solution I found so far (and which I currently use), is setting the text in html. But I'm having problems with that...
When the LayoutManager decides that the JLabel should be narrowed, with a plain-text in a JLabel, the text gets kind of cropped, and "..." is added.
(e.g.: "My Long Text" -> becomes: "My Long T...")
With html inside a JLabel, the text is wrapped somewhere on a space-character, leaving the rest of outside the drawable area, and invisible as the JLabel's height is unchanged.
(e.g.: "My Long Text" -> becomes: "My Long")
In my case the JLabel is rendered in a JTable, which gets resized by the user, not to mention in different screen resolutions.
I tried adding a "nowrap" attribute or a ""-tag to the html, but it looks like this is ignored.
Leaving me -I think- with one solution: painting the label myself.
Or not?
Any suggestions?
Examples?
Thank you.
Here's a very simple example:
Try to resize this panel horizontally, and see what happens with the text inside both JLabel's...
(there's no indication for the user, that the text of the second JLabel is not the complete content)
-> In the example, the JLabel's height changes, but when rendered inside the framework's JTable, the height of the rows doesn't change and I don't want it to change. Without the use of HTML it doesn't change the height either...
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MultiJLabel
extends JFrame
{
public MultiJLabel()
{
super("Multi-colored JLabel test");
JPanel pnl = new JPanel();
pnl.setLayout(new BorderLayout());
pnl.add(new JLabel("This is a test of My Long Text"), BorderLayout.NORTH);
pnl.add(new JLabel("<html>This is a test of <font color='#ffbebe'>My Long Text</font></html>"), BorderLayout.SOUTH);
this.getContentPane().add(pnl);
this.pack();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args)
{
new MultiJLabel();
}
}
Here's a picture of the original problem, where our users are not aware that the client's Order Number is not what the grid is showing, because this column has HTML-formatted text to show multi-colors.
Thank you all for your comments, but I was impatient and created my own JLabel.
I know it may be a poor programmed version, but it works for me...
You can test it by altering the above example with:
JMultiColorLabel lbl = new JMultiColorLabel("This is a test of My Long Text");
lbl.setColors(new int[]{10,15}, new Color[]{Color.RED,Color.BLUE});
lbl.setPreferredSize(new Dimension(200,20));
pnl.add(lbl, BorderLayout.SOUTH);
And use this class:
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.util.HashMap;
import javax.swing.JLabel;
public class JMultiColorLabel
extends JLabel
{
private static final String STRING_OVERFLOW = "...";
private HashMap<Integer, Color> extraColors = new HashMap<Integer, Color>();
public JMultiColorLabel(String text)
{
super(text);
}
public void setColors(int[] indices, Color[] colors)
{
for (int i = 0; i < indices.length; i++)
this.extraColors.put(indices[i], colors[i]);
}
protected void paintComponent(Graphics g)
{
// Get text-contents of Label
String text = this.getText();
// No text in the JLabel? -> No risk: super
if (text == null || text.length() == 0)
{
super.paintComponent(g);
return;
}
// Content Array of characters to paint
char[] chars = text.toCharArray();
// Draw nice and smooth
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Draw background
if (this.isOpaque())
{
g2d.setColor(this.getBackground());
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
}
// FontMetrics to calculate widths and height
FontMetrics fm = g2d.getFontMetrics();
// Available space
Insets ins = this.getInsets();
int maxSpace = this.getWidth()-(ins.left+ins.right);
boolean overflow = (fm.stringWidth(text) > maxSpace);
// Starting offset
int offset = ins.left+1;
// The start Color is the default
g2d.setColor(this.getForeground());
// Loop over characters
for (int i = 0; i < chars.length; i++)
{
// Switch Color?
if (this.extraColors.containsKey(i))
g2d.setColor(this.extraColors.get(i));
// Check if we still have enough room for this character
if (overflow && offset >= (maxSpace-fm.stringWidth(STRING_OVERFLOW)))
{ // Draw overflow and stop painting
g2d.drawString(STRING_OVERFLOW, offset, (fm.getHeight()+ins.top));
return;
}
else // We have the space -> Draw the character
g2d.drawString(String.valueOf(chars[i]), offset, (fm.getHeight()+ins.top));
// Move cursor to the next horizontal position
offset += fm.charWidth(chars[i]);
}
}
}
To prevent line wrapping when using html-text in JLabels, wrap the text in nobr (no-break) tags:
new JLabel("<html><nobr>This is a test of <font color='#ffbebe'>My Long Text</font></nobr></html>")
When using the nobr-tags, the line will not be wrapped, but it won't be truncated as well. So, there won't be any ellipsis (...) at the end of the shown text, but it will just cut off.
The missing ... might actually be of advantage in a table as there is no additional width lost by the ellipsis, and thus more content shown. But to the user it might be less obvious that there is more content without them.
Related
The problem is simple. I want to create a vertical tree of values, where as you descend down the levels, the amount of values gets exponentially larger. Let's say the 1st level has 1 numerical value, the next has 10, then the next has 100, then the next has 1000, and so on. The first level is connected to the 2nd level with the use of lines, and the 2nd to the 3rd, and so on, much like a game tree. These values are also evenly spaced, so let's say you have a JPanel which is 500x500. At a y of 100, you have 4 values, and so to evenly space them out, you would have a value at 100, one at 200, and so on.
I've tried incorporating drawString, and connecting them with the drawLine method, and placing this so called diagram on a JPanel. That is actually quite simple, and it works if you only have as many as about 50~ values in a singular level. However, when you only have a 1600x900 screen, you can't fit 100 values (on the x axis, which is 1600) without having a big jumbled up mess.
I was thinking there could be 2 possible solutions for this.
One is that the JPanel is not limited to a set resolution (a.k.a the size of your screen) and is scrollable. If it was 10000 x 900 then making this gigantic tree diagram would actually be quite simple, and I could easily fit the 100 values with enough space between them for the values to actually be discernable. However, as far as I know, it's not possible.
The second solution is that I write these values into a file, but I'm not sure how to go about this.
Does anyone know, theoretically speaking, what could be the simplest solution for properly displaying a large tree diagram filled with hundreds of values in a single level?
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Performing Custom Painting section.
It turns out it's possible to create one 10000 x 900 drawing JPanel. Adjust the JScrollPane preferred size to the size you want to display. The height should be at least 950 pixels to allow room for the horizontal scroll bar.
I created a checkerboard pattern so you can see that the drawing JPanel does scroll.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LargeDrawingJPanel implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new LargeDrawingJPanel());
}
#Override
public void run() {
JFrame frame = new JFrame("Large Drawing JPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel drawingPanel = new DrawingPanel();
JScrollPane scrollPane = new JScrollPane(drawingPanel);
scrollPane.setPreferredSize(new Dimension(1400, 950));
frame.add(scrollPane, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(10000, 900));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Color[] colors = { Color.RED, Color.BLACK };
int colorIndex = 0;
int x = 0;
int y = 0;
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 9; j++) {
g2d.setColor(colors[colorIndex]);
colorIndex = (colorIndex == 0) ? 1 : 0;
g2d.fillRect(x, y, 100, 100);
y += 100;
}
x += 100;
y = 0;
}
}
}
}
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 have a certain text, that i want to annotate for the user. Unfortunately i don't even see where to begin. My algorithm gives as output a range on a string. What i am going for is something like this:
I would need two ways to marker the Characters ( Blue line, red line), maybe also to invert the character (Give a character a different background), or make them fat. What is especially difficult is aligning the Pictures (here designated by two black dots) with the characters. Since the characters should be in Courier New, i could know where to put the offset, but i cannot seem to do it.
Lastly i would have to apply a break after X characters and begin a new line, just like in the picture. I have not found any example how to approach this with java yet. With python i could use ImageDraw, but i am out of the water with java.
is it possible to show this in a canvas on the screen and export this as svg or pdf? I dont know any libraries that could do this. So i would be happy to receive some suggestions/examples also along this way.
The key is to deal with the FontMetrics API. The best you can do is looking at this reference doc.
Here is a sample code demonstrating this usage. It draws red and blue lines around an "Hello world" text according a range of chars.
The text is inside a JLabel, but you can adapt the paint method on any component (but you will have to call graphics.drawChars to paint the text.)
(the code is not very nice, but it demonstrates the usage of FontMetrics)
package com.example.swing;
import javax.swing.*;
import java.awt.*;
public class DemoFontMetrics {
public static void main(String[] args){
JFrame frame = new JFrame();
DecoratedLabel label = new DecoratedLabel("hello world !",new int[]{2,4}, new int[]{6,9});
JPanel textContainer = new JPanel(new FlowLayout());
textContainer.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
textContainer.add(label);
frame.getContentPane().add(textContainer);
frame.pack();
frame.setVisible(true);
}
private static class DecoratedLabel extends JLabel{
int startBlue;
int endBlue;
int startRed;
int endRed;
private DecoratedLabel(String text, int[] blueRange, int[] redRange) {
super(text);
startBlue = blueRange[0];
endBlue = blueRange[1];
startRed = redRange[0];
endRed = redRange[1];
}
#Override
public void paint(Graphics g) {
super.paint(g); //draw text
//set line with : 3
Stroke stroke = new BasicStroke(3f);
((Graphics2D)g).setStroke(stroke);
FontMetrics fm = g.getFontMetrics();
int h = fm.getHeight();
//compute blue line coordonate
fm.stringWidth(getText().substring(0,startBlue));
int x1 = fm.stringWidth(getText().substring(0, startBlue));
int x2 = fm.stringWidth(getText().substring(0, endBlue));
g.setColor(Color.BLUE);
g.drawLine(x1,0,x2,0);// draw blue line
//compute red line coordonates
int x3 = fm.stringWidth(getText().substring(0,startRed));
int x4 = fm.stringWidth(getText().substring(0, endRed));
g.setColor(Color.RED);
g.drawLine(x3,h-1,x4,h-1); // draw redline
}
}
}
If the text is displayed via JTextPane you can conveniently define a custom HighlightPainter, that draws lines above or under the text.
Then you can add highlights to the text pane programmatically by calling:
textPane.getHighlighter().addHighlight(startPos, endPos,
myLineHighlightPainter);
Images may as well easily be added to the pane, by:
textPane.setIcon(myImageIcon);
You can create svg directly for example: http://xmlgraphics.apache.org/batik/ it's an xml based vector graphics format.
EDIT: You can display svg in java, you can create pdf's with it from java. You can publish it in the web (simply as svg).
I run into a problem where I have a JTable laid out using GridBagLayout manager and the number of rows in the table is not fixed. I intend to fill the space assigned to the table with all its cells, however there is a big blank (and white) space between the last row of the table and the next component in the container.
As a potential solution, I wonder if I can adjust the height of the cells to fill the space assigned to the table. So for example, if there are three rows, then the height of the space should be equally divided into three rows. If there is only one row, then this row should take up the whole space available.
Any suggestion are welcome, and if there is a better way to achieve the desired effect, please enlighten me. Thanks.
P.S. I am using JTable within a JPanel instead of a JScrollPane, if that makes any difference.
Edit: So I've tried the following code, which certainly adjusts height of the rows depending on the number of the rows present, but it still leaves a blank white space after the last row and before the next component. Wondering why?
// re-size the header and row height to fill the whole tPanel
int panelHeight = tPanel.getHeight();
int desiredRowHeight = panelHeight / (numOfRows + 1);
friendsInfo.getTableHeader().setPreferredSize(new Dimension(table.getColumnModel().getTotalColumnWidth(), desiredRowHeight));
table.setRowHeight(desiredRowHeight);
Yes you can. Just set the row heights. You would have to use something like here. Obviously I assume here that your panel has a 'constant' size. Otherwise the layout will make sure to resize it to appropriate size, i.e. table size.
If yes, then you can use the panel height for your calculations of the height each row should take.
EDIT1:
Below is an example showing how it might be used to do so using GridBagLayout. I did all to make it look as best as possible though still it has a strange behaviour (for a short time it gets minimal size) when you making the frame smaller. But then again it might be default behaviour for the layout which I am not aware of.
NOTE: I am not an expert in using this layout manager (personally I hate it). Thus if there are some parameters which should/shouldn't be set please do let me know (and feel free to edit the answer).
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.JTableHeader;
public class TableRowResizeTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final JTable table = new JTable(3,3);
final JTableHeader tHeader = table.getTableHeader();
final JPanel tPanel = new JPanel(new GridBagLayout());
tPanel.setBackground(Color.CYAN);
ComponentListener cL = new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
super.componentResized(e);
// re-size the header and row height to fill the whole tPanel
int panelHeight = tPanel.getHeight();
int numOfRows = table.getRowCount();
int desiredRowHeight = panelHeight / (numOfRows + 1);
int gap = panelHeight - desiredRowHeight * (numOfRows + 1);
tHeader.setPreferredSize(new Dimension(tHeader.getPreferredSize().width,
desiredRowHeight+gap));
tHeader.revalidate();
tHeader.repaint();
if(desiredRowHeight <1)
desiredRowHeight = 1;
table.setRowHeight(desiredRowHeight);
table.revalidate();
table.repaint();
System.out.println("tPanel componentResized p.h="+tPanel.getHeight()
+"; desiredRowHeight="+desiredRowHeight+"; gap="+gap);
}
};
tPanel.addComponentListener(cL);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL;
c.gridx = 0;
c.gridy = 0;
c.weighty = 1.0;
tPanel.add(tHeader, c);
c.gridy = 1;
c.weighty = 0.0;
tPanel.add(table,c);
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBackground(Color.RED);
contentPane.add(tPanel);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println("before f.setVisible p.h="+tPanel.getHeight());
f.setVisible(true);
System.out.println("after f.setVisible p.h="+tPanel.getHeight());
}
});
}
}
I'm working on building a chess game in Java, and I'm currently having a bit of trouble getting the GUI exactly the way I want it with Swing. I'm using a GridLayout to organize a grid of 8x8 ChessButtons (which override the JButton so that I can store extra information inside of them such as coordinates). Originally, the ChessButtons wouldn't appear unless I moused over them, but I solved that problem by placing each ChessButton inside a separate JPanel and setting each button's setPreferredSize() to a set height and width.
Now, my problem is that there seems to be a small margin or padding above (and/or below?) each button. I've made sure to set setHgap(0) and setVgap(0) for the GridLayout, so I'm pretty sure the mysterious margin is coming from either the buttons or the JPanels. But, I can't seem to get rid of them, and they seem to be causing each ChessButton to shift a little bit up/down whenever I mouse of them.
I realize this description of the problem might be a little hard to visualize, so I've taken a screenshot (using JButtons rather than ChessButtons so the gaps are slightly easier to recognize): http://img3.imageshack.us/img3/6656/jbuttonmargins.png
Here is the code I used to initialize each ChessButton:
chessBoard = new JPanel(new GridLayout(8, 8, 0, 0));
chessBoard.setBorder(BorderFactory.createEmptyBorder());
for (int i = 0; i <= 65; i++) {
//Create a new ChessButton
ChessButton button = new ChessButton("hi");
button.setBorder(BorderFactory.createEmptyBorder());
button.setPreferredSize(new Dimension(75, 75));
button.setMargin(new Insets(0, 0, 0, 0));
//Create a new JPanel that the ChessButton will go into
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(75, 75));
buttonPanel.setBorder(BorderFactory.createEmptyBorder());
buttonPanel.add(button);
//Add the buttonPanel to the grid
chessBoard.add(buttonPanel);
}
So, how can I get rid of these vertical spaces between buttons? I'm relatively new to Swing, so I'm sorry if the answer is extremely obvious, but I'd appreciate any help anyone might have to offer! Thanks in advance!
Don't add an empty border; do use setBorderPainted(false).
Addendum: As #camickr notes, the panel's layout may include default gaps. The example below uses no-gap GridLayout accordingly.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/questions/4331699 */
public class ButtonBorder extends JPanel {
private static final int N = 8;
private static final int SIZE = 75;
public ButtonBorder() {
super(new GridLayout(N, N));
this.setPreferredSize(new Dimension(N * SIZE, N * SIZE));
for (int i = 0; i < N * N; i++) {
this.add(new ChessButton(i));
}
}
private static class ChessButton extends JButton {
public ChessButton(int i) {
super(i / N + "," + i % N);
this.setOpaque(true);
this.setBorderPainted(false);
if ((i / N + i % N) % 2 == 1) {
this.setBackground(Color.gray);
}
}
}
private void display() {
JFrame f = new JFrame("ButtonBorder");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ButtonBorder().display();
}
});
}
}
Originally, the ChessButtons wouldn't appear unless I moused over them, but I solved that problem by placing each ChessButton inside a separate JPanel and setting each button's setPreferredSize() to a set height and width
That is not the proper solution. There is no reason to use a JPanel to hold the buttons. In fact, this is probably the cause of the problem. The buttons should show up when you add them to a GridLayout. If they don't show up its probably because you added the buttons to the GUI after making the GUI visible. Components should be added to the GUI BEFORE it is made visible.
Now, my problem is that there seems to be a small margin or padding above (and/or below?) each button
I don't understand why there also isn't a horizontal gap. When you create a JPanel, by default it uses a FlowLayout which also contains a horizontal/vertical gap of 5 pixels. So I understand why you might have the vertical gap of 10 pixels. I don't understand why there is no horizontal gap.
If you need more help post your SSCCE demonstrating the problem. And the SSCCE should use regular JButtons. Get the basics working with standard components before you start playing with custom components. That way you know if the problem is with your custom code or not.
Try adding chessBoard.setPreferredSize(600, 600) to create a JPanel for the board that only has room to fit the buttons (8 buttons each way * 75 size each way on the buttons).