Time shift in updating JavaFX GUI with actual position from Arduino/Grbl - java

I want to show the actual position of a machine controlled with an arduino and installed grbl in JavaFX. Therefore I have a timer in the FXML Controller to send a command (?) every 200 milliseconds via the serial terminal to the arduino/grbl.
FXML Controller
Timer timer = new Timer();
TimerTask updatePos = new TimerTask() {
#Override
public void run() {
grblSender.sendLine("?");
}
};
timer.schedule(updatePos, 200, 200);
Then I have a Listener class to catch the incoming responds from the serial terminal to process them.
GrblListener
class GrblListener implements SerialPortEventListener {
#Override
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR() && event.getEventValue() > 0){
try {
String input = GrblSender.serialPort.readString();
System.out.println(input.trim());
if(input.startsWith("<Idle"))
Main.controller.updateCurrentPosition(input.trim());
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
}
In the FXML controller I want to update textFields for x,y and z position with the method updateCurrentPosition.
FXML Controller
public void updateCurrentPosition(String position){
try{
String[] pos = position.split(":");
try{
String mPos = pos[1];
try{
String[] mPosSplit = mPos.split(",");
textFieldPositionX.setText(mPosSplit[0]);
textFieldPositionY.setText(mPosSplit[1]);
textFieldPositionZ.setText(mPosSplit[2]);
}catch(Exception e){}
}catch(Exception e){}
}catch(Exception e){}
}
The problem is, that the GUI is only updated after a command is finished.
E.g. I send the command: G0 X10
Then the GUI is showing the correct position after the command (X:10, Y:0, Z:0), but not the changing position while the processing of the command.
Output of the console is correct and NOT time shifted:
<Run,MPos:0.008,0.000,0.000,WPos:0.008,0.000,0.000>
ok
<Run,MPos:0.292,0.000,0.000,WPos:0.292,0.000,0.000>
ok
<Run,MPos:0.976,0.000,0.000,WPos:0.976,0.000,0.000>
ok
<Run,MPos:2.068,0.000,0.000,WPos:2.068,0.000,0.000>
ok
<Run,MPos:3.380,0.000,0.000,WPos:3.380,0.000,0.000>
ok
<Run,MPos:4.332,0.000,0.000,WPos:4.332,0.000,0.000>
ok
<Run,MPos:4.876,0.000,0.000,WPos:4.876,0.000,0.000>
ok
<Idle,MPos:5.000,0.000,0.000,WPos:5.000,0.000,0.000>
ok
<Idle,MPos:5.000,0.000,0.000,WPos:5.000,0.000,0.000>
ok
What's the mistake? Should I use threads and when so how?

Related

jPanel doesn't redraw, waiting for server messages

I'm creating a connect four game with sockets: 1 server running and two clients that should connect to play the game. I'm having some troubles with the jPanels that are not updating because of the sockets (I think).
When the game (client) starts, you get a jPanel with input box for the IP address and a submit button. If the submit button is pressed, I want to display a message that the game is being prepared and it's waiting for a second player to join.
submitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!input.getText().equals("")) try {
prefs.put("SavedIp", input.getText());
errorLabel.setText("Preparing game and waiting for other players...");
parentLayout.startGame(input.getText());
} catch (SocketTimeoutException timeout) {
errorLabel.setText("Server timed out.");
} catch (IOException ioeException) {
errorLabel.setText("Server not found!");
} finally {
setTheCursor(Cursor.getDefaultCursor());
}
else errorLabel.setText("Enter an IP adress");
}
});
However in the startGame method, a new GamePanel is created, and in that constructor a new PlayField is created and in that PlayField a new connection is created with sockets.
Once it's connected, it runs a method checkForNextAction to see if it receives a message from the server. It keeps running that method until the server sends a message.
Problem: I don't see the message appear when I press submit. Instead it hangs until a second player joins, and then the server sends a message that the game can start and the gameboard is shown. Can't I just make the message change instantly to the text that I've set? The jPanel probably doesn't update because it's running a method and waiting for a message to come.
I have a similar problem in-game. When a player puts a coin in a column, this move is sent to the server but the coin isn't drawn on the jPanel. Instead it hangs/freezes. The other client makes his move and only then the jPanel of the first client gets updated with the coin from the first move ànd the coin from the other player in the second move. So it seems the move only gets drawn after the other player makes a move.
Does anyone have an idea? I tried to use this.revalidate() and such things but I can't seem to force the jPanel to update before he executes the startGame method.
Your problem is a Swing threading problem, since your code that waits, pauses the Swing event thread, freezing all GUI painting and user interaction. The solution: use a background thread such as a SwingWorker to do the waiting for you. Please check out Concurrency in Swing.
Something like,
submitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!input.getText().equals("")) {
prefs.put("SavedIp", input.getText());
errorLabel.setText("Preparing game and waiting for other players...");
final ParentWorker parentWorker = new ParentWorker(input.getText());
parentWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
setTheCursor(Cursor.getDefaultCursor());
try {
parentWorker.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
// here's where you check for your socket or io exceptions
}
}
}
});
parentWorker.execute();
// parentLayout.startGame(input.getText());
} else {
errorLabel.setText("Enter an IP adress");
}
}
});
and...
class ParentWorker extends SwingWorker<Void, Void> {
private String text;
public ParentWorker(String text) {
this.text = text;
}
#Override
protected Void doInBackground() throws Exception {
parentLayout.startGame(text);
return null;
}
}

How to populate GUI with ethernet data? (Java)

Currently developing a GUI in Java that communicates through Ethernet. It is designed to send data through one port and receive data through the other. The data received is used to populate a dynamic section of the GUI that changes with the data received that unfortunately must also be scaled to fit on the screen. My question is how using Java would I go about populating part of the GUI with a scaled version of the Ethernet data received?
Using swing for the display and awt for the listener. Data is received from java socket. Still unclear on exact way received data is packaged but trying to get a base idea on how to populate the virtual screen. separate thread to populate the screen most likely but also how to actually populate the screen with scaled version.
The GUI is designed to emulate a physical display unit with physical buttons and graphical display (colored words as well as arrows and other graphics, original idea was to just map it pixel for pixel but scaling throws me off).
Here is a snippet of the code, the virtual screen is not populated at the moment, just white outline and the communication port is not opened yet (all McduPanel does is paint static image to the screen, and setKey just sets a String variable based on the button pressed and sends it through the open port):
private McduPanel mPanel;
public McduGui() {
mPanel = new McduPanel();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice vc = env.getDefaultScreenDevice();
JFrame window = new JFrame();
window.addMouseListener(new MouseClickHandler());
window.add(mPanel);
window.setUndecorated(true);
window.setResizable(false);
vc.setFullScreenWindow(window);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
getPorts();
} catch (IOException ex) {
System.out.println(ex);
}
}
public static class MouseClickHandler implements MouseListener {
#Override
public void mousePressed(MouseEvent me) {
int screenX = me.getXOnScreen();
int screenY = me.getYOnScreen();
System.out.println("screen(X,Y) = " + screenX + "," + screenY);
setKey(screenX,screenY);
}
#Override
public void mouseReleased(MouseEvent e) {
}
#OverrideDo
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
public static void getPorts() throws IOException {
String screen = "host"; //host name
String charData = "host"; //host name
int screenPort = 71;//Integer.parseInt(71);
int charPort = 72;//port number
Socket echoSocket = new Socket(screen, 71);
PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
}
To further clarify:
A static image is painted to the screen with Strings mapped to positions on the screen that will send the String associated to that position every time it sees a mouse press. There is a virtual screen within the GUI that will change based on data received from port. It is up in the air what that data will be right now, but by design it is supposed to be the exact same as what physical screen looks like.
Best example I can give is think of a gameboy, the gameboy image is static on the panel, but virtual screen keeps updating based on the data received from the port. That box needs to be refreshed and more than likely scaled from the original size.
OK. I really tried hard to understand your problem. I am still not sure if your problem is painting, threads or reading from a socket, but I made a runnable example. The code is super ugly, but you can execute it as it is. The code create a "test server" which writes to a port every some seconds and a "test client" which reads from this port every some seconds. After the client read some text, it will print it on the screen.
Note that this is just an example - super ugly as I said, but it runs right out of the box. Also not that I strongly recommend to not paint any stuff! Use JButtons to display buttons and JTextFields (or JTextAreas) to display text. Do not print it by painting on the screen!
import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RemoteConsole extends JPanel {
private String text = "Start";
public static void main(String[] args) throws Exception {
// your class is called McduPanel
RemoteConsole remoteConsole = new RemoteConsole();
// JFrame which contains all components
JFrame frame = new JFrame();
frame.setSize(400, 500);
frame.setVisible(true);
frame.getContentPane().add(remoteConsole);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ServerSocket serverSocket = new ServerSocket(4564);
// this is a test server which just writes "test"
// to a port every 1 seconds
new Thread() {
public void run() {
try {
Socket socket = new Socket("localhost", 4564);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
System.out.println("send");
out.println("test");
sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
// a test client which checks the port every 1.5 seconds
// and paints the text to a JPanel
new Thread() {
public void run() {
try {
Socket socket = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String message = in.readLine();
System.out.println("received: " + message);
remoteConsole.appendText(message);
remoteConsole.repaint();
sleep(1500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(text, 75, 100);
}
public void appendText(String text) {
this.text += text;
}
}

JProgressBar not working properly

So my JProgressBar I have set up doesn't work the way I want it. So whenever I run the program it just goes from 0 to 100 instantly. I tried using a ProgressMonitor, a Task, and tried a SwingWorker but nothing I tried works.
Here is my program:
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
jProgressBar2.setValue(progress);
}
});
}
#MadProgrammer Here is my attempt at making a swing worker and writing each name to the document and updating the progress bar. The program gets to around 86 percent and stops, never creating the finished document. The program creates a blank document. Here are the two methods first is the SwingWorker object I made:
public class GreenWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
int max = greenList.size();
XWPFParagraph tmpParagraph;
XWPFRun tmpRun;
FileInputStream file =
new FileInputStream(location + "GreenBandList.docx");
gDocument = new XWPFDocument(OPCPackage.open(file));
for (int i = 0; i < max; i++) {
tmpParagraph = gDocument.getParagraphs().get(0);
tmpRun = tmpParagraph.createRun();
if (greenList.get(i).length() == 1) {
tmpRun.setBold(true);
tmpRun.setText(greenList.get(i));
tmpRun.setBold(false);
} else {
tmpRun.setText(greenList.get(i));//Write the names to the Word Doc
}
int progress = Math.round(((float) i / max) * 100f);
setProgress(progress);
}
return null;
}
}
And here is the code for the button that starts it and has my property change event.
private void GenerateGreenList() throws IOException, InterruptedException {
//Need to fix the bug that removes the Letter Header in Yellow Band list
//********************************************************************\\
//Delete the old list and make a new one
File templateFile = new File(location + "\\backup\\GreenTemplate.docx");
FileUtils.deleteQuietly(new File(location + "GreenBandList.docx"));
FileUtils.copyFile(templateFile, new File(location +
"GreenBandList.docx"));
//Get the New Entries
String[] entries = jTextPane3.getText().split("\n");
for (String s : entries) {
if (s != null) {
greenList.add(s);
}
}
//Resort the list
Collections.sort(greenList);
//Write the names to the document
GreenWorker worker = new GreenWorker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
jProgressBar2.setValue((Integer) evt.getNewValue());
}
}
});
worker.execute();
if (worker.isDone()) {
try {
gDocument.write(new FileOutputStream(new File(location + "GreenBandList.docx")));
////////////////////////////////////////////////////////////
} catch (IOException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
JOptionPane.showMessageDialog(null, "Green Band List Created!");
jProgressBar2.setValue(0);
}
}
I used the property change listener from one of your other posts but I don't really understand what the one you wrote does or what it does in general?
Swing is a single threaded environment, that is, there is a single thread which is responsible for processing all the events that occur within the system, including repaint events. Should anything block this thread for any reason, it will prevent Swing from processing any new events, including, repaint events...
So all this ...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex); }
jProgressBar2.setValue(progress);
}
});
Is constantly pausing the Event Dispatching Thread, preventing it from actually doing any updates (or at least spacing them randomly)...
It's also likely that your outer loop is been run from within the context of the EDT, meaning that until it exists, nothing in the Event Queue will be processed. All your repaint requests will be consolidated down to a single paint request and voila, instant filled progress bar...
You really should use a SwingWorker - I know you said you tried one, but you've not shown any code as to your attempt in this regards, so it's difficult to know why it didn't work, however...
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and dual welding JProgressBar example
SwingWorker and JProgressBar example
And forgive me if we haven't said this a few times before :P
You are evoking Thread.sleep inside the EvokeLater which means that it is running on another thread than your for loop. i.e., your for loop is completing instantaneously (well, however long it takes to loop from 1 to 100, which is almost instantaneously).
Move Thread.sleep outside of EvokeLater and it should work as you intend.
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
jProgressBar2.setValue(progress);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
Edit: agree with #MadProgrammer. It appears this is just an illustrative question, but you should make sure whatever you're trying to accomplish here you use a SwingWorker for.

Java SWT updating canvas from another thread

I'm developing a Java application that does basically:
Starts a server in a new thread. This server opens a socket connection and waits for messages.
Creates a Shell with a Canvas (in the main thread) and whenever server receives a message, I need to draw a line using the points contained in it.
I've already read some threads about this issue (on updating SWT from another thread) and I've tried to create a method called by my server whenever it receives a message:
public static void doPaint(final Canvas canvas, final Draw draw){
if (canvas != null && draw != null){
Display.getDefault().syncExec(new Runnable() {
#Override
public void run() {
canvas.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
System.out.println("Printing line....");
e.gc.setBackground(e.display.getSystemColor(SWT.COLOR_WHITE));
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_BLACK));
e.gc.setLineWidth(3);
e.gc.drawLine((int)draw.getStartX(),(int)draw.getEndX(),(int)draw.getStartY(),(int)draw.getEndY());
}
});
}
});
}
}
EDIT
This is the loop that waits for socket messages and triggers the actions:
while(isConnected()){
try{
System.out.println("Waiting for connection...");
Socket server = getServerSocket().accept();
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream(), Const.ENC_UTF8));
String inputLine;
while(((inputLine = in.readLine()) != null)){
processInput(inputLine, canvas);
}
}catch(IOException ioex){
System.out.println(ioex.getMessage());
ioex.printStackTrace();
}catch (Exception ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
}
}
and my processInput method is:
protected void processInput(String inputLine, Canvas canvas){
//get draw from input stream
Draw draw = DrawUtil.getDrawFromInput(inputLine);
//draw points on live-mode
BBCanvas.doPaint(canvas, draw);
//append draw node to XML file
DrawUtil.writeDrawToFile(draw);
}
... but the runnable in the doPaint method is never executed. Any hints?
EDIT 2
This is the code that creates the main shell:
public MainWindow(BBServer server) {
this.server = server;
Display display = new Display();
this.mainShell = createShell(display);
getMainShell().open();
while (!getMainShell().isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}

Why does calling the main method of a different class not work correctly?

I'm in the process of writing a game. The game plays background music while it is running. This works fine, and I've decided to add a main menu, as their are three types of this game:
Single Player
Two Player
Online
When I run these classes individually (which have their own main methods - obviously), they work perfectly fine. However, in my Welcome Menu class, which is responsible for the main menu (all necessary imports are there, just not shown here):
public class WelcomeMenu implements ActionListener {
public void setButtonBG(JButton button, String imgPath) throws IOException //this method is reponsible for setting images to their corresponding JButton(s)
{
BufferedImage img = ImageIO.read(ClassLoader.getSystemResource(imgPath));
ImageIcon sp = new ImageIcon(img);
button.setIcon(sp);
button.setBorderPainted(false);
}
private JFrame welcomeWindow = new JFrame("Tic-Tac-Toe");
private JButton singlePlayerButton = new JButton();
private JButton twoPlayerButton = new JButton();
private JButton onlineButton = new JButton();
public WelcomeMenu() throws IOException
{
//START OF CONSTRUCTOR
//Main window is being sized, default way to close, and internal layout
welcomeWindow.setSize(600, 420);
welcomeWindow.setLayout(new CardLayout());
//Object res = this.getClass().getResource("/");
//System.out.println(res);
BufferedImage bf = ImageIO.read(ClassLoader.getSystemResource("images/mainMenuBG.jpg"));
welcomeWindow.setContentPane(new backImage(bf)); // adding created component to the JFrame using the backImage class
welcomeWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
welcomeWindow.setLocationRelativeTo(null);
welcomeWindow.setResizable(false);
welcomeWindow.setVisible(true);
//setting the icon
try
{
java.net.URL url = ClassLoader.getSystemResource("images/icon.png");
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
welcomeWindow.setIconImage(img);
}
catch(NullPointerException n)
{
System.out.println("Image could not be fetched.");
}
//adding custom buttons
//ImageIcon singlePlayer = new ImageIcon("images/singlePlayerButton.jpg");
//setting sizes
singlePlayerButton.setSize(387, 72);
twoPlayerButton.setSize(387, 72);
onlineButton.setSize(387, 72);
//setting background images to buttons
setButtonBG(singlePlayerButton, "images/sPlayerButton.jpg");
setButtonBG(twoPlayerButton, "images/tPlayerButton.jpg");
setButtonBG(onlineButton, "images/mPlayerButton.jpg");
//adding listeners
singlePlayerButton.addActionListener(this);
twoPlayerButton.addActionListener(this);
onlineButton.addActionListener(this);
//adding the custom buttons
welcomeWindow.add(singlePlayerButton);
welcomeWindow.add(twoPlayerButton);
welcomeWindow.add(onlineButton);
//setting locations and visibility
singlePlayerButton.setLocation(110, 90);
singlePlayerButton.setVisible(true);
twoPlayerButton.setLocation(110, 182);
twoPlayerButton.setVisible(true);
onlineButton.setLocation(110, 274);
onlineButton.setVisible(true);
//END OF CONSTRUCTOR
}
public static TicTacToeTP spg;
//All actions are done here
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == singlePlayerButton)
{
System.out.println("<LOG> SINGLE PLAYER GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
if(e.getSource() == twoPlayerButton)
{
System.out.println("<LOG> TWO PLAYER GAME REQUESTED");
try
{
//spg = new TicTacToeTP("images/black-squareMod_RED.jpg");
//spg.playBackgroundSong();
TicTacToeTP.main(null);
}
catch(IOException io)
{
System.out.println("IO EXCEPTION!");
}
welcomeWindow.setVisible(false);
welcomeWindow.dispose();
}
if(e.getSource() == onlineButton)
{
System.out.println("<LOG> ONLINE GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
}
public static void main(String[] args) throws IOException
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
{
}
}
});
new WelcomeMenu();
}
}
... if I click the Two Player button, for example, it plays the audio ONLY. None of my other components load. Just an empty JFrame. Notice how in the actionPerformed() method, I tried both TicTacToeTP.main(null) and (commented out, now) instantiating a new TicTacToeTP object AND calling the playBackgroundSong() method. If I eliminate this methods call, and just instantiate the object, it works fine - but no music.
Why is this happening, and how can I fix it?
Here is the playBackgroundSong() method:
private Player p = null;
//private InputStream fis = null;
public void playBackgroundSong() //responsible for playing background music
{
//PausablePlayer p = null;
InputStream fis = null;
ArrayList<InputStream> stream = new ArrayList<InputStream>(); //this ArrayList contains multiple audio files that the method will loop through >> defined below
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Basic space - The XX - Instrumental.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Mirrors [ Upbeat Electronic Instrumental ] Spence Mills HQ Free Beat Download 2012.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Static [ Aggressive Dark Pop Hip Hop Rap Instrumental ] Spence Mills Free Beat Download Link 2012 HD.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 soundtrack Med Sci 1.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 Soundtrack Ops 2.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
Collections.shuffle(stream);
for(int i = 0; i < stream.size(); i++)
{
try
{
fis = stream.get(i);
}
catch (NullPointerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p = new Player(fis);
}
catch (JavaLayerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p.play();
}
catch (JavaLayerException ee)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ee);
}
}
playBackgroundSong();
}
You appear to be playing a long-running bit of code, playBackgroundSong(), on the Swing event dispatch thread or EDT. This thread is responsible for painting the GUI and interacting and responding to user input, and if it gets tied up, the program essentially freezes. This might not have been an issue when you called this method in the main method -- basically off of the Swing event thread, but is an issue when it is specifically called on the event dispatch thread. A possible solution: play your music in a background thread. A SwingWorker might work well for you, and there are decent tutorials on the use of these and the EDT. Google "Concurrency in Swing", and check out what will likely be the first hit for more.
As an aside: you usually don't want to call another class's main method. Instead create an instance of the other class and use it.
Edit You state:
Thanks. Looking at this part: docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html Seems to explain what I want to do, correct? I am reading it all, by the way
Actually you could go even simpler. Since you're not waiting for a result from your playBackgroundSong(), you could possibly just call it in its own simple thread by just wrapping it in a Runnable and then putting that in a Thread:
new Thread(new Runnable() {
public void run() {
playBackgroundSong();
}
}).start();

Categories