JButtons only appear when mouse hover over them - java

I have a problem (could be more than one..) with my project.
JButton components only show up when I hover the mouse over them.
My project, basically, is taking data from MySQL and setting it on buttons.
For example:
'Aaa', 1000, 'alphabet' on jbutton[0]
'Bbb', 50, 'alphabet2' on jbutton[1]
and so on...
Buttons are on JPanel which is in a JScrollPane. (I did this on purpose as data can not be fit in one panel without scroll and when I click the the button, a new window relating to the info on the clicked button have to pop up)
And I added an ActionListener on another button set which are 'category' buttons(chicken, pizza) to put data on the buttons I mentioned above. When the category button is clicked, data according to the category is extracted and set on buttons one by one.
I searched many times to solve the problem, but I couldn't find the answer. Just assuming, it happened because I used setLayout(null) all over, or because buttons are added after the main frame is set visible.
It's good to solve the problem but I, more importantly, want to know the reason why.
Please help me to find the cause of this problem so that I don't make the same error next time and avoid bad practices!
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JbuttonNotShowUp extends JFrame implements ActionListener {
JButton chicken, pizza;
JButton[] jbtnArray;
JPanel jp, jpFullofButtons;
JScrollPane jsp;
public JbuttonNotShowUp() {
jp = new JPanel();
jp.setLayout(null);
jpFullofButtons = new JPanel();
jpFullofButtons.setLayout(null);
jsp = new JScrollPane(jpFullofButtons, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
chicken = new JButton("chicken");
pizza = new JButton("pizza");
jp.setBounds(0, 0, 440, 650);
chicken.setBounds(25, 80, 61, 35);
pizza.setBounds(90, 80, 61, 35);
jsp.setBounds(25, 140, 385, 450);
chicken.addActionListener(this);
pizza.addActionListener(this);
jp.add(jsp);
jp.add(chicken);
jp.add(pizza);
add(jp);
setBounds(0, 0, 450, 650);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
JbuttonNotShowUp f = new JbuttonNotShowUp();
}
#Override
public void actionPerformed(ActionEvent e) {
JButton jbutton = (JButton) e.getSource();
jpFullofButtons.removeAll();
DataDAO dao = new DataDAO();
ArrayList<DataVO> list = dao.dataExtract(jbutton.getText());
jbtnArray = new JButton[list.size()];
int y = 0;
for (int i = 0; i < list.size(); i++) {
jbtnArray[i] = new JButton(
list.get(i).getName() + "," + list.get(i).getPrice() + "," + list.get(i).getDescription());
jbtnArray[i].setSize(390, 50);
jbtnArray[i].setLocation(0, y);
jbtnArray[i].addActionListener(this);
jpFullofButtons.add(jbtnArray[i]);
y += 50;
}
}
}

Problems:
You're using a null layout-using JPanel to hold JButtons in a JScrollPane which will make the scroll pane fail in its ability to show scroll bars and scroll effectively
You add components into a container (the same JPanel above) without telling the GUI to repaint the container, and so the components, the added JButtons, don't display. This latter is fixed by calling jpFullofButtons.repaint(); after adding components to the JPanel -- but the JScrollPane still won't work right
Better to use a decent layout manager, here perhaps a GridLayout, and call revalidate() and repaint() on the container, the jpFullofButtons JPanel, after adding components to it.
Side note about your MRE attempt: it's almost there, but you still left in the DAO requirement as well as an undefined class, DataVO, preventing us from coping, pasting, and running your code.
My MRE example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.*;
#SuppressWarnings("serial")
public class JButtonsShowUp extends JPanel {
private JButton reAddButtonsBtn = new JButton("Re-Add Buttons");
private JPanel jpFullofButtons = new JPanel(new GridLayout(0, 1));
private JScrollPane jsp = new JScrollPane(jpFullofButtons);
public JButtonsShowUp() {
reAddButtonsBtn.addActionListener(e -> reAddButtons());
JPanel topPanel = new JPanel();
topPanel.add(reAddButtonsBtn);
jsp.setPreferredSize(new Dimension(385, 450));
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(jsp, BorderLayout.CENTER);
}
private void reAddButtons() {
jpFullofButtons.removeAll();
int max = 100;
for (int i = 0; i < max; i++) {
String randomText = "";
for (int j = 0; j < 5; j++) {
char c = (char) ('a' + (int) (26 * Math.random()));
randomText += c;
}
double randomPrice = 10 + 20 * Math.random();
final DataVO2 data = new DataVO2(randomText, randomPrice);
String text = String.format("Text: %s%02d, Price: $%1.2f", randomText, i, randomPrice);
JButton button = new JButton(text);
button.addActionListener(e -> buttonAction(data));
jpFullofButtons.add(button);
}
jpFullofButtons.revalidate();
jpFullofButtons.repaint();
}
private void buttonAction(DataVO2 data) {
System.out.println("Button pressed: " + data);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JButtonsShowUp mainPanel = new JButtonsShowUp();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class DataVO2 {
private NumberFormat priceFormat = NumberFormat.getCurrencyInstance(Locale.US);
private String name;
private double price;
public DataVO2(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
#Override
public String toString() {
String priceText = priceFormat.format(price);
return "DataVO2 [name=" + name + ", price=" + priceText + "]";
}
}

Related

How to stop components adapting to the size of a JPanel that is inside a JScrollPane

The components inside a JPanel (which has a BoxLayout) are getting resized when there's lack of space.
The JPanel is inside a JScrollPane, but because of the fact that the components get resized, the scroll bar is useless.
The JScrollPane is also content inside a JTabbedPane by the way.
Setting a minimum size and preferred size to every component doesn't fix the problem:
this.setPreferredSize(new Dimension(100,20));
this.setMinimumSize(new Dimension(100,20));
Any idea of how to deal with this?.
Screenshot of the problem:
This is how I wan't it to look like, with a fixed size:
I took what information was visible in your image and created an example Swing GUI that displays the same information.
I don't know how my code is different from your code. I placed a JLabel and two JTextAreas inside of a download JPanel. I created a main JPanel to hold the download JPanels.
Here's the complete runnable code I used. I made the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class MusicDownloadGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MusicDownloadGUI());
}
private final MusicDownloadModel model;
public MusicDownloadGUI() {
this.model = new MusicDownloadModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Music Download");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JScrollPane createMainPanel() {
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
panel.setBackground(Color.WHITE);
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
for (Track track : model.getDownloads()) {
panel.add(createDownloadPanel(track));
}
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
return scrollPane;
}
private JPanel createDownloadPanel(Track track) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
panel.setBackground(Color.WHITE);
JLabel label = new JLabel(new ImageIcon(track.getAlbumCover()));
panel.add(label);
JTextArea titleArea = new JTextArea(3, 30);
titleArea.setEditable(false);
titleArea.setText(createTitleArea(track));
panel.add(titleArea);
JTextArea artistArea = new JTextArea(3, 25);
artistArea.setEditable(false);
artistArea.setText(createArtistArea(track));
panel.add(artistArea);
return panel;
}
private String createTitleArea(Track track) {
StringBuilder builder = new StringBuilder();
builder.append(track.getTitle());
builder.append(System.lineSeparator());
builder.append("Download -- ");
builder.append(track.getPercentDownloaded());
builder.append("%");
// System.out.println(builder.toString());
return builder.toString();
}
private String createArtistArea(Track track) {
StringBuilder builder = new StringBuilder();
builder.append("Artist: ");
builder.append(track.getArtist());
builder.append(System.lineSeparator());
builder.append("Duration: ");
int minutes = track.getDuration() / 60;
int seconds = track.getDuration() % 60;
builder.append(minutes);
builder.append(" minutes, ");
builder.append(seconds);
builder.append(" seconds");
builder.append(System.lineSeparator());
builder.append("Quality: ");
builder.append(track.getQuality());
return builder.toString();
}
public class MusicDownloadModel {
private final List<Track> downloads;
public MusicDownloadModel() {
this.downloads = new ArrayList<>();
Track track = new Track("Bandaga", "Otra Copa", "0.6 kbytes", 216);
track.setPercentDownloaded(42);
addDownload(track);
addDownload(new Track("Bandaga", "Ahora Dice Que Me Ama", "0.6 kbytes", 198));
addDownload(new Track("Camin", "Tu Nombre (feat. JC Reyes, El Daddy) - Remix",
"0.6 kbytes", 246));
addDownload(new Track("Bandaga", "Como Tu", "0.6 kbytes", 205));
addDownload(new Track("Pablo Alboran", "Liueve Sobre Mo Jado", "0.6 kbytes", 228));
}
public void addDownload(Track track) {
this.downloads.add(track);
}
public List<Track> getDownloads() {
return downloads;
}
}
public class Track {
private int percentDownloaded;
private final int duration;
private final String artist, quality, title;
private final BufferedImage albumCover;
public Track(String artist, String title, String quality, int duration) {
this.artist = artist;
this.title = title;
this.quality = quality;
this.duration = duration;
this.percentDownloaded = 0;
this.albumCover = new BufferedImage(40, 20, BufferedImage.TYPE_INT_RGB);
Graphics g = albumCover.getGraphics();
g.setColor(Color.BLUE);
g.fillRect(0, 0, albumCover.getWidth(), albumCover.getHeight());
g.dispose();
}
public int getPercentDownloaded() {
return percentDownloaded;
}
public void setPercentDownloaded(int percentDownloaded) {
this.percentDownloaded = percentDownloaded;
}
public int getDuration() {
return duration;
}
public String getArtist() {
return artist;
}
public String getQuality() {
return quality;
}
public String getTitle() {
return title;
}
public BufferedImage getAlbumCover() {
return albumCover;
}
}
}
A BoxLayout respects the minimum and maximum sizes of components added to it.
By default a JPanel doesn't have a maximum size so it grows to fill the space available.
So one solution is to override the getMaximumSize() method of the panel to be equal to the preferred size.
a) Run the code as is below to see the default behavour. Click the "Add Row" button to see how the layout changes as rows are added.
b) Then repeat after changing the getMaximumSize() method to use the preferred size.
import java.awt.*;
import javax.swing.*;
public class BoxLayoutRow extends JPanel
{
private int rowIndex;
private JPanel rowPanel;
public BoxLayoutRow()
{
setLayout( new BorderLayout() );
rowPanel = new JPanel();
rowPanel.setLayout( new BoxLayout(rowPanel, BoxLayout.Y_AXIS) );
add(new JScrollPane(rowPanel), BorderLayout.CENTER);
JButton addRow = new JButton("Add Row");
add(addRow, BorderLayout.PAGE_END);
addRow.addActionListener((e) -> this.addRow());
}
private void addRow()
{
rowIndex++;
JPanel row = new JPanel()
{
#Override
public Dimension getMaximumSize()
{
return super.getMaximumSize();
//return getPreferredSize();
}
};
row.setAlignmentX(0.0f);
row.add( new JLabel("Row: " + rowIndex) );
row.setBorder(BorderFactory.createLineBorder(Color.RED));
rowPanel.add( row );
revalidate();
repaint();
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("BoxLayoutRow");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new BoxLayoutRow() );
frame.setSize(400, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(() -> createAndShowUI());
}
}

amount of generated JLabels seems random on each start

I am trying generate a JLabel grid in Java, but on every start the generated JLabels vary, on one start of the program there can be 25 visual JLabels, and without changing the code and restarting there can be 27 visual JLabels, im so confused, I have no idea what might be causing this. In theory there should be 169 JLabels visual on the screen (13 x 13 grid).
public class GUI {
JFrame frame;
JPanel panel;
int matrixLength = 13;
JLabel label[] = new JLabel[matrixLength * matrixLength];
public GUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
frame.setResizable(false);
panel = (JPanel) frame.getContentPane();
panel.setLayout(null);
for (JLabel labels : label) {
labels = new JLabel();
labels.setVisible(true);
}
}
public void drawLabels() {
int xInc = 50;
int yInc = 50;
int xStart = 50;
int yStart = 0;
int y = yStart;
int x = 50;
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel(" ");
label[i].setOpaque(true);
label[i].setVisible(true);
label[i].setBackground(Color.black);
if (i % (matrixLength) == 0) {
y += yInc;
x = xStart;
} else {
x += xInc;
}
System.out.println("i: " + i + " | y: " + y + " | x: " + x);
label[i].setBounds(x, y, 40, 40);
panel.add(label[i]);
}
}
}
I created the following GUI from your code.
Here are the changes I made.
I added a main method so I could start the application. In the main method, I called the SwingUtilities invokeLater method to ensure that the Swing components are created and executed on the Event Dispatch Thread.
I used two Swing layout managers to create the GUI. The JFrame has a default BorderLayout. The JPanel I created to hold the JLabels uses a GridLayout.
I added a text value to each of the JLabels so you could see them in the grid.
Here's the complete runnable code I used to create the GUI.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LabelGridGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LabelGridGUI();
}
});
}
JFrame frame;
int matrixLength = 13;
JLabel label[] = new JLabel[matrixLength * matrixLength];
public LabelGridGUI() {
frame = new JFrame("Label Grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createLabelPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setResizable(false);
frame.setVisible(true);
}
public JPanel createLabelPanel() {
JPanel panel = new JPanel(new GridLayout(0, matrixLength));
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel("X");
label[i].setBackground(Color.black);
label[i].setForeground(Color.yellow);
label[i].setOpaque(true);
panel.add(label[i]);
}
return panel;
}
}

JPanel not scrolling in JScrollPane

I have a JPanel that I create like so
JPanel statsKeysPanel = new JPanel(new MigLayout("insets 0", "[]", ""));
and populate with a dynamic number of JLabels stacked on top of each other. For the sake of an example:
for(int i = 0; i < 30; i++) {
statsKeysPanel.add(new JLabel("" + i + " key value"), "wrap");
}
I then create and add the scroller like so
JPanel panel = new JPanel(new MigLayout("insets 0", "[center][][center][]", "[][]"));
final JScrollPane keysScroller = new JScrollPane(this.statsKeysPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
keysScroller.setMaximumSize(new Dimension(100, 300));
panel.add(keysScroller, "cell 0 1");
The max of 300 is applied but the 15 out of 30 JLabels that don't fit in 300px are hidden, and scrolling doesn't work. What am I doing wrong? (image below)
final JScrollPane keysScroller = new JScrollPane(this.statsKeysPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
Why are you using NEVER for both the horizontal and vertical scrollbar? I would think this would prevent a scrollbar from appearing.
I generally don't set either property and just let the scrollpane determine when to display the scrollbar. Sometimes I use ALWAYS to reserve space for the scrollbar.
You are using unnecessarily two panels; one will suffice. I think that
you have omitted the code that caused your error.
Here is a working example:
package com.zetcode;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import net.miginfocom.swing.MigLayout;
public class StatsKeyEx extends JFrame {
public StatsKeyEx() {
initUI();
}
private void initUI() {
JPanel pnl = new JPanel(new MigLayout());
for (int i = 0; i < 60; i++) {
pnl.add(new JLabel("" + i + " key value"), "wrap");
}
JScrollPane spane = new JScrollPane(pnl);
spane.setPreferredSize(new Dimension(150, 200));
add(spane);
pack();
setTitle("Scrolling");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
StatsKeyEx ex = new StatsKeyEx();
ex.setVisible(true);
}
});
}
}
The scrollbars are shown as needed.

drawImage() on JPanel OR add Image on top of GridLayout

I have a 100 by 100 grid of labels. I've got a method which creates and populates an array of Strings. The next method creates an array of labels and then adds the String (created from previous method) to the labels using the setText() method. Some of the labels contain images too. Method after that takes those JLabels and adds them to a JPanel of Grid Layout(lets call this x1). Then I've added the JPanel to a JScrollPane(x2), the JScrollPane gets added to another JPanel(x3) with an empty border and this final JPanel(x3) gets added to the JFrame. So that's how I've created the grid and I'm happy with that, I don't want to change it.
I would like to add an image to x1 - the JPanel with Grid Layout.
For this I would have to add the paintComponent method and use the drawImage() method. My question is how will Eclipse know which panel to add the image to? I's prefer not to create a separate class for x1, I did that before and it just didn't work out right and I rather not go down that incredibly frustrating road again, I'm sorry!
I have considered using a Glass Pane however I would no longer be able to see the images of the JLabels - which is really important.
I think adding the image to the background of the JPanel will be best because I also want to have a button which shows/hides the grid lines - the borders of the JLabels.
I hope I'm making sense.
Below is the code. I understand it's a lot of code in one class. I did have it in two separate classes but it just didn't work me. I find this much easier. I hope you don't mind
package roverMars;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
public class MenuPanel extends JPanel {
private static final long serialVersionUID = -3928152660110599311L;
public JPanel frame, textfield, buttons, cpPanel;
public JTextField Commands;
public JButton Plot, Submit, Undo;
public JLabel Position, cpLabel;
public Border loweredetched;
public JCheckBox gridLines;
public SubmitButton sub;
static final int rows = 100, columns = 100;
// ******IMAGES******
static BufferedImage North, South, West, East;
public void ImageLoader() {
try {
North = ImageIO.read(this.getClass().getResource("North.png"));
South = ImageIO.read(this.getClass().getResource("South.png"));
West = ImageIO.read(this.getClass().getResource("West.png"));
East = ImageIO.read(this.getClass().getResource("East.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Error occured: " + e);
e.printStackTrace();
}
}
// ******IMAGES******
public void createMenu(JPanel p) {
// Text Field Panel
Commands = new JTextField(20);
textfield = new JPanel();
textfield.setPreferredSize(new Dimension(150, 50));
textfield.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
textfield.setBackground(new Color(204, 153, 255));
textfield.add(Commands);
// Have a button next to the Text Field to clear contents.
// Might need to give the JPanel a new Flow Layout.
// Buttons Panel
buttons = new JPanel();
buttons.setPreferredSize(new Dimension(150, 250));
buttons.setLayout(new BoxLayout(buttons, BoxLayout.Y_AXIS));
buttons.setBackground(new Color(170, 051, 170));
// Create and Add buttons to the Buttons Panel
buttons.add(Box.createRigidArea(new Dimension(30, 10)));
Plot = new JButton("Plot");
Plot.setAlignmentX(Component.CENTER_ALIGNMENT);
Plot.setAlignmentY(Component.CENTER_ALIGNMENT);
buttons.add(Plot);
buttons.add(Box.createRigidArea(new Dimension(30, 10)));
Submit = new JButton("Submit");
Submit.setAlignmentX(Component.CENTER_ALIGNMENT);
Submit.setAlignmentY(Component.CENTER_ALIGNMENT);
Submit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sub = new SubmitButton();
sub.Submit(Commands);
cpLabel.setText("*****SET CURRENT POSITION*****");
labels[2][2].setIcon(new ImageIcon(North));
// I will be able to move the rover from here using for loops
// and if statements.
}
});
buttons.add(Submit);
buttons.add(Box.createRigidArea(new Dimension(30, 10)));
Undo = new JButton("Undo");
Undo.setAlignmentX(Component.CENTER_ALIGNMENT);
Undo.setAlignmentY(Component.CENTER_ALIGNMENT);
buttons.add(Undo);
buttons.add(Box.createRigidArea(new Dimension(30, 10)));
gridLines = new JCheckBox();
gridLines.setText("Show gridlines");
gridLines.setAlignmentX(Component.CENTER_ALIGNMENT);
gridLines.setAlignmentY(Component.CENTER_ALIGNMENT);
gridLines.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// Set the colour of the JLabels array from here.
System.out.println("clicked");
}
});
buttons.add(gridLines);
buttons.add(Box.createRigidArea(new Dimension(30, 20)));
loweredetched = BorderFactory
.createEtchedBorder(EtchedBorder.RAISED);
cpLabel = new JLabel("Current position: ", JLabel.CENTER);
cpPanel = new JPanel();
cpPanel.setBackground(new Color(153, 153, 204));
cpPanel.add(cpLabel);
cpPanel.setBorder(loweredetched);
// Panel for the main window
JPanel frame = new JPanel();
frame.setPreferredSize(new Dimension(150, 350));
frame.setLayout(new BorderLayout());
frame.add(textfield, BorderLayout.NORTH);
frame.add(buttons, BorderLayout.CENTER);
// This Main Panel
p.setPreferredSize(new Dimension(350, 700));
p.setBackground(new Color(153, 153, 204));
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setBorder(BorderFactory.createEmptyBorder(10, 50, 10, 25));
p.add(Box.createRigidArea(new Dimension(100, 100)));
p.add(frame);
p.add(Box.createRigidArea(new Dimension(15, 15)));
p.add(cpPanel);
p.add(Box.createRigidArea(new Dimension(100, 300)));
}
// From line 142 to 202 is everything to do with creating the Grid
public void StringArray(String[][] labelText) {
int x = 1; // increment rows
for (int i = 0; i < labelText.length; i++) { // x
for (int j = 0; j < labelText.length; j++) { // y
labelText[i][j] = Integer.toString(x); // populate string
x++;
}
}
}
public void JLabelArray(JLabel[][] label, String[][] labelText) {
for (int i = 0; i < label.length; i++) { // x
for (int j = 0; j < label.length; j++) { // y
label[i][j] = new JLabel();
label[i][j].setText(labelText[i][j]);
label[i][j].setOpaque(false);
label[i][j].setBorder(BorderFactory.createLineBorder(new Color(
0, 155, 200), 1));
// label[i][j].setBackground(Color.WHITE);
}
}
}
public void populateGrid(JPanel Grid, JLabel[][] label) { // Add Labels to
// Panel,
String x1[][] = new String[rows][columns];
StringArray(x1);
JLabelArray(label, x1);
Grid.setBackground(Color.RED);
int gHeight = label.length, gWidth = label.length;
Grid.setLayout(new GridLayout(gWidth, gHeight));
for (int i = 0; i < label.length; i++) { // x
for (int j = 0; j < label.length; j++) { // y
Grid.add(label[i][j]);
}
}
}
public void createGrid(JPanel finalPanel, JPanel Grid) {
// Add Grid to Scroll Pane
JScrollPane x4 = new JScrollPane(Grid);
x4.setPreferredSize(new Dimension(600, 600)); // DO NOT DELETE THIS.
x4.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
x4.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
// Add Scroll Pane to another Panel with the Border
finalPanel.setBackground(new Color(153, 153, 204));
finalPanel.setBorder(BorderFactory.createEmptyBorder(50, 25, 50, 50));
finalPanel.add(x4);
}
// Variables for creaeteGUI method.
static MenuPanel t = new MenuPanel();
static JPanel menu = new JPanel();
static JPanel finalPanel = new JPanel();
static JPanel gridPanel = new JPanel();
static JLabel labels[][] = new JLabel[rows][columns];
public static void createGUI() {
t.createMenu(menu);
t.populateGrid(gridPanel, labels);
t.createGrid(finalPanel, gridPanel);
JFrame f = new JFrame();
f.setTitle("Project Testing");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setLocation(100, 100);
f.setAlwaysOnTop(true);
f.setSize(500, 500);
f.add(finalPanel, BorderLayout.CENTER);
f.add(menu, BorderLayout.WEST);
f.pack();
}
public static void main(String args[]) {
createGUI();
t.ImageLoader();
labels[2][2].setIcon(new ImageIcon(West));
}
}
Thank you so much! I really appreciate any help or suggestions :D
As you said what you need to do is to override the paintComponent method of the JPanel and put a drawImage(...) in there. So:
#Override
public void paintComponent(Graphics g)
{
//super.paintComponent(g);
  g.drawImage(image, 0, 0, null);
}
Where image is an instance of the class Image that you loaded previously in the initialization code (don't load it in the paintComponent, that would be too slow and you only want to load it once).
There are 2 ways to accomplish that:
Make your own class extending JPanel and put that code there. You probably will want to create also a method setBackgroundImage(Image) that you can call from you main class to pass the image that you loaded from the disk.
Make an anonymous class, that is doing something similar but without explicitely defining a new class. To do so instead of creating the panel like this:
JPanel gridPanel = new JPanel();
do it like this:
JPanel gridPanel = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
//super.paintComponent(g);
  g.drawImage(image, 0, 0, null);
}
};
Of course you must do this in the actual code (not as an static initialization) since you want to make sure that you load the image before.
Finally a couple of suggestions:
Variable names start in lower case by convention (as opposite to class names that start in upper case). You don't do this for example in the JPanel Grid argument and Comands field.
You are violating Swing's single threading rule. That is, you must call invokeLater in your main wrapping your GUI initializing code. For example look at Swing's Hello World. You can find a detailed explanation of this here.

JButtons won't update on button click

Currently displays a GUI with an 8x8 grid of randomized colored buttons. The newButton is to reset the score display to 0 and reset the grid with a fresh like it does on startup after being clicked. I haven't been able to find many solutions other than that it's to do with the way Java displays it's buttons and the way layering works. Here are the 2 classes I'm using.
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtonsApp extends JFrame implements ActionListener {
private static byte ROWS = 8;
public int useThis;
ShinyButtons shiny = new ShinyButtons();
public static ImageIcon[] icons = {new ImageIcon("RedButton.png"),
new ImageIcon("OrangeButton.png"),
new ImageIcon("YellowButton.png"),
new ImageIcon("GreenButton.png"),
new ImageIcon("BlueButton.png"),
new ImageIcon("LightGrayButton.png"),
new ImageIcon("DarkGrayButton.png")};
public ShinyButtonsApp(String title) {
super(title); // Set title of window
setDefaultCloseOperation(EXIT_ON_CLOSE); // allow window to close
setSize(578, 634); // Set size of window
setResizable(false);
getContentPane().setLayout(null);
JLabel aLabel = new JLabel("Score: ");
aLabel.setLocation(10, 570);
aLabel.setSize(80,30);
getContentPane().add(aLabel);
JTextField scoreField = new JTextField();
scoreField.setText(Integer.toString(shiny.score));
scoreField.setEditable(false);
scoreField.setHorizontalAlignment(JTextField.RIGHT);
scoreField.setLocation(60, 570);
scoreField.setSize(120,30);
scoreField.setBackground(Color.WHITE);
getContentPane().add(scoreField);
JButton newButton = new JButton("New Game");
newButton.addActionListener(this);
newButton.setLocation(348,570);
newButton.setSize(110,30);
getContentPane().add(newButton);
JButton quitButton = new JButton("Quit");
quitButton.setLocation(468,570);
quitButton.setSize(80,30);
getContentPane().add(quitButton);
resetButtons2();
}
public void actionPerformed(ActionEvent e) {
shiny.score = 0;
shiny.resetButtons();
resetButtons2();
}
public void resetButtons2() {
for (int r=0; r<ROWS; r++) {
for (int c=0; c<ROWS; c++) {
ImageIcon image1 = icons[(int)shiny.getButton(r,c)];
JButton button = new JButton(image1);
button.setLocation(10+(69*r),10+(69*c));
button.setSize(69,69);
button.setBorder(BorderFactory.createLineBorder(Color.GRAY,1));
getContentPane().add(button);
}
}
}
public static void main(String[] args) {
ShinyButtonsApp frame;
frame = new ShinyButtonsApp("Shiny Buttons"); // Create window
frame.setVisible(true); // Show window
}
}
and
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtons extends JPanel{
public static byte RED = 0;
public static byte ORANGE = 1;
public static byte YELLOW = 2;
public static byte GREEN = 3;
public static byte BLUE = 4;
public static byte LIGHT_GRAY = 5;
public static byte DARK_GRAY = 6;
public static byte ROWS = 8;
public byte[][] buttonTable;
public int score = 0;
public ShinyButtons() {
buttonTable = new byte[ROWS][ROWS];
resetButtons();
}
public void resetButtons() {
for (int r=0; r<ROWS; r++)
for (int c=0; c<ROWS; c++)
buttonTable[r][c] = (byte)(Math.random()*7);
}
public byte getButton(int r, int c) { return buttonTable[r][c]; }
public int getScore() { return score; }
}
Building on to what this answer points out (using layout managers instead of setting size, as you should be doing) you could reset the the images just by looping through the components (JLabels) of the JPanel and changing their icons.
This particular example uses JLabels with MouseListeners but it could easily be switched to JButtons with ActionListeners
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons); <--- call reset method from below
score = 0;
scoreField.setText(String.valueOf(score));
}
});
....
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
Here's the complete running code. You just need to replace the image paths.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class CircleImages {
private int score = 0;
private JTextField scoreField = new JTextField(10);
public CircleImages() {
scoreField.setEditable(false);
final ImageIcon[] icons = createImageIcons();
final JPanel iconPanel = createPanel(icons, 8);
JPanel bottomLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
bottomLeftPanel.add(new JLabel("Score: "));
bottomLeftPanel.add(scoreField);
JPanel bottomRightPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
JButton newGame = new JButton("New Game");
bottomRightPanel.add(newGame);
JButton quit = new JButton("Quit");
bottomRightPanel.add(quit);
JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
bottomPanel.add(bottomLeftPanel);
bottomPanel.add(bottomRightPanel);
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons);
score = 0;
scoreField.setText(String.valueOf(score));
}
});
JFrame frame = new JFrame();
frame.add(iconPanel);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
private JPanel createPanel(ImageIcon[] icons, int gridSize) {
Random random = new Random();
JPanel panel = new JPanel(new GridLayout(gridSize, gridSize));
for (int i = 0; i < gridSize * gridSize; i++) {
int index = random.nextInt(icons.length);
JLabel label = new JLabel(icons[index]);
label.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
score += 1;
scoreField.setText(String.valueOf(score));
}
});
label.setBorder(new LineBorder(Color.GRAY, 2));
panel.add(label);
}
return panel;
}
private ImageIcon[] createImageIcons() {
String[] files = {"blackcircle.png",
"bluecircle.png",
"greencircle.png",
"greycircle.png",
"orangecircle.png",
"redcircle.png",
"yellowcircle.png"
};
ImageIcon[] icons = new ImageIcon[files.length];
for (int i = 0; i < files.length; i++) {
icons[i] = new ImageIcon(getClass().getResource("/circles/" + files[i]));
}
return icons;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CircleImages();
}
});
}
}
You are creating a new set of buttons in resetButtons2() and placing them on top (or rather under) of the already existing set of buttons in the same locations. You should create the set of buttons once and only update their icons upon reset.
You should do a number of things:
Use a proper layout manager, e.g., GridLayout
Create the 8x8 grid of buttons only once and replace their icons when needed
Call invalidate/repaint to refresh the content pane
And for a JFrame you don't need getContentPane().add(...), you can directly do add(...)
Two things.
First, make sure you remove the existing buttons first. Alternatively, you could simply update the state of the buttons. This would require you to create an array or List of buttons first, which your reset method would then iterate over and update their properties as required.
Second, make use of an appropriate layout manager. A null layout ias a very bad idea. You do not control the font metrics of the underlying platform and this will change how your buttons look on different systems, making your UI less dynamic then it should be

Categories