Adding Grid of Buttons to JPanel - java

I'm trying to make a grid of 20px x 20px buttons that I define as "cells", blank by default, no special decorations such as shading, and change color when clicked. (They are meant to show "1" just for testing purposes). I make a Cell class to define these buttons, give each an ActionListener.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Cell implements ActionListener
{
private JButton button;
private EditorPanel editorPanel;
public Cell(EditorPanel editorPanel){
button = new JButton("1'");
button.addActionListener(listener -> colorCell());
button.setPreferredSize(new Dimension(20,20));
button.setMargin(new Insets(0,0,0,0));
button.setOpaque(true);
button.setContentAreaFilled(false);
this.editorPanel = editorPanel;
}
public JButton getButton() {
return button;
}
public void colorCell()
{
button.setBackground(Color.BLACK);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
and then use an array of Cell objects (cells) in my EditorPanel class to create a grid of these buttons with dimensions defined by "col" and "row".
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class EditorPanel{
public JFrame jframe;
public JPanel jpanel;
public static EditorPanel editorPanel;
public Render render;
public static final int col = 45, row = 45, tile_size=20;
public static final int panelWidth=900, panelHeight=900;
public Dimension dim;
public int coloredPixels;
public Cell[][] cells;
public void getFrame() {
editorPanel = new EditorPanel();
dim = Toolkit.getDefaultToolkit().getScreenSize();
jframe = new JFrame("Pixel Art Creator");
jframe.setVisible(true);
jframe.setSize(panelWidth+17, panelHeight+40);
jframe.setLocation(dim.width/2 - jframe.getWidth()/2, dim.height/2 - jframe.getHeight()/2);
jframe.add(render = new Render());
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel addCells()
{
cells=new Cell[row][col];
JPanel panel = new JPanel(new GridLayout(row, col));
for(int i = 0; i< row; i++){
for(int j = 0; j<col; j++){
cells[i][j] = new Cell(this);
panel.add(cells[i][j].getButton());
}
}
return panel;
}
public static void main (String[] args)
{
editorPanel = new EditorPanel();
editorPanel.getFrame();
editorPanel.addCells();
}
}
I then try to add each created Cell object that I attempted to put into the cells array in the addCells() method and add it to my JPanel. When I run this code I don't get any buttons, meaning that these buttons aren't being added to JPanel. How should I go about this?

So, two "significant" issues:
editorPanel.addCells(); never adds the JPanel that it creates to anything, so it will never be displayed
Calling JFrame#setVisible BEFORE you've finished establishing the UI can cause the UI elements not to show up on the UI. You can fix this by calling revalidate and repaint on the container which is changed, but if possible, simply get the UI established first, then make it visible
I would, however, suggest a slight change in approach. Rather then making Cell a class which contains a JButton, and then exposing that button to other aspects of your UI, I would make Cell a component and simply add it to the what ever container you want, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int y = 0; y < 20; y++) {
gbc.gridy = y;
for (int x = 0; x < 20; x++) {
gbc.gridx = x;
add(new Cell(), gbc);
}
}
}
}
public class Cell extends JPanel {
public Cell() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
colorCell();
}
});
setBorder(new LineBorder(Color.GRAY));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
protected void colorCell() {
if (getBackground() != Color.DARK_GRAY) {
setBackground(Color.DARK_GRAY);
} else {
setBackground(null);
}
}
}
}
Now, I've just used a plain old JPanel in the this case, but you could just as easily extend from a JButton or JToggledButton ... but I might be tempted to use a factory pattern instead, but that's me.
The purpose of using a GridBagLayout is to allow the frame and outer containers to be resized without changing the size of the Cells themselves, unlike GridLayout, which will try and make the cells fill the available space

Related

JFrame doesn't appear unless method invoked in main

I have a class which create a JFrame with an image but everytime I create the class and run the method to instantiate it, it doesn't appear. However, I have noticed that if I was to create the exact same class and run the same method in the main then the frame appears.
This is most of the code from the class with the JFrame that I am trying to create:
JFrame myFrame= new JFrame();
public void CreateFrame()
{
JLabel background=new JLabel(new ImageIcon("image.jpg"));
myFrame.add(background);
background.setLayout(new FlowLayout());
myFrame.setLayout(new GridLayout(1,1));
myFrame.setSize(360,250);
myFrame.setUndecorated(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.pack();
myFrame.setVisible(true);
}
If I run the code
MyClass mc = new MyClass();
mc.CreateFrame();
in a method in another class it doesn't come up. However, if I run the exact same code in a main method, it works.
For example, this doesn't work:
Example 1
public class otherClass extends JFrame
{
public void MethodA()
{
MyClass mc = new MyClass();
mc.CreateFrame();
}
public static void main(String[] args)
{
otherClass oc = new otherClass();
oc.MethodA();
}
}
but this does work
Example 2
public class otherClass extends JFrame
{
public void MethodA()
{
//CODE
}
public static void main(String[] args)
{
otherClass oc = new otherClass();
oc.MethodA();
MyClass mc = new MyClass();
mc.CreateFrame();
}
}
Can anyone see where I'm going wrong? Sorry if a stupid mistake, I'm still getting to grips with Java.
Thanks
EDIT
import javax.swing.ImageIcon;
import javax.swing.JWindow;
import javax.swing.JLabel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.util.Timer;
import java.util.Date;
import javax.swing.JFrame;
public class MyClass
{
JFrame homeFrame = new JFrame();
public void createFrame()
{
JLabel background=new JLabel(new ImageIcon("images.jpg"));
myFrame.add(background);
background.setLayout(new FlowLayout());
myFrame.setLayout(new GridLayout(1,1));
myFrame.setSize(360,250);
myFrame.setUndecorated(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.setAlwaysOnTop(true);
myFrame.pack();
myFrame.setVisible(true);
durationOfTime();
}
public void durationOfTime()
{
MainProgram mp = new MainProgram();
long startTime = System.currentTimeMillis();
long elapsedTime = 0L;
int count =0;
while (elapsedTime < 2*1000)
{
if(count==0)
{
mp.launchInitiation();
}
count+=1;
elapsedTime = (new Date()).getTime() - startTime;
}
myFrame.setVisible(false);
mp.homeFrame.setVisible(true);
}
public static void main(String[] args)
{
MyClass mc = new MyClass();
mc.createFrame();
}
}
Full code from class with JFrame trying to make. I am trying to use this JFrame as a splash screen but whatever class I call
MyClass mc = new MyClass();
mc.createFrame();
from, it just doesn't appear. Two seconds do pass by before my main GUI appears up but this method is supposed to be called in a login type frame. However, I have tested it with a blank JFrame / GUI to appear upon button click also and it still doesn't appear.
EDIT2
I also previously tried this SplashScreen example by # http://examples.oreilly.com/jswing2/code/ch08/SplashScreen.java but I couldn't get it to work (same problem, appears when called from main but not when called from action listener)
import java.awt.*;
import javax.swing.*;
public class SplashScreen extends JWindow {
private int duration;
public SplashScreen(int d) {
duration = d;
}
// A simple little method to show a title screen in the center
// of the screen for the amount of time given in the constructor
public void showSplash() {
JPanel content = (JPanel)getContentPane();
content.setBackground(Color.white);
// Set the window's bounds, centering the window
int width = 450;
int height =115;
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screen.width-width)/2;
int y = (screen.height-height)/2;
setBounds(x,y,width,height);
// Build the splash screen
JLabel label = new JLabel(new ImageIcon("oreilly.gif"));
JLabel copyrt = new JLabel
("Copyright 2002, O'Reilly & Associates", JLabel.CENTER);
copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
content.add(label, BorderLayout.CENTER);
content.add(copyrt, BorderLayout.SOUTH);
Color oraRed = new Color(156, 20, 20, 255);
content.setBorder(BorderFactory.createLineBorder(oraRed, 10));
// Display it
setVisible(true);
// Wait a little while, maybe while loading resources
ClassToLoad ctl = new ClassToLoad();
try {
Thread.sleep(duration);
ctl.initiate();
} catch (Exception e) {}
setVisible(false);
}
public void showSplashAndExit() {
showSplash();
System.exit(0);
}
public static void main(String[] args) {
// Throw a nice little title page up on the screen first
SplashScreen splash = new SplashScreen(10000);
// Normally, we'd call splash.showSplash() and get on with the program.
// But, since this is only a test...
splash.showSplashAndExit();
}
}
I added the code in the lines with ClassToLoad and this SplashScreen is called on an action listener, what happens is the program waits the 2 seconds that I tell it to, no frame appears, and then the main class that I wanted to load while the splash screen is visible loads. I tried this method first but this didn't work which lead to me using the code listed above this edit
EDIT 3
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame implements ActionListener
{
JPanel thePanel = new JPanel(null); //layout
JButton button = new JButton();
public void startGUI()
{
this.setLayout(new GridLayout(1,1));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CREATEMYPANEL();
this.add(thePanel);
this.setTitle("NO_TITLE_SET");
this.setSize(400,400);
this.setVisible(true);
this.setResizable(true);
}
public void CREATEMYPANEL()
{
button.setLocation(242,151);
button.setSize(100,50);
button.addActionListener(this);
button.setText("button");
thePanel.add(button);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==button)
{
System.out.println("button has been pressed ");
SplashScreen splash = new SplashScreen(1000);
splash.showSplash();
}
}
public static void main(String[] args )
{
TestFrame tf = new TestFrame();
tf.startGUI();
}
}
An example of where I call splash screen from. Still doesn't work. Also, just a note that the image I am loading is a local image
Apologies for bad question formatting
Your code works for me except for some details I noticed:
You're calling setSize(...) and then calling pack(). Probably your image isn't being loaded and thus your JFrame has a size of 0, 0. (And thus it looks like it never appears). .pack() and .setSize(...) are mutually exclusive.
You're setting the JLabel's layout manager to FlowLayout but never adding anything to it. (You can safely remove it)
I see you're importing java.util.Timer if you want to dispose the JFrame after 2 seconds, then you should be using a javax.swing.Timer instead. Otherwise you could get problems related to threading.
Also don't forget to place your program on the Event Dispatch Thread (EDT) as Swing is not thread safe
Following above recommendations you can have this code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SplashscreenSample {
private JFrame myFrame;
private JLabel background;
private Timer timer;
public void createFrame() {
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFrame.dispose();
#SuppressWarnings("serial")
JFrame frame = new JFrame(getClass().getSimpleName()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer.stop();
}
});
myFrame = new JFrame(getClass().getSimpleName());
try {
background = new JLabel(new ImageIcon(new URL("http://cdn.bulbagarden.net/upload/thumb/6/6b/175Togepi.png/250px-175Togepi.png")));
} catch (MalformedURLException e) {
e.printStackTrace();
}
myFrame.add(background);
timer.setInitialDelay(2000);
timer.start();
myFrame.setLayout(new GridLayout(1, 1));
myFrame.setUndecorated(true);
myFrame.setAlwaysOnTop(true);
myFrame.pack();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SplashscreenSample().createFrame());
}
}
Or you can use the Splashscreen class...
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
public class SplashScreen extends JWindow {
private int duration;
public SplashScreen(int d) {
duration = d;
}
// A simple little method to show a title screen in the center
// of the screen for the amount of time given in the constructor
public void showSplash() {
ImageIcon icon = null;
try {
icon = new ImageIcon(new URL("http://www.cqsisu.com/data/wallpapers/5/718448.gif"));
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JPanel content = (JPanel) getContentPane();
content.setBackground(Color.white);
// Set the window's bounds, centering the window
int width = icon.getIconWidth();
int height = icon.getIconHeight();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screen.width - width) / 2;
int y = (screen.height - height) / 2;
setBounds(x, y, width, height);
// Build the splash screen
JLabel label = new JLabel(icon);
JLabel copyrt = new JLabel("Copyright 2002, O'Reilly & Associates", JLabel.CENTER);
copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
content.add(label, BorderLayout.CENTER);
content.add(copyrt, BorderLayout.SOUTH);
Color oraRed = new Color(156, 20, 20, 255);
content.setBorder(BorderFactory.createLineBorder(oraRed, 10));
// Display it
setVisible(true);
// Wait a little while, maybe while loading resources
loadResources();
setVisible(false);
}
public void loadResources() {
TestFrame tf = new TestFrame();
try {
Thread.sleep(duration);
tf.startGUI();
} catch (Exception e) {
}
}
public static void main(String[] args) {
SplashScreen splash = new SplashScreen(10000);
splash.showSplash();
}
}
Try creating and setting the frame visible in a constructor of the class.
Could it be that while your program is counting
while (elapsedTime < 2*1000)
{
if(count==0)
{
mp.launchInitiation();
}
count+=1;
elapsedTime = (new Date()).getTime() - startTime;
}
it is blocking for said 2 seconds and waiting for this method to finish, return back to the create method and then just finish that one?
it seems this could be a better comment, but i need 50 rep for some reason to comment.

How to change action after the 1st click

I'm stacked!! I am relatively new to java and I have been days searching the web to solve my problem without success, its now time to ask for your help.
I cannot...(actually do not know) how to change the actionlistener (actionPerformed) after the second click in an array of JButtons. Please find the code below so that you can guide me.
This is how the program performs right now.
On the 1st click on the grid, the border of the button clicked will change to 'blue' and another button will change its boarder to 'red'. on the next click the same action is performed.
What I need is to change action when the 'red' bordered button is clicked, lets say change the color of the buttons from the 'red' to the 'blue' buttons.(x 3 buttons).
The logic about how to perform the final result I think I can do on my own but my problem is how to change the action when the red bordered button is clicked.
Your help is much appreciated!
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class ChangeGrid
{
private JButton[][] bu1 = new JButton[10][10];
public ChangeGrid(JFrame frame)
{
super();
JPanel pCenter = new JPanel();
JPanel pTop = new JPanel();
frame.add(pCenter, BorderLayout.CENTER);
frame.add(pTop, BorderLayout.NORTH);
JPanel Grid10x10 = new JPanel(new GridLayout(10,10));
pCenter.add(Grid10x10);
for(int c = 0; c< 10; c++)
{
for (int r = 0; r< 10; r++)
{
bu1[c][r] = new JButton("X");
Grid10x10.add(bu1[c][r]);
final int i = c;
final int j = r;
bu1[i][j].addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
int f = (3-1);
bu1[i][j].setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
if ((j+f)<=9)
{
bu1[i][j+f].setBorder(BorderFactory.createLineBorder(Color.RED, 2));
}
else
{
JOptionPane.showMessageDialog(null,"move your 1st click more to the center");
}
}
});
}
}
}
}
import javax.swing.JFrame;
public class GUIFrame extends JFrame
{
public GUIFrame()
{
super("Grid 10 x 10");
this.setSize(1350, 700);
this.setVisible(true);
this.setResizable(true);
this.setDefaultCloseOperation(GUIFrame.EXIT_ON_CLOSE);
}
}
import javax.swing.JFrame;
public class Main
{
public static void main(String args[])
{
JFrame frame = new GUIFrame();
ChangeGrid pC = new ChangeGrid(frame);
frame.pack();
}
}
You can change your ActionListener like next:
bu1[i][j].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int f = (3 - 1);
Border border = bu1[i][j].getBorder();
if(border instanceof LineBorder){
LineBorder lBorder = (LineBorder) border;
if(lBorder.getLineColor().equals(Color.RED)){
//red border clicked
redBorderAction(bu1[i][j]);
return;
}
}
defaultAction(i,j,f);
}
});
And other methods:
private void defaultAction(int i, int j, int f) {
bu1[i][j].setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
if ((j + f) <= 9) {
bu1[i][j + f].setBorder(BorderFactory.createLineBorder(Color.RED, 2));
} else {
JOptionPane.showMessageDialog(null,"move your 1st click more to the center");
}
}
private void redBorderAction(JButton btn) {
btn.setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
}

Java GUI: Image will be overwritten, Path the same -> show it in the frame (image still the same)

I want to show a changing image on my frame. The imagepath is always the same, but the image will be getting overwritten every 10 seconds from another program.
The problem is that the image is not changing when I overwrite it with another image with the same name. So in my understanding: Compiler looks every look in the path and gets the image -> when the image changed it will be changed on the frame!
I hope you understand my problem and somebody could help me.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GUI extends JFrame{
public ImageIcon imageBar;
public JLabel labelimage1;
private JLabel labelimage2;
private JLabel bar1 = new JLabel();
private JLabel bar2 = new JLabel();
private JLabel bar3 = new JLabel();
private JLabel bar4 = new JLabel();
private JLabel bar5 = new JLabel();
private JButton buttonBar1 = new JButton("1");
private JButton buttonBar2 = new JButton("2");
private JButton buttonBar3 = new JButton("3");
private JButton buttonBar4 = new JButton("4");
private JButton buttonBar5 = new JButton("5");
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private JPanel panel3 = new JPanel();
private JFrame window = new JFrame("Interface");
public GUI(){
//set the layouts
panel1.setLayout(new GridLayout(1, 2));
panel2.setLayout(new GridLayout(2, 1));
panel3.setLayout(new GridLayout(2, 5));
//place Panel2 and Panel3 in the window
panel1.add(panel2);
panel1.add(panel3);
//----Panel2
//refreshImage();
//----Panel3
panel3.add(buttonBar1); //add the bars 1-5 on panel3
panel3.add(buttonBar2);
panel3.add(buttonBar3);
panel3.add(buttonBar4);
panel3.add(buttonBar5);
//configure the frame
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setSize(800, 400);
window.getContentPane().add(panel1);
}
public void refreshImage() {
panel2.removeAll(); //delete the old panel
//panel2.repaint();
//panel2.revalidate()
DrawImage pan = new DrawImage();
panel2.add(pan);
panel2.add(labelimage2);
}
}
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class DrawImage extends JPanel implements ActionListener{
private ImageIcon image;
public DrawImage(){
image = new ImageIcon("C:\\Users\\usuario\\Desktop\\image.png");
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
image.paintIcon(this, g, 50, 50);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
import java.io.File;
public class Main {
public static void main(String[] args) {
GUI Interface = new GUI();
while(true)
{
Interface.refreshImage();
try {
Thread.sleep(5000); //wait for 5000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Thank you very much!
The likely cause is Java is caching the image in memory, associated with the source name. So rather then trying to reload the image again, Java simply returns the cached version.
You could use ImageIcon#getImage#flush to force Java to reconstruct the image
Problems
You are calling refreshImage from a Thread other then the Event Dispatching Thread, this could cause issues with the updating of the components and cause rendering artifacts
You are forcefully removing the DrawImage pane and adding a new instance, rather the trying to reload the image
You're calling repaint within the paintComponent method, don't do this...
You should consider using a Swing Timer, which will allow you to schedule a regular update and be notified within the context of the Event Dispatching Thread.
You could provide a simple refresh method which flushes the current ImageIcon and schedule a repaint of the panel...or you could just use a JLabel and save your self the time
An example of Image#flush
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SlideShow {
public ImageIcon imageBar;
public static void main(String[] args) {
new SlideShow();
}
public SlideShow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawImage());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawImage extends JPanel {
private ImageIcon image;
public DrawImage() {
image = new ImageIcon("D:\\thumbs\\image.png");
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
refresh();
}
});
timer.start();
}
public void refresh() {
image.getImage().flush();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
}
The problem with this, is because the image data is loaded in a background thread, it won't may no be available when the component is first repainted, which could make the component appear to flicker.
A better approach would be to use ImageIO.read, which will ensure that the image is fully loaded before the method returns, the draw back here is that could cause the application to "pause" momentary as the image is loaded, personally, I'd use the refresh method to stop the the Timer (or set the Timer to non-repeating), start a background Thread to load the image (using ImageIO.read) call repaint (which is thread safe) and restart the Timer...
Your while (true) loop risks typing up the Swing event thread locking your program. If it doesn't do that, then you risk unpredictable threading issues by making Swing calls off of the event Thread. These problems can be solved easily by your using a Swing Timer not a while true loop to do your swapping.
Rather than removing and adding components, why not simply display images as ImageIcons within a single non-swapped JLabel.
To swap images here, simply call setIcon(...) on the JLabel.
For an example of using a Swing Timer to swap images, please check out my answer to a similar question here.
For example:
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TimerImageSwapper {
public static final String[] IMAGE_URLS = {
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_02.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_04.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_08.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_05.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_06.png" };
private ImageIcon[] icons = new ImageIcon[IMAGE_URLS.length];
private JLabel mainLabel = new JLabel();
private int iconIndex = 0;;
public TimerImageSwapper(int timerDelay) throws IOException {
for (int i = 0; i < icons.length; i++) {
URL imgUrl = new URL(IMAGE_URLS[i]);
BufferedImage image = ImageIO.read(imgUrl);
icons[i] = new ImageIcon(image);
}
mainLabel.setIcon(icons[iconIndex]);
new Timer(timerDelay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
iconIndex++;
iconIndex %= IMAGE_URLS.length;
mainLabel.setIcon(icons[iconIndex]);
}
}).start();
}
public Component getMainComponent() {
return mainLabel;
}
private static void createAndShowGui() {
TimerImageSwapper timerImageSwapper;
try {
timerImageSwapper = new TimerImageSwapper(5 * 1000);
JFrame frame = new JFrame("Timer Image Swapper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(timerImageSwapper.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

How to remove a JButton in a JButton matrix?

I want to remove a certain botton using MouseListener from a matrix of bottons and add a JLabel in the empty, so I use:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public MyClass(){
object = new Object();
bottons = new JButton[5][5];
labels = new JLabel[5][5];
myPanel = new JPanel();
myPanel.setLayout(new GridLayout(5,5));
click =false;
for(int i = 0 ; i<5 ; i++){
for(int j = 0; j<5 ; j++){
myPanel.add(bottons[i][j] = new JButton());
}
}
}
public void mouseReleased(MouseEvent e)
if(click){
remove(bottons[object.getx][object.gety]);//this is correct? or is there another way?
myJPanel.add(labels[object.getx][object.gety] = new JLabel("1"));
click = false;
}
But nothing happen, haha
Thanks for the help.
When you add/remove components from a visible GUI the basic code is:
panel.remove(...);
panel.add(...);
panel.revalidate();
panel.repaint();
Also "MyJPanel" is not a standard Java variable name. Variable names in Java should NOT start with an upper case character. You didn't do that with your other variables, so be consistent!
Given the fact the i and j have no context in the mouse listener method, no, it's probably not a good idea.
The next question is, what is the mouse listener attached to? If it's attached to the button, then it might be better to use a ActionListener.
In either case you could use the source of the event...
Object source = e.getSource();
if (source instanceof JButton) {
JButton btn = (JButton)source;
//find index of button in array...
remove(btn);
//...
revalidate();
}
Updated
A simpler solution might be to simply dump the buttons and labels into a List, for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ButtonUpdates {
public static void main(String[] args) {
new ButtonUpdates();
}
public ButtonUpdates() {
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 implements ActionListener {
private List<JButton> btns = new ArrayList<>(25);
private List<JLabel> lbls = new ArrayList<>(25);
public TestPane() {
setLayout(new GridLayout(5,5));
for (int index = 0; index < 25; index++) {
JButton btn = new JButton(Integer.toString(index));
JLabel lbl = new JLabel(Integer.toString(index));
btns.add(btn);
lbls.add(lbl);
btn.addActionListener(this);
add(btn);
}
}
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JButton) {
JButton btn = (JButton) source;
int index = btns.indexOf(source);
JLabel lbl = lbls.get(index);
index = getComponentZOrder(btn);
remove(btn);
add(lbl, index);
revalidate();
}
}
}
}
This makes looking up what has being actioned and what needs to be replaced easier.
When switching components, you also need to know where the component needs to be added, for this I simply used getComponentZOrder before I removed the JButton

How to access public method of external class in order to repaint on JPanel?

I can not access public method of my class MyPanel which extends JPanel. In MyPanel I previously had private method called moveSquare, but in order to make it work for external requests, I changed it to public, but it still do not work? How to make it working?
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseMotionAdapter;
public class mull {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel p = createAndShowGUI();
iterate(p);
// "The method iterate(MyPanel) in the type mull is not applicable for the arguments (JPanel)"
}
});
}
private static JPanel createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// how to grab link to this panel - in order to use it in iteration loop ?
MyPanel p = new MyPanel();
f.add(p);
// f.add(new MyPanel());
f.pack();
f.setVisible(true);
return p;
}
private static void iterate(JPanel p){
// the loop should change square position on each iteration
// how to implement ?
for (int i = 0; i < 999; i++){
((MyPanel) p).moveSquare(100 + i*10, 200 + i*10); // here is problem:
//"Cannot make a static reference to the non-static method moveSquare(int, int) from the type MyPanel"
}
}
}
class MyPanel extends JPanel {
private int squareX = 50;
private int squareY = 50;
private int squareW = 200;
private int squareH = 200;
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
}
// originally this method was private - in orger to access it within mull, it vas changed to public
public void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(900,700);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}
What does this syntax do ((MyPanel) p).moveSquare(100 + i*10, 200 + i*10); ?
How to paint custom shapes (ovals) in iterate(p)?
It doesn't seem like you're even calling iterate().
But in any case, your moveSquare method is not static, and thus expects a specific MyPanel instance to work on. So you'll probably want to keep a reference to your panel. Say, instead of f.add(new MyPanel()), you could use:
MyPanel p = new MyPanel();
f.add(p);
and then pass p to iterate and call p.moveSquare(100,200) in there.
You need to have a reference to MyPanel somewhere. In class mull add this at the top:
MyPanel myPanel = null;
Then when you add the panel do it like this:
myPanel = new MyPanel();
f.add(myPanel);
You can now reference myPanel from inside your class mull. Also classes should alwats start with a capital in Java (just because), so change it to Mull.

Categories

Resources