Client-Server Java GUI: read/write causing program to freeze - java

I'm doing a client/server program in Java (including a GUI).
I've got the following code in the client:
public class SBListener implements ActionListener{
public void actionPerformed(ActionEvent e){
try{
outToServer.writeUTF(usn.getText().trim());
System.out.println("sent username to server");
playerExists = inToClient.readBoolean();
System.out.println("past getting player");
System.out.println("player exists = " + playerExists);
}catch(IOException a){
System.err.println(a);
}
if(playerExists == false){
JButton submitInfo = new JButton("submit info");
submitInfo.addActionListener(new SBNewInfoListener());
init.add(new JLabel(""));//dummy element to get the right alignment
init.add(new JLabel("First Name:"));
init.add(fn);
init.add(new JLabel("Last Name:"));
init.add(ln);
init.add(submitInfo);
add(init, BorderLayout.WEST);
init.setVisible(true);
init.revalidate();
init.repaint();
}
}
}
And the following code in the Server:
String username = inp.readUTF();
System.out.println(username);
out.writeBoolean(false);
System.out.println("wrote boolean, waiting for fn/ln/un");
fn = inp.readUTF();
System.out.println("got fn");
ln = inp.readUTF();
un = inp.readUTF();
But when the button that calls SBListener is clicked, the program freezes when it gets to the point where the Server is waiting for fn/ln/username. I added a bunch of system.out statements for debugging and I get up to the one that says "wrote boolean, waiting for fn/ln/un".
Basically, I'm trying to update the screen after the Server returns a false value. Specifically, I want to add two text fields for first & last name. I then want to send those values to the server.
Can anyone tell me how to fix this? Thanks in advance for any help!

Don't execute client/server code in an ActionListener. This will cause the Event Dispatch Thread to block while waiting for a response from the server. When EDT is blocked the whole GUI freezes.
Read the section from the Swing tutorial on Concurrency for more information. You need so use a separate Thread for the client/server code. Or you can use a SwingWorker as discussed in the tutorial.

My guess is that outToServer isn't being flushed. I would guess (although I can't tell from your sample code) that outToServer is a DataOutputStream. You need to call .flush to get the data out of the buffer and onto the wire.
Try this:
outToServer.writeUTF(usn.getText().trim());
outToServer.flush();

Related

How can i change the JTextArea string to something else

In my code i have made my JtextArea public and in my code i have called the jtextare and setTextArea however when i press that button because its a thread it doesnt allow me to change the JTextArea whenever my scanner works
public void scan() throws InterruptedException {
try {
//This is the part i called it but doesnt change the jtextfield into getUid
Login login = new Login();
login.jTextField_username.setText(getUid);
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
CardTerminal terminal = terminals.get(0);
System.out.println("Waiting for a card..");
if (terminal == null) {
return;
}
terminal.waitForCardPresent(0);
Card card = terminal.connect("T=1");
System.out.println("Card: " + card);
System.out.println("Protocol: " + card.getProtocol());
CardChannel channel = card.getBasicChannel();
ResponseAPDU response = channel.transmit(new CommandAPDU(new byte[]{(byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00}));
System.out.println("Response: " + response.toString());
if (response.getSW1() == 0x63 && response.getSW2() == 0x00) {
System.out.println("Failed");
}
System.out.println("UID: " + bin2hex(response.getData()));
getUid = bin2hex(response.getData());
} catch (CardException ex) {
Logger.getLogger(CardId.class.getName()).log(Level.SEVERE, null, ex);
}
}
Note that we cannot compile nor run a code snippet, and so any answer given will need to include guesses, but that being said, I think that the problem is that you have a faulty assumption here:
//This is the part i called it but doesnt change the jtextfield into getUid
Login login = new Login(); // **** A ****
login.jTextField_username.setText(getUid); // **** B ****
At line A you create a new Login object, but is this the actual displayed object? I have a feeling that it's not, that you've already created and displayed the Login window, and are now creating a new one, one never displayed, and on line B are changing its state (the text held in one of its text components). If my guess is correct, then the better solution is to change the state of the actual displayed Login object, not a new and distinct one that you're creating in this method. How to do this? Impossible to state give the information that you've given so far.
If you want a more robust answer, then you will want to create and post a valid [Minimal, Complete, and Verifiable example](Minimal, Complete, and Verifiable example) in with your question -- please check out the link as it will explain all.
Other unrelated issues:
Your question mentions JTextArea, but the code suggests that we're dealing with a JTextField -- which is it?
Your question text suggests that you're mixing Scanner/console input with a Swing GUI. If this is so, I strongly urge you to not go this route, to get all input via the GUI. This will save you hours of debugging and frustration.

Can't get text to append to jtextarea

I am trying to create a console like function for some software. I have the output formatted as I want but only for console output using System.out.println. I am trying to get some form of text in the jtextarea. I have tried using .setText() and .append() yet had no lucky with either. I was wondering if anyone could help me spot why it's not working? My application uses 2 forms, Any help is appreciated as always..
Form2 f2 = new Form2();
f2.openMe(comboOne.getSelectedItem().toString());
form2 code is as follows:
public void openMe(String message) {
System.out.println("Console Output");
System.out.println("---------------------------");
System.out.println("Printer selected: "+ message);
System.out.println("\n");
//ta.setText(message);
ta.append("hi");
}

Java - Sending of ImageIcon through ObjectOutputStream works first time, but not after that

I'm working on a server/client project in Java where, at any point during the running of the program, the client can request a set of details related to a unique ID, and the server returns the relevant set of details. This is done through PrintWriter objects accessing the socket.getOutputStream, and works fine.
I am trying to also include the sending/receiving of an image from the server to the client, and have met some very strange behaviour from the program.
The methods that send and receive the images are shown below:
SERVER-SIDE:
//send image associated with item
//through ObjectOutputStream to client
private void sendItemImage(BidItem item)
{
try
{
//wrap object output stream around
//output stream to client at this socket
ObjectOutputStream imageOutput =
new ObjectOutputStream(client.getOutputStream());
//send image object to client
imageOutput.writeObject(item.getItemImage());
}
catch (IOException ioEx)
{
//alert server console
System.out.println("\nUnable to send image for item "
+ item.getItemCode() + " to "
+ bidderName + "!");
//no exit from system
//bidding can still continue
}
}
CLIENT-SIDE:
//to be displayed on GUI
private static void receiveItemImage()
{
try
{
//wrap ObjectInputStream around socket
//to receive objects sent from server
ObjectInputStream imageInput =
new ObjectInputStream(socket.getInputStream());
//read in image and store in ImageIcon instance
image = (ImageIcon) imageInput.readObject();
//re-create label object to be blank
imageLabel = new JLabel();
//remove label containing last image
imagePanel.remove(imageLabel);
//just ignores command if it does not already contain image
//apply image to label
imageLabel.setIcon(image);
//apply image to CENTER of panel
imagePanel.add(imageLabel, BorderLayout.CENTER);
}
//problem in input stream
catch (IOException ioEx)
{
//alert user
JOptionPane.showMessageDialog(
null, "Error receiving image!");
//allow system to continue
//no exit
}
//problem casting to ImageIcon type
catch (ClassNotFoundException cnfEx)
{
//alert user
JOptionPane.showMessageDialog(
null, "Error converting Object to ImageIcon!");
//allow system to continue
//no exit
}
}
So, each time there is a request, an ObjectOutpuStream and ObjectInputStream are created to handle the passing of the image, using the socket.getOutputStream/socket.getInputStream.
These methods are first called when a client connects to the server, and the first image and set of details are sent automatically. This works fine, but any subsequent attempts at requesting the image throughout the program result in the catch (IOException) clause being met, and the error messages shown above being displayed.
I cannot for the life of me work out why it would work the first time but not again after this. If anyone could point me in the right direction, that would be great!
Thanks,
Mark
You should only wrap a stream once. In this case, you can't wrap it again as this will not work for an Object Stream.
Once you are wrapping the stream only once, call ObjectOutputStream.reset() after sending an image. If you don't do this it will just pass the reference to the object again (and use a lot of memory)

create a text file in java

I have a problem about creating a textfile with the name I want.
I want to create a textfile named : 'username' Subjects.
private void saveSubjects(){
RegisterFrame r = new RegisterFrame();
String username = r.txtUser.getText();;
try{
FileWriter f = new FileWriter(username + "" + "Subjects" + ".txt", true);
String subjects[] = lstSubjects.getItems();
for(int i = 0; i<subjects.length; i++){
f.write(subjects[i] + "\r\n");
}
f.close();
JOptionPane.showMessageDialog(null, "Data saved!", "Data Saved", JOptionPane.INFORMATION_MESSAGE);
}catch(Exception e){
JOptionPane.showMessageDialog(null, "Nothing Inputted!", "Error", JOptionPane.ERROR_MESSAGE);
}
}
I want to get the username from RegisterFrame as it is inputted there but it's not working.
I know it's a simple thing but I'm still a beginner in this. How can I solve this?
Thanks in advance
try this:
String username = r.txtUser.getText();
System.out.println("The loaded username is: " + username);
then you will see where your problem is : writing into the file OR getting the username text.
If the problem is in getting the text, consider other way of getting it or modify the question by removing the file write part and specifiing the username getting part.
Otherwise, IDK where the error is.
BTW: how is it not working? the file is not created at all? do you see any errors? the file has wrong name? please specify
Your code for writing the file seems to be fine. Based on your code I tried this which worked perfectly:
public static void main(String[] args) {
FileWriter f = null;
try {
f = new FileWriter("Subjects.txt", true);
String subjects[] = {"subject1", "subject2"};
for (String subject : subjects) {
f.write(subject + "\r\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(f);
}
}
I'd say your problem is elsewhere.
Please note that best practice dictates that Closeable objects such as FileWriter should be closed in a finally block
Assuming new RegisterFrame() starts up a GUI window, the issue is your code runs before you have a chance to type in your name. Instead you need to use event listeners to capture the contents of text fields, otherwise the code to get the name runs immediately after the window opens, long before you have a chance to type anything in.
The timeline is like this:
RegisterFrame starts a new thread to display the GUI without blocking your code
Your code immediately pulls "" from txtUser, which is of course empty
Now you type your name in
Nothing happens, because nothing in your code is paying attention to that action
Instead, it should be:
RegisterFrame starts a new thread to display the GUI without blocking your code
The method returns, or starts doing work that isn't dependent on the GUI
Now you type your name in
An event listener is triggered from the new thread, and the associated action to get the name and write to a file is executed
You have to decide what sort of listener makes sense for your use case, for instance you might want to wait until the user clicks a button (that says "Submit" or "Write File" for instance) and register an ActionListener on that button. Then you put your username polling and file writing behavior in that action* and you're golden!
*I should add that in truth you want to do as little as possible in ActionListeners, and it would be better to check if the username is not empty, then pass the actual work off to another thread, for instance with a SwingWorker, but for your purposes I suspect it will be alright to not worry about that.

How to Clear variables from JTextFields without closing whole program?

I have created a text file in which to store some variables which are taken from text fields. But in order to submit new variables to this text file, I need to close my program and reopen it. The dispose(); command closes the JFrame taking me to my main menu but upon opening the menu again and submitting different values, the values from the previous time have been resubmitted. Is there a simple way to amend this?
Here is my write to .txt code:
public class writeto {
static String data = AddProperty.inputdata;
BufferedWriter out;
public writeto(){
try{
out = new BufferedWriter(new FileWriter("writeto.txt", true));
out.write(data);
out.newLine();
out.close();
}catch(IOException e){
System.out.println("you have an error" + e);
}
}
}
and where the method is called in my addproperty class
submitproperty.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
housenumber1 = houseNumber.getText();
streetname1 = streetName.getText();
town1 = town.getText();
postcode1 = postcode.getText();
beds1 = beds.getText();
price1 = price.getText();
type1 = type.getText();
inputdata = housenumber1 + " " + streetname1 + " " + town1 + " " +
postcode1 +" " + beds1 + " " + price1 + " " + type1;
writeto write = new writeto();
dispose();
}
});
}
From your menu you should always create a new JFrame with new widgets (like text fields). A new text field has no content, if you show a text field again, it will still display it's previous content.
Additional remarks:
Please use standard naming conventions - not only when you show code to others. In your case: class names shall start with a capital letter, camel-case notation is preferred (writeto -> WriteTo)
The writeto class abuses the constructor. The code in your constructor does not create an writeto object but dumps some strings to a file. Put this kind of code to a method, not to a constructor.
The BufferedWriter will not be closed if an exception occurs. Look around at stackoverflow, a lot of questions/answers show the correct io-closeing pattern
disposing the jframe is a risk - the code is executed after pressing a button (correct?), inside a method on a button that is displayed on the frame (correct?). In that case the button may be disposed while a method on the button object is still executed.. Try setVisible(false) if you just want to hide the JFrame (like "close the dialog")
You would benefit greatly from using a database as opposed to a text file. Further your question displays a fundamental lack of knowledge of not only Swing, but basic CRUD (Create, Read, Update, Delete) functionality.
To answer your question you can clear your text field with textField1.setText("");
I would read up on using a database for storing data. It will make life much easier for you.

Categories

Resources