I'm new to Java and I have this code that I use to connect to a server using sockets
Client Class Code
public class Client {
Socket mysocket;
BufferedReader inFromServer;
DataOutputStream outToServer;
public Socket connect(String nameServer, int portServer) {
try
{
mysocket=new Socket(nameServer, portServer);
outToServer=new DataOutputStream(mysocket.getOutputStream());
inFromServer=new BufferedReader(new InputStreamReader(mysocket.getInputStream()));
}
catch(UnknownHostException e)
{
System.err.println("Host error"); // Display Error
}
catch(Exception e)
{
System.out.print(e.getMessage());
System.out.print("Connection Error!"); // Display Error
System.exit(1);
}
return mysocket;
}
GUI Code
package Client;
import java.awt.EventQueue;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.SystemColor;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextPane;
public class WindowClient {
private JFrame frmSocketConnection;
private JTextField TxtIP;
private JTextField TxtPort;
private JTextField TxtInput;
Client client = new Client();
public static boolean isNumeric(String strNum) {
if (strNum == null) {
return false;
}
try {
double d = Double.parseDouble(strNum);
} catch (NumberFormatException nfe) {
return false;
}
return true;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
WindowClient window = new WindowClient();
window.frmSocketConnection.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public WindowClient() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frmSocketConnection = new JFrame();
frmSocketConnection.setTitle("Socket Connection");
frmSocketConnection.getContentPane().setBackground(Color.WHITE);
frmSocketConnection.setBounds(100, 100, 983, 633);
frmSocketConnection.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmSocketConnection.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
panel.setBounds(725, 0, 244, 596);
frmSocketConnection.getContentPane().add(panel);
panel.setLayout(null);
TxtIP = new JTextField();
TxtIP.setFont(new Font("Tahoma", Font.PLAIN, 16));
TxtIP.setBounds(10, 89, 224, 34);
panel.add(TxtIP);
TxtIP.setColumns(10);
JLabel lblIP = new JLabel("IP Address");
lblIP.setFont(new Font("Tahoma", Font.BOLD, 18));
lblIP.setHorizontalAlignment(SwingConstants.CENTER);
lblIP.setBounds(10, 45, 224, 34);
panel.add(lblIP);
TxtPort = new JTextField();
TxtPort.setFont(new Font("Tahoma", Font.PLAIN, 16));
TxtPort.setColumns(10);
TxtPort.setBounds(10, 216, 224, 34);
panel.add(TxtPort);
JLabel lblPort = new JLabel("IP Port");
lblPort.setHorizontalAlignment(SwingConstants.CENTER);
lblPort.setFont(new Font("Tahoma", Font.BOLD, 18));
lblPort.setBounds(10, 172, 224, 34);
panel.add(lblPort);
JButton btnConnect = new JButton("Connect");
btnConnect.setFocusPainted(false);
btnConnect.setBackground(SystemColor.controlHighlight);
btnConnect.setFont(new Font("Tahoma", Font.BOLD, 18));
btnConnect.setBounds(34, 317, 176, 48);
panel.add(btnConnect);
JButton btnDisconnect = new JButton("Disconnect");
btnDisconnect.setFocusPainted(false);
btnDisconnect.setEnabled(false);
btnDisconnect.setFont(new Font("Tahoma", Font.BOLD, 18));
btnDisconnect.setBackground(SystemColor.controlHighlight);
btnDisconnect.setBounds(34, 396, 176, 48);
panel.add(btnDisconnect);
TxtInput = new JTextField();
TxtInput.setFont(new Font("Tahoma", Font.PLAIN, 16));
TxtInput.setForeground(Color.WHITE);
TxtInput.setBackground(Color.DARK_GRAY);
TxtInput.setBounds(10, 547, 617, 39);
frmSocketConnection.getContentPane().add(TxtInput);
TxtInput.setColumns(10);
JButton btnEnter = new JButton("Enter");
btnEnter.setFocusPainted(false);
btnEnter.setBackground(SystemColor.controlHighlight);
btnEnter.setFont(new Font("Tahoma", Font.PLAIN, 18));
btnEnter.setBounds(623, 547, 92, 39);
frmSocketConnection.getContentPane().add(btnEnter);
JTextPane TxtConsole = new JTextPane();
StyledDocument doc = TxtConsole.getStyledDocument();
Style style = TxtConsole.addStyle("Stile", null);
TxtConsole.setFont(new Font("Monospaced", Font.PLAIN, 16));
TxtConsole.setForeground(Color.WHITE);
TxtConsole.setBackground(Color.DARK_GRAY);
TxtConsole.setBounds(10, 10, 705, 525);
frmSocketConnection.getContentPane().add(TxtConsole);
btnConnect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btnConnect.setEnabled(false);
btnDisconnect.setEnabled(true);
if (TxtIP.getText().length() == 0 || TxtPort.getText().length() == 0) {
StyleConstants.setForeground(style, Color.red);
try {
doc.insertString(doc.getLength(), "Error. One field is empty! \n",style);
btnConnect.setEnabled(true);
btnDisconnect.setEnabled(false);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
else if (!isNumeric(TxtPort.getText())) {
StyleConstants.setForeground(style, Color.red);
try {
doc.insertString(doc.getLength(), "The port field has to be a number! \n",style);
btnConnect.setEnabled(true);
btnDisconnect.setEnabled(false);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
else {
StyleConstants.setForeground(style, Color.white);
try {
doc.insertString(doc.getLength(), "Connection... \n",style);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
});
TxtInput.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TxtInput.setText("");
}
});
btnEnter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnDisconnect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
TxtIP.setText("");
TxtPort.setText("");
}
});
}
}
and I have a GUI in another class. In that class I have a JTextPane that I want to use as a "console" that display anything
This is an image of the GUI that i have at the moment
I want to display the error strings from the Client class into the JTextPane that it's in another class and I don't really know how to do it
There are many ways to communicate between data and ensure to pass it.
You can choose to throw the error/exception from Client class and ensure to catch it and put that error into the JTextPane
I could simply try this out:
public static class Client {
Socket mysocket;
BufferedReader inFromServer;
DataOutputStream outToServer;
public Socket connect(String nameServer, int portServer) throws Exception {
try
{
mysocket=new Socket(nameServer, portServer);
outToServer=new DataOutputStream(mysocket.getOutputStream());
inFromServer=new BufferedReader(new InputStreamReader(mysocket.getInputStream()));
}
catch(UnknownHostException e)
{
throw new Exception("Unknown Host Error: " + e.getMessage());
}
catch(Exception e)
{
System.out.print("Connection Error!"); // Display Error
throw new Exception("Connection Error! " + e.getMessage());
}
return mysocket;
}
}
A very simple version would be:
Client c = new Client();
String errorMessage = "";
try {
c.connect("localhost", 8010);
} catch (Exception e) {
errorMessage = e.getMessage();
}
JTextPane pane = new JTextPane();
SimpleAttributeSet attributeSet = new SimpleAttributeSet();
StyleConstants.setBold(attributeSet, true);
// Set the attributes before adding text
pane.setCharacterAttributes(attributeSet, true);
// A very simple version of that errorMessage for illustrations only
pane.setText(errorMessage == null ? "Welcome" : errorMessage);
In your case, if you are connecting on a button action, then:
btnConnect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btnConnect.setEnabled(false);
btnDisconnect.setEnabled(true);
// if-else
// ...
else {
StyleConstants.setForeground(style, Color.white);
try {
Client c = new Client();
String errorMessage = "";
try {
c.connect("localhost", 8010);
doc.insertString(doc.getLength(), "Connecting...", style);
} catch (Exception e) {
// Setting the error Message
doc.insertString(doc.getLength(), e.getMessage(), style);
}
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
});
Related
I am a first-year programming student and I was tasked to make a Login and Register program using Java Swing (Application Window) and BufferedReader+Writer. I am now able to write a username and password into a text file via BWriter, however I have no idea how to make the Login read the text file and only Login when the inputted username and password in their respected TextField matches the one I wrote into the text file. (For reference the text file looks like this after I wrote the supposed username and password from the Register portion: Redman, 1234)
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.awt.event.ActionEvent;
public class Register {
private JFrame frame;
private JTextField tfNewUser;
private JTextField tfNewPass;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Register window = new Register();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Register() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setTitle("Register");
frame.setBounds(100, 100, 286, 324);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JLabel lblNewLabel = new JLabel("REGISTER ");
lblNewLabel.setBounds(10, 11, 250, 26);
lblNewLabel.setFont(new Font("Tahoma", Font.BOLD, 12));
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(lblNewLabel);
tfNewUser = new JTextField();
tfNewUser.setBounds(117, 48, 143, 20);
frame.getContentPane().add(tfNewUser);
tfNewUser.setColumns(10);
tfNewPass = new JTextField();
tfNewPass.setBounds(117, 79, 143, 20);
tfNewPass.setColumns(10);
frame.getContentPane().add(tfNewPass);
JButton btnReg = new JButton("REGISTER");
btnReg.setBounds(10, 110, 250, 23);
btnReg.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String regUser = tfNewUser.getText().toString();
String regPass = tfNewPass.getText().toString();
addReg(regUser, regPass);
}
});
frame.getContentPane().add(btnReg);
JButton btnUpdate = new JButton("UPDATE CREDENTIALS");
btnUpdate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
UpdateCreds newformu = new UpdateCreds();
newformu.main(null);
frame.setVisible(false);
}
});
btnUpdate.setBounds(10, 213, 250, 23);
frame.getContentPane().add(btnUpdate);
JButton btnReturn = new JButton("RETURN TO LOGIN");
btnReturn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Login newform = new Login();
newform.main(null);
frame.setVisible(false);
}
});
btnReturn.setBounds(10, 142, 250, 23);
frame.getContentPane().add(btnReturn);
JLabel lblNewLabel_1 = new JLabel("New Username: ");
lblNewLabel_1.setBounds(10, 48, 97, 14);
frame.getContentPane().add(lblNewLabel_1);
JLabel lblNewLabel_1_1 = new JLabel("New Password: ");
lblNewLabel_1_1.setBounds(10, 82, 97, 14);
frame.getContentPane().add(lblNewLabel_1_1);
JButton btnDeleteAcc = new JButton("DELETE ACCOUNT");
btnDeleteAcc.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
deleteAcc();
}
});
btnDeleteAcc.setBounds(10, 247, 250, 23);
frame.getContentPane().add(btnDeleteAcc);
JLabel lblAccountSettings = new JLabel("ACCOUNT SETTINGS");
lblAccountSettings.setBounds(10, 176, 250, 26);
lblAccountSettings.setHorizontalAlignment(SwingConstants.CENTER);
lblAccountSettings.setFont(new Font("Tahoma", Font.BOLD, 12));
frame.getContentPane().add(lblAccountSettings);
}
public void errorPane (String msg, String status) {
JOptionPane.showMessageDialog(frame, msg, status, JOptionPane.ERROR_MESSAGE);
}
public void succMess (String smsg, String status2) {
JOptionPane.showMessageDialog(frame, smsg, status2, JOptionPane.INFORMATION_MESSAGE);
}
public void clearTF() {
tfNewUser.setText("");
tfNewPass.setText("");
}
public void addReg(String regUser, String regPass) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("Creds", true));
bw.write(regUser+", "+regPass);
bw.flush();
bw.newLine();
bw.close();
succMess ("Account registered!", "SUCCESS");
clearTF();
}
catch (Exception e) {
errorPane("There is a problem with the data. Please input new data.", "ERROR" );
}
}
public void deleteAcc() {
try {
String record;
String regUser = tfNewUser.getText().toString();
File tempCred = new File("Creds_temp");
File cred = new File ("Creds");
BufferedReader br = new BufferedReader(new FileReader(cred));
BufferedWriter bw = new BufferedWriter(new FileWriter(tempCred));
while((record = br.readLine())!=null) {
if(record.contains(regUser))
continue;
bw.write(record);
bw.flush();
bw.newLine();
}
br.close();
bw.close();
cred.delete();
tempCred.renameTo(cred);
succMess ("Account Deleted!", "SUCCESS");
}
catch (Exception e) {
errorPane("Cannot find account. Please register an account first.", "ERROR" );
}
}
}
So assuming that the login file only deals with the authentication...
Read the .txt file line by line (I'm using Java Scanner for convenience, but you could use FileReader or anything else as well)
Split each line by comma delimiters and store the data in a hash map
Compare whether the user input matches one
In Login.java:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.HashMap;
public class Login {
private HashMap<String, String> userData = new HashMap<String, String>();
private String name;
private String password;
void readFile() {
try {
// read file
File file = new File("passwords.txt"); // replace with file name!!
Scanner reader = new Scanner(file);
// loop through each line inside the file being read
while (reader.hasNextLine()) {
String str = reader.nextLine();
String[] user = str.split(", "); // user[0] = anything before ", " and user[1] = anything after ", "
userData.put(user[0], user[1]); // store username and password
}
reader.close(); // remember to close the reader
} catch (FileNotFoundException e) {
System.out.println("Something happened...");
e.printStackTrace();
}
}
public boolean loggedIn() {
return password.equals(userData.get(name));
}
// constructor to execute on instance creation
public Login(String name, String password) {
// initialize data
this.name = name;
this.password = password;
readFile();
}
}
And pretend your user data file (passwords.txt) looks something like:
Redman, 1234
Bob, $up3r-$ecur3
Rob, pls don't hack
Using the class is pretty easy:
Login attempt = new Login(username, password); // replace with requested variables as string
boolean success = attempt.loggedIn();
if(success) {
// logged in successfully
} else {
// incorrect username or password!
}
Working (only login) example.
Hope that helps you get somewhere.
I'm starting with Socket Server in Java. I've written already simple app where I can send text between hosts. I'm sending with my message name of the host which is sending and here is my problem, how can I get host message?
Can someone just change my code to show host name instead of message?
Here is the code:
public class FMain extends JFrame {
private JPanel contentPane = null;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
FMain frame = new FMain();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public FMain() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 508, 321);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
PReceiver receiver = new PReceiver();
receiver.setBorder(new LineBorder(new Color(0, 0, 0)));
receiver.setBounds(35, 13, 423, 106);
contentPane.add(receiver);
PSender sender = new PSender((String) null, 0);
sender.setBorder(new LineBorder(new Color(0, 0, 0)));
sender.setBounds(35, 132, 423, 129);
contentPane.add(sender);
}
}
And the class which is receiving:
interface MyListener {
void messageReceived(String theLine);
}
class Receiver {
private List < MyListener > ml = new ArrayList < MyListener > ();
private Thread t = null;
private int port = 0;
private ServerSocket s = null;
private boolean end = false;
public void stop() {
t.interrupt();
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() {
end = false;
t = new Thread(new Runnable() {
#Override
public void run() {
try {
s = new ServerSocket(port);
while (true) {
Socket sc = s.accept();
InputStream is = sc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String theLine = br.readLine();
ml.forEach((item) - > item.messageReceived(theLine));
sc.close();
}
} catch (SocketException e) {} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.start();
}
public void addMyListener(MyListener m) {
ml.add(m);
}
public void removeMyListener(MyListener m) {
ml.remove(m);
}
Receiver(int port) {
this.port = port;
}
}
public class PReceiver extends JPanel implements MyListener {
private JTextField txtPort;
private Receiver r = null;
private JTextField txtMessage;
/**
* Create the panel.
*/
public PReceiver() {
setLayout(null);
txtPort = new JTextField();
txtPort.setBounds(282, 13, 62, 22);
add(txtPort);
// txtPort.setColumns(10);
JLabel lblPort = new JLabel("port:");
lblPort.setBounds(241, 16, 35, 16);
add(lblPort);
JToggleButton btnListen = new JToggleButton("Listen");
btnListen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (btnListen.isSelected()) {
r = new Receiver(Integer.parseInt(txtPort.getText()));
r.addMyListener(PReceiver.this);
r.start();
} else {
r.stop();
}
}
});
btnListen.setBounds(265, 70, 79, 25);
add(btnListen);
JLabel lblMessage = new JLabel("message");
lblMessage.setBounds(12, 51, 56, 16);
add(lblMessage);
txtMessage = new JTextField();
txtMessage.setBounds(12, 71, 220, 22);
add(txtMessage);
//txtMessage.setColumns(10);
}
#Override
public void messageReceived(String theLine) {
txtMessage.setText(theLine);
}
}
And the sender class:
class Sender {
public void send(String message, String host, int port) {
Socket s;
try {
s = new Socket(host, port);
OutputStream out = s.getOutputStream();
PrintWriter pw = new PrintWriter(out, false);
pw.println(message);
pw.flush();
pw.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class PSender extends JPanel {
private JTextField txtMessage;
private JTextField txtHost;
private JTextField txtPort;
private JLabel lblMessage;
/**
* Create the panel.
*/
public PSender(String host, int port) {
setLayout(null);
txtMessage = new JTextField();
txtMessage.setBounds(12, 77, 216, 22);
add(txtMessage);
//txtMessage.setColumns(10);
JButton btnSend = new JButton("Send");
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
new Sender().send(txtMessage.getText(), txtHost.getText(), Integer.parseInt(txtPort.getText()));
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
});
btnSend.setBounds(268, 76, 78, 25);
add(btnSend);
txtHost = new JTextField();
txtHost.setBounds(51, 13, 149, 22);
add(txtHost);
//txtHost.setColumns(10);
txtPort = new JTextField();
txtPort.setBounds(268, 13, 78, 22);
add(txtPort);
//txtPort.setColumns(10);
JLabel lblHost = new JLabel("host:");
lblHost.setBounds(12, 16, 35, 16);
add(lblHost);
JLabel lblPort = new JLabel("port:");
lblPort.setBounds(231, 16, 35, 16);
add(lblPort);
lblMessage = new JLabel("message");
lblMessage.setBounds(12, 58, 56, 16);
add(lblMessage);
}
}
So here is my GUI as you can see.
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Frame1 {
private JFrame frame;
private JTextField textFieldnum1;
private JTextField textFieldnum2;
private JTextField textFieldAns;
private Termostat thermo;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Frame1 window = new Frame1();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Frame1() {
initialize();
}
private void initialize() {
thermo = new Termostat();
frame = new JFrame();
frame.setBounds(100, 100, 696, 250);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
textFieldnum1 = new JTextField();
textFieldnum1.setBounds(176, 11, 147, 46);
frame.getContentPane().add(textFieldnum1);
textFieldnum1.setColumns(10);
textFieldnum2 = new JTextField();
textFieldnum2.setBounds(176, 154, 147, 46);
frame.getContentPane().add(textFieldnum2);
textFieldnum2.setColumns(10);
JButton btnNewButton = new JButton("Convert to celcius");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
double myf = thermo.convertToCelcius(Double.parseDouble(textFieldnum1.getText()));
textFieldAns.setText(String.valueOf(myf));
}
});
btnNewButton.setBounds(0, 0, 171, 68);
frame.getContentPane().add(btnNewButton);
JButton btnNewButton_1 = new JButton("Convert to fahrenheit");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
textFieldAns.setText(String.valueOf(myf));
}
});
btnNewButton_1.setBounds(0, 143, 171, 68);
frame.getContentPane().add(btnNewButton_1);
textFieldAns = new JTextField();
textFieldAns.setBounds(354, 90, 147, 46);
frame.getContentPane().add(textFieldAns);
textFieldAns.setColumns(10);
JLabel lblNewLabel = new JLabel("Converted");
lblNewLabel.setBounds(285, 94, 112, 38);
frame.getContentPane().add(lblNewLabel);
}
}
And here comes my problem. When i made my class that i wanna run the input in to calculate celcius to fahrenheit, i dont want it to crash when i type anything else than numbers. but i cant get it to work so i need you guys help to get the try catch to work.
Im very thankful for all help i get.
import javax.swing.JOptionPane;
public class Termostat {
public double convertToCelcius(double input) {
double far = 0;
try {
far = (input - 32) * 5 / 9;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Wrong input");
return far;
}
return far;
}
public double convertToFahrenheit(double input) {
double cel = 1;
try {
cel = (input * 9 / 5) + 32;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Wrong input");
return cel;
}
return cel;
}
}
This is the line where you get probably an Exception:
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
So guard it with a NumberFormatException (parseDouble).
You can use the NumberUtil.isNumber(str) to check if the input is a number. Here is more information
you must use try catch when you want to parse text field texts to Double using this method Double.parseDouble(text)
write them them like this and remove your try catches inside your convertToFahrenheit and convertToCelcius methods
JButton btnNewButton_1 = new JButton("Convert to fahrenheit");
btnNewButton_1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
try { // start trying to parse input string to double
double myf = thermo.convertToFahrenheit(Double.parseDouble(textFieldnum2.getText()));
textFieldAns.setText(String.valueOf(myf));
} catch (NumberFormatException ex) { // catch the exception that you mentioned
JOptionPane.showMessageDialog(null, "Wrong input");
textFieldAns.setText("");
}
}
});
I'm having issues updating a JLabel value using invokeLater.
I have a separate method outside of the main function that runs invokeLater, but when I click the search button to update the value, it's not updating in the same instance of the gui.
I have to relaunch the gui in eclipse to get the value to change.
I'm not sure what I'm doing wrong so any help is greatly appreciated.
I'm running this method threadStart(); in the actionListener of the button.
Here's the method
private void threadStart() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
testLabel.setText(CN);
}
Here's the full class as a reference.
import java.awt.EventQueue;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import javax.naming.ldap.LdapName;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JTextArea;
import javax.swing.JTable;
public class MISControlPanel {
JFrame frame;
static JTextField textField;
private JTextField textField_1;
final JTextArea textArea = new JTextArea();
JLabel selectedComputerFromAD = new JLabel("testing");
String sCurrentLine = null;
String CN = null;
JLabel testLabel = new JLabel("test");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MISControlPanel window = new MISControlPanel();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*
* #throws IOException
*
* #wbp.parser.entryPoint
*/
public MISControlPanel() throws IOException {
initialize();
}
/**
* Initialize the contents of the frame.
*
* #throws IOException
*/
private void initialize() throws IOException {
frame = new JFrame();
frame.getContentPane().setBackground(Color.LIGHT_GRAY);
frame.getContentPane().setForeground(Color.RED);
frame.setBounds(100, 100, 658, 618);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setTitle("MIS Advanced Computerers");
frame.setResizable(false);
FileWriter fw = new FileWriter("C:\\Users\\anoc5f\\Desktop\\Output.txt");
File tempFile = new File("myTempFile.txt");
JButton searchComputerButton = new JButton("Search");
searchComputerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
threadStart();
String line;
BufferedWriter bw = null;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(tempFile));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String s = null;
Process p = null;
/*
* try { // p = Runtime.getRuntime().exec(
* "cmd /c start c:\\computerQuery.bat computerName"); } catch
* (IOException e1) { // TODO Auto-generated catch block
* e1.printStackTrace(); }
*/
try {
p = Runtime.getRuntime().exec("c:\\computerQuery.bat");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
StringBuffer sbuffer = new StringBuffer();
BufferedReader in = new BufferedReader(new InputStreamReader(p
.getInputStream()));
try {
while ((line = in.readLine()) != null) {
System.out.println(line);
// textArea.append(line);
String dn = "CN=FDCD111304,OU=Workstations,OU=SIM,OU=Accounts,DC=FL,DC=NET";
LdapName ldapName = new LdapName(dn);
String commonName = (String) ldapName.getRdn(
ldapName.size() - 1).getValue();
}
ComputerQuery.sendParam();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InvalidNameException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally
{
try {
fw.close();
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
try {
in.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ComputerQuery.sendParam();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
testLabel.setText(CN);
}
});
}
});
try (BufferedReader br = new BufferedReader(new FileReader(
"resultofbatch.txt"))) {
final Pattern PATTERN = Pattern.compile("CN=([^,]+).*");
try {
while ((sCurrentLine = br.readLine()) != null) {
String[] tokens = PATTERN.split(","); // This will return
// you a array,
// containing the
// string array
// splitted by what
// you write inside
// it.
// should be in your case the split, since they are
// seperated by ","
// System.out.println(sCurrentLine);
CN = sCurrentLine.split("CN=", -1)[1].split(",", -1)[0];
System.out.println(CN);
testLabel.setText(CN);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
// SwingUtilities.invokeLater(updateCN());
searchComputerButton.setBounds(419, 19, 89, 20);
frame.getContentPane().add(searchComputerButton);
textField = new JTextField();
textField.setBounds(285, 19, 124, 20);
frame.getContentPane().add(textField);
textField.setColumns(10);
JLabel lblComputerName = new JLabel("Computer Name:");
lblComputerName.setForeground(Color.BLACK);
lblComputerName.setFont(new Font("Tahoma", Font.BOLD, 14));
lblComputerName.setBounds(159, 13, 124, 29);
frame.getContentPane().add(lblComputerName);
JLabel lblSelectedComputer = new JLabel("Selected Computer:");
lblSelectedComputer.setFont(new Font("Tahoma", Font.BOLD, 14));
lblSelectedComputer.setBounds(205, 78, 143, 30);
frame.getContentPane().add(lblSelectedComputer);
java.net.InetAddress localMachine = null;
try {
localMachine = java.net.InetAddress.getLocalHost();
} catch (UnknownHostException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
textArea.setBackground(Color.GRAY);
textArea.setForeground(Color.WHITE);
textArea.setFont(textArea.getFont().deriveFont(Font.BOLD));
textArea.setBounds(10, 387, 632, 191);
textArea.setEditable(false); // might cause design view not to come up
frame.getContentPane().add(textArea);
JButton btnNewButton = new JButton("SSO REPAIR");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnNewButton.setBounds(36, 183, 132, 23);
frame.getContentPane().add(btnNewButton);
JLabel lblNewLabel = new JLabel("Batch File Fixes");
lblNewLabel.setFont(new Font("Tahoma", Font.BOLD, 12));
lblNewLabel.setBounds(53, 158, 115, 14);
frame.getContentPane().add(lblNewLabel);
JLabel lblIpAddress = new JLabel("IP Address:");
lblIpAddress.setFont(new Font("Tahoma", Font.BOLD, 14));
lblIpAddress.setBounds(261, 104, 102, 22);
frame.getContentPane().add(lblIpAddress);
JLabel label = null;
try {
label = new JLabel(Inet4Address.getLocalHost().getHostAddress()); // Get
// User
// ID
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
label.setFont(new Font("Tahoma", Font.BOLD, 14));
label.setForeground(Color.RED);
label.setBounds(349, 105, 99, 21);
frame.getContentPane().add(label);
JLabel lblPcCommunication = new JLabel("PC Communication");
lblPcCommunication.setFont(new Font("Tahoma", Font.BOLD, 12));
lblPcCommunication.setBounds(279, 158, 115, 14);
frame.getContentPane().add(lblPcCommunication);
JButton btnPingComputer = new JButton("PING");
btnPingComputer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnPingComputer.setBounds(306, 183, 64, 23);
frame.getContentPane().add(btnPingComputer);
JButton remoteAssistanceButton = new JButton(
"Remote Assistance by PC Name");
remoteAssistanceButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
remoteAssistanceButton.setBounds(215, 251, 246, 23);
frame.getContentPane().add(remoteAssistanceButton);
JButton btnPingIndefinetely = new JButton("PING INDEFINETELY");
btnPingIndefinetely.setBounds(260, 217, 156, 23);
frame.getContentPane().add(btnPingIndefinetely);
JButton btnRdcByIp = new JButton("RDC by IP Address");
btnRdcByIp.setBounds(261, 353, 156, 23);
frame.getContentPane().add(btnRdcByIp);
JButton btnRdcByName = new JButton("RDC by PC Name");
btnRdcByName.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnRdcByName.setBounds(248, 319, 180, 23);
frame.getContentPane().add(btnRdcByName);
JLabel lblLoggedInOpid = new JLabel("Logged in OPID:");
lblLoggedInOpid.setFont(new Font("Tahoma", Font.BOLD, 14));
lblLoggedInOpid.setBounds(228, 127, 135, 20);
frame.getContentPane().add(lblLoggedInOpid);
JLabel lblNewLabel_1 = new JLabel(System.getProperty("user.name")
.toUpperCase());
lblNewLabel_1.setFont(new Font("Tahoma", Font.BOLD, 14));
lblNewLabel_1.setForeground(Color.RED);
lblNewLabel_1.setBounds(348, 130, 86, 14);
frame.getContentPane().add(lblNewLabel_1);
JButton btnHiddenShare = new JButton("HIDDEN SHARE");
btnHiddenShare.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnHiddenShare.setBounds(484, 183, 132, 23);
frame.getContentPane().add(btnHiddenShare);
JLabel lblAdditionalTools = new JLabel("Tools");
lblAdditionalTools.setFont(new Font("Tahoma", Font.BOLD, 12));
lblAdditionalTools.setBounds(526, 157, 126, 20);
frame.getContentPane().add(lblAdditionalTools);
JButton btnNewButton_1 = new JButton("Remote Assistance by IP Address");
btnNewButton_1.setBounds(215, 285, 246, 23);
frame.getContentPane().add(btnNewButton_1);
JButton gpUpdate = new JButton("GP UPDATE");
gpUpdate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
gpUpdate.setBounds(36, 217, 132, 23);
frame.getContentPane().add(gpUpdate);
JButton btnForced = new JButton("NURMED REG FIX");
btnForced.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnForced.setBounds(36, 251, 132, 23);
frame.getContentPane().add(btnForced);
JButton btnCleaConsoler = new JButton("CLEAR");
btnCleaConsoler.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
textArea.setText("");
}
});
btnCleaConsoler.setBounds(563, 353, 79, 23);
frame.getContentPane().add(btnCleaConsoler);
JLabel lblOpid = new JLabel("Find Computer by OPID:");
lblOpid.setFont(new Font("Tahoma", Font.BOLD, 14));
lblOpid.setBounds(104, 53, 180, 14);
frame.getContentPane().add(lblOpid);
textField_1 = new JTextField();
textField_1.setBounds(285, 50, 124, 20);
frame.getContentPane().add(textField_1);
textField_1.setColumns(10);
JButton btnNewButton_2 = new JButton("Search");
btnNewButton_2.setBounds(419, 50, 89, 23);
frame.getContentPane().add(btnNewButton_2);
testLabel.setForeground(Color.RED);
testLabel.setFont(new Font("Tahoma", Font.BOLD, 14));
testLabel.setBounds(358, 78, 150, 24);
frame.getContentPane().add(testLabel);
}
private void threadStart() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
testLabel.setText(CN);
}
});
}
}
My recommendations are again that you should:
Have your batch file output to the standard output, the console, if you will.
Trap that output by capturing the InputStream and the ErrorStream from your Process. These can be trapped together by redirecting the error stream.
You should do all of this in a background thread such as with a SwingWorker.
I'd make the SwingWorker specifically of type, SwingWorker<Integer, String> so that it can "publish" the Strings read in from its InputStream, and then it can eventually return the process's integer exit code to make sure that the process ran OK.
For instance, say I had a bat file in the user working directory called test.bat that simply printed out the directory of the path passed into it:
test.bat
dir %1
You could call this from a GUI and display the results using the techniques described above.
Note that my code below borrows heavily from MadProgrammer's wonderful answer that can be found here: Printing a Java InputStream from a Process. Please check his answer including his description and up-vote it if it helps you to better understand what's going on.
Also be sure to read Concurrency in Swing for all the details on how to do background threading and in particular SwingWorker use in Swing GUI's.
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestBatGui extends JPanel {
public static final String BATCH_FILE_PATH = "test.bat";
private JTextArea resultArea = new JTextArea(30, 80);
public TestBatGui() {
resultArea.setFocusable(false); // not allow user edits
resultArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane scrollPane = new JScrollPane(resultArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
int keyCode = KeyEvent.VK_H;
String path = System.getProperty("user.home");
buttonPanel.add(new JButton(new ShowDirAction("Home Dir", keyCode, path)));
keyCode = KeyEvent.VK_W;
path = System.getProperty("user.dir");
buttonPanel.add(new JButton(new ShowDirAction("Working Dir", keyCode,
path)));
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
// Action/ActionListener to be used by my buttons
private class ShowDirAction extends AbstractAction {
private String path;
public ShowDirAction(String name, int keyCode, String path) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.path = path;
}
#Override
public void actionPerformed(ActionEvent e) {
// our SwingWorker
BatchFileWorker batchFileWorker = new BatchFileWorker(
resultArea, BATCH_FILE_PATH, path);
// add a listener to respond when the worker is done
batchFileWorker.addPropertyChangeListener(new BatchFileWorkerListener());
batchFileWorker.execute(); // execute the worker
}
}
// class to listen for when the worker has completed its work
// and then this class extracts the SwingWorker's results via .get()
// and does house cleaning if need be.
private class BatchFileWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
BatchFileWorker worker = (BatchFileWorker) evt.getSource();
try {
// extract the result returned from the worker's doInBackground() method
// and most importantly, trap any exceptions thrown
int exitValue = worker.get();
String displayText = "";
if (exitValue != 0) {
displayText = String.format("Error when running batch, Exit Value: %d", exitValue);
} else {
displayText = "Batch file ran without error";
}
((Consumer<String>) worker).accept(displayText);
((Consumer<String>) worker).accept("\n");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
// Our SwingWorker. It's also a Consumer so that outside classes, namely the InputConsumer
// can pass the strings that it reads back into the worker via the accept(...) method
private class BatchFileWorker extends SwingWorker<Integer, String> implements Consumer<String> {
private JTextArea resultArea;
private String batchFilePath;
private String dirPath;
public BatchFileWorker(JTextArea resultArea, String batchFilePath,
String dirPath) {
this.resultArea = resultArea;
this.batchFilePath = batchFilePath;
this.dirPath = dirPath;
}
#Override
protected Integer doInBackground() throws Exception {
// command list to load into the process builder
List<String> commandList = new ArrayList<>();
int exitCode = 0;
publish("Getting dir for " + dirPath);
commandList.add("cmd");
commandList.add("/c");
commandList.add(batchFilePath);
commandList.add(dirPath);
// create the process builder
ProcessBuilder pBuilder = new ProcessBuilder(commandList);
// add the error stream to the input stream so now we have only one stream to handle
pBuilder.redirectErrorStream();
Process p = pBuilder.start(); // create our process
InputStream is = p.getInputStream(); // get its InputStream and use it
InputStreamReader isr = new InputStreamReader(is); // to create a
BufferedReader br = new BufferedReader(isr); // BufferedReader
InputConsumer consumer = new InputConsumer(br, this); // pass into our consumer object
Thread thread = new Thread(consumer); // start this in a background thread
thread.start();
exitCode = p.waitFor(); // wait in this thread for the error code
thread.join(); // join two threads
br.close(); // close the BufferedReader
return exitCode;
}
#Override // this allows our InputConsumer to pass Strings read back into the SwingWorker
public void accept(String text) {
publish(text);
}
#Override // published text will be sent here on the EDT, to be placed into the JTextArea
protected void process(List<String> chunks) {
for (String chunk : chunks) {
resultArea.append(chunk + "\n");
}
}
}
// to read in from the BufferedReader, passing text back into its consumer
private class InputConsumer implements Runnable {
private BufferedReader br;
private Consumer<String> consumer;
public InputConsumer(BufferedReader br, Consumer<String> consumer) {
this.br = br;
this.consumer = consumer;
}
#Override
public void run() {
String line = null;
try {
while ((line = br.readLine()) != null) {
consumer.accept(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void createAndShowGui() {
TestBatGui mainPanel = new TestBatGui();
JFrame frame = new JFrame("TestBatGui");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
EDIT: The code now works! Here's how I did it:
package me.nrubin29.jterminal;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.ArrayList;
public class JTerminal extends JFrame {
private JTextPane area = new JTextPane();
private JTextField input = new JTextField("Input");
private SimpleAttributeSet inputSAS = new SimpleAttributeSet(), output = new SimpleAttributeSet(), error = new SimpleAttributeSet();
private File workingFolder = FileSystemView.getFileSystemView().getDefaultDirectory();
public JTerminal() throws IOException {
super("JTerminal");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
StyleConstants.setForeground(inputSAS, Color.GREEN);
StyleConstants.setBackground(inputSAS, Color.BLACK);
StyleConstants.setForeground(output, Color.WHITE);
StyleConstants.setBackground(output, Color.BLACK);
StyleConstants.setForeground(error, Color.RED);
StyleConstants.setBackground(error, Color.BLACK);
input.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
String command = input.getText();
if (command.equals("")) return;
setTitle("JTerminal (" + command.split(" ")[0] + ")");
input.setText("");
input.setEditable(false);
write(inputSAS, command);
Process bash = new ProcessBuilder("bash").directory(workingFolder).start();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(bash.getOutputStream());
outputStreamWriter.write(command);
outputStreamWriter.close();
int code = bash.waitFor();
writeStream(bash.getErrorStream(), error);
writeStream(bash.getInputStream(), output);
input.setEditable(true);
setTitle("JTerminal");
if (code == 0 && command.split(" ").length > 1) workingFolder = new File(command.split(" ")[1]);
} catch (Exception ex) { error(ex); }
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
});
area.setBackground(Color.black);
area.setCaretColor(Color.green);
area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
area.setEditable(false);
JScrollPane pane = new JScrollPane(area);
pane.setBorder(BorderFactory.createLineBorder(Color.GREEN));
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
pane.setPreferredSize(new Dimension(640, 460));
input.setBackground(Color.black);
input.setForeground(Color.green);
input.setCaretColor(Color.green);
input.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
input.setBorder(BorderFactory.createLineBorder(Color.GREEN));
add(pane);
add(input);
Dimension DIM = new Dimension(640, 480);
setPreferredSize(DIM);
setSize(DIM);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(true);
pack();
setVisible(true);
input.requestFocus();
}
public static void main(String[] args) throws IOException {
new JTerminal();
}
private void write(SimpleAttributeSet attributeSet, String... lines) {
try {
if (lines.length == 0) return;
for (String line : lines) {
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), line + "\n", attributeSet);
}
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), "\n", attributeSet);
}
catch (Exception e) { error(e); }
}
private void error(Exception e) {
write(error, "An error has occured: " + e.getLocalizedMessage());
e.printStackTrace(); //TODO: temp.
}
private void writeStream(InputStream s, SimpleAttributeSet color) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(s));
ArrayList<String> strs = new ArrayList<String>();
while(reader.ready()) strs.add(reader.readLine());
if (strs.size() > 0) write(color, strs.toArray(new String[strs.size()]));
}
catch (Exception e) { error(e); }
}
}
I have been working on a Java terminal application. It works except that it only prints the output of the first command. Here's a picture of the GUI when I try to run ls more than once.
package me.nrubin29.jterminal;
import javax.swing.*;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.ArrayList;
public class JTerminal extends JFrame {
private JTextPane area = new JTextPane();
private JTextField input = new JTextField("Input");
private SimpleAttributeSet inputSAS = new SimpleAttributeSet(), output = new SimpleAttributeSet(), error = new SimpleAttributeSet();
public JTerminal() throws IOException {
super("JTerminal");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
StyleConstants.setForeground(inputSAS, Color.GREEN);
StyleConstants.setBackground(inputSAS, Color.BLACK);
StyleConstants.setForeground(output, Color.WHITE);
StyleConstants.setBackground(output, Color.BLACK);
StyleConstants.setForeground(error, Color.RED);
StyleConstants.setBackground(error, Color.BLACK);
final Process bash = new ProcessBuilder("/bin/bash").start();
input.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
String command = input.getText();
if (command.equals("")) return;
setTitle("JTerminal (" + command.split(" ")[0] + ")");
input.setText("");
input.setEditable(false);
write(inputSAS, command);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(bash.getOutputStream());
outputStreamWriter.write(command);
outputStreamWriter.close();
bash.waitFor();
writeStream(bash.getErrorStream(), error);
writeStream(bash.getInputStream(), output);
input.setEditable(true);
setTitle("JTerminal");
} catch (Exception ex) { error(ex); }
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
});
area.setBackground(Color.black);
area.setCaretColor(Color.green);
area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
area.setEditable(false);
JScrollPane pane = new JScrollPane(area);
pane.setBorder(BorderFactory.createLineBorder(Color.GREEN));
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
pane.setPreferredSize(new Dimension(640, 460));
input.setBackground(Color.black);
input.setForeground(Color.green);
input.setCaretColor(Color.green);
input.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
input.setBorder(BorderFactory.createLineBorder(Color.GREEN));
add(pane);
add(input);
Dimension DIM = new Dimension(640, 480);
setPreferredSize(DIM);
setSize(DIM);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(true);
pack();
setVisible(true);
input.requestFocus();
}
public static void main(String[] args) throws IOException {
new JTerminal();
}
private void write(SimpleAttributeSet attributeSet, String... lines) {
try {
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), "\n", attributeSet);
for (String line : lines) {
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), line + "\n", attributeSet);
}
}
catch (Exception e) { error(e); }
}
private void error(Exception e) {
write(error, "An error has occured: " + e.getLocalizedMessage());
e.printStackTrace(); //TODO: temp.
}
private void writeStream(InputStream s, SimpleAttributeSet color) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(s));
ArrayList<String> strs = new ArrayList<String>();
while(reader.ready()) strs.add(reader.readLine());
if (strs.size() > 0) write(color, strs.toArray(new String[strs.size()]));
}
catch (Exception e) { error(e); }
}
}
A Process object can be used only once, so subsequent calls to Process.waitFor() just immediately return (as the process is already terminated).
Instead you have to request a new Process each time from your ProcessBuilder.
Here is the correct code:
package me.nrubin29.jterminal;
import javax.swing.*;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.ArrayList;
public class JTerminal extends JFrame {
private JTextPane area = new JTextPane();
private JTextField input = new JTextField("Input");
private SimpleAttributeSet inputSAS = new SimpleAttributeSet(), output = new SimpleAttributeSet(), error = new SimpleAttributeSet();
public JTerminal() throws IOException {
super("JTerminal");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
StyleConstants.setForeground(inputSAS, Color.GREEN);
StyleConstants.setBackground(inputSAS, Color.BLACK);
StyleConstants.setForeground(output, Color.WHITE);
StyleConstants.setBackground(output, Color.BLACK);
StyleConstants.setForeground(error, Color.RED);
StyleConstants.setBackground(error, Color.BLACK);
final ProcessBuilder builder = new ProcessBuilder("/bin/bash");
input.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
String command = input.getText();
if (command.equals("")) return;
setTitle("JTerminal (" + command.split(" ")[0] + ")");
input.setText("");
input.setEditable(false);
write(inputSAS, command);
Process bash = builder.start();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(bash.getOutputStream());
outputStreamWriter.write(command);
outputStreamWriter.close();
bash.waitFor();
writeStream(bash.getErrorStream(), error);
writeStream(bash.getInputStream(), output);
input.setEditable(true);
setTitle("JTerminal");
} catch (Exception ex) { error(ex); }
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
});
area.setBackground(Color.black);
area.setCaretColor(Color.green);
area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
area.setEditable(false);
JScrollPane pane = new JScrollPane(area);
pane.setBorder(BorderFactory.createLineBorder(Color.GREEN));
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
pane.setPreferredSize(new Dimension(640, 460));
input.setBackground(Color.black);
input.setForeground(Color.green);
input.setCaretColor(Color.green);
input.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
input.setBorder(BorderFactory.createLineBorder(Color.GREEN));
add(pane);
add(input);
Dimension DIM = new Dimension(640, 480);
setPreferredSize(DIM);
setSize(DIM);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(true);
pack();
setVisible(true);
input.requestFocus();
}
public static void main(String[] args) throws IOException {
new JTerminal();
}
private void write(SimpleAttributeSet attributeSet, String... lines) {
try {
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), "\n", attributeSet);
for (String line : lines) {
area.getStyledDocument().insertString(area.getStyledDocument().getLength(), line + "\n", attributeSet);
}
}
catch (Exception e) { error(e); }
}
private void error(Exception e) {
write(error, "An error has occured: " + e.getLocalizedMessage());
e.printStackTrace(); //TODO: temp.
}
private void writeStream(InputStream s, SimpleAttributeSet color) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(s));
ArrayList<String> strs = new ArrayList<String>();
while(reader.ready()) strs.add(reader.readLine());
if (strs.size() > 0) write(color, strs.toArray(new String[strs.size()]));
}
catch (Exception e) { error(e); }
}
}
Once a process has exited, it can not be "read" from or "written" to.
You're code will also block on the "waitFor" method, meaning that your UI won't be updated until the process has completed running. This is really helpful...
Instead, you need to start the process and allow it to continue running, monitoring the state in the background.
Because Swing is a single threaded environment, you need to be careful about how you handle long running/blocking processes and updates to the UI.
To this end, I've used a SwingWorker to read the output of the Process in a background thread and re-sync the updates back to the Event Dispatching Thread. This allows the UI to continue running and remain responsive while the output from the running process is read in...
Also, instead of "running" a new command each time, creating a new process, you will need to write to the Process's input put stream.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestTerminal {
public static void main(String[] args) {
new TestTerminal();
}
public TestTerminal() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea output;
private JTextField input;
private Process process;
public TestPane() {
setLayout(new BorderLayout());
output = new JTextArea(20, 20);
input = new JTextField(10);
output.setLineWrap(false);
output.setWrapStyleWord(false);
output.setEditable(false);
output.setFocusable(false);
add(new JScrollPane(output));
add(input, BorderLayout.SOUTH);
input.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = input.getText() + "\n";
input.setText(null);
output.append("\n" + cmd + "\n\n");
if (process == null) {
ProcessBuilder pb = new ProcessBuilder("bash");
pb.directory(new File("."));
try {
process = pb.start();
InputStreamWorker isw = new InputStreamWorker(output, process.getInputStream());
isw.execute();
} catch (IOException ex) {
ex.printStackTrace();
input.setEnabled(false);
}
new Thread(new Runnable() {
#Override
public void run() {
int exit = -1;
try {
exit = process.waitFor();
} catch (InterruptedException ex) {
}
System.out.println("Exited with " + exit);
input.setEnabled(false);
}
}).start();
}
OutputStream os = process.getOutputStream();
try {
os.write(cmd.getBytes());
os.flush();
} catch (IOException ex) {
ex.printStackTrace();
input.setEnabled(false);
}
}
});
}
}
public class InputStreamWorker extends SwingWorker<Void, Character> {
private InputStream is;
private JTextArea output;
public InputStreamWorker(JTextArea output, InputStream is) {
this.is = is;
this.output = output;
}
#Override
protected void process(List<Character> chunks) {
StringBuilder sb = new StringBuilder(chunks.size());
for (Character c : chunks) {
sb.append(c);
}
output.append(sb.toString());
}
#Override
protected Void doInBackground() throws Exception {
int in = -1;
while ((in = is.read()) != -1) {
publish((char)in);
}
return null;
}
}
}
I would also recommend that you avoid KeyListener where you can. JTextField utilises a ActionListener, which will be called when ever the user presses the "action" key, what ever that might be for the given platform...