Simple Output Prints Twice to JTextArea in Java - java

I was wondering why the JTextArea prints the same line twice. Im using multithreading and im new to this concept. I was wondering if that's where the issue is. As of looking it over I tried seeing if any run methods were called twice to cause such a thing. There aren't any loops in the code either. The line that says "Prints twice?" in the GameThread class is where the issue starts. Thanks for help.
Main Menu Class
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.awt.event.ActionEvent;
public class MainMenu {
private JFrame menu;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainMenu window = new MainMenu();
window.menu.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
* #throws IOException
*/
public MainMenu() throws IOException {
initialize();
}
/**
* Initialize the contents of the frame.
* #throws IOException
*/
private void initialize() throws IOException {
menu = new JFrame();
menu.getContentPane().setBackground(Color.BLACK);
menu.setTitle("Zombie Game");
menu.setBounds(100, 100, 574, 374);
menu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
menu.getContentPane().setLayout(null);
JButton btnPlay = new JButton("Play");
// button action on click
btnPlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
GameScreen enterGame = new GameScreen();
menu.setVisible(false);
enterGame.run();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
JLabel lblNewLabel = new JLabel("Zombie Survival");
lblNewLabel.setFont(new Font("Tahoma", Font.BOLD, 40));
lblNewLabel.setForeground(Color.WHITE);
lblNewLabel.setBounds(118, 34, 381, 73);
menu.getContentPane().add(lblNewLabel);
btnPlay.setBackground(Color.WHITE);
btnPlay.setForeground(Color.RED);
btnPlay.setFont(new Font("Tahoma", Font.BOLD, 17));
btnPlay.setToolTipText("Click to begin.");
btnPlay.setBounds(225, 190, 118, 54);
menu.getContentPane().add(btnPlay);
}
}
Game Board
import java.awt.EventQueue;
import java.io.PrintStream;
import javax.swing.JFrame;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.JTextArea;
import java.awt.Font;
import javax.swing.JScrollPane;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class GameScreen {
private JFrame gameFrm;
/**
* Launch the application.
*/
public void run() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GameScreen window = new GameScreen();
window.gameFrm.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
* #throws InterruptedException
*/
public GameScreen() throws InterruptedException {
initialize();
}
/**
* Initialize the contents of the frame.
* #throws InterruptedException
*/
private void initialize() throws InterruptedException {
gameFrm = new JFrame();
gameFrm.getContentPane().setBackground(Color.BLACK);
gameFrm.getContentPane().setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 478, 718, 134);
gameFrm.getContentPane().add(scrollPane);
JTextArea displayTextArea = new JTextArea();
displayTextArea.setLineWrap(true);
displayTextArea.setWrapStyleWord(true);
displayTextArea.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
}
}
});
scrollPane.setViewportView(displayTextArea);
displayTextArea.setFont(new Font("Monospaced", Font.PLAIN, 18));
displayTextArea.setForeground(Color.WHITE);
displayTextArea.setBackground(Color.BLACK);
PrintStream printStream = new PrintStream(new CustomOutputStream(displayTextArea));
System.setOut(printStream);
JLabel forestPicture = new JLabel("New label");
forestPicture.setIcon(new ImageIcon("C:\\Users\\fstal\\Documents\\Java Programs\\UpdatedZombieGame\\src\\gameForest.jpg"));
forestPicture.setBounds(0, 0, 738, 622);
gameFrm.getContentPane().add(forestPicture);
gameFrm.setBackground(Color.WHITE);
gameFrm.setTitle("Zombie Game");
gameFrm.setBounds(100, 100, 752, 659);
gameFrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Game work
GameThread gThread = new GameThread();
gThread.start();
}
}
Thread Class
public class GameThread extends Thread {
static String [] zombies = {"Zombie", "Fast Zombie", "Big Zombie", "Crawler"};
static String [] bag = {"Assault Rifle", "SMG", "Shotgun", "Sniper"};
static int [] zHealth = {100, 90, 200, 50};
static int [] damage = {90, 80, 100, 200};
static int playerHealth = 50;
public void run() {
try {
System.out.println("Zombies are coming!");
//Thread.sleep(2000);
System.out.println("Prints twice?");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
CustomOutputStream Class for TextArea
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JTextArea;
public class CustomOutputStream extends OutputStream {
private JTextArea displayTextArea;
CustomOutputStream(JTextArea textArea) {
this.displayTextArea = textArea;
}
#Override
public void write(int b) throws IOException {
// redirects data to the text area
displayTextArea.append(String.valueOf((char)b));
// scrolls the text area to the end of data
displayTextArea.setCaretPosition(displayTextArea.getDocument().getLength());
}
}

You're creating two instance of the GameScreen, so your output get's printed twice
When you perform...
btnPlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
GameScreen enterGame = new GameScreen();
menu.setVisible(false);
enterGame.run();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
It calls the GameScreen constructor, which calls initialize()
/**
* Create the application.
*
* #throws InterruptedException
*/
public GameScreen() throws InterruptedException {
initialize();
}
And when you call run, it does it again...
/**
* Launch the application.
*/
public void run() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GameScreen window = new GameScreen();
window.gameFrm.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
You really don't need to do this again in run.
Now that we've discussed that problem, you have a number of other issues.
Firstly, Swing is NOT thread safe and you should never modify the UI (or anything the UI relies on) from outside the context of the Event Dispatching Thread.
See Concurrency in Swing for some more details (and possible solutions)
Second, null layouts are generally a bad idea - it made a mess of your UI on my PC. You should really take the time to learn how to use the various layout managers available in the API - see Laying Out Components Within a Container

Related

Progress Bar value is not updating [duplicate]

I have made a very simple code to show it here, i have a button that should show a JDialog to check the progress status, i am using the invoke late to go through EDT and my loop isn't in the run method, so why isn't my bar updating ?
here is the code
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JBarEx extends JFrame {
private JTextField progStatus = new JTextField("Undefined");
private JButton dialogBtn = new JButton("Show Progression dialog");
final JDialog dlg = new JDialog((JFrame) null, "prog Title", false);
final JProgressBar dpb = new JProgressBar(0, 100);
public JBarEx() {
JPanel pan = new JPanel();
dialogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
showProgress();
}
});
progStatus.setEditable(false);
pan.add(progStatus);
pan.add(dialogBtn);
setContentPane(pan);
this.setSize(200, 100);
setVisible(true);
}
public void showProgress() {
dlg.add(BorderLayout.CENTER, dpb);
dlg.add(BorderLayout.NORTH, new JLabel("prog message"));
dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dlg.setSize(300, 75);
dlg.setLocationRelativeTo(null);
dlg.setVisible(true);
for (int i = 0; i < 100; i++) {
final int ii = i;
try {
Thread.sleep(25);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateBar(ii);
}
});
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void updateBar(int newValue) {
dpb.setValue(newValue);
}
public static void main(String[] args) {
JBarEx jbx = new JBarEx();
}
}
Your showProgress method is being executed within the context of the Event Dispatching Thread. The EDT is responsible for, amongst other things, processing paint requests. This means that so long as your for-loop is executing, the EDT can not process any new paint requests (or handle the invokeLater events either) as it is blocking the EDT.
While there are any number of possible ways to solve the problem, based on your code example, the simplest would be to use a SwingWorker.
It has the capacity to allow your to execute the long running task the a background thread (freeing up the EDT), but also allows you means for publishing updates (if required) so that they can be processed in the EDT and also provides handy progress notification.
For example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class SwingWorkerProgress {
public static void main(String[] args) {
new SwingWorkerProgress();
}
public SwingWorkerProgress() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pbProgress;
private JButton start;
public TestPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
pbProgress = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
add(pbProgress, gbc);
start = new JButton("Start");
gbc.gridy++;
add(start, gbc);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start.setEnabled(false);
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pbProgress.setValue(progress);
repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
start.setEnabled(true);
break;
}
}
}
});
pw.execute();
}
});
}
}
public class ProgressWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
for (int i = 0; i < 100; i++) {
setProgress(i);
try {
Thread.sleep(25);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
}
Check out Concurrency in Swing for more details
Even if you fix the loop as others have pointed out, you'd still block the event dispatch thread. The for loop is run in showProgress() which is called from an event listener. The updates are pushed to the event queue, but that does not get processed until the loop has completed.
Use a Swing Timer instead. Something like this:
Timer timer = new Timer(25, new ActionListener() {
private int position;
#Override
public void actionPerformed(ActionEvent e) {
position++;
if (position < lastPosition) {
updateBar(position);
} else {
((Timer) e.getSource).stop();
}
}
});
timer.start();
where lastPosition would be the state where you want the progress bar to stop.
Unrelated to that bug, but a bug still, you should not create swing components outside the event dispatch thread. It's best to do it right from the start:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JBarEx jbx = new JBarEx();
}
});
}
for (int i = 0; i < 0; i++) {
You will never enter this code so will never call the updateBar(..) method
i needs to be greater than 0 in this case. If it is 1 then updateBar will be called once, if 2 then updateBar will be called twice etc
Also rather than doing
Thread.sleep(25);
take a look at java executors as these will help with your scheduling and remove the need for the sleep

Add a background to a JFrame

I want to add a background to my JFrame, but I can't get it done.
I have searched on the internet to find to some tutorials on it.
I am still a newbie and I want to learn these things.
This is what I have so far.
package gui;
import java.awt.Desktop;
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JLabel BackgroundLabel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Gui frame = new Gui();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Gui() {
setTitle("Exile Launcher");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1000, 563);
contentPane = new JPanel();
contentPane.setBorder(null);
setContentPane(contentPane);
contentPane.setLayout(null);
BufferedImage BackgroundImage = null;
try {
BackgroundImage = ImageIO.read(this.getClass().getResource("/Images/Background.jpg"));
} catch (IOException ex) {
}
JLabel BackgroundLabel = new JLabel(new ImageIcon(BackgroundImage));
add(BackgroundLabel);
JButton HomeButton = new JButton("Home");
HomeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Desktop.getDesktop().browse(new URL("http://www.google.nl").toURI());
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (URISyntaxException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
HomeButton.setBounds(10, 9, 50, 50);
contentPane.add(HomeButton);
JButton ForumButton = new JButton("Vote");
ForumButton.setBounds(10, 70, 50, 50);
contentPane.add(ForumButton);
JButton VoteButton = new JButton("New button");
VoteButton.setBounds(10, 131, 50, 50);
contentPane.add(VoteButton);
}
}
But I get this error:
java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(ImageIO.java:1388)
at gui.Gui.<init>(Gui.java:59)
at gui.Gui$1.run(Gui.java:36)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
UPDATE
I've got it running. First off your using null layout but not specifying the aspects you need to be focusing on. You don't actually create your background image when you just do "add(backgroundLabel);" you need to run backgroundLabel.setBounds(new Rectangle(int x, int y, width, hight); I'm going to give you the entire code. Make sure you have the file path reset to what you need.
Just drop it in, set your path and it should run. You will need to make sure the class name matches whatever your expecting to have but here you go:
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
private final JPanel contentPane;
private JLabel BackgroundLabel;
Image background;
/**
* Launch the application.
*/
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
final Gui frame = new Gui();
frame.setVisible(true);
} catch (final Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Gui() {
this.setTitle("Exile Launcher");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(100, 100, 1000, 563);
this.contentPane = new JPanel();
this.contentPane.setBorder(null);
this.setContentPane(this.contentPane);
this.contentPane.setLayout(null);
try {
this.background = ImageIO.read(new File("src/Images/Background.jpg"));
} catch (final IOException e) {
e.printStackTrace();
}
final JLabel backgroundLabel = new JLabel(new ImageIcon(this.background));
backgroundLabel.setBounds(new Rectangle(0, 0, 1000, 563));
this.add(backgroundLabel);
final JButton HomeButton = new JButton("Home");
HomeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
try {
Desktop.getDesktop().browse(new URL("http://www.google.nl").toURI());
} catch (final MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (final IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (final URISyntaxException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
HomeButton.setBounds(10, 9, 50, 50);
this.contentPane.add(HomeButton);
final JButton ForumButton = new JButton("Vote");
ForumButton.setBounds(10, 70, 50, 50);
this.contentPane.add(ForumButton);
final JButton VoteButton = new JButton("New button");
VoteButton.setBounds(10, 131, 50, 50);
this.contentPane.add(VoteButton);
}
// Final Piece to add an image to the jpanel
public void paintComponent(final Graphics pic) {
this.paintComponent(pic);
pic.drawImage(this.background, 0, 0, null);
}
}
Exception is Self Explanatory
BackgroundImage = ImageIO.read(this.getClass().getResource("/Images/Background.jpg"));
You are passing illegalArgument to read() method of ImageIO class
As JavaDoc syas
public static BufferedImage read(File input)
throws IOException
Returns a BufferedImage as the result of decoding a supplied File with
an ImageReader chosen automatically from among those currently
registered. The File is wrapped in an ImageInputStream. If no
registered ImageReader claims to be able to read the resulting stream,
null is returned.
You need to pass the File Class Object like this :
BackgroundImage = ImageIO.read(new File("C:\\Users\\Ruud\\workspace\\ExileLauncher\\Images\\Background.jpg"));
Note : You need to pass the absolute path of the file where it is located
A suggestion: if you are catching an Exception try to print it so that you may know the root cause.
try {
BackgroundImage = ImageIO.read(this.getClass().getResource("/Images/Background.jpg"));
} catch (IOException ex) {
ex.printStackTrace();// Here printing the stackTrace of Exception
}

What is the best layout in Java for scrolling text?

im trying to do a bar that show some messages and I got a trouble with it, check the image below to see what I have so far:
http://i.stack.imgur.com/xSMtY.png
So, in the top bar, i have a panel made by myself that contains labels, each message is a label and it will roll in the panel, the problem is when the message go out of the screen i want her to go to the end of the queue, but since im using BoxLayout in my made up JPanel i can't do it, in the white bar, i got the same layout and i get the same problem, i dont know how i can keep rooling without break the chain...
(In Java)
If anyone of you can help me i will be glad for it...
Thank you all in advance for your time :)
Edit: as requested i will post some code here:
this is my custom panel code:
package smstest;
import entidades.MensagemParaEcra;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import static java.lang.Thread.sleep;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
*
* #author NEMESIS
*/
public class MyPanel extends JPanel {
private JLabel label;
//private MyPanel panel;
private LinkedList<String> texto;
private LinkedList<MensagemParaEcra> msgs;
private LinkedList<JLabel> labels;
private int x = 0, tamanho;
public MyPanel() {
texto = new LinkedList<>();
msgs = new LinkedList<>();
labels = new LinkedList<>();
//config panel
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.setBackground(Color.black);
Dimension dim = new Dimension(1500, 30);
tamanho = 1500;
this.setPreferredSize(dim);
this.repaint();
this.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {
tamanho = MyPanel.this.getWidth();
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public void componentHidden(ComponentEvent e) {
}
});
// start the scrolling of the labels
start();
}
public void addMensagem(MensagemParaEcra msg) {
labels.add(new JLabel(msg.getTexto() + " -- "));
refresh();
}
public void removerMsg(int id) {
int size = msgs.size();
for (int i = 0; i < size; i++) {
if (msgs.get(i).getId() == id) {
msgs.remove(i);
}
}
refresh();
}
private void refresh() {
int size = labels.size();
labels.get(0).setLocation(0, 0);
for (int i = 0; i < size; i++) {
labels.get(i).setForeground(Color.white);
labels.get(i).setFont(new Font("Tahoma", Font.BOLD, 40));
labels.get(i).setOpaque(true);
labels.get(i).setBackground(Color.red);
MyPanel.this.add(labels.get(i));
// since im using a box layout it's useless but otherwise this
// may add my labels one after the other
if (i > 0) {
int largura = labels.get(i - 1).getWidth();
labels.get(i).setLocation(x + largura, 0);
} else {
labels.get(i).setLocation(x, 0);
}
}
}
private void start() {
final Runnable running = new Runnable() {
#Override
public void run() {
MyPanel.this.repaint();
}
};
Thread t = new Thread() {
public void run() {
while (true) {
for (JLabel lb : labels) {
// make the labels get 3 pixels to the left
lb.setLocation(lb.getLocation().x -3, 0);
}
try {
SwingUtilities.invokeAndWait(running);
sleep(30);
} catch (InterruptedException ex) {
Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
t.start();
}
}
And this is the frame that have the 2 bars for the scrolling text:
package smstest;
import entidades.DadosDaAplicacao;
import entidades.MensagemParaEcra;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import static java.lang.Thread.sleep;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
/**
*
* #author NEMESIS
*/
public final class MonitorDeMensagensFrame extends javax.swing.JFrame {
private static final MonitorDeMensagensFrame instance = new MonitorDeMensagensFrame();
private static Point point = new Point();
private int tamanho = 1500;
private JLabel label;
private JLabel label1;
/**
* Creates new form MonitorDeMensagensFrame
*/
public MonitorDeMensagensFrame() {
initComponents();
MyPanel topPanel = new MyPanel();
// its an undecorated frame so i have the listers to move it
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
point.x = e.getX();
point.y = e.getY();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
Point p = getLocation();
setLocation(p.x + e.getX() - point.x, p.y + e.getY() - point.y);
}
});
// setting the size of the frame
setSize(getRes().width, 73);
setLocation(0, 0);
PanelMsg.repaint();
// create the labels for the below bar
criarPub();
// add messages to the upper bar using a method in MyPanel
// this messages now are made up for tests
topPanel.addMensagem(new MensagemParaEcra(0, "msg 1"));
topPanel.addMensagem(new MensagemParaEcra(1, "msg 2"));
topPanel.addMensagem(new MensagemParaEcra(2, "msg 3"));
topPanel.addMensagem(new MensagemParaEcra(3, "msg 4"));
topPanel.addMensagem(new MensagemParaEcra(4, "msg 5"));
topPanel.addMensagem(new MensagemParaEcra(5, "msg 6"));
topPanel.addMensagem(new MensagemParaEcra(6, "msg 7"));
// start the rolling text on the below bar
startPub();
}
private Dimension getRes() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
// Get the current screen size
Dimension scrnsize = toolkit.getScreenSize();
return scrnsize;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
PanelMsg = new javax.swing.JPanel();
PanelPublicidade = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setUndecorated(true);
getContentPane().setLayout(new java.awt.GridLayout(2, 0));
PanelMsg.setBackground(new java.awt.Color(255, 0, 0));
PanelMsg.setMinimumSize(new java.awt.Dimension(173, 20));
PanelMsg.setLayout(new java.awt.BorderLayout());
getContentPane().add(PanelMsg);
PanelPublicidade.setBackground(new java.awt.Color(102, 255, 102));
PanelPublicidade.setMinimumSize(new java.awt.Dimension(403, 25));
javax.swing.GroupLayout PanelPublicidadeLayout = new javax.swing.GroupLayout(PanelPublicidade);
PanelPublicidade.setLayout(PanelPublicidadeLayout);
PanelPublicidadeLayout.setHorizontalGroup(
PanelPublicidadeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 806, Short.MAX_VALUE)
);
PanelPublicidadeLayout.setVerticalGroup(
PanelPublicidadeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 26, Short.MAX_VALUE)
);
getContentPane().add(PanelPublicidade);
pack();
}// </editor-fold>
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MonitorDeMensagensFrame().setVisible(true);
}
});
}
public static MonitorDeMensagensFrame getInstance() {
return instance;
}
public void criarPub() {
String msg = DadosDaAplicacao.getInstance().getMsgPublicidade();
PanelPublicidade.setLayout(new BoxLayout(PanelPublicidade, BoxLayout.X_AXIS));
PanelPublicidade.setBackground(Color.black);
Dimension dim = new Dimension(1500, 30);
PanelPublicidade.setPreferredSize(dim);
PanelPublicidade.repaint();
PanelPublicidade.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {
tamanho = PanelMsg.getWidth();
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public void componentHidden(ComponentEvent e) {
}
});
label = new JLabel("");
label1 = new JLabel("");
label.setText(msg + " ");
label1.setText(msg + " ");
label.setForeground(Color.black);
label.setFont(new Font("Tahoma", Font.PLAIN, 40));
label.setOpaque(true);
label.setBackground(Color.white);
label1.setForeground(Color.black);
label1.setFont(new Font("Tahoma", Font.PLAIN, 40));
label1.setOpaque(true);
label1.setBackground(Color.white);
PanelPublicidade.add(label);
PanelPublicidade.add(label1);
label.setLocation(PanelPublicidade.getLocation().x, PanelPublicidade.getLocation().y);
label1.setLocation(label.getWidth(), label.getLocation().y);
PanelPublicidade.repaint();
}
public void startPub() {
final int tamanho = label.getWidth();
final Runnable running = new Runnable() {
#Override
public void run() {
PanelPublicidade.repaint();
}
};
Thread t = new Thread() {
#Override
public void run() {
while (true) {
label.setLocation(label.getLocation().x - 3,0);
label1.setLocation(label1.getLocation().x - 3, 0);
// if(label.getLocation().x + tamanho == 0){
// label.setLocation(label1.getLocation().x, 0);
// }
try {
SwingUtilities.invokeAndWait(running);
sleep(28);
} catch (InterruptedException ex) {
Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(MonitorDeMensagensFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
t.start();
}
// Variables declaration - do not modify
private javax.swing.JPanel PanelMsg;
private javax.swing.JPanel PanelPublicidade;
// End of variables declaration
}
There is the code...
Thank you for the help :)

Multithreading program not working

I am trying to make this work. I create a window, with one text field and button, then I run the run() method which should refresh text in textfield, and when I click on button it should iterate number by 1. I want to make this work simultaneously but I am stuck. It just iterates the number but do not refresh a value in textfield.Could you please help me somehow? I thought its easy to learn about Threads but...no :-D Here is the code.
Window class
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class Okno extends JFrame implements ActionListener,Runnable {
private JFrame o = new JFrame();
private static JTextField t = new JTextField();
private JTextField t2 = new JTextField();
private static int x = 0;
protected JButton b = new JButton("KLIK");
Okno() {
o.setVisible(true);
o.setBounds(0, 0, 300, 200);
o.setLayout(null);
o.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.setBounds(10, 10, 60, 20);
t2.setBounds(80, 10, 60, 20);
b.setBounds(50, 80, 60, 30);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
while (true) {
Okno.work();
System.out.println("Klik");
}
}
});
o.add(t);
o.add(b);
o.add(t2);
}
public static int iter(){
x++;
return x;
}
public static void work(){
try {
iter();
System.out.println(x);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void run() {
while(true){
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.setText(Integer.toString(x));
System.out.println("RUN");
}
}
}
Main Class
public class ThreadDemo {
public static void main(String args[]) {
Okno o = new Okno();
while(true){
o.run();
}
}
}
Swing is single threaded. Calling Thread.sleep prevents UI updates. Use a Swing Timer instead.
From GETah's answer to java stopwatch that updates gui every second:
Something along these lines should do it:
import java.awt.EventQueue;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/a/11058263/230513 */
public class Clock {
private Timer timer = new Timer();
private JLabel timeLabel = new JLabel(" ", JLabel.CENTER);
public Clock() {
JFrame f = new JFrame("Seconds");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(timeLabel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.schedule(new UpdateUITask(), 0, 1000);
}
private class UpdateUITask extends TimerTask {
int nSeconds = 0;
#Override
public void run() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
timeLabel.setText(String.valueOf(nSeconds++));
}
});
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final Clock clock = new Clock();
}
});
}
}
The timeLabel will always display the number of seconds the timer
has been running.
You will need to correctly format it to display "hh:mm:ss"; one approach is shown here.
Create a container and add the label to it so that you can display it as part of the GUI.
Compare the result to this alternate using javax.swing.Timer.

Problems with a SwingWorker

I'm trying to get a SwingWorker to work.
I've the following code at the moment:
public class ImageWorker extends SwingWorker<Void, Void> implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch(IOException ex)
{
ex.getMessage();
}
this.execute();
}
#Override
protected Void doInBackground()
{
try
{
while (true)
{
displayImage(basicImage);
Thread.sleep(1000L);
if(isCancelled())
return null;
}
}
catch(InterruptedException e)
{
e.getMessage();
}
return null;
}
private void displayImage(final Icon image)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
imageLabel.setIcon(image);
}
});
}
I was expecting the images to appear in the JLabel, but I only see the JFrame popping up. The files are loaded correctly Ive tested that in another setup.
Any pointers?
Here is an example using a Timer rather than using the SwingWorker which really isn't appropriate to your situation. Note that it's not too different from your existing code.
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class ImageWorker implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
private boolean isBasic = true;
private int delay = 1000; //milliseconds
private Timer timer;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch (IOException ex)
{
ex.getMessage();
ex.printStackTrace();
}
frame.addKeyListener(this);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(isBasic) {
//display basic image
imageLabel.setIcon(basicImage);
}
else {
//display white image
imageLabel.setIcon(whiteImage);
}
//toggle the flag
isBasic = !isBasic;
}
};
//use a timer instead of SwingWorker
timer = new Timer(delay, taskPerformer);
timer.start();
}
#Override
public void keyPressed(KeyEvent e)
{
//key pressed, we want to stop toggling so stop the timer
timer.stop();
//do whatever else you were doing to set the value for isCancelled();
}
#Override
public void keyReleased(KeyEvent e)
{
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e)
{
// TODO Auto-generated method stub
}
}
A SwingWorker is not appropriate for your situation look into a Timer in the swing package. Here is a link to the API: http://download.oracle.com/javase/6/docs/api/javax/swing/Timer.html
You have the timer run and change an image every second since that is what you need.
Also, whenever you have exceptions, print out a stacktrace or the message at least. Otherwise you won't know if an exception occurs and is caught.

Categories