I'm trying to create a smooth animation from one JPanel to the next where the second JPanel is both taller and wider than the first requiring me to rescale the JFrame. To do this I created the following code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
public class Example1 extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
public Example1()
{
initComponents();
}
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // get look and feel based on OS
}
catch (ClassNotFoundException ex) // catch all errors that may occur
{
Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
}
catch (InstantiationException ex)
{
Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
}
catch (UnsupportedLookAndFeelException ex)
{
Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
}
EventQueue.invokeLater(new Runnable()
{
public void run() // run the class's constructor, therefore starting
// the UI being built
{
new Example1().setVisible(true);;
}
});
}
private WindowListener exitListener = new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
closingEvent(); // if window closing, go to exit menu
}
};
private void initComponents() // method to build initial view for user for installation
{
// instantiating elements of the GUI
pnlStart = new JPanel();
lblMain = new JLabel();
lblDivider = new JLabel();
lblTextPrompt = new JLabel();
txtAccNum = new JTextField();
btnNext = new JButton();
btnExit = new JButton();
pnlStart.setVisible(true);
add(pnlStart); // adding the panel to the frame
removeWindowListener(exitListener);
addWindowListener(exitListener); // removing before adding the windowlistener, ensures there is only one listener there
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // setting "x" button to do nothing except what exitListener does
setPreferredSize(new Dimension(600, 400)); // setting measurements of jframe
setTitle("Example 1.0"); // setting title on JFrame
setResizable(false); // disabling resizing
setLayout(null); // ensuring I can specify element positions
setBackground(Color.WHITE); // setting background color
lblMain.setText("<html>Please input a number below how many accounts you would like to<br>create: </html>"); // main label that explains what happens, html used for formatting
lblMain.setFont(lblMain.getFont().deriveFont(18.0f)); // changing font size to 16
lblMain.setBounds(27, 60, 540, 100); // setting position and measurements
add(lblMain); // adding label to JFrame
lblTextPrompt.setText("Amount of accounts (1-10):");
lblTextPrompt.setFont(lblMain.getFont().deriveFont(16.0f));
lblTextPrompt.setBounds(166, 190, 198, 18);
lblTextPrompt.setLabelFor(txtAccNum);
add(lblTextPrompt);
txtAccNum.setFont(lblMain.getFont());
txtAccNum.setBounds(374, 187, 50, 26);
txtAccNum.addKeyListener(new KeyAdapter()
{
public void keyTyped(KeyEvent e)
{
if (txtAccNum.getText().length() >= 4) // limit textfield to 3 characters
e.consume();
}
});
txtAccNum.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
AccDetails(Integer.parseInt(txtAccNum.getText()));
}
});
add(txtAccNum);
lblDivider.setText(""); // ensuring no text in label
lblDivider.setBounds(10, 285, 573, 10); // setting bounds and position of dividing line
lblDivider.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY)); // setting border to label for the dividing
add(lblDivider); // adding it to JFrame
btnNext.setText("Next"); // adding text to button for starting
btnNext.setFont(lblMain.getFont().deriveFont(14.0f)); // setting font size
btnNext.setBounds(495, 315, 80, 35); // positioning start button
btnNext.addActionListener(new ActionListener() // add listener for action to run method
{
public void actionPerformed(ActionEvent evt)
{
AccDetails(Integer.parseInt(txtAccNum.getText()));
}
});
add(btnNext); // adding button to JFrame
btnExit.setText("Exit"); // adding text to button for exiting
btnExit.setFont(btnNext.getFont()); // getting font from start button
btnExit.setBounds(20, 315, 80, 35); // positioning on form
btnExit.addActionListener(new ActionListener() // add listener for action to run method
{
public void actionPerformed(ActionEvent evt)
{
closingEvent(); // running cancel method (same method as hitting the "x" button on the form)
}
});
add(btnExit); // adding button to JFrame
repaint(); // repainting what is displayed if going coming from a different form
revalidate(); // revalidate the elements that will be displayed
pack(); // packaging everything up to use
setLocationRelativeTo(null); // setting form position central
txtAccNum.requestFocusInWindow(); // setting focus on start button when everything is loaded
}
private void AccDetails(int accNum)
{
getContentPane().removeAll();
// instantiating elements of the GUI
pnlAccDetails = new JPanel();
pnlAccDetails.setVisible(true);
add(pnlAccDetails); // adding the panel to the frame
removeWindowListener(exitListener);
addWindowListener(exitListener); // removing before adding the windowlistener, ensures there is only one listener there
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // setting "x" button to do nothing except what exitListener does
while (sizeW != 750 && sizeH != 500)
{
setBackground(Color.BLACK);
Point loc = getLocationOnScreen();
setPreferredSize(new Dimension(sizeW, sizeH));
pnlAccDetails.setPreferredSize(new Dimension(sizeW, sizeH));
repaint();
revalidate();
pack();
sizeW += 1.5;
sizeH += 1;
if (toggle)
{
setLocation((int)(loc.getX() - 0.75), (int)(loc.getY() - 0.5));
toggle = false;
}
else
{
toggle = true;
}
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
setTitle("Example 1.0"); // setting title on JFrame
setResizable(false); // disabling resizing
setLayout(null); // ensuring I can specify element positions
setBackground(Color.WHITE); // setting background color
repaint(); // repainting what is displayed if going coming from a different form
revalidate(); // revalidate the elements that will be displayed
pack(); // packaging everything up to use
setLocationRelativeTo(null); // setting form position central
}
private void closingEvent()
{
if (JOptionPane.showConfirmDialog(null, "<html><center>Are you sure you want to quit?</center></html>", "Quit?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
System.exit(0); // output warning that it would cancel installation, if accepted...
else // if not accepted...
{
}
}
// objects used in UI
private JPanel pnlStart;
private JPanel pnlAccDetails;
private JLabel lblMain;
private JLabel lblDivider;
private JLabel lblTextPrompt;
private JTextField txtAccNum;
private JButton btnNext;
private JButton btnExit;
private int sizeW = 600;
private int sizeH = 400;
private boolean toggle = false;
}
While this code does work, during the resizing, the form doesn't retain it's background colour and instead has a black outline with the new measurements. I understand, from the research I've done, this is due to the rendering engine used. Is there anyway to force the render engine to run at each iteration or is there another way of doing this? I've seen the suggestion of using Universal Tween Engine however I couldn't find any resizing examples, especially for the JFrame.
Thanks in advance
As stated in the above comments (by #Sergiy Medvynskyy) blocking the Swing Thread caused it to not render correctly. With using a Swing Timer the animation works smoothly. The code I have used for the solution is:
timer = new Timer (10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
Point loc = getLocationOnScreen();
setPreferredSize(new Dimension(sizeW, sizeH));
pnlAccDetails.setPreferredSize(new Dimension(sizeW, sizeH));
repaint();
revalidate();
pack();
sizeW += 3;
sizeH += 2;
if (toggle)
{
setLocation((int)(loc.getX() - 0.75), (int)(loc.getY() - 0.5));
toggle = false;
}
else
{
toggle = true;
}
if (sizeW == 750 && sizeH == 500)
{
timer.stop();
}
}
});
timer.start();
The above code is used in place of the while loop in my original question. Thanks to Sergiy Medvynskyy for the answer.
Related
I am having trouble with a game I am making. I am attempting to fade a JLabel, using a Timer. So far, I have been able to set a JLabel as transparent, and I have been able to make a working Timer. But somehow, I am not able to combine them together. I can set a JLabel's background to
l.setBackground(new Color(0, 0, 0, 200));
(l being desired JLabel to change the color of, of course)
and it works. The JLabel is transparent.
But I have not been able to put it into a timer so that the color fades:
public static void fadeLabel(JLabel lab, int steps, int target) {
class fade extends Thread {
public void run() {
Timer t = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(lab.getBackground().getAlpha());
lab.setBackground(new
Color(lab.getBackground().getRed(),
lab.getBackground().getGreen(),
lab.getBackground().getBlue(),
lab.getBackground().getAlpha() + steps));
if (lab.getBackground().getAlpha() == target) {
((Timer) e.getSource()).stop();
}
}
});
t.start();
}
}
new Thread(new fade()).start();
}
instead, it just goes from black to transparent. Nothing in-between. It also throws the error java.lang.IllegalArgumentException: Color parameter outside of expected range: Alpha. However, I have set the step to -5 (the rate at which it fades, in this case, fades out, as it is negative) and if you remember, I set the alpha to something that is divisible by five, and I also have a checker for when it gets to the target, so that it stops the Timer when it reaches that target. Is there something I'm doing wrong? Is the JLabel's background updating too fast for it to show? Any help would be great.
Edit:
I have fixed the java.lang.IllegalArgumentException: Color parameter outside of expected range: Alpha. But the other one about the JLabel not fading is still there, and I don't know how to fix it.
I'm not directly answering your question. A wrote some code, take a look :D
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyWindow extends JFrame {
public MyWindow() {
initComponents();
}
private void initComponents() {
setTitle( "Fading labels :)" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
setSize( 400, 400 );
setLocationRelativeTo( null );
setLayout( new FlowLayout() );
for ( int i = 0; i < 550; i++ ) {
JLabel lab = new JLabel( "x" );
add( lab );
fadeLabel( lab, 10, i / 10, 0 );
}
}
private void fadeLabel( JLabel label, int steps, int skipSteps, int targetAlpha ) {
new LabelFader( label, steps, skipSteps, targetAlpha ).start();
}
private class LabelFader {
JLabel label;
int steps;
int skipSteps;
int targetAlpha;
LabelFader( JLabel label, int steps, int skipSteps, int targetAlpha ) {
this.label = label;
this.steps = steps;
this.skipSteps = skipSteps;
this.targetAlpha = targetAlpha;
}
void start() {
Color startColor = label.getForeground();
int startAlpha = startColor.getAlpha();
int deltaAlpha = startAlpha - targetAlpha;
if ( deltaAlpha > 0 ) {
int alphaStep = deltaAlpha / steps;
new Thread( new Runnable() {
#Override
public void run() {
int totalIterations = steps + skipSteps;
int currIteration = 1;
for ( int i = 0; i < totalIterations; i++ ) {
if ( skipSteps == 0 ) {
int newAlpha = startAlpha - alphaStep * currIteration++;
newAlpha = newAlpha < 0 ? 0 : newAlpha;
Color newColor = new Color(
startColor.getRed(),
startColor.getGreen(),
startColor.getGreen(),
newAlpha );
label.setForeground( newColor );
} else {
skipSteps--;
}
try {
Thread.sleep( 100 );
} catch ( InterruptedException exc ) {
exc.printStackTrace();
}
}
Color newColor = new Color(
startColor.getRed(),
startColor.getGreen(),
startColor.getGreen(),
targetAlpha );
label.setForeground( newColor );
}
}).start();
}
}
}
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
public void run() {
new MyWindow().setVisible( true );
}
});
}
}
A JLabel is not opaque by default, so its background is not painted. Therefore changing its background color will have no effect - unless you explicitly made your JLabel opaque by calling the relevant method, as in
lab.setOpaque(true)
Forgive me but I couldn't find that in the code you posted.
Also, code that affects the GUI needs to be performed on the Event Dispatch Thread (EDT). Your code that changes the JLabel background color is being run in a separate thread. The result of running that code is therefore unpredictable. The javax.swing.Timer class does not need to be run in a separate thread. Simply create a Timer object and then call its start method. So just take your code that creates the Timer out of the Thread and put it in with the rest of your GUI code.
If you would like a small, demo program showing how to fade the text of a JLabel, let me know.
EDIT: Here is the demo that fades the JLabel text. A JFrame containing a JLabel and a JButton. Click the JButton and the JLabel text fades until it disappears.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.WindowConstants;
/**
* Tests <i>Swing</i> {#link javax.swing.Timer timer}.
*/
public class LabelDim {
private int alpha;
private JButton button;
private JFrame frame;
private JLabel label;
private Timer timer;
public LabelDim() {
timer = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (alpha > 0) {
alpha -= 15;
label.setForeground(new Color(0, 0, 0, alpha));
}
else {
timer.stop();
}
}
});
}
private void showGui() {
frame = new JFrame("Dim");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
label = new JLabel("I am a fading label.", SwingConstants.CENTER);
alpha = label.getForeground().getAlpha();
label.setFont(label.getFont().deriveFont(24.0f));
label.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
frame.add(label, BorderLayout.CENTER);
button = new JButton("Start");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
JPanel panel = new JPanel();
panel.add(button);
frame.add(panel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
LabelDim instance = new LabelDim();
EventQueue.invokeLater(() -> instance.showGui());
}
}
SECOND EDIT:
Here's some sample code that works. It'll throw the Exception you've already fixed but this is just for demonstration purposes only :).
Play with the label.setOpaque and its background and tell what happens with yourself. If you need to draw the label background set that flag to true.
If you do not need to draw its background do not modify label's background and do not set it to be opaque and modifying the foreground color should be more than enough! :)
package main;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main extends JFrame {
JLabel label;
JButton btn;
public Main() {
setSize(500,500);
setLayout(new FlowLayout());
label = new JLabel("My super awesome label");
//label.setOpaque(true); //Play with these lines and see what happens
//label.setBackground(Color.BLUE); //Play with these lines and see what happens
btn = new JButton("Click me");
btn.setSize(200,200);
btn.addActionListener(
(ActionEvent evt) -> {
Timer t = new Timer(100,
(ActionEvent event) -> {
Color foreground = label.getForeground();
Color background = label.getBackground();
foreground = decreaseAlpha(foreground);
background = decreaseAlpha(background);
label.setForeground(foreground);
label.setBackground(background);
}
);
t.start();
}
);
this.add(label);
this.add(btn);
}
public static void main(String[] args) {
(new Main()).setVisible(true);
}
public Color decreaseAlpha(Color original) {
return new Color(original.getRed(), original.getGreen(), original.getBlue(), original.getAlpha() - 10);
}
}
EDIT:
You might be changing your background of your label instead of its foreground...
Timer t = new Timer(10, (ActionEvent evt)-> {
l.setForeground(new
Color(l.getForeground().getRed(),
l.getForeground().getGreen(),
l.getForeground().getBlue(),
l.getForeground().getAlpha() - 1)
);
l.invalidate();
});
t.start();
Being l your label
Also, don't do this:
new Thread(new fade()).start();
Your fade class is already a Thread because it's extending it. Use (new fade()).start(); instead
I am new to JPanel and don't quite understand how to reset it. Once a picture is chosen and the user wants to select a new one, I want it to erase the old selected picture and paste the new one. But I'm not sure how. I've seen repaint() and revalidate() used, but I clearly don't know how to use it. So how do I accomplish this?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRadioButtonMenuItem;
public class Menu extends JFrame {
JMenuBar menuBar;
ButtonGroup pictureGroup, problemsGroup;
BufferedImage picture1img, picture2img, picture3img;
JMenu choiceOfThreePictures, numberOfProblems;
JRadioButtonMenuItem picture1, picture2, picture3, fourProblems, nineProblems, sixteenProblems;
// /Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture1.jpg
// /Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture2.png
// /Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture3.jpg
public Menu() {
// Create the menu bar.
menuBar = new JMenuBar();
setJMenuBar(menuBar);
// Create Picture choices on Menu Bar
choiceOfThreePictures = new JMenu("Picture Choices");
// Add Picture choices on Menu Bar
menuBar.add(choiceOfThreePictures);
// Create MenuItems onto Picture choices
pictureGroup = new ButtonGroup();
picture1 = new JRadioButtonMenuItem("Picture 1");
picture2 = new JRadioButtonMenuItem("Picture 2");
picture3 = new JRadioButtonMenuItem("Picture 3");
// Add Picture Choices to Picutre choices menu
choiceOfThreePictures.add(picture1);
pictureGroup.add(picture1);
choiceOfThreePictures.add(picture2);
pictureGroup.add(picture2);
choiceOfThreePictures.add(picture3);
pictureGroup.add(picture3);
// Create Number Of Problems on Menu Bar
numberOfProblems = new JMenu("Number Of Problems");
// Add Number Of problems on Menu Bar
menuBar.add(numberOfProblems);
// Create Menu Items onto Number Of problems
problemsGroup = new ButtonGroup();
fourProblems = new JRadioButtonMenuItem("4");
nineProblems = new JRadioButtonMenuItem("9");
sixteenProblems = new JRadioButtonMenuItem("16");
// Add Number Of problems onto menu
numberOfProblems.add(fourProblems);
problemsGroup.add(fourProblems);
numberOfProblems.add(nineProblems);
problemsGroup.add(nineProblems);
numberOfProblems.add(sixteenProblems);
problemsGroup.add(sixteenProblems);
// Start creating ActionListeners
picture1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("Working");
try {
picture1img = ImageIO.read(new File("/Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture1.jpg"));
getContentPane().add(new JLabel(new ImageIcon(picture1img)));
revalidate();
repaint();
setVisible(true);
} catch (IOException e) {
System.out.println("Couldn't find image.");
}
}
});
picture2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("Working");
try {
picture2img = ImageIO.read(new File("/Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture2.jpg"));
getContentPane().add(new JLabel(new ImageIcon(picture2img)));
revalidate();
repaint();
setVisible(true);
} catch (IOException e) {
System.out.println("Couldn't find image.");
}
}
});
picture3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println("Working");
try {
picture3img = ImageIO.read(new File("/Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture3.jpg"));
getContentPane().add(new JLabel(new ImageIcon(picture3img)));
revalidate();
repaint();
setVisible(true);
} catch (IOException e) {
System.out.println("Couldn't find image.");
}
}
});
}
public static void main(String[] args) {
Menu mb = new Menu();
mb.setSize(900, 700);
mb.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mb.setVisible(true);
}
}
You are using it just fine, you can even remote repaint() call as revalidate is more then enought. The problem is, that you are adding new images but you are not removing previously added images from the contentPane that is why it is not switching.
So if you do
picture3img = ImageIO.read(new File("/Users/Administrator/Dropbox/Java/HW6Wilson/HW6Wilson/Picture3.jpg"));
getContentPane().removeAll(); // HERE IS IMPORTANT PART
getContentPane().add(new JLabel(new ImageIcon(picture3img)));
revalidate();
It will work
The better approach would be to hold single label as a "image display" and use setIcon(icon) on JLabel insteed of changing whole labels.
I'm going to post this again and try to be more precise and succinct this time around. I have installed WindowBuilder and have been using that to generate my GUI code.
So I have my GUI set up and everything going. WindowBuilder automatically makes a method called initialize() and that's where all my GUI code is.
I have redacted a lot of my code. I think I have left everything needed to identify what it is I'm trying to do.
I'm not sure if the code below works, being redacted and all, but in general, whenever the user clicks the "ROLL" button on the GUI, it should execute the rollDice() method, which cycles a side of a dice for .1 second each, and finally stopping and landing on the final value.
I have been trying like crazy to implement a method to do this, but anything and everything I make regarding to the GUI outside of the initialize() class does not work at all - yet returns no errors in my code. Any help would be appreciated!
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Font;
import java.awt.Image;
import java.awt.Label;
import javax.swing.JScrollPane;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.util.*;
import javax.swing.JComboBox;
import java.awt.Color;
import javax.swing.SwingConstants;
public class PigDice {
public JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PigDice window = new PigDice();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}//Main Method
static void diceTumble(){
}
static void pausee(int x){
try {
Thread.sleep(x);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//endsPause
/**
* Create the application.
*/
public PigDice() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 1038, 892);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(0, 0, 1016, 830);
frame.getContentPane().add(panel);
panel.setLayout(null);
JButton btnRoll = new JButton("Roll");
btnRoll.setFont(new Font("Tahoma", Font.BOLD, 24));
btnRoll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tumbleDice();
}
});
btnRoll.setBounds(292, 639, 135, 52);
panel.add(btnRoll);
}
static void tumbleDice(){
for(int i = 0; i < 25; i++){
sleep(100);
JPanel panel_1 = new JPanel();//panel for dice1
panel_1.setBounds(277, 393, 150, 150);
panel.add(panel_1);
panel_1.setLayout(null);
JPanel panel_2 = new JPanel();//panel for dice2
panel_2.setBounds(564, 393, 150, 150);
panel.add(panel_2);
panel_2.setLayout(null);
JLabel dice1 = new JLabel("dice1");
dice1.setHorizontalAlignment(SwingConstants.CENTER);
dice1.setBounds(0, 0, 150, 150);
Image die1 = new ImageIcon(this.getClass().getResource("" + tumble())).getImage();
dice1.setIcon(new ImageIcon(die1));
panel_1.add(dice1);
JLabel dice2 = new JLabel("dice2");
dice2.setHorizontalAlignment(SwingConstants.CENTER);
dice2.setBounds(0, 0, 150, 150);
Image die2 = new ImageIcon(this.getClass().getResource("" + tumble())).getImage();
dice2.setIcon(new ImageIcon(die2));
panel_2.add(dice2);
}//for loop
}//tumbleDice method
String tumble(){
int random = (int) (Math.random() * 6) + 1;
if(random == 1)
return "/side1.png";
if(random == 2)
return "/side2.png";
if(random == 3)
return "/side3.png";
if(random == 4)
return "/side4.png";
if(random == 5)
return "/side5.png";
return "/side6.png";
}
}//end PigDice
Don't keep creating new components. If you want to change the image, then just use the setIcon() method of the JLabel.
Don't use a null layout. Swing was designed to be used with layout managers.
Don't use Thread.sleep(). This causes the Event Dispatch Thread to sleep which means the GUI can't repaint itself. Instead use a Swing Timer.
The Swing Tutorial has examples of all these suggestions so read the tutorial for the basics.
Also, don't continually read the image files. This is not very efficient if you are going to loop 25 times. Instead the images should be loaded in the constructor of your class. Then maybe store them in an ArrayList and just return the random index of the Icon you want to display in the label.
I have created this Progress Code and now I want it to close automatically after going to 100% and also open a new Frame with Text in the frame. So how do I do this?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.sql.*;
import java.util.*;
class Progress extends JFrame implements ActionListener {
JProgressBar pb;
JButton b1;
Progress() {
super("Progress");
setLayout(null);
b1 = new JButton("Start");
b1.setBackground(Color.LIGHT_GRAY);
pb = new JProgressBar(1,100);
pb.setValue(0);
pb.setStringPainted(true);
pb.setForeground(Color.green);
pb.setBackground(Color.pink);
b1.setBounds(20, 20, 80, 25);
pb.setBounds(110, 20, 200, 25);
pb.setVisible(false);
add(b1);
add(pb);
b1.addActionListener(this);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
int i=0;
if(e.getSource()==b1) {
pb.setVisible(true);
try {
while(i<=100) {
Thread.sleep(50);
pb.paintImmediately(0, 0, 200, 25);
pb.setValue(i);
i++;
}
} catch(Exception e1) {
System.out.print("Caughted exception is ="+e1);
}
}
}
public static void main(String arg[]) {
logindemo m=new logindemo();
m.setSize(400,250);
m.setVisible(true);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - m.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - m.getHeight()) / 2);
m.setLocation(x, y);
}
}
This is the code for my Progress bar.
So a thing before the answer.
ProgressBar
In your code while progress is increasing rest of the application is frozen. If you want to avoid it, it's good to have progress bar code in another Thread. But remember to use SwingWorker instead of classic Threads.
Also read the thing what Andrew Thompson mentioned in his comments.
To "close" or rather hide main frame u can call one of these methods
setVisible(false);
or
dispose();
To open new Window/Frame or whatever, you have to put it after the while loop. You can check it with code below, just add this method to your class and call it after the loop.
private void dialogMessage() {
Object[] options = {"OK"};
int result = JOptionPane.showOptionDialog(this,
"Done!", "",
JOptionPane.OK_OPTION, JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (result == JOptionPane.OK_OPTION) {
System.exit(0);
}
}
To read more about JOptionPane check out this link How to Make Dialogs
1.I am making a cookie click clone i know so mature I'm only 12 and I'm testing my abilities. I have a problem I'm trying to get a label to update but it just won't
tried everything
Also sorry in advance for weird indentation and messiness I'm not great at making good looking code
class
package learning;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.JPanel;
public class Learning extends JFrame implements MouseListener {
int clicks;
boolean Update;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Learning().start();
}
public void start(){
ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(600,600);
setResizable(false);
JLabel Click = new JLabel("Clicks: " + clicks);
Click.setFont(new Font("Arial",Font.PLAIN , 20));
panel.add(Click);
Click.setSize(100,100);
Click.setVisible(true);
addMouseListener(this);
if(Update == true){
Click.setText("Clicks: "+ clicks);
System.out.println("Reached");
}
}
#Override
public void mouseClicked(MouseEvent e) {
clicks += 1;
System.out.println(clicks);
Update = true;
if(Update = true){
Update = false;
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Other picture class
package learning;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImageImplement extends JPanel {
private Image img;
public ImageImplement(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
#Override
public void paintComponent(Graphics g){
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
}
Problem #1
Swing, like most GUI's, is event driven, that is something happens and you respond to it. This makes your program non-linear (the code doesn't progress in a straight line).
Events can happen at any time for a multitude of reasons, depending on the event. This means...
if(Update == true){
Click.setText("Clicks: "+ clicks);
System.out.println("Reached");
}
Will never be true, because the event has not occurred at the time the program interprets this command
Problem #2
To over come this issue, your mouseClicked event handler will need to know about the objects you want to update. Currently, you are declaring your variables within a local scope, within the start method...
public void start(){
//...
ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
//...
JLabel Click = new JLabel("Clicks: " + clicks);
}
You will need to change these so that they are accessible at a class instance level
public class Learning extends JFrame implements MouseListener {
int clicks;
boolean Update;
private ImageImplement panel;
private JLabel Click
public void start(){
//...
//ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
//...
//JLabel Click = new JLabel("Clicks: " + clicks);
Click = new JLabel("Clicks: " + clicks);
}
This will allow you to access these objects from any method within any instance of the current class.
Then, within your mouseClicked handler, you can update the Click label...
#Override
public void mouseClicked(MouseEvent e) {
clicks += 1;
Click.setText("Clicks: "+ clicks);
}
Problem #3
Mouse events are contextual to the component that the MouseListener is registered. This means a few things, but in your case, it's possible that the JLabel and ImageImplement could potentially block block mouse events from reaching the component that the MouseListener is registered to.
Instead, it might be better to add the MouseListener to the ImageImplement instead...
addMouseListener(panel);
Additional
JLabel is capable of displaying images, unless you're playing on doing some kind of image manipulation or graphical effect, it might just be easier to use it instead.
You should be calling super.paintComponent in your ImageImplement's paintComponent before doing any additional painting.
You should avoid using setPreferred/Minimum/MaximumSize and instead, override these methods as you need to achieve your desired results