I have a simple server to client program that lets the server send text to the clients, There is no connection problems. However, I'm not sure what to put the while loop which updates the JLabel of the sent text. If I put while(true) I get an error saying no lines found.
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Client {
private static JLabel l = new JLabel();
public Client() {
JFrame f = new JFrame("Client");
JPanel p = new JPanel(null);
f.setSize(300, 150);
f.setLocationRelativeTo(null);
l.setSize(300, 20);
l.setLocation(0, 65);
p.add(l);
f.add(p);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) throws IOException {
new Client();
Socket socket = new Socket("localhost", 12000);
Scanner in = new Scanner(socket.getInputStream());
while(/* code goes here */) {
l.setText(in.nextLine());
}
}
}
private class PollingThread implements Runnable {
public void run() {
while (true) {
try {
l.setText(in.nextLine());
} catch (/* */) {
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.d(TAG, "Thread interrupted");
}
}
}
Create a private nested class inside Client class.
Initiate the thread from Client class's main() method.
PollingThread mPollingThread = new PollingThread();
mPollingThread.start();
I have a method showMessage() that appends a string onto a JTextArea and i want to call it in my "class in the class" (ServerThread). How can i accomplish this without having Main main; or Main main = new Main();
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
}
}
Example: in the run method i want to have something like main.showMessage(string) without having a Main object declared.
Just declare your method as static
public static void showMessage(final String m)
That way, you can call it like this -
Main.showMessage("Some String");
declare both showMessage method and chatWindow field static. Then you can call as Main.showMessage("whatever") where you want.
But a more elegant solution will be communicating these two singletons over listeners.
Declare an interface MessageListener with a method say onMessage(String message)
interface MessageListener {
public void onMessage(String message);
}
in ServerThread keep a list of MessageListeners and in run method invoke them
class ServerThread extends Thread {
// class content
static List<MessageListener> messageListeners = new ArrayList<>();
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
then make your Main class implementing MessageListener and in onMessage method call showMessage, also do not forget to register ServerThreads listener registry
public class Main extends JFrame implements MessageListener {
// class content
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
// other content
}
// class content
#Override
public void onMessage(String message) {
showMessage(message);
}
}
that's all. then the whole code looks like:
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class Main extends JFrame implements MessageListener {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
#Override
public void onMessage(String message) {
showMessage(message);
}
}
interface MessageListener {
public void onMessage(String message);
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
static List<MessageListener> messageListeners = new ArrayList<>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
Basically I am just writing a socket.
For some reason I keep getting this error though
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Main.ChatClient.main(ChatClient.java:143)
which is line " String server = args[0]; "
What does the args need to be to fix this issue?
package Main;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Observable;
import java.util.Observer;
// Class to manage Client chat Box.
public class ChatClient {
Main a = new Main();
/** Chat client access */
static class ChatAccess extends Observable {
private Socket socket;
private OutputStream outputStream;
#Override
public void notifyObservers(Object arg) {
super.setChanged();
super.notifyObservers(arg);
}
/** Create socket, and receiving thread */
public void InitSocket(String server, int port) throws IOException {
socket = new Socket(server, port);
outputStream = socket.getOutputStream();
Thread receivingThread = new Thread() {
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
notifyObservers(line);
} catch (IOException ex) {
notifyObservers(ex);
}
}
};
receivingThread.start();
}
private static final String CRLF = "\r\n"; // newline
/** Send a line of text */
public void send(String text) {
try {
outputStream.write((text + CRLF).getBytes());
outputStream.flush();
} catch (IOException ex) {
notifyObservers(ex);
}
}
/** Close the socket */
public void close() {
try {
socket.close();
} catch (IOException ex) {
notifyObservers(ex);
}
}
}
/** Chat client UI */
static class ChatFrame extends JFrame implements Observer {
private JTextArea textArea;
private JTextField inputTextField;
private JButton sendButton;
private ChatAccess chatAccess;
public ChatFrame(ChatAccess chatAccess) {
this.chatAccess = chatAccess;
chatAccess.addObserver(this);
buildGUI();
}
/** Builds the user interface */
private void buildGUI() {
textArea = new JTextArea(20, 50);
textArea.setEditable(false);
textArea.setLineWrap(true);
add(new JScrollPane(textArea), BorderLayout.CENTER);
Box box = Box.createHorizontalBox();
add(box, BorderLayout.SOUTH);
inputTextField = new JTextField();
sendButton = new JButton("Send");
box.add(inputTextField);
box.add(sendButton);
// Action for the inputTextField and the goButton
ActionListener sendListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String str = inputTextField.getText();
if (str != null && str.trim().length() > 0)
chatAccess.send(str);
inputTextField.selectAll();
inputTextField.requestFocus();
inputTextField.setText("");
}
};
inputTextField.addActionListener(sendListener);
sendButton.addActionListener(sendListener);
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
chatAccess.close();
}
});
}
/** Updates the UI depending on the Object argument */
public void update(Observable o, Object arg) {
final Object finalArg = arg;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(finalArg.toString());
textArea.append("\n");
}
});
}
}
public static void main(String[] args) {
System.out.println("troll");
String server = args[0];
System.out.println("reached here");
int port =2222;
ChatAccess access = new ChatAccess();
JFrame frame = new ChatFrame(access);
frame.setTitle("MyChatApp - connected to " + server + ":" + port);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
try {
access.InitSocket(server,port);
} catch (IOException ex) {
System.out.println("Cannot connect to " + server + ":" + port);
ex.printStackTrace();
System.exit(0);
}
}
}
Given:
String server = args[0];
I'd suggest you provide the server name as your first argument to your program
With
public static void main(String[] args)
args is the array of command line args passed in.
I am trying to build a Swing solution for compressing files which is relayed on the rar command line. As the GUI needs to stay responsive I've wrapped the code for dealing with the command line into a SwingWorker class.
SwingWorker<Boolean, String> worker = new SwingWorker<Boolean, String>(){
protected Boolean doInBackground() throws Exception {
Runtime rt = Runtime.getRuntime();
try {
//daj processu da ode u background nekako, da ga ne sjebem sa ctrl + c (winrar umesto rar)
String command = "my command, this works just fine";
Process p = rt.exec(command, null, new File("C:\\Program Files\\WinRar"));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String s = null;
System.out.println("<INPUT>");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("</INPUT>");
InputStream stderr = p.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
System.out.println("<ERROR>");
String line = null;
while ( (line = br.readLine()) != null){
System.out.println(line);
return false;
}
System.out.println("</ERROR>");
int exitVal = p.waitFor();
//EXIT VALUE IS ALWAYS 0, EVEN IF I INTERRUPT IT WITH CTRL+C
System.out.println("Process exitValue: " + exitVal);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
return false;
}
return true;
}
#Override
protected void process(List<String> chunks) {
// TODO Auto-generated method stub
//SOME GUI UPDATES
}
#Override
protected void done() {
// TODO Auto-generated method stub
Boolean status = false;
try {
status = get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//MORE GUI UPDATES
if(status){
tableList.setValueAt("Done", row, 3);
} else{
tableList.setValueAt("Error", row, 3);
}
super.done();
}
};
worker.execute();
When I delete printing of input and error, exit value is printed as soon as rar appears on the screen. So there is no actual point of "waitFor()" method in my code. What I need is to check if rar closed without interrupts (like CTRL + C, or hitting "X" on cmd window) and get the exit code. I've tried adding shutdown hook on runtime (rt variable) but it reacts when I close the whole GUI.
You need to get your input and error streams, and read from them each in its own thread. Right now your error stream never has a chance because of the blocking while loop ahead of it.
I've used the following code (although it is years old...):
Enum: GobblerType.java
enum GobblerType {
ERROR, OUTPUT
}
Class StreamGobbler.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
public class StreamGobbler implements Runnable {
private InputStream is;
private GobblerType type;
private OutputStream os;
public StreamGobbler(InputStream is, GobblerType type) {
this(is, type, null);
}
public StreamGobbler(InputStream is, GobblerType type, OutputStream redirect) {
this.is = is;
this.type = type;
this.os = redirect;
}
public void run() {
try {
PrintWriter pw = null;
if (os != null) {
pw = new PrintWriter(os, true);
}
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (pw != null) {
pw.println(line);
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
And then have used it like so:
Process proc = Runtime.getRuntime().exec(.....); // TODO: Fix!
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), GobblerType.ERROR);
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), GobblerType.OUTPUT);
new Thread(errorGobbler).start();
new Thread(outputGobbler).start();
int exitVal = proc.waitFor();
proc.destroy();
OK, I created some code as a proof of concept program. I've modified my Gobbler a bit so that it doesn't require an OutputStream but rather uses a PropertyChangeListener to notify listeners of any text coming from the InputStream. For this to work, all my code is in the same package, and note that package names are key, and you would likely need to change yours. Running this code does behave as expected. It is a bit overly simplistic and probably should use some type of blocking queue for passing information between classes.
GobblerType.java
An enum to distinguish the two type of stream gobblers in use
package pkg2;
public enum GobblerType {
ERROR, OUTPUT
}
StreamGobbler2.java
The stream gobbler that uses an input stream reader to get text from the input stream, puts the text into a text field, and notifies listeners of new text. It uses a PropertyChangeListener for the notification. This is a crude way to producer-consumer, and risks not capturing all passed information. Better would be to use a blocking queue of some sort.
package pkg2;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
public class StreamGobbler2 implements Callable<Void> {
private PropertyChangeSupport support = new PropertyChangeSupport(this);
private InputStream is;
private GobblerType type;
private String text;
public StreamGobbler2(InputStream is, GobblerType type) {
this.is = is;
this.type = type;
}
#Override
public Void call() throws Exception {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
setText(line);
}
return null;
}
public GobblerType getType() {
return type;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
public void setText(String text) {
String oldValue = null;
String newValue = text;
this.text = text;
support.firePropertyChange(type.toString(), oldValue, newValue);
}
public String getText() {
return text;
}
}
ProcessLauncher.java
This is a non-Swing class that captures the information from the two gobblers. Again, better would be to use blocking queues (next iteration)
package pkg2;
import java.beans.PropertyChangeListener;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ProcessLauncher implements Callable<Integer> {
private ExecutorService execService = Executors.newFixedThreadPool(2);
private List<String> commands;
private List<PropertyChangeListener> listeners = new ArrayList<>();
public ProcessLauncher(List<String> commands) {
this.commands = commands;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.add(listener);
}
#Override
public Integer call() throws Exception {
ProcessBuilder pb = new ProcessBuilder(commands);
Process p = pb.start();
int exitValue = 0;
try (InputStream inputStream = p.getInputStream();
InputStream errorStream = p.getErrorStream()) {
StreamGobbler2 errorGobbler = new StreamGobbler2(inputStream, GobblerType.OUTPUT);
StreamGobbler2 outputGobbler = new StreamGobbler2(errorStream, GobblerType.ERROR);
for (PropertyChangeListener listener : listeners) {
errorGobbler.addPropertyChangeListener(listener);
outputGobbler.addPropertyChangeListener(listener);
}
List<Future<Void>> futures = new ArrayList<>();
futures.add(execService.submit(errorGobbler));
futures.add(execService.submit(outputGobbler));
execService.shutdown();
exitValue = p.waitFor();
for (Future<Void> future : futures) {
future.get();
}
}
return exitValue;
}
}
SwingWorkerWrapper.java
Wrapper to use the above class in a Swing fashion
package pkg2;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.SwingWorker;
public class SwingWorkerWrapper extends SwingWorker<Integer, Void> {
private ProcessLauncher processLauncher;
public SwingWorkerWrapper(List<String> commands) {
processLauncher = new ProcessLauncher(commands);
processLauncher.addPropertyChangeListener(new LauncherListener());
}
#Override
protected Integer doInBackground() throws Exception {
return processLauncher.call();
}
private class LauncherListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
}
}
MainGui.java
GUI class that uses the above SwingWorker. Run this class to get the whole show on the road. Once running, press the "Launch Process" button for this program to run the TestProgram in a separate JVM.
package pkg2;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class MainGui extends JPanel {
private static final String[] CMD_TEXT = {"java", "-cp"};
private static final String TEST_PROGRAM = "pkg2.TestProgram";
private JTextArea inputTextArea = new JTextArea(15, 30);
private JTextArea errorTextArea = new JTextArea(15, 30);
private List<String> commands = new ArrayList<>();
public MainGui() {
for (String cmd : CMD_TEXT) {
commands.add(cmd);
}
String classpath = System.getProperty("java.class.path");
commands.add(classpath);
commands.add(TEST_PROGRAM);
inputTextArea.setFocusable(false);
JScrollPane inputScrollPane = new JScrollPane(inputTextArea);
inputScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Border outsideBorder = BorderFactory.createTitledBorder("Input Messages");
Border border = BorderFactory.createCompoundBorder(outsideBorder, inputScrollPane.getBorder());
inputScrollPane.setBorder(border);
errorTextArea.setFocusable(false);
JScrollPane errorScrollPane = new JScrollPane(errorTextArea);
errorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
outsideBorder = BorderFactory.createTitledBorder("Error Messages");
border = BorderFactory.createCompoundBorder(outsideBorder, errorScrollPane.getBorder());
errorScrollPane.setBorder(border);
JPanel twoAreasPanel = new JPanel(new GridLayout(1, 0, 3, 3));
twoAreasPanel.add(inputScrollPane);
twoAreasPanel.add(errorScrollPane);
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 3, 3));
btnPanel.add(new JButton(new LaunchProcessAction()));
btnPanel.add(new JButton(new ExitAction()));
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
setLayout(new BorderLayout(3, 3));
add(twoAreasPanel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
private class SwWrapperListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
SwingWorkerWrapper swW = (SwingWorkerWrapper) evt.getSource();
try {
int exitCode = swW.get();
inputTextArea.append("Exit Code: " + exitCode + "\n");
} catch (InterruptedException e) {
e.printStackTrace();
inputTextArea.append(e.getLocalizedMessage());
inputTextArea.append("\n");
} catch (ExecutionException e) {
e.printStackTrace();
inputTextArea.append(e.getLocalizedMessage());
inputTextArea.append("\n");
}
} else if (GobblerType.OUTPUT.toString().equals(evt.getPropertyName())) {
inputTextArea.append(evt.getNewValue() + "\n");
} else if (GobblerType.ERROR.toString().equals(evt.getPropertyName())) {
errorTextArea.append(evt.getNewValue() + "\n");
}
}
}
private class LaunchProcessAction extends MyAction {
public LaunchProcessAction() {
super("Launch Process", KeyEvent.VK_L);
}
#Override
public void actionPerformed(ActionEvent e) {
SwingWorkerWrapper swWrapper = new SwingWorkerWrapper(commands);
swWrapper.addPropertyChangeListener(new SwWrapperListener());
swWrapper.execute();
}
}
private class ExitAction extends MyAction {
public ExitAction() {
super("Exit", KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private static abstract class MyAction extends AbstractAction {
public MyAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
}
private static void createAndShowGui() {
MainGui mainPanel = new MainGui();
JFrame frame = new JFrame("Main GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
TestProgram.java
Don't run this program directly, but rather have the Main GUI run this. Be sure that this code and all the code is compiled however
package pkg2;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestProgram extends JPanel {
private JTextField textField = new JTextField(20);
private JSpinner exitCodeSpinner = new JSpinner(new SpinnerNumberModel(0, -10, 10, 1));
public TestProgram() {
SendTextAction sendTextAxn = new SendTextAction();
textField.setAction(sendTextAxn);
JPanel panel1 = new JPanel();
panel1.add(textField);
panel1.add(new JButton(sendTextAxn));
JPanel panel2 = new JPanel();
panel2.add(new JLabel("Exit Code:"));
panel2.add(exitCodeSpinner);
panel2.add(new JButton(new ExitCodeAction()));
panel2.add(new JButton(new ThrowExceptionAction()));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(panel1);
add(panel2);
}
private static abstract class MyAction extends AbstractAction {
public MyAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
}
private class SendTextAction extends MyAction {
public SendTextAction() {
super("Send Text", KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
textField.setText("");
System.out.println(text);
}
}
private class ExitCodeAction extends MyAction {
public ExitCodeAction() {
super("Exit Code", KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
int exitCode = (int) exitCodeSpinner.getValue();
System.exit(exitCode);
}
}
private class ThrowExceptionAction extends MyAction {
public ThrowExceptionAction() {
super("Throw Exception", KeyEvent.VK_T);
}
#Override
public void actionPerformed(ActionEvent e) {
// throw some unchecked exception
throw new NumberFormatException("Unchecked exception thrown from within TestProgram");
}
}
private static void createAndShowGui() {
TestProgram mainPanel = new TestProgram();
JFrame frame = new JFrame("Test Program");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
The content in the JFrame WaitingFrame doesn't show up as expected. This is in essence what I am trying to do:
package org.brbcoffee.missinggui;
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main {
public static KeynoteServer server;
public static void main(String[] args){
JFrame frame = new JFrame("SSCCE");
JButton btn = new JButton("Test");
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
connectToPhone();
}
});
frame.add(btn);
frame.pack();
frame.setVisible(true);
}
public static void connectToPhone(){
WaitingFrame wf = new WaitingFrame();
wf.setVisible(true);
server = new KeynoteServer();
if (server.setup()){
System.out.println("Server set up and connected");
} else {
System.out.println("Couldn't connect");
}
wf.dispose();
}
}
#SuppressWarnings("serial")
class WaitingFrame extends JFrame {
public WaitingFrame(){
setTitle("Waiting");
this.setLocationByPlatform(true);
JLabel label = new JLabel("Waiting for client..."); // This will never show
JPanel content = new JPanel();
content.add(label);
this.add(content);
pack();
}
}
class KeynoteServer{
private int port = 55555;
private ServerSocket server;
private Socket clientSocket;
public boolean setup() {
try {
server = new ServerSocket(55555);
server.setSoTimeout(10000);
clientSocket = server.accept();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}
When setup() is called the WaitingFrame does indeed show up, but the contents are missing. I've tried different image formats, but it does work from other methods and classes, so that shouldn't matter. Does anyone know what's going on here?
Use SwingUtilities.invokeLater()/invokeAndWait() to show your frame because all the GUI should be updated from EDT.