Java ImageIcon on JButton duplicates image - java

The goal of this post is to figure out why it is duplicating both images on both buttons. It is VERY odd and should not be happening. That is the main goal. Then it would be finding a solution. Thank you!
Image of what it looks like
I've made an MRE
It outputs both images on both buttons and I don't know why.
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameManager extends JFrame{
private final Map <String, String> images = new HashMap<>(2);
GameManager()
{
images.put("Articuno", "https://i.ya-webdesign.com/images/articuno-transparent-pokemon-xy-17.gif");
images.put("Rayquaza", "https://play.pokemonshowdown.com/sprites/ani-back-shiny/rayquaza.gif");
JPanel pnlPokemonInParty = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//Why does it put both images on both buttons? It actually sets the images on top of one another.
//You can tell which image is in the front and which is behind the other.
//I'm setting the buttons to be transparent. Setting the buttons to not be transparent will cover the the image below it,
//that's how I know they're being stacked on top of one another.
JButton btn1 = gifBtn("Articuno");
JButton btn2 = gifBtn("Rayquaza");
c.gridx = 0;
pnlPokemonInParty.add(btn1, c);
c.gridx = 1;
pnlPokemonInParty.add(btn2, c);
this.add(pnlPokemonInParty);
this.pack();
this.setVisible(true);
}
public JButton gifBtn(String name)
{
final JButton btn = new JButton();
URL url = null;
try {
url = new URL(images.get(name));
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
Icon icon = new ImageIcon(url);
btn.setIcon(icon);
btn.setBackground(new Color(50,50,50,0));
return btn;
}
public static void main(String[] args)
{
GameManager gameManager = new GameManager();
}
}
I can hide the problem by not setting the background color of the Jbuttons to be transparent but that doesn't solve the problem.
Why does this happen?
I'm more so worried about the two images being on the same JButton, but there is another issue that is easily noticeable when looking at the image that I don't really know how to explain.

When posting a question it is recommended to post an MRE like the following:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameManager extends JFrame{
private final Map <String, String> images = new HashMap<>(2);
GameManager()
{
images.put("Articuno", "https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/256x256/Box_Green.png");
images.put("Rayquaza", "https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/256x256/Box_Red.png");
JPanel pnlPokemonInParty = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton btn1 = gifBtn("Articuno");
JButton btn2 = gifBtn("Rayquaza");
c.gridx = 0;
pnlPokemonInParty.add(btn1, c);
c.gridx = 1;
pnlPokemonInParty.add(btn2, c);
this.add(pnlPokemonInParty);
this.pack();
this.setVisible(true);
}
public JButton gifBtn(String name)
{
final JButton btn = new JButton();
URL url = null;
try {
url = new URL(images.get(name));
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
Icon icon = new ImageIcon(url);
btn.setIcon(icon);
btn.setBackground(new Color(50,50,50,0));
return btn;
}
public static void main(String[] args)
{
GameManager gameManager = new GameManager();
}
}
The code works fine using publicly available images so it suggests that there is a problem with the local resource.
MRE makes helping much easier and it
is a powerful debugging tool. It many case, while preparing one, you are likely to find the problem.
Edit 1: With the newly add mre the problem is clear now: each button shows the two images one on top of the other.
The problem indeed disappears when removing btn.setBackground(new Color(50,50,50,0));
This may be explained by "setBackground() doesn't read well on some platforms" taken from #trashgod answer.
The problem can be eliminated by setting LAF as explained in this answer by #Andrew Thompsom.
Here is an mre demonstrating it.
It is up to the look and feel to honor this property, some may
choose to ignore it.
(Quoted from JComponent#setBackground(Color) documentation.)
Edit 2:
A custom JButton which overrides paintComponent works properly (with transparent color where alfa is to 0 like new Color(50,50,50,0) or any other color):
class Main extends JFrame{
private final Map <String, String> images = new HashMap<>();
Main()
{
images.put("Articuno", "https://66.media.tumblr.com/d9105814c15295196a3dbe75c32ba1a0/tumblr_oagpklvBGf1scncwdo1_400.gif");
images.put("Rayquaza", "https://play.pokemonshowdown.com/sprites/ani-back-shiny/rayquaza.gif");
images.put("GreenCircle", "https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Circle_Green.png");
images.put("RedBox", "https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/256x256/Box_Red.png");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(Color.WHITE);
this.setLayout(new FlowLayout());
this.add(gifBtn("GreenCircle"));
this.add(gifBtn("RedBox"));
this.add(gifBtn("Articuno"));
this.add(gifBtn("Rayquaza"));
this.pack();
this.setVisible(true);
}
public JButton gifBtn(String name)
{
JButton btn = new CustomButton();
try {
URL url = new URL(images.get(name));
btn.setIcon(new ImageIcon(url));
} catch (MalformedURLException ex) { ex.printStackTrace(); }
return btn;
}
public static void main(String[] args) throws Exception
{
new Main();
}
}
class CustomButton extends JButton{
private final Color bgColor = new Color(255,192,203,0);
public CustomButton() {
//setBorderPainted(false); //optioal
setContentAreaFilled(false);
setOpaque(false);
}
#Override
public void paintComponent(Graphics g){
g.setColor(bgColor);
Rectangle r = g.getClipBounds();
g.fillRect(r.x, r.y, r.width, r.height);
super.paintComponent(g);
}
}
JComponent#setBackground(Color) documentation states:
Direct subclasses of JComponent must override paintComponent to honor this property.
It is up to the look and feel to honor this property, some may choose to ignore it.
from some reason JButton does not.

Related

How to call this method into my other file?

I want to be able to call the Introduction.Intro() method into my main file code, but it tells me I am unable to call a non-static method intro from a static context. Since I am still fairly new to coding I'm not entirely sure what the problem is. I've added my codes down below. I've tried countless online methods but sadly none have seemed to work.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Start extends JFrame implements ActionListener
{
private JFrame Main;
private JPanel PanelA, PanelB, PanelC;
private JLabel Text, ImageL;
private JButton Button;
private ImageIcon Image;
public Start ()
{
//Button
Button = new JButton("Start");
Button.addActionListener(new ButtonListener());
//Text
Text = new JLabel("Welcome To The Game"); //ADD NAME OF THE GAME
//Image
Image = new ImageIcon(getClass().getResource("download.jfif")); //ADD THE IMAGE FOR WELCOME
ImageL = new JLabel(Image);
//Top Panel (PanelA) - Image
PanelA = new JPanel();
PanelA.setBorder(BorderFactory.createEmptyBorder(0,200,150,200));
PanelA.setLayout(new FlowLayout(FlowLayout.CENTER));
PanelA.add(ImageL);
//Middle Panel (PanelB) - Text
PanelB = new JPanel();
PanelB.setBorder(BorderFactory.createEmptyBorder(50,200,10,200));
PanelB.setLayout(new FlowLayout(FlowLayout.CENTER));
PanelB.add(Text);
//Bottom Panel (PanelC) - Buttons
PanelC = new JPanel();
PanelC.setBorder(BorderFactory.createEmptyBorder(0,200,20,200));
PanelC.setLayout(new FlowLayout(FlowLayout.CENTER));
PanelC.add(Button);
//Main Frame
Main = new JFrame ();
Main.add(PanelA, BorderLayout.NORTH);
Main.add(PanelB, BorderLayout.CENTER);
Main.add(PanelC, BorderLayout.SOUTH);
Main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Main.setTitle("GAME TITLE"); //ADD THIS LATER
Main.pack();
Main.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent ae)
{
}
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == Button)
{
Introduction.Intro1(); //THESE LINE RIGHT HERE
return null; //THESE LINE RIGHT HERE
}
}
}
public static void main(String[] args)
{
new Start();
}
}
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Introduction
{
private JFrame Main;
private JPanel PanelD;
private JLabel Text, ImageL;
private JButton Button;
private ImageIcon Image;
public void Intro()
{
Image = new ImageIcon(getClass().getResource("guy.jfif"));
ImageL = new JLabel(Image);
PanelD = new JPanel();
PanelD.setBorder(BorderFactory.createEmptyBorder(0,100,10,100));
PanelD.setLayout(new FlowLayout(FlowLayout.CENTER));
PanelD.add(ImageL);
PanelD.setVisible(true);
Main.add(PanelD, BorderLayout.NORTH);
}
}
EDIT: So I made another method in the Introduction class where I added this line of code, it managed to fix the error, however, the panel isn't being saved and my JFrame is outputting blank.
public static JFrame Intro1()
{
Introduction M = new Introduction();
return M;
}
If you are looking to initialize the Introduction class in main method of Start class, You can add belo code in main method after Start()
Introduction M = new Introduction();
You main method becomes :
public static void main(String[] args)
{
new Start();
Introduction M = new Introduction();
m.Intro
}
Looking at this set of code, It looks like there is incompatible issue, as you have declare JFrame as return type, while you are returning instance of Introduction.
public static JFrame Intro1()
{
Introduction M = new Introduction();
return M;
}

Why am I not able to add a JPanel to a JPanel?

I would like to draw something like this weather map:
On the top, there is a header which contains information (title, ...) and below there is the actual picture. I tried to model the program like the following but it does not show the image of the weather map.
Later I would like to be able to resize the whole weather map (title and picture).
public class Application {
public static void main(String[] args) {
Window meteoWindow = new Window();
meteoWindow.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame {
Container c;
WeatherMap wm1;
public Window() {
c = getContentPane();
// Loading weather maps
wm1 = new WeatherMap("http://www.link-to-image.com/weatherimage.png");
// ---
c.add(wm1);
setTitle("Meteoview Alpha");
setSize(new Dimension(1920, 1080));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class WeatherMap extends JPanel {
private DescriptionPanel descriptionPanel;
private ImagePanel imagePanel;
private WeatherImage weatherImage;
public WeatherMap(String urlPath) {
imagePanel = new ImagePanel();
descriptionPanel = new DescriptionPanel("Wetterkarte 1");
weatherImage = new WeatherImage("http://www.linktoweatherimage/image.png");
}
}
import javax.swing.*;
import java.awt.*;
public class DescriptionPanel extends JPanel {
private String name;
private JLabel nameLabel;
public DescriptionPanel(String name) {
this.name = name;
nameLabel = new JLabel(name, JLabel.LEFT);
setLayout(new FlowLayout());
add(nameLabel);
}
}
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel() {
//setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
try {
image = ImageIO.read(new URL("http://www.linktoimage/image.png"));
System.out.println("Successfully read...");
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
As you can see, I tried it with a few different approaches, but nothing really works. Can you help me to model this? (JPanel on JPanel, or BufferedImage on JPanel, ...)
imagePanel = new ImagePanel();
descriptionPanel = new DescriptionPanel("Wetterkarte 1");
weatherImage = new WeatherImage("http://www.modellzentrale.de/WRF4km/12Z/15h/RR3h_eu.png");
You create 3 components, but you don't add the components to the panel.
Not really sure what you are trying to do since you attempt to read the same image twice, so I don't know why you have a "WeatherImage" and an "ImagePanel".
So I will just suggest you first try something like the following to understand how to use a panel with a layout manager.
imagePanel = new ImagePanel();
descriptionPanel = new DescriptionPanel("Wetterkarte 1");
setLayout( new BorderLayout() );
add(descriptionPanel, BorderLayout.PAGE_START);
add(imagePanel, BorderLayout.CENTER);
Also, then is no need to create a custom painting to simply paint an image at it actual size. You can just add the Image to a JLabel by using an ImageIcon:
image = ImageIO.read(…);
JLabel imageLabel = new JLabel( new ImageIcon(image) );
Now you add the label to any panel you want.

JAVA JButton in a different class refuses to activate when pressed

I'm failing to understand why my yankee and whiskey JButtons aren't working. Right now I only want them to close the program when romeo is greater than 1 and sierra is greater than 1.
import java.awt.*;
import java.lang.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.util.Scanner;
public class AlphaMenu extends JFrame /*implements actionPerformed*/
{
private GraphicsDevice gamma;
public JButton charlie, zulu, yankee, xray;
public JFrame beta;
public JPanel delta, echo, foxtrot, golf, hotel;
public JTextArea whiskey, victor;
public BorderLayout uniform;
public ImageIcon bg;
public JLabel tango;
public int sierra, romeo;
public Integer quebec, papa;
public ActionEvent oscar;
public ActionEvent november;
public AlphaMenu()
{
//Initialization of Objects
charlie = new JButton("EXIT");
zulu = new JButton("Enter Time");
yankee = new JButton("Enter Amount of Money");
xray = new JButton("Calculate");
sierra = 0;
romeo = 0;
quebec = new Integer(0);
papa = new Integer(0);
whiskey = new JTextArea(2, 15);
victor = new JTextArea(2, 15);
bg = new ImageIcon("background.gif");
beta = new JFrame();
delta = new JPanel();
echo = new JPanel();
foxtrot = new JPanel();
golf = new JPanel();
hotel = new JPanel();
uniform = new BorderLayout();
ImageIcon bg = new ImageIcon("background.gif");
tango = new JLabel("");
tango.setIcon(bg);
//Modification of panels
beta.add(delta, uniform.PAGE_END);
beta.add(golf, uniform.PAGE_START);
beta.add(echo, uniform.LINE_START);
beta.add(foxtrot, uniform.LINE_END);
beta.add(hotel, uniform.CENTER);
golf.add(tango);
//Modification of JButton charlie & adding of JButtons
charlie.setPreferredSize(new Dimension(100, 50));
delta.add(charlie);
charlie.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
echo.add(whiskey);
echo.add(yankee);
foxtrot.add(victor);
foxtrot.add(zulu);
//Modification of JFrame beta
beta.setUndecorated(true);
beta.setExtendedState(JFrame.MAXIMIZED_BOTH);
beta.setResizable(false);
beta.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
beta.setVisible(true);
}
public void buttonSetup() throws NumberFormatException
{
//Modification of JButton yankee & JTextArea whiskey & int sierra
romeo = quebec.parseInt(whiskey.getText());
yankee.setPreferredSize(new Dimension(300, 50));
yankee.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent oscar)
{
System.exit(0);
}
});
//Modification of JButton zulu & JTextArea victor & int romeo
sierra = papa.parseInt(victor.getText());
zulu.setPreferredSize(new Dimension(300, 50));
zulu.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent november)
{
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e)
{
}
public static void main(String[] args)
{
new AlphaMenu();
}
}
So, you have two JTextArea (JTextField would probably be better) and a button. you want some buttons to execute exit when the text of both textareas is an integer greater than 1.
seems that your buttonSetup() function isn't called anywhere.
Anyway, I'd create an ActionListener that reads the texts, converts to integer, tests your condition and executes exit(). This ActionListener should be added to all the buttons you want to perform the action
final ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
final int intRomeo = Integer.parseInt(romeo.getText());
final int intSierra = Integer.parseInt(sierra .getText());
if (intRomeo > 1 && intSierra > 1) {
// whatever you want to do
System.exit(0);
}
} catch (/*NumberFormat*/ Exception e) {
// ...not integers
}
};
}
whiskey.addActionListener(al);
yankee.addActionListener(al);
I have to add: the variable names you are using are really bad. Consider choosing something more significative.
For starters, readability...it would probably help the "sloppiness" if you used more appropriate names for your variables, indented different sections of code, and used comments to help describe sections in layman's terms. Maybe "btnExit" and "btnCalculate" would help make things a little easier to navigate.
Moving forward, you also don't have two different classes here, you have one class with several methods. Which is fine but wanted to inform you of that. I think maybe you need to add the buttons to their panels after your action listeners and formatting for each button. I'm just getting into some swing stuff myself and I've noticed moving the .add() functions around in the code has helped when I run into issues like this. Try the following bellow. I indented and used new naming conventions for the comments, but the code uses your convention.
//add the pnlEcho to frmBeta
beta.add(echo, uniform.LINE_START);
//format btnYankee
yankee.setPreferredSize(new Dimension(300, 50));
//btnYankee action listener
yankee.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) { //default action event
System.exit(0); //you could use this
beta.dispose(); //or you could dispose the frame and
//do more work after it is gone
}
});
//add btnYankee to pnlEcho
echo.add(yankee);
I'm failing to understand why my yankee and whiskey JButtons aren't
working
The variable wiskey is not JButton type but JTextArea type.

Java - a simple PlayerAction counter to practice object-oriented programming

I am learning the basics of Java and decided to practice working on objects, by making a simple program which I called a 'PlayerAction Counter'. It does nothing more that counting an 'action' which is fired by clicking '+1' button and additionally reset the counter, when the 'Reset' button is clicked. For this case I've made a Application.java which holds the main method and launches the program, Interface.java for GUI, EventHandling.java for events and Person.java which holds interface components and methods to change their state. It looks like this:
My idea was to create the window in Interface class and set it's layout, then create two Person objects called PlayerOne and Player Two. The Person class creates two labels and two buttons and set a label of one by a constructor parameter.
I've managed to add these two objects' elements to the GUI by getters and it looks just fine. I added ActionListener to both buttons in Person class and it also works just fine.
I am stuck on getting back to Person fields and methods from EventHandling class. I've created a setValueLabel() which increases by one a value of 'action' and sets it on the label, but I have to idea how to launch the method from another class. I can not make another object inside (throws StackOverFlow error), but should it not somehow refer to those two made in Interface class?
Here is the code:
Application.java
import java.awt.EventQueue;
public class Application {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Interface().setVisible(true);
}
});
}
}
Interface.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
public class Interface extends JFrame {
private JLabel titleLabel;
private JPanel mainPanel;
private JPanel leftPanel, rightPanel;
private JSeparator separator;
Person PlayerOne = new Person("PlayerOne");
Person PlayerTwo = new Person("PlayerTwo");
public Interface() {
//Basic init
setTitle("PlayerAction Counter");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//Layout
mainPanel = new JPanel();
add(mainPanel);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
leftPanel = new JPanel();
rightPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
leftPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(leftPanel, BorderLayout.WEST);
separator = new JSeparator(SwingConstants.VERTICAL);
mainPanel.add(separator, BorderLayout.CENTER);
titleLabel = new JLabel("PlayerAction Counter");
mainPanel.add(titleLabel, BorderLayout.PAGE_START);
//Components init
PlayerTwo.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getPersonLabel());
PlayerTwo.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueLabel());
PlayerTwo.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueUpButton());
PlayerTwo.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
leftPanel.add(PlayerTwo.getValueResetButton());
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
rightPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
mainPanel.add(rightPanel, BorderLayout.EAST);
PlayerOne.getPersonLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getPersonLabel());
PlayerOne.getValueLabel().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueLabel());
PlayerOne.getValueUpButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueUpButton());
PlayerOne.getValueResetButton().setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(PlayerOne.getValueResetButton());
pack();
}
}
Person.java
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JLabel;
public class Person {
private JLabel personLabel;
private JLabel valueLabel;
private JButton valueUpButton;
private JButton valueResetButton;
private int actionValue = 0;
public Person(String s) {
personLabel = new JLabel(s);
setComponents();
}
private void setComponents() {
valueUpButton = new JButton("+1");
valueResetButton = new JButton("Reset");
valueLabel = new JLabel(""+actionValue);
EventHandling eventHand = new EventHandling(valueUpButton, valueResetButton);
valueResetButton.addActionListener(eventHand);
valueUpButton.addActionListener(eventHand);
}
public void setValueLabel() {
actionValue++;
valueLabel.setText("" +actionValue);
}
public JLabel getPersonLabel() {
return personLabel;
}
public JLabel getValueLabel() {
return valueLabel;
}
public JButton getValueUpButton() {
return valueUpButton;
}
public JButton getValueResetButton() {
return valueResetButton;
}
}
EventHandling.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
public class EventHandling implements ActionListener {
private JButton valueUpButton;
private JButton valueResetButton;
public EventHandling(JButton valueUpButton, JButton valueResetButton) {
this.valueUpButton = valueUpButton;
this.valueResetButton = valueResetButton;
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == valueUpButton) {
//no idea how to launch Person.setValueLabel();
//creating new Person object throws StackOverFlow error and I doubt that's the way
}
else if (event.getSource() == valueResetButton) {
}
}
}
I do hope my issue is understandable. The question is: how should it be done?
Please keep in mind that I am a complete rookie and try to learn OOP, but am very confused by it. Please point my mistakes in thinking and the code.
Any feedback will be greatly appraciated.
Thank you.

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();
}
});
}
}

Categories

Resources