Java JLayeredPane contents flickering on refresh - java

I have a project in NetBeans that uses a layered pane to display overlapping panels by switching between them as necessary. When started, the program displays an intro animation on one of the panels (running on a separate thread), achieved by the following:
public class IntroPanel extends javax.swing.JPanel implements Runnable {
private boolean finished;
private int opacity;
private JLabel[] labels = new JLabel[3];
public IntroPanel() {
initComponents();
labels[0] = jLabel1;
labels[1] = jLabel2;
labels[2] = jLabel3;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
for(JLabel label : labels)
label.setForeground(new Color(200,200,200,opacity));
}
#Override
public void run(){
while (!finished) {
while (opacity < 255) {
try {
Thread.sleep(30);
opacity += 5;
repaint();
} catch (InterruptedException ex) {
Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
repaint();
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
}
while (opacity > 0) {
try {
Thread.sleep(30);
opacity -= 5;
repaint();
} catch (InterruptedException ex) {
Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
}
finished = true;
}
}
The intended effect is to have three JLabels fade in, stay on screen for a moment then fade out. The first two labels contain italics text with a large font size, the third contains small-print. The issues here:
The text of the first two labels appears non-italics while fading in or out, only briefly becoming italics while the labels aren't fading.
The third label (the small-print, non-italics one) doesn't fade at all, instead "shaking" rapidly up and down during the repaint loops.
I read about how it's a better idea to write my own active rendering method instead of using paintComponent() but replacing paintComponent() with the following:
public void render() {
Graphics g = getGraphics();
for(JLabel label : labels)
label.setForeground(new Color(200,200,200,opacity));
g.dispose();
}
does the same flickering. Am I missing something here or looped repaints and layered frames just don't mix?

You should do none of the code in your paintComponent inside of that method. That should be in another region of your program. paintComponent is for painting only, not for setting state.
Your while loops should be replaced by Swing Timer, and this is where the setForground calls should go.
You should post a minimal, complete valid, example, a small program that we can compile run and test. Your code does not allow this.
For example:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class IntroPanel extends JPanel {
private static final int DELAY_TIME = 5;
protected static final Color FG_COLOR = Color.blue;
private List<JLabel> labelList = new ArrayList<JLabel>();
private List<Color> colorList = new ArrayList<>();
public IntroPanel() {
for (int i = 0; i < 255; i++) {
colorList.add(new Color(0, 0, 255, i));
}
for (int i = 0; i < 255; i++) {
colorList.add(new Color(0, 0, 255, 255 - i));
}
setLayout(new GridLayout(0, 1));
JLabel label1 = new JLabel("Label 1");
label1.setFont(label1.getFont().deriveFont(Font.ITALIC, 24));
add(label1);
labelList.add(label1);
JLabel label2 = new JLabel("Label 2");
label2.setFont(label2.getFont().deriveFont(Font.ITALIC, 24));
add(label2);
labelList.add(label2);
JLabel label3 = new JLabel("Label 3");
label3.setFont(label3.getFont().deriveFont(Font.PLAIN, 10));
add(label3);
labelList.add(label3);
new Timer(DELAY_TIME, new ActionListener() {
private int index = 0;
#Override
public void actionPerformed(ActionEvent evt) {
if (index < colorList.size()) {
for (JLabel label : labelList) {
label.setForeground(colorList.get(index));
}
index++;
} else {
((Timer)evt.getSource()).stop();
}
}
}).start();
}
private static void createAndShowGUI() {
IntroPanel paintEg = new IntroPanel();
JFrame frame = new JFrame("IntroPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Related

Why wont this threading code work properly with the GUI? [Java Swing] [Threading]

My project uses Java Swing as a GUI. I am making a Towers of Hanoi game. I've just about got the GUI all working, but my solve command wont work properly.
Without threading calls, it immediately solves the towers as expected. I added a couple Thread.waits expected it to solve it step by step so the user can see how it does but instead, it waits some time, then solves the entire puzzle at once. I'm thinking it might not be repainting, but I'm not sure why. Does anyone know what is going on?
Heres the code for the solve:
public class Solver {
public Solver() {
// nothing
}
public void solve(
int numberBlocks,
int startPin,
int auxiliaryPin,
int endPin) {
if (numberBlocks == 1) {
movePin(startPin, endPin);
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
movePin(startPin, endPin);
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);
}
}
private void movePin(int startPin, int endPin) {
TowersOfHanoiGame.moveTopBlock(startPin, endPin);
}
Here is the code from the GUI that does the work:
I know its terribly written, this is my first time writing with Java Swing, Im learning it as I go. If anyone has any pointers on how to better structure this, I'd love to hear about that also.
I'm pasting the whole class, but the important methods are initListeners, and moveTopBlock, and the methods they call.
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class TowersOfHanoiGame {
private static JFrame mainWindow;
private static JPanel mainContentPanel;
private static JPanel content;
private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
private Color[] randomColors = new Color[8];
private Dimension menuSize = new Dimension(100, 100);
private static final int DISCSTEXTSIZE = 20;
private static final int MOVESTEXTSIZE = 30;
private ActionListener downButtonListener;
private ActionListener upButtonListener;
private ActionListener solveButtonListener;
private JLabel discs;
private JLabel moves;
private int discsNumber = 3;
private int movesNumber = 0;
private Solver solver = new Solver();
public TowersOfHanoiGame() {
// do nothing
initRandomColors();
initBlocks(3);
}
/**
* Initialize and display the game
*/
public void display() {
initListeners();
initWindow();
mainWindow.setVisible(true);
}
private void initListeners() {
downButtonListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (discsNumber > 3) {
discsNumber--;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();
}
}
};
upButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (discsNumber < 8) {
discsNumber++;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();
}
}
};
solveButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
solver.solve(discsNumber, 0, 1, 2);
}
};
}
private void updateLabels() {
discs.setText("DISCS: " + discsNumber);
moves.setText("MOVES: " + movesNumber);
}
/**
* Init the main window
*/
private void initWindow() {
mainWindow = new JFrame("Towers Of Hanoi");
initContentPanel();
mainWindow.setContentPane(mainContentPanel);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(1000, 1000);
mainWindow.setResizable(false);
mainWindow.getContentPane().setBackground(Color.WHITE);
}
/**
* Init the main content panel
*/
private void initContentPanel() {
mainContentPanel = new JPanel(new BorderLayout(50, 50));
JPanel menu = initMenuFrame();
content = initContentFrame();
mainContentPanel.add(menu, BorderLayout.PAGE_START);
mainContentPanel.add(content, BorderLayout.CENTER);
}
private static JPanel initContentFrame() {
JPanel ret = new JPanel(new BorderLayout());
JPanel pegs = new JPanel(new BorderLayout());
pegs.setBackground(Color.WHITE);
ret.setBackground(Color.WHITE);
Peg peg1 = new Peg(25, 500, 1.2);
Peg peg2 = new Peg(50, 500, 1.2);
Peg peg3 = new Peg(0, 500, 1.2);
peg1.addBlocks(pegOneBlocks);
peg2.addBlocks(pegTwoBlocks);
peg3.addBlocks(pegThreeBlocks);
pegs.add(peg1, BorderLayout.LINE_START);
pegs.add(peg2, BorderLayout.CENTER);
pegs.add(peg3, BorderLayout.LINE_END);
ret.add(pegs, BorderLayout.CENTER);
return ret;
}
private Color randomColor() {
int R = (int)(Math.random() * 256);
int G = (int)(Math.random() * 256);
int B = (int)(Math.random() * 256);
Color color = new Color(R, G, B); // random color, but can be bright or
// dull
// to get rainbow, pastel colors
Random random = new Random();
final float hue = random.nextFloat();
final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
color = Color.getHSBColor(hue, saturation, luminance);
return color;
}
private void initRandomColors() {
for (int i = 0; i < 8; i++) {
randomColors[i] = randomColor();
}
}
private void initBlocks(int numBlocks) {
int startWidth = Block.LONGESTWIDTH;
for (int i = 0; i < numBlocks; i++) {
Block b = new Block((startWidth - (i * 15)), randomColors[i]);
pegOneBlocks.add(b);
}
}
private static void clearContentFrame() {
mainContentPanel.remove(content);
mainContentPanel.repaint();
}
private void clearBlockArrays() {
pegOneBlocks.clear();
pegTwoBlocks.clear();
pegThreeBlocks.clear();
}
public static void reDrawContentFrame() {
content = initContentFrame();
mainContentPanel.add(content, BorderLayout.CENTER);
mainContentPanel.repaint();
}
public static void moveTopBlock(int startPin, int destinationPin) {
Block b = null;
if (startPin == 0) {
b = pegOneBlocks.get(pegOneBlocks.size() - 1);
pegOneBlocks.remove(pegOneBlocks.size() - 1);
}
else if (startPin == 1) {
b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
pegTwoBlocks.remove(pegTwoBlocks.size() - 1);
}
else if (startPin == 2) {
b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
pegThreeBlocks.remove(pegThreeBlocks.size() - 1);
}
if (destinationPin == 0) {
pegOneBlocks.add(b);
}
else if (destinationPin == 1) {
pegTwoBlocks.add(b);
}
else if (destinationPin == 2) {
pegThreeBlocks.add(b);
}
reDrawContentFrame();
content.validate();
mainContentPanel.validate();
mainWindow.validate();
}
/**
* Build the menu panel
*
* #return menu panel
*/
private JPanel initMenuFrame() {
JPanel ret = new JPanel(new BorderLayout());
ret.setPreferredSize(menuSize);
// left
JPanel left = new JPanel(new FlowLayout());
left.setPreferredSize(menuSize);
JLabel label = new JLabel("DISCS: 3");
discs = label;
label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
Button down = new Button("Decrease");
down.addActionListener(downButtonListener);
Button up = new Button("Increase");
up.addActionListener(upButtonListener);
left.add(label);
left.add(up);
left.add(down);
// mid
moves = new JLabel("MOVES: 0");
moves.setHorizontalAlignment(JLabel.CENTER);
moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));
// right
JPanel right = new JPanel(new FlowLayout());
Button solve = new Button("Solve");
solve.addActionListener(solveButtonListener);
Button reset = new Button("Reset");
right.add(solve);
right.add(reset);
// sync
JPanel menu = new JPanel(new BorderLayout());
menu.add(left, BorderLayout.LINE_START);
menu.add(moves, BorderLayout.CENTER);
menu.add(right, BorderLayout.LINE_END);
ret.add(menu, BorderLayout.CENTER);
return ret;
}
}
solveButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
solver.solve(discsNumber, 0, 1, 2);
}
};
The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.
What you need to do is start a separate Thread when you invoke the solver.solve(...) method.
Read the section from the Swing tutorial on Concurrency for more information.
Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.

Image switching in swing

My task is to switch two images after capturing mouse click, means when any user clicks on two images both should switch.
but somehow in my code not able to detect the mouse click,
imageAnimal = createImageIcon("Lion", "Lion");
Image scale = imageAnimal.getImage().getScaledInstance(200,200,Image.SCALE_SMOOTH);
imageAnimal = new ImageIcon(scale);
image1Label = new JLabel("", imageAnimal, JLabel.CENTER);
imageMot = createImageIcon("car", "car");
Image scale = imageMot.getImage().getScaledInstance(200,200,Image.SCALE_SMOOTH);
imageMot = new ImageIcon(scale);
image1Label = new JLabel("", imageMot, JLabel.CENTER);
---Code to catch mouse event
public void switch() {
abstract class MouseListener implements ActionListener {
public void actionPerformed(MouseEvent event){
boolean clicked = false;
JPanel imageClicked1;
JPanel imageClicked2 = (JPanel) event.getSource();
int numClicks = 0;
for(int i = 0; i < temp.size(); i++)
{
if(clicked)
{
numClicks++;
imageClicked1 = (JPanel) event.getSource();
if(numClicks == 2)
{
switchImages(imageClicked1, imageClicked2);
}
}
MAINpanel.repaint();
MAINpanel.revalidate();
}
}
public void switchImages(JPanel img1, JPanel img2)
{
//ArrayList<JPanel>sorted = new ArrayList<JPanel>();
JPanel t;
JPanel posValue, nextValue;
for(int i = 0; i < temp.size(); i++)
{
for(int k = 1; k < temp.size(); k++)
{
if(temp.get(i) == img1 && temp.get(k) == img2)
{
posValue = temp.get(k);
nextValue = temp.get(i);
t = temp.get(k);
posValue = temp.get(i);
nextValue = t;
}
}
}
for(int i = 0; i < 5; i++)
{
mainPanel.add(temp.get(i), BorderLayout.CENTER);
}
}
}
}
For better help sooner, post a Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example. See example below.
One way to get image(s) for an example is to hot link to images seen in this Q&A. See example below.
It seems to make no sense to declare and add the mouse listener within the switch method. But maybe an MCVE / SSCCE would make it clear.
MAINpanel.repaint(); Ouch.. Use labels to display the images! On switch, swap their ImageIcon instances. See example below.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.*;
public class ImageSwitch {
private JComponent ui = null;
JLabel label1 = new JLabel();
JLabel label2 = new JLabel();
ImageIcon imageIconA;
ImageIcon imageIconB;
ImageSwitch() {
try {
initUI();
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
private void switchImages() {
if (label1.getIcon().equals(imageIconA)) {
label1.setIcon(imageIconB);
label2.setIcon(imageIconA);
} else {
label1.setIcon(imageIconA);
label2.setIcon(imageIconB);
}
}
public void initUI() throws MalformedURLException {
if (ui!=null) return;
ui = new JPanel(new GridLayout(0,1,2,2));
ui.setBorder(new EmptyBorder(4,4,4,4));
imageIconA = new ImageIcon(new URL("https://i.stack.imgur.com/OVOg3.jpg"));
imageIconB = new ImageIcon(new URL("https://i.stack.imgur.com/lxthA.jpg"));
label1.setIcon(imageIconA);
label2.setIcon(imageIconB);
ui.add(label1);
ui.add(label2);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
switchImages();
}
};
label1.addMouseListener(mouseListener);
label2.addMouseListener(mouseListener);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ImageSwitch o = new ImageSwitch();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}

Why is my thread not working properly in Swing?

I am printing simple value to append JTextArea using simple for loop, and when I run it, it's properly Run if I print value in console output...
But if I append JTextArea and print value in the text area, they are appended all after whole program run.
public class SwingThread {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread window = new SwingThread();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SwingThread() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea();
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
try
{
for(int i = 0 ; i <= 5 ; i++)
{
textArea.append("Value "+i+"\n");
System.out.println("Value is" + i);
Thread.sleep(1000);
}
}
catch(Exception e)
{
System.out.println("Error : "+e);
}
}
});
}
}
I want to append one by one, but it was appended after the whole program runs.
Your problem is with your use of Thread.sleep, since when you call this on the Swing event thread (or EDT for Event Dispatch Thread) as you are doing, it will put the entire Swing event thread to sleep. When this happens the actions of this thread cannot be performed, including painting the GUI (updating it) and interacting with the user, and this will completely freeze your GUI -- not good. The solution in this current situation is to use a Swing Timer as a pseudo-loop. The Timer creates a loop within a background thread and guarantees that all code within its actionPerformed method will be called on the Swing event thread, a necessity here since we don't want to append to the JTextArea off of this thread.
Also as others have noted, if all you want to do is to perform a repeated action with delay in Swing, then yes, use this Swing Timer. If on the other hand you wish to run a long-running bit of code in Swing, then again this code will block the EDT and will freeze your program. For this situation use a background thread such as one supplied by a SwingWorker. Please check out Lesson: Concurrency in Swing for more on this.
e.g.,
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
The whole thing:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;
public class SwingThread2 {
protected static final int MAX_VALUE = 5; // our constant
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread2 window = new SwingThread2();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SwingThread2() {
initialize();
}
private void initialize() {
frame = new JFrame();
// frame.setBounds(100, 100, 450, 300); // avoid this
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea(15, 40);
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
// better to avoid setting sizes but instead to
// let the components size themselves vis pack
frame.pack();
frame.setLocationRelativeTo(null);
}
}
Just for further information, here is an example of the same program above that uses a SwingWorker to perform a long running action, and then update a JProgressBar with this action. The worker is quite simple, and simply uses a while loop to advance a counter variable by a bounded random amount. It then transmits uses this value to update its own progress property (a value that can only be from 0 to 100, and so in other situations, the value will need to be normalized to comply with this). I attach a PropertyChangeListener to the worker, and this is notified on the Swing event thread whenever the worker's progress value changes and also whenever the SwingWorker changes state, such as when it is done operating. In the latter situation, the worker's StateValue becomes StateValue.DONE. The listener then updates the GUI accordingly. Please ask if any questions.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class SwingThread2 {
protected static final int MAX_VALUE = 5; // our constant
private JFrame frame;
private JProgressBar progressBar = new JProgressBar();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread2 window = new SwingThread2();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SwingThread2() {
initialize();
}
private void initialize() {
frame = new JFrame();
// frame.setBounds(100, 100, 450, 300); // avoid this
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea(15, 40);
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant
// int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
progressBar.setStringPainted(true);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
bottomPanel.add(new JButton(new MyAction("Press Me")));
bottomPanel.add(progressBar);
frame.getContentPane().add(bottomPanel, BorderLayout.PAGE_END);
// better to avoid setting sizes but instead to
// let the components size themselves vis pack
frame.pack();
frame.setLocationRelativeTo(null);
}
private class MyAction extends AbstractAction {
public MyAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
public void actionPerformed(ActionEvent e) {
progressBar.setValue(0);
setEnabled(false);
MyWorker myWorker = new MyWorker();
myWorker.addPropertyChangeListener(new WorkerListener(this));
myWorker.execute();
}
}
private class WorkerListener implements PropertyChangeListener {
private Action action;
public WorkerListener(Action myAction) {
this.action = myAction;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
int progress = (int) evt.getNewValue();
progressBar.setValue(progress);
} else if ("state".equals(evt.getPropertyName())) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
action.setEnabled(true);
#SuppressWarnings("rawtypes")
SwingWorker worker = (SwingWorker) evt.getSource();
try {
// always want to call get to trap and act on
// any exceptions that the worker might cause
// do this even though get returns nothing
worker.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
private class MyWorker extends SwingWorker<Void, Void> {
private static final int MULTIPLIER = 80;
private int counter = 0;
private Random random = new Random();
#Override
protected Void doInBackground() throws Exception {
while (counter < 100) {
int increment = random.nextInt(10);
Thread.sleep(increment * MULTIPLIER);
counter += increment;
counter = Math.min(counter, 100);
setProgress(counter);
}
return null;
}
}
}

How to write some 'pause' in method?

Here I have a method
public static Color pickColor(){
final aero.colorpicker.Frame frame = new aero.colorpicker.Frame();
new Thread(new Runnable() {
#Override
public void run() {
while (!frame.isSelected()) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return frame.getColorPicked();
}
isSelected() is flag that makes us know that user CHOOSED the color he want.
The problem is - if I use it like
Color c = pickColor(); in c will write default (black) color of aero.colorpicker.Frame class.
I need pause here, which will wait for select.
package aero.colorpicker;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Aero on 28.12.2014.
*/
public class Frame extends JFrame {
//MAINFIELD
private Color colorPicked = Color.black;
private boolean selected = false;
//GUIFIELDS
private JPanel rightPanel;
private JLabel R;
private JLabel G;
private JLabel B;
private JTextField RData;
private JTextField GData;
private JTextField BData;
private JPanel RPanel;
private JPanel GPanel;
private JPanel BPanel;
private ColorPanel colorPanel;
private JButton pick;
private BufferedImage colors;
private JLabel imageLabel;
public Frame(){
initFrame();
setVisible(true);
}
private void initComponents(){
rightPanel = new JPanel();
R = new JLabel("R");
G = new JLabel("G");
B = new JLabel("B");
RData = new JTextField();
GData = new JTextField();
BData = new JTextField();
RPanel = new JPanel();
GPanel = new JPanel();
BPanel = new JPanel();
colorPanel = new ColorPanel();
pick = new JButton("Pick");
}
private void addListeners(){
RData.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getRed();
colorPanel.repaint();
}
});
GData.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getGreen();
colorPanel.repaint();
}
});
BData.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getBlue();
colorPanel.repaint();
}
});
pick.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getRed();
getBlue();
getGreen();
Frame.this.setVisible(false);
}
});
imageLabel.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
int x, y;
x = e.getX();
y = e.getY();
setColorPicked(new Color(colors.getRGB(x, y)));
colorPanel.repaint();
RData.setText(Integer.toString(getColorPicked().getRed()));
BData.setText(Integer.toString(getColorPicked().getBlue()));
GData.setText(Integer.toString(getColorPicked().getGreen()));
}
});
}
private void getRed(){
int r;
try {
r = Integer.parseInt(RData.getText());
}catch (NumberFormatException nfe){
RData.setText("0");
r = 0;
}
setColorPicked(r, getColorPicked().getGreen(), getColorPicked().getBlue());
}
private void getGreen(){
int g;
try {
g = Integer.parseInt(GData.getText());
}catch (NumberFormatException nfe){
GData.setText("0");
g = 0;
}
setColorPicked(getColorPicked().getRed(), g, getColorPicked().getBlue());
}
private void getBlue(){
int b;
try {
b = Integer.parseInt(BData.getText());
}catch (NumberFormatException nfe){
BData.setText("0");
b = 0;
}
setColorPicked(getColorPicked().getRed(), getColorPicked().getGreen(), b);
}
private void initFrame(){
this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
this.setLayout(new BorderLayout());
this.setSize(369, 194);
this.setTitle("Color picker");
this.setResizable(false);
initComponents();
InputStream input = Frame.class.getClassLoader().getResourceAsStream("colorGradient.jpg");
try {
colors = ImageIO.read(input);
} catch (IOException e) {
e.printStackTrace();
}
imageLabel = new JLabel(new ImageIcon(colors));
this.add(imageLabel, BorderLayout.CENTER);
rightPanel.setLayout(new GridLayout(5, 1));
RPanel.setLayout(new GridLayout(1, 2));
GPanel.setLayout(new GridLayout(1, 2));
BPanel.setLayout(new GridLayout(1, 2));
RPanel.add(R);
RPanel.add(RData);
GPanel.add(G);
GPanel.add(GData);
BPanel.add(B);
BPanel.add(BData);
rightPanel.add(RPanel);
rightPanel.add(GPanel);
rightPanel.add(BPanel);
rightPanel.add(colorPanel);
rightPanel.add(pick);
this.add(rightPanel, BorderLayout.EAST);
this.repaint();
addListeners();
}
public Color getColorPicked() {
return colorPicked;
}
private void setColorPicked(Color colorPicked) {
this.colorPicked = colorPicked;
}
private void setColorPicked(int r, int g, int b){
this.colorPicked = new Color(r, g, b);
}
private void setSelected(){
selected = true;
}
public boolean isSelected(){
return selected;
}
private class ColorPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(colorPicked);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
Your issue here is that your method pickColor creates the thread that waits for a colour to be picked, starts it and then exits. In other words pickColor isn't waiting for the thread to complete. The thread itself does nothing when it does complete.
One solution would be to wait until the thread completes before exiting the method. That would still be poor design, however. It is possible (in fact, likely) that you are calling pickColor within the thread processing UI events (i.e. the dispatch thread) which will make the UI unresponsive. It also uses a unnecessary busy wait.
If this is what you want to do then you'll need to understand how to create a new event queue. You also need to understand how to use semaphores to block the thread. I'll provide the code here but I wouldn't recommend dumping it into your application without understanding what you are doing. This is designed to be a subclass of your dialog class so that the method used to close the dialog can be overwritten to notify the blocked thread.
For the method that shows the colour picking dialog:
public synchronized Color pickColor() {
// code to create and show the dialog
EventQueue tempEventQueue = new EventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(tempEventQueue);
try {
wait();
} catch (InterruptedException ex) {
// stop waiting on interrupt
} finally {
tempEventQueue.pop();
}
// return colour from dialog
}
For the method that is called when the user closes the dialog:
public synchronized void closeChooser() {
notifyAll();
super.closeChooser(); // or whatever it's called
}
The correct solution is to have two methods: one to open the colour pick dialog and then a second which is called when the dialog closes. I don't know what capabilities aero.colorpicker.Frame has but if it doesn't provide this then you could subclass it and override whatever method is called when the user accepts or cancels.

Update JLabel every X seconds from ArrayList<List> - Java

I have a simple Java program that reads in a text file, splits it by " " (spaces), displays the first word, waits 2 seconds, displays the next... etc... I would like to do this in Spring or some other GUI.
Any suggestions on how I can easily update the words with spring? Iterate through my list and somehow use setText();
I am not having any luck. I am using this method to print my words out in the consol and added the JFrame to it... Works great in the consol, but puts out endless jframe. I found most of it online.
private void printWords() {
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel(w.name,SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
I have a window that get's created with JFrame and JLable, however, I would like to have the static text be dynamic instead of loading a new spring window. I would like it to flash a word, disappear, flash a word disappear.
Any suggestions on how to update the JLabel? Something with repaint()? I am drawing a blank.
Thanks!
UPDATE:
With the help from the kind folks below, I have gotten it to print correctly to the console. Here is my Print Method:
private void printWords() {
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
However, it isn't updating the lable? My contructor looks like:
public TimeThis() {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
//_textField.setText("loading...");
}
Getting there... I'll post the fix once I, or whomever assists me, get's it working. Thanks again!
First, build and display your GUI. Once the GUI is displayed, use a javax.swing.Timer to update the GUI every 500 millis:
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListsner() {
private Iterator<Word> it = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (it.hasNext()) {
label.setText(it.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
Never use Thread.sleep(int) inside Swing Code, because it blocks the EDT; more here,
The result of using Thread.sleep(int) is this:
When Thread.sleep(int) ends
Example code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.swing.*;
//http://stackoverflow.com/questions/7943584/update-jlabel-every-x-seconds-from-arraylistlist-java
public class ButtonsIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private Queue<Icon> iconQueue = new LinkedList<Icon>();
private JLabel label = new JLabel();
private Random random = new Random();
private JPanel buttonPanel = new JPanel();
private JPanel labelPanel = new JPanel();
private Timer backTtimer;
private Timer labelTimer;
private JLabel one = new JLabel("one");
private JLabel two = new JLabel("two");
private JLabel three = new JLabel("three");
private final String[] petStrings = {"Bird", "Cat", "Dog",
"Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"};
private boolean runProcess = true;
private int index = 1;
private int index1 = 1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ButtonsIcon t = new ButtonsIcon();
}
});
}
public ButtonsIcon() {
iconQueue.add(UIManager.getIcon("OptionPane.errorIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.informationIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.warningIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.questionIcon"));
one.setFont(new Font("Dialog", Font.BOLD, 24));
one.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
two.setFont(new Font("Dialog", Font.BOLD, 24));
two.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
three.setFont(new Font("Dialog", Font.BOLD, 10));
three.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
labelPanel.setLayout(new GridLayout(0, 3, 4, 4));
labelPanel.add(one);
labelPanel.add(two);
labelPanel.add(three);
//labelPanel.setBorder(new LineBorder(Color.black, 1));
labelPanel.setOpaque(false);
JButton button0 = createButton();
JButton button1 = createButton();
JButton button2 = createButton();
JButton button3 = createButton();
buttonPanel.setLayout(new GridLayout(0, 4, 4, 4));
buttonPanel.add(button0);
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
//buttonPanel.setBorder(new LineBorder(Color.black, 1));
buttonPanel.setOpaque(false);
label.setLayout(new BorderLayout());
label.add(labelPanel, BorderLayout.NORTH);
label.add(buttonPanel, BorderLayout.SOUTH);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
label.setPreferredSize(new Dimension(d.width / 3, d.height / 3));
add(label, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
startBackground();
startLabel2();
new Thread(this).start();
printWords(); // generating freeze Swing GUI durring EDT
}
private JButton createButton() {
JButton button = new JButton();
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setIcon(nextIcon());
button.setRolloverIcon(nextIcon());
button.setPressedIcon(nextIcon());
button.setDisabledIcon(nextIcon());
nextIcon();
return button;
}
private Icon nextIcon() {
Icon icon = iconQueue.peek();
iconQueue.add(iconQueue.remove());
return icon;
}
// Update background at 4/3 Hz
private void startBackground() {
backTtimer = new javax.swing.Timer(750, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private Action updateBackground() {
return new AbstractAction("Background action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
// Update Label two at 2 Hz
private void startLabel2() {
labelTimer = new javax.swing.Timer(500, updateLabel2());
labelTimer.start();
labelTimer.setRepeats(true);
}
private Action updateLabel2() {
return new AbstractAction("Label action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
two.setText(petStrings[index]);
index = (index + 1) % petStrings.length;
}
};
}
// Update lable one at 3 Hz
#Override
public void run() {
while (runProcess) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
one.setText(petStrings[index1]);
index1 = (index1 + 1) % petStrings.length;
}
});
try {
Thread.sleep(300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Note: blocks EDT
private void printWords() {
for (int i = 0; i < petStrings.length; i++) {
String word = petStrings[i].toString();
System.out.println(word);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
three.setText(word);
}
three.setText("<html> Concurency Issues in Swing<br>"
+ " never to use Thread.sleep(int) <br>"
+ " durring EDT, simple to freeze GUI </html>");
}
public BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;
class TimeThis extends JFrame {
private static final long serialVersionUID = 1L;
private ArrayList<Word> words;
private JTextField _textField; // set by timer listener
public TimeThis() throws IOException {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
_textField.setText("loading...");
readFile(); // read file
printWords(); // print results
}
public void readFile(){
try {
BufferedReader in = new BufferedReader(new FileReader("adameve.txt"));
words = new ArrayList<Word>();
int lineNum = 1; // we read first line in start
// delimeters of line in this example only "space"
char [] parse = {' '};
String delims = new String(parse);
String line = in.readLine();
String [] lineWords = line.split(delims);
// split the words and create word object
//System.out.println(lineWords.length);
for (int i = 0; i < lineWords.length; i++) {
Word w = new Word(lineWords[i]);
words.add(w);
}
lineNum++; // pass the next line
line = in.readLine();
in.close();
} catch (IOException e) {
}
}
private void printWords() {
final Timer timer = new Timer(100, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
class Word{
private String name;
public Word(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) throws IOException {
JFrame ani = new TimeThis();
ani.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ani.setVisible(true);
}
}
I got it working with this code... Hope it can help someone else expand on their Java knowledge. Also, if anyone has any recommendations on cleaning this up. Please do so!
You're on the right track, but you're creating the frame's inside the loop, not outside. Here's what it should be like:
private void printWords() {
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel("", SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
textLabel.setTest(w.name);
}
}

Categories