WindowEvent.WINDOW_CLOSING terminates program early - java

I am attempting to use a GUI to write out to a text file. I ran into a problem while doing this, and was able to figure out that the WindowEvent is somehow terminating the program early for some reason.
Initially I had outFile.close(); after the WindowEvent line, so the text from the JTextArea wouldn't be transferred to the text file. After switching a few lines of code around, I realized that when trying to automatically close the JFrame with the WindowEvent, none of the code afterwards executed.
How can I fix this problem?
import ...
public class TxtManager {
static Input input;
public static void overwriteCurrentFile() throws IOException {
TxtManager txt = new TxtManager();
input = new Input(txt);
}
public synchronized void sendData() throws IOException {
try {
BufferedWriter outFile = new BufferedWriter(new FileWriter(file1));
String data = input.textArea.getText();
outFile.write(data);
outFile.close();
input.frame.dispatchEvent(new WindowEvent(input.frame,WindowEvent.WINDOW_CLOSING));
// Code from this point on in the try block does not execute.
System.out.println("Finished with the write out..."); // Used for pinpointing the problem
JOptionPane.showMessageDialog(null,"Data in " + TxtManager.file1 + " has been overwritten successfully.");
TxtManager.showData = true;
TxtManager.menu2();
} catch (Exception ex) {
JOptionPane.showMessageDialog(null,"Error: " + ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
}
}
}
class Input extends Thread {
TxtManager txt;
public JTextArea textArea;
public JFrame frame;
private JButton button;
public Input(TxtManager txt) throws IOException {
this.txt = txt;
JOptionPane.showMessageDialog(null,"Enter desired data into the GUI screen.\n" +
"Press the <Done> button once you are finished.");
frame = new JFrame("Prompt");
JPanel panel = new JPanel(new BorderLayout());
frame.add(panel);
JLabel label = new JLabel("Enter desired data.");
panel.add(label,BorderLayout.NORTH);
textArea = new JTextArea(15,80);
panel.add(textArea,BorderLayout.CENTER);
panel.add(new JScrollPane(textArea));
button = new JButton("Done");
panel.add(button,BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
start();
}
public void run() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
txt.sendData();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null,"Error: " + ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
}
}
});
}
}

I believe your problem stems from this line (assuming input.frame is equivalent to the frame you create here)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
From the API
EXIT_ON_CLOSE (defined in JFrame): Exit the application using the System exit method. Use this only in applications.
What this all means is that when you throw the WindowClosing event, the frame (rightfully) tries to close itself. This in turn calls the default close operation, which happens to be EXIT_ON_CLOSE, which calls System.exit() right there. This ends your program without executing any more lines of code. What you're probably looking for is WindowConstants.DISPOSE_ON_CLOSE instead of Frame.EXIT_ON_CLOSE, which should close the window and dispose its resources without exiting your program.
Although honestly, it might make more sense to just hide your window via Frame.setVisible(false);.That way if you wanted to reuse the frame in the future, there wouldn't be as much overhead starting it up.

Don't close window during method execution. If you want to hide the window, use setVisible(false) instead. Close it after finishing your method

Related

Cant append to JTextArea

I'm trying to create a text chat with Java. I have a Server and a Client that connect to each other using Streams, and send data using the objectInputStream and objectOutputStream.
I have GUI's for both the client and the server.
I made these GUI's using intellij's GUI Form.
server GUI form image
The problem I'm having is when I try to display text to the GUI of the server. I can append to the GUi if I call my relayToAll method from the JTextField actionlistener, which then send the message to all the clients and prints it out in the servers GUI.
If i try to call the same method from where I receive the input, then the append to the text area does not work.
Can anyone tell me why its not appending?
Thanks
public class ServerTest {
private JTextField textField1;
private JTextArea textArea1;
private JPanel Panel;
static private ObjectOutputStream objectOutputStream;
static private ObjectInputStream objectInputStream;
static private Socket client;
static private ArrayList<Socket> clients = new ArrayList<Socket>();
static private ArrayList<ObjectOutputStream> objectOutputStreams = new ArrayList<>();
public void relayToAll(String message){
try {
for(int i = 0; i < clients.size(); i++) {
ObjectOutputStream output = objectOutputStreams.get(i);
output.writeObject(message);
output.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
appendTextArea(message);
}
public void appendTextArea(String text){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
System.out.println("This should go to the Server GUI: " + text);
textArea1.append(text + "\n");
}
});
}
public ServerTest() {
textField1.addActionListener(e -> {
System.out.println(e.getActionCommand());
relayToAll(e.getActionCommand());
textField1.setText("");
});
}
public void ReadInput(ObjectInputStream input, int port){
try {
String oldMessage = "";
while (true) {
String message = (String) input.readObject();
if (message != oldMessage){
System.out.println(port + ": " + message);
oldMessage = message;
relayToAll(port + ": " + message);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void IOSetup(){
try {
ServerSocket serverSocket = new ServerSocket( 6969 );
ExecutorService executor = Executors.newFixedThreadPool(5);
System.out.println("server on\n");
for (int i = 0; i < 5; i++){
client = serverSocket.accept();
clients.add(client);
System.out.println("Connection from: "+ client.getPort());
objectOutputStream = new ObjectOutputStream(client.getOutputStream());
objectOutputStreams.add(objectOutputStream);
objectInputStream = new ObjectInputStream(clients.get(i).getInputStream());
executor.submit(() -> {
ReadInput(objectInputStream, client.getPort());
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Server");
frame.setContentPane(new ServerTest().Panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
ServerTest application = new ServerTest();
application.IOSetup();
}
Actually you've got kind of a silly mistake. Please check lines (A) and (B) below:
public static void main(String[] args) {
JFrame frame = new JFrame("Server");
frame.setContentPane(new ServerTest().Panel); // *************** (A)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
ServerTest application = new ServerTest(); // *************** (B)
application.IOSetup();
}
Do you see a problem? You're creating TWO ServerTest objects, one that has its Panel variable added to the JFrame and that gets displayed, and the other that is set up for IO communication. The ActionListener changes the state of the displayed JTextArea while the IO communications changes the state of a JTextArea that is in the second ServerTest instance, the one not displayed.
One improvement is to create only one instance:
public static void main(String[] args) {
ServerTest application = new ServerTest(); // create one instance
JFrame frame = new JFrame("Server");
// frame.setContentPane(new ServerTest().Panel);
frame.setContentPane(application.Panel); // and use in both places
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//ServerTest application = new ServerTest();
application.IOSetup(); // and use in both places
}
Other problems:
You've got long-running code long running and blocking in a background thread, and that is potentially dangerous, and the only reason that your GUI is not getting frozen is because you're starting the GUI (incorrectly) on the main thread and off of the Swing event thread. For more on this, you will want to read up on Swing concurrency: Lesson: Concurrency in Swing
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.

I want to Print multiple lines of Text using a JTextPane to a window

I've search this question in different wording for the past day or two now and I just can not solve it :/,
I have Window that pops up on the screen that looks like a Command Prompt there is a two buttons Run and Stop. Anyways I have on the screen once you press start it starts "Scanning files" It says "Scanning 1-1900 something" counts up to 1900 and then says Scan completed, after that I want text to go Under the existing Text
and write multiple lines of text to mess with my friend for example.
{
Scan Completed
"wait time inbetween each line of text"
Hack initialized
"wait time inbetween each line of text"
Hack installing...
"wait time inbetween each line of text"
Hack installed
ECT
}
Hopefully someone can Help me, every one I looked at did not work with my code :/
I'm new to code as well so...
thanks in advance anyways here my code its not to long :P.
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("Happy Monday v0.05");
Container contentPane = frame.getContentPane();
JTextPane jta = new JTextPane();
JButton button = new JButton("Run");
JButton buttonstop = new JButton("Stop");
contentPane.add(button);
contentPane.add(buttonstop);
button.setBounds(-1,283,465,40);
buttonstop.setBounds(465,283,469,40);
frame.add(jta).setBackground(Color.black);
console(jta);
//Window
frame.setSize(950, 650 / 16 * 9);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
new SwingWorker<Void, Object>(){
#Override
protected Void doInBackground() throws Exception {
outputTest("Scanning...");
return null;
}}.execute();
}});
}
//Testing OUTPUTS:/
public static void outputTest(String msg){
for(int i=0;i<1969;i++){
System.out.println(i+" "+msg);
try {
Thread.sleep(01);
System.out.println("Scan Complete");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public static void console(final JTextPane area) throws IOException {
area.setContentType("text/html");
final PipedInputStream outPipe = new PipedInputStream();
System.setOut(new PrintStream(new PipedOutputStream(outPipe), true));
new SwingWorker<Void, String>() {
#Override
protected Void doInBackground() throws Exception {
Scanner s = new Scanner(outPipe);
while (s.hasNextLine()){
String line = s.nextLine();
publish(line + "\n");
}
return null;
}
#Override
protected void process(List<String> chunks) {
for (String line : chunks){
area.setText("<font size=\"5\" color=\"green\">"+line+"</font>");
}
}
}.execute();
}
}
The setText method does not appends the line.It overrides the text.So previous text won't be visible.
You have to append text, but have to find an mechanism for that as append method do not exist. In your console method, you can add these:
Document doc = area.getDocument();
Thread.sleep(2000);
doc.insertString(doc.getLength(),"hack installing....\n", null);
Thread.sleep(2000);
doc.insertString(doc.getLength(),"Hack installed...\n", null);
Note:
Calling Thread.sleep() is not recommended directly as you are using multi-threaded environment.It's just for your example haven't scanned your code.
public class NotEditableOutputArea extends JTextPane {
public NotEditableOutputArea() {
setEditable(false);
DefaultCaret caret = (DefaultCaret) getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
Font defaultFont = new Font("monospaced", Font.PLAIN, 12);
setFont(defaultFont);
}
public void appendColorText(String text, Color c) {
StyledDocument doc = getStyledDocument();
Style style = addStyle("Style", null);
StyleConstants.setForeground(style, c);
try {
doc.insertString(doc.getLength(), text, style);
} catch (BadLocationException e) {
}
}
public void setColorText(String text, Color c) {
setText(null);
appendColorText(text, c);
}
}

The program freezes when i put a while loop in a action listener

The program freezes because I put a loop in the action listener for the grandma button.I know why it won't work, but I can't seem to find a way around it. Can anyone tell me away around it.
I'm new to Java, and to practice I'm making a cookie clicker game. If you do not know what cookie clicker is, it is essentially a game where you click a button to get more cookies, and then use cookies to buy more items that automatically produce cookies. In this program, there is a cookie button that works, and a grandma button that should trigger a while loop, that will add a cookie every 5 seconds.
public class conn extends JFrame {
public int cookies;
//public int cps;
public int grandmas;
public int pg;
JButton ck;
JButton bgrandma;
//JTextArea cpslog;
JTextArea Cookies;
//JTextArea amount;
conn() {
super("");
setLayout(new BorderLayout());
JFrame scree = new JFrame();
pg = pg + 10;
ck = new JButton("Cookie");
add(ck, BorderLayout.CENTER);
ck.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
cookies++;
Cookies.setText(null);
Cookies.setEditable(false);
Cookies.append( cookies + " Cookies");
}
});
Cookies = new JTextArea();
add(Cookies, BorderLayout.PAGE_START);
bgrandma = new JButton("Buy a Grandma(" + pg + ")");
add(bgrandma, BorderLayout.WEST);
bgrandma.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(cookies >= pg) {
grandmas++;
//cps++;
//cps++;
cookies = cookies-pg;
Cookies.setText(null);
Cookies.append(cookies + " Cookies");
}
while(grandmas > 0) {
cookies++;
Cookies.setText(null);
Cookies.append(cookies + " Cookies");
try {
Thread.sleep(5000 / grandmas);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
setVisible(true);
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Cookie Clicker");
}
}
In this program, there is a cookie button that works, and a grandma button that should trigger a while loop, that will add a cookie every 5 seconds.::
Don't use a loop in the ActionListener. The loop blocks the Event Dispatch Thread and prevents the GUI from repainting itself.
Instead you should be using a Swing Timer
Read the sections from the Swing Tutorial on:
Concurrency in Swing
How to Use Timers
for more information.
Also, variable names should NOT start with an upper case character. Sometimes your names are correct and sometimes they are not. Be consistent!!!
And get rid of all that blank space. Use proper formatting if you want to post code for people to read. Right now the posted code is a mess to read.

unable to stop stream when i DISPOSE_ON_CLOSE

I am trying to stop the stream when i close the jframe. i do not want to EXIT_ON_CLOSE beacuse i do not want to exit my application. When i use DISPOSE_ON_CLOSE the frame closes but the audiostream keeps on playing. Is there a way to stop this stream without the use of some external button.(i want to close the stream just by clicking "X" on the jframe).
Thank you for help.
public class MediaPlayer {
private JFrame ourFrame = new JFrame();
private EmbeddedMediaPlayerComponent ourMediaPlayer;
private String mediapath = "";
MediaPlayer(String vlcPath,String mediaURL) {
this.mediapath = mediaURL;
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), vlcPath);
ourMediaPlayer = new EmbeddedMediaPlayerComponent();
ourFrame.setContentPane(ourMediaPlayer);
ourFrame.setSize(1200, 800);
ourFrame.setVisible(true);
ourFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public void run() {
ourMediaPlayer.getMediaPlayer().playMedia(mediapath);
}
}
You can handle your stream closing operation on window close, with below:
ouFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
// close/stop audio stream here
System.out.println("closed");
}
});

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