How to change the image of a JButton? - java

I'm working on a memory game program. I have 30 JButtons on a JPanel. When the user is clicking and finds a match (meaning two buttons with the same image) I want to change the image on the JButton to a different image. However this does not happen while the program is running.
How can I do this?
I was doing this:
cards[i].setIcon(cardBack);
where cardBack is an ImageIcon that I already have.

you can use this code:
Icon i=new ImageIcon("image.jpg");
jButton1.setIcon(i);
and copy your image (image.jpg) to your project folder!

Use a JToggleButton. More specifically, use the setIcon and setSelectedIcon methods. Using this approach, you'll avoid reinventing the wheel.
Example:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
final class JToggleButtonDemo {
public static final void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
}
private static final void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout()); // For presentation purposes only.
final JToggleButton button = new JToggleButton(UIManager.getIcon("OptionPane.informationIcon"));
button.setSelectedIcon(UIManager.getIcon("OptionPane.errorIcon"));
frame.add(button);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Related

JButton and JTextField

What's wrong? ImageIcon and the frame's size are working properly.
But the JTextField and the JButton aren't.
I need the solution.
import javax.swing.*;
import javax.swing.ImageIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Alkalmazás");
frame.setVisible(true);
frame.setSize(500,500);
frame.setResizable(false);
JTextField field = new JTextField();
field.setBounds(40,250, 300,35);
JButton button = new JButton(new ImageIcon("table.png"));
button.setBounds(40,400, 250,25);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tf.setText(""something);
}
});
frame.add(field);
frame.add(button);
}
}
You didn't mention what's "not working properly", but there are a few errors with your code:
Don't call your class Frame, it may confuse you or others about java.awt.Frame, something that may work would be MyFrame
Right now all your class is inside the main method and it's not placed inside the Event Dispatch Thread (EDT), to fix this, create an instance of your class and call a method createAndShowGUI (or whatever you want to name it) inside SwingUtilities.invokeLater()
For Example:
public static void main(String args[]) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI)
}
Or if using Java 7 or lower, use the code inside this answer in point #2.
setVisible(true) should be the last line in your code, otherwise you may find some visual glitches that may be resolved until you move your mouse above your window or something that triggers the call to repaint() of your components.
Instead of calling setSize(...) directly, you should override getPreferredSize(...) of your JPanel and then call pack() on your JFrame, see this question and the answers in it: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
You're adding 2 components to the CENTER of BorderLayout, which is a JFrame's default layout manager, there are other layout managers and you can combine them to make complex GUI's.
setBounds(...) might mean that you're using null-layout, which might seem like the easiest way to create complex layouts, however you will find yourself in situations like this one if you take that approach, it's better to let Swing do the calculations for you while you use layout managers. For more, read: Why is it frowned upon to use a null layout in Swing?
With all the above tips now in mind, you may have a code similar to this one:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class MyFrame {
private JFrame frame;
private JPanel pane;
private JTextField field;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI);
}
private void createAndShowGUI() {
frame = new JFrame("Alkalmazás");
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
field = new JTextField(10);
button = new JButton("Click me");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
field.setText("something");
}
});
pane.add(field);
pane.add(button);
frame.add(pane);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now you have an output similar to this one:
What about you want the JTextField to have a more "normal" size? Like this one:
You'll have to embed field inside another JPanel (with FlowLayout (the default layout manager of JPanel)), and then add that second JPanel to pane, I'm not writing the code for that as I'm leaving that as an exercise to you so you learn how to use multiple layout managers

Java: JFrame image only appears when maximizing window

I am trying to get an image to appear inside of my JFrame. However, this image only appears when I maximize the GUI window. My image is located inside my src folder. I was wondering if I am implementing JFrame incorrectly.
UPDATED CODE
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JLabel(new ImageIcon("logo.png")));
frame.pack();
frame.setVisible(true);
Simple example.
The image is placed within stof package. The example makes use of ImageIO to load the image. The reason for this is two fold.
If something goes wrong, an exception is raised, so you can diagnose it
ImageIO.read won't return until the image is fully loaded. This means that, unlike ImageIcon, you know the image is available for rendering once the call returns. Just remember, if the image is large and you do this from within the event dispatching thread, you will cause the UI to "stall"
Example
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
BufferedImage image = ImageIO.read(Test.class.getResource("/stof/Background.png"));
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}

Java : using graphics component within an action listener

I've made a JFrame with Diferent JButtons and i'd like to get an image from another class. Any ideas? Or how draw on the same class but on the action performed?
Because it doesnt let me to do any drawings...my complier always gives me error messages
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.*;
public class red extends JFrame {
public JButton b;
public JButton b1;
public JButton b2;
public JButton b3;
public JButton b4;
public static Image p;
public static Graphics g;
public red() throws IOException {
gui1 x = new gui1();
setTitle(" ");
setSize(1200,700);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
b= new JButton("click");
b1= new JButton();
b.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e0){
b1.setBounds(0, 0, 200, 200);
b.show(false);
add(x);
}
});
b.setBounds(0, 0, 100, 100);
add(b1);
add(b);
setVisible(true);
}
public static void main(String[] args) throws IOException {
red k = new red();
}
}
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class gui1 extends Canvas {
public static Image p;
public void paint(Graphics g){
g.drawImage(p, 700, 200, 100, 100, this);
}
{
try {
p= ImageIO.read(new File("Lighthouse.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Phew! I see A LOT of errors in your code (even after I corrected the compilation errors):
You're not following the Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized
while red is a noun it should be more descriptive and be capitalized. The same goes for gui1
You're extending JFrame which in plain english would say: red is a JFrame, you should really avoid this and create your GUI based on JPanels instead... see Java Swing using extends JFrame vs callint it inside of class
You're setting size (a REAAAAAAALLY big one window for the JButton sizes you're using), instead use pack()
You're using null-layout, while pixel-perfect GUIs might seem like the easiest way to create complex GUIs for Swing newbies, the more you use them the more problems related to this you'll find in the future, they are hard to maintain and cause random problems, they don't resize, etc. Please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? for more information about why you should avoid its use and why you should change your GUI to work with Layout Managers along with Empty Borders for extra spacing between components.
You're making use of a deprecated method JFrame#show() you should be using JFrame#setVisible(...) instead.
Related to point #4, you shouldn't be calling setBounds(...) method, but let that calculations to the layout managers.
You're not placing your program on the Event Dispatch Thread (EDT), Swing is not thread safe, you can fix this by changing your main() method as follows:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
You're mixing AWT and Swing components, instead of using AWT's Canvas use Swing's JPanel which has more functionality and support.
Images will become embedded resources once they're packaged in a JAR file, so it's wise to start treating them as if they already were, not as external files as shown in the embedded-resource tag.
Once you change from Canvas to JPanel you should override its paintComponent(...) method and not paint(...) and call it's super.paintComponent(g) method as the first line, also don't forget to add the #Overrides annotation. See the tutorial on Swing custom painting.
You're abusing the use of static keyword, see how does the static keyword works?
After seeing all the above errors I recommend you to go back and Learn the basics of the language before starting with a graphical environment which will only add more difficulty to your learning.
From what I understand you want to draw an image on a button click, if that's the case then you can wrap your image in a JLabel and add that JLabel to a JPanel which then is added to a parent JPanel which is later added to the JFrame:
As you can see in the GIF above, the icon is displayed after user presses the button.
Obviously this can be improved for the GUI to be more "attractive" with combinations of layout managers and empty borders as stated before.
This was done with the following code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ImageDrawingFromOneClassToAnother {
private JFrame frame;
private JPanel pane;
private JPanel leftPane;
private JPanel rightPane;
private ImageIcon icon;
private JButton button;
private JLabel label;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ImageDrawingFromOneClassToAnother().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
icon = new ImageIcon(this.getClass().getResource("king.png")); //Read images as if they were already embedded resources
button = new JButton("Draw image");
label = new JLabel(""); //Create an empty label
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(icon); //On button click, we set the icon for the empty label
}
});
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200); //Set a size for the main panel
}
};
pane.setLayout(new GridLayout(1, 2)); //The main panel
leftPane = new JPanel(); //The button panel
leftPane.setLayout(new BoxLayout(leftPane, BoxLayout.PAGE_AXIS));
leftPane.add(button);
rightPane = new JPanel(); //The panel where the image will be drawn
rightPane.add(label);
//We add both (button and image) panels to the main panel
pane.add(leftPane);
pane.add(rightPane);
frame.add(pane); //Add the main panel to the frame
frame.pack(); //Calculate its preferred size
frame.setVisible(true); //Set it to be visible
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

Can't dispose of jframe window?

I'm trying to dispose of the difficulty window after any one of the difficulty button's are clicked but it won't happen. I've tried .dispose and frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); but i can't get it. Is it just placement or more?
import java.awt.FlowLayout;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridLayout;
public class Game extends JFrame{
public static JFrame frame = new JFrame();
private JLabel lab;
public static void main(String[] args) {
Game difficulty = new Game();
difficulty.setSize(350,105);
difficulty.setTitle("Difficulty.");
difficulty.setVisible(true);
difficulty.setLocationRelativeTo(null);
/**Game sudoku = new Game();
sudoku.setSize(900, 900);
sudoku.setVisible(false);*/
}
public Game(){
setLayout(new FlowLayout());
lab = new JLabel("Please select your difficulty.");
add(lab);
JButton easy;
easy = new JButton("Easy");
add(easy);
easy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
System.out.println("You clicked the button");
JFrame.dispose();
}
});
JButton medium;
medium = new JButton("Medium");
add(medium);
JButton hard;
hard = new JButton("Hard");
add(hard);
JButton evil;
evil = new JButton("Evil!");
add(evil);
}
}
First of all you're extending JFrame and creating an object of JFrame, if I'm not wrong, this shouldn't be done.
public class Game extends JFrame{
public static JFrame frame = new JFrame();
And as #Salah said, JFrame is not static, so it should be:
public JFrame frame = new JFrame();
To solve your problem, you're disposing a new JFrame (yes, you have 3 JFrames in one class, instead of 1, which is what you want), with: JFrame.dispose(); if you already created an object or you're extending JFrame, you can:
this.dispose(); //For the extended JFrame
or
frame.dispose(); //For the object you created
dispose() method is not a static, so it'll not work by calling it directly from JFrame class
JFrame.dispose();
try to do :
dispose();
Or to dispose the frame object you have created
frame.dispose();
Read more about JFrame
I had the same problem:
this.dispose();
solved my problem.
Try setting the jFrame to invisible before disposing it:
public void disposeJFrame(JFrame frame){
frame.setVisible(false);
frame.dispose();
}
If you're wanting to close the whole program, you can use System.exit(0);
Instead JFrame.dispose();, use frame.dispose() or JFrame.this.dispose();

How to set text above and below a JButton icon?

I want to set text above and below a JButton's icon. At the moment, in order to achieve this, I override the layout manager and use three JLabel instances (i.e. 2 for text and 1 for the icon). But this seems like a dirty solution.
Is there a more direct way of doing this?
Note -I'm not looking for a multi-line solution, I'm looking for a multi-label solution. Although this article refers to it as a multi-line solution, it actually seems to refer to a multi-label solution.
EXAMPLE
import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public final class JButtonDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new JMultiLabelButton());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static final class JMultiLabelButton extends JButton
{
private static final long serialVersionUID = 7650993517602360268L;
public JMultiLabelButton()
{
super();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new JCenterLabel("Top Label"));
add(new JCenterLabel(UIManager.getIcon("OptionPane.informationIcon")));
add(new JCenterLabel("Bottom Label"));
}
}
private static final class JCenterLabel extends JLabel
{
private static final long serialVersionUID = 5502066664726732298L;
public JCenterLabel(final String s)
{
super(s);
setAlignmentX(Component.CENTER_ALIGNMENT);
}
public JCenterLabel(final Icon i)
{
super(i);
setAlignmentX(Component.CENTER_ALIGNMENT);
}
}
}
There is not way to split the text between the top/bottom of a JButton. This would involve custom painting.
Since I'm not sure of your exact requirement I'll just through out a few random ideas:
You can use a JButton with text & icon. There are methods in the API that allow you to controal where text is positioned relative to the icon. Then you would need a second label for the other line of text. Basically the same as you current solution but you only need two labels.
You could use the Text Icon and Compound Icon classes to create 1 Icon out of 3 separate Icons. Then you can just add the icon to a button.
Use a JTextPane. Its supports an insertIcon() method. So you could add a line of text, add the icon and then add the other line of text. You can play with the paragraph attributes of the text pane to align the text horizontally within the space if you don't want the text left justified. You can also play with the background color to make it look like a label.
Example using the CompoundIcon:
import java.awt.*;
import javax.swing.*;
public final class JButtonDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JButton button = new JButton();
CompoundIcon icon = new CompoundIcon(CompoundIcon.Axis.Y_AXIS,
new TextIcon(button, "Top Label"),
UIManager.getIcon("OptionPane.informationIcon"),
new TextIcon(button, "Bottom Label"));
button.setIcon( icon );
button.setFocusPainted( false );
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add( button );
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
you have two four options
1) use JLabel + Icon + Html (<= Html 3.2)
2) use XxxButtonUI and override all required methods from API
3) JLayeredPane with translucency???, another Layout with translucency, as JLabel or JComponent to the JButton,
4) there are around lots of Graphics SW that can to prepare Background as *.jpg for Icon, then is very simple to change whatever by Event, Action or actual setting for JButton
not correct way is looking for JLabel + Whatever instead of JButton, I think that is halfsized workaround
Find another LayoutManager, here: http://download.oracle.com/javase/tutorial/uiswing/layout/visual.html

Categories