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());
}
});
}
}
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 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.
I've been practicing Java GUI development and on one of my projects I'm using a GridBagLayout with various controls such as JLabel, JComboBoxe, and a JTable encased in a JScrollPane.
However, I've noticed the JScrollPane seems to affect my JPanel where unless my height is a certain amount (522 px or greater according to .Pack()) my JComboBoxe seem to "compact" and the width will be set to fit the text instead of the size I specified (200 px).
So my question is what is causing this and how would I fix it so the JFrame's height can be smaller without causing my JComboBoxes to behave like that.
Screenshot of what my app looks like before/after resize:
Current code for my application:
package gui;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.SwingConstants;
public class MainWindow {
public static void main(String[] args) {
MainWindow main = new MainWindow();
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JComboBox<String> cmbTeam, cmbPosition;
JLabel lblTeam, lblPosition, lblResults;
JTable table;
JSeparator sep1,sep2;
int rowCount;
GridBagConstraints gbc = new GridBagConstraints();
panel.setLayout(new GridBagLayout());
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = 1;
gbc.gridx = 0;
gbc.gridy = 0;
lblTeam = new JLabel("First Label");
panel.add(lblTeam, gbc);
gbc.gridx = 1;
lblPosition = new JLabel("Second Label");
panel.add(lblPosition, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
cmbTeam = new JComboBox<>(new String[]{"Data1","Data2","Data3"});
cmbTeam.setPreferredSize(new Dimension(200,25));
panel.add(cmbTeam, gbc);
gbc.gridx = 1;
cmbPosition = new JComboBox<>(new String[]{"Data1","Data2","Data3"});
cmbPosition.setPreferredSize(new Dimension(200,25));
panel.add(cmbPosition, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 2;
sep1 = new JSeparator(SwingConstants.HORIZONTAL);
panel.add(sep1,gbc);
gbc.gridy = 3;
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1;
table = new JTable(new String[][]{{"AA","AB","AC"},{"BA","BB","BC"},{"CA","CB","CC"}}, new String[]{"Col1","Col2","Col3"});
table.setFillsViewportHeight(true);
panel.add(new JScrollPane(table),gbc);
gbc.gridy = 4;
gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
sep2 = new JSeparator(SwingConstants.HORIZONTAL);
panel.add(sep2,gbc);
rowCount = table.getRowCount();
lblResults = new JLabel(rowCount + " results found.");
gbc.gridy = 5;
panel.add(lblResults, gbc);
frame.setTitle("GridBagLayout Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(panel);
frame.pack();
}
}
EDIT: I fixed the height issue by setting a minimum dimension for each JComboBox, but that white space that's generated from .pack() is still not fixed. I also noticed if I resize the window vertically and make it smaller the table's width seems to decrease by a single pizel. Maybe that has something to do with it?
what is causing this and
In general, when there is not enough space to display a component at its preferred size in a GridbagLayout the component will snap to its minimum size. I'm not sure why changing the height is causing the preferred width to change but somehow this is resulting in the combo boxes being displayed at their minimum width.
how would I fix it so the JFrame's height can be smaller without causing my JComboBoxes to behave like that.
Take advantage of the default BorderLayout of the frame. Add your components separately to the frame:
//frame.add(panel);
frame.add(panel, BorderLayout.NORTH);
frame.add(new JScrollPane(table));
frame.add(lblResults, BorderLayout.SOUTH);
Of course you will need to tidy up the rest of the code since you no longer add the scrollpane and label to the panel.
You will still see the combo boxes shrink when the width is decreased.
Edit:
but that whitespace that's generated from .pack() is still not fixed.
JTable has a hardcoded preferred size for the "viewport". You can override this by doing something like:
table.setPreferredScrollableViewportSize(table.getPreferredSize());
That is probably because Scollpane tries to fill entire space. The setPrefferedSize sets, as you may notice from its name, not strict size. Methods setMaximumSize and setMinimumSize set strict limitations (in fact not, but almost :) ). Since that, add these 2 rows of code:
cmbTeam.setMinimumSize(new Dimension(200,25));
cmbPosition.setMinimumSize(new Dimension(200,25));
As camickr said, a GridBagLayout will revert all components to their minimum sizes whenever there isn't enough room for every component's preferred size.
An easy solution is to make the minimum size the same as the preferred size:
// Make sure these lines come AFTER you've set the preferred sizes.
cmbTeam.setMinimumSize(cmbTeam.getPreferredSize());
cmbPosition.setMinimumSize(cmbPosition.getPreferredSize());
I've been trying to get a scrollable JTextArea to appear to the right of a JList where the JTextArea takes up most of the space but leaves a good portion for the JList (3/4 of the frame for the JTextArea, 1/4 for the JList). The problem is that the weights of the constraints seem to be ignored when LineWrap on the JTextArea is set to true.
Without line wrap, the JTextArea takes up about 3/4 of the frame and the JList takes up the other 1/4, which is what I want. But when line wrapping is turned on, the JTextArea attempts to take up as much space as possible and crushes the JList down to the width of the strings it contains. The interesting thing is that this only appears to happen once you resize the window (looks fine initially), and if you type anything into the JTextArea, it slowly expands, pushing the JList back. This has been confusing me to say the least.
I made a screenshot of what it looks like without line wrapping and with line wrapping after resizing the window:
Here's some example code showing you what I mean. Remove the line wrap statements and it'll look fine, but keep them there and you'll see that upon resizing, the JList is squished.
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.*
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel(new GridBagLayout());
JTextArea area = new JTextArea();
DefaultListModel<String> model = new DefaultListModel<>();
JList<String> list = new JList<String>(model);
JScrollPane scroll = new JScrollPane(area,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (int i = 0; i < 5; i++)
model.addElement("Example" + i);
area.setLineWrap(true);
area.setWrapStyleWord(true);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 0.3;
panel.add(scroll, c);
c = new GridBagConstraints();
c.gridx = 1;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 0.1;
panel.add(list, c);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 300);
frame.setVisible(true);
}
}
You can use ipadx to define minimal possible width
c.weightx = 0.1;
c.ipadx=desiredPixelsWidthForTheList;
panel.add(list, c);
UPDATE
Also you can place both in a JSplitPane and define desired proportions.
The short answer is that the text area gets more width than you want because its preferred width is much larger than that of the list.
Keep in mind that weightx doesn't determine what percentage of space a component will occupy but the proportional amount of space that's added to or taken away from the component's size. In this case, for example, the "extra" space is the difference between the frame's width (or more accurately, its content pane's width) which you explicitly set to 500 and the combined widths of the text area and the list. In other words, both the scroll pane / text area and the list will be displayed at their preferred sizes PLUS 75% of the left-over space for the text area and 25% for the list. Again, since the text area's preferred size is large to begin with, it occupies a bigger portion of the screen than what you want.
As a couple of people have already pointed out, a simple way to get the results you want is to explicitly specify the number of rows and columns for the text area. On the other hand, you should avoid explicitly setting a size, preferred or otherwise as discussed in questions like this.
As far as the mysteriously shrinking list goes, I suspect that's a bug in GridBagLayout. It seems to ignore the maximum size of the JList initially but then respects it when it lays out the components as a result of the frame resizing, which is why it suddenly shrinks and then never gets larger again. That's not normally an issue because like JTextArea, a JList is normally contained within a scroll pane, which is something you should probably also consider doing.
try using .setPreferredSize() to components
I have modified your code. Just specified the size of textarea and list like this
list.setPreferredSize(new Dimension(frame.getWidth()/4, frame.getHeight()));
area.setPreferredSize(new Dimension(frame.getWidth()*(3/4), frame.getHeight()));
check the full code below:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel(new GridBagLayout());
JTextArea area = new JTextArea();
DefaultListModel model = new DefaultListModel();
JList list = new JList(model);
JScrollPane scroll = new JScrollPane(area,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (int i = 0; i < 5; i++)
model.addElement("Example" + i);
frame.setSize(500, 300);
list.setPreferredSize(new Dimension(frame.getWidth()/4, frame.getHeight()));
area.setPreferredSize(new Dimension(frame.getWidth()*(3/4), frame.getHeight()));
area.setLineWrap(true);
area.setWrapStyleWord(true);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 0.3;
panel.add(scroll, c);
c = new GridBagConstraints();
c.gridx = 1;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 0.1;
panel.add(list, c);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
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).