Below is my code:
package Project1;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Font;
import javax.swing.JScrollBar;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class DonorChat extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
String get=null;
String s1=null;
DataOutputStream dos;
DataInputStream dis;
JButton btnNewButton;
private JPanel contentPane;
public JTextField textField;
public JTextArea textArea ;
public JButton btnNewButton_1;
public DonorChat() {
setTitle("Donor Chat");
// setIconImage(Toolkit.getDefaultToolkit().getImage("E:\\algorithm\\Project1\\Project1\\Blood.png"));
setIconImage(Toolkit.getDefaultToolkit().getImage("E:\\algorithm\\Project1\\Project1\\Blood.png"));
setForeground(Color.RED);
setFont(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(0, 0, 800, 1000);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
textArea= new JTextArea();
textArea.setFont(new Font("Tahoma", Font.BOLD, 17));
textArea.setBounds(31, 222, 707, 522);
contentPane.add(textArea);
textField = new JTextField();
textField.setFont(new Font("Tahoma", Font.BOLD, 17));
textField.setBounds(31, 793, 510, 105);
contentPane.add(textField);
textField.setColumns(10);
textField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
btnNewButton = new JButton("Send\r\n");
btnNewButton.setFont(new Font("Tahoma", Font.BOLD, 17));
btnNewButton.setForeground(Color.RED);
btnNewButton.setBackground(Color.LIGHT_GRAY);
btnNewButton.setBounds(602, 820, 125, 47);
contentPane.add(btnNewButton);
JScrollBar scrollBar = new JScrollBar();
scrollBar.setBounds(717, 222, 21, 522);
contentPane.add(scrollBar);
btnNewButton_1 = new JButton("CONNECT TO SERVER");
btnNewButton_1.setBackground(Color.RED);
btnNewButton_1.setForeground(Color.DARK_GRAY);
btnNewButton_1.setFont(new Font("Times New Roman", Font.BOLD, 29));
btnNewButton_1.setBounds(31, 60, 707, 86);
contentPane.add(btnNewButton_1);
btnNewButton_1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
try {
ServerSocket ss=new ServerSocket(9995);
Socket snSocket=ss.accept();
dos=new DataOutputStream(snSocket.getOutputStream());
dis=new DataInputStream(snSocket.getInputStream());
getValue();
ss.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
setVisible(true);
}
public void getValue() throws IOException{
btnNewButton.removeActionListener(null);
while(true){
s1=dis.readUTF();
if (s1.equals("stop")){
textArea.setText("Client Want to Stop:"+s1);
break;
}
else{
System.out.println("Client Says:"+s1);
textArea.setText("Client Says:"+s1);
}
System.out.println("Type Something for Client");
btnNewButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0){
try {
dos.writeUTF(get);
}
catch(Exception e){
}
}
});
}
}
}
I am building a window for server which needs a connection button to connect with the server socket, but after setting up the client for that server and after sending client a message, the message is showing on the console for eclipse but not on the textarea which what I actually wants to be
So please help me out by having a look at my code.
Two problems:
while (true)
loop is blocking the AWT event dispatch thread.AWT/Swing is single threaded. When your “CONNECT TO SERVER” button’s ActionListener is called, it is called in the AWT event dispatch thread. No other events will be processed until that method returns.
So when that ActionListener calls getValue()
, and getValue() reads from a socket until "stop"
is encountered, all processing of events is suspended. Nothing gets repainted. There will be no response to mouse or keyboard input, because the MouseEvents and KeyEvents are not processed.
You must perform I/O operations like reading from a socket on a different thread. However, Swing methods must be executed in the AWT event dispatch thread.
One solution is to use the SwingWorker class, whose publish
and process
methods allow you to send multiple data elements from a background thread to the AWT even dispatch thread.
For sending to the socket, you can use a thread-safe BlockingQueue to store the lines to send, then use a loop in a different thread (not the AWT event dispatch thread) to obtain the text from that BlockingQueue and send it to the socket.
The method addActionListener
actually adds a listener to a button. All of the listeners you add will be called when the button is pressed.
So, if you call addActionListener
every time your loop executes, you will have added a listener for each piece of data you read from the socket!
You should only add an ActionListener to a button once—usually right after you have created the button.
So, if we move the I/O to other threads and use a BlockingQueue to keep track of lines to send, it looks something like this:
private final BlockingQueue<String> linesToSend =
new LinkedBlockingDeque<>();
public DonorChat() {
// ...
textField.addActionListener(new ActionListener() {
linesToSend.add(textField.getText());
});
btnNewButton.addActionListener(new ActionListener() {
linesToSend.add(textField.getText());
});
// ...
}
private void getValue(Socket snSocket) {
textArea.setText("");
SwingWorker<Void, String> socketReader =
new SwingWorker<Void, String>() {
@Override
protected Void doInBackground()
throws IOException {
// Runs in another thread.
// No AWT/Swing calls allowed here!
dis = new DataInputStream(snSocket.getInputStream());
while (true) {
String s1 = dis.readUTF();
if (s1.equals("stop")) {
publish("Client wants to stop.");
break;
}
publish("Client says: " + s1);
}
snSocket.close();
return null;
}
@Override
protected void process(List<String> linesRead) {
// Runs in event dispatch thread thread.
// AWT/Swing calls only; no I/O allowed here!
for (String line : linesRead) {
textArea.append(line + "\n");
}
}
};
socketReader.execute();
// Lines to send were added in AWT event dispatch thread
// by ActionListeners.
// We want to send them to the socket in a different thread.
Runnable linesSender = new Runnable() {
@Override
public void run() {
try {
dos = new DataOutputStream(snSocket.getOutputStream());
while (true) {
dos.writeUTF(linesToSend.take());
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(linesSender).start();
}
Some other important notes:
catch
block. Exceptions tell you what went wrong and where, which is very valuable information. If you’re not sure what to put in a catch
block, write e.printStackTrace();
so you can see the full details of the exception.