Using JFrame from another class

前端 未结 2 602
甜味超标
甜味超标 2020-12-22 06:39

Hi I\'m small a little issue trying to append some text to a JTextArea from another class within the same package. Below is the main class that pertains to the

相关标签:
2条回答
  • 2020-12-22 06:45

    the append function is run nothing appears in the text area of the jFrame

    There's not enough information available in you question to ascertain why this might be happening, how ever, there are a number of important pieces of information you need to take into account.

    1. Swing is single threaded and not thread safe
    2. You want to, as much as possible, decouple of the code

    Basically, the first point means that you shouldn't be running any long running or blocking processes within the Event Dispatching Thread AND you should not be modifying the UI (or any state the UI relies on) from outside the context of the Event Dispatching Thread

    Start by taking a look at Concurrency in Swing for more details.

    The second point means that, for even given part of your code, you want to be asking, "how hard would it be to replace it with some other implementation?" - If the amount of work scares you, then your code is probably to tightly coupled.

    To that end, I started with...

    public interface Client {
        public void append(String message);
    }
    

    This is really basic, but it means that some component can send a message to some other component and neither should care about each other beyond this capability.

    Next, I looked at ServerThread. Basically this class becomes responsible for the management of the Socket and delivery of the messages to the Client. Because of the requirements of Swing, I've used a SwingWorker. This allows me to run the Socket code on a background thread, but ensure that the messages are delivered to the Client within the context of the Event Dispatching Thread

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.Socket;
    import java.util.List;
    import javax.swing.SwingWorker;
    
    public class ServerThread extends SwingWorker<Void, String> {
    
        private String host;
        private int port;
        private Client client;
    
        //Constructor
        ServerThread(String host, int port, Client client) {
            this.host = host;
            this.port = port;
            this.client = client;
        }
    
        @Override
        protected void process(List<String> chunks) {
            for (String message : chunks) {
                client.append(message);
            }
        }
    
        @Override
        protected Void doInBackground() throws Exception {
            try (Socket socket = new Socket(host, port)) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                    String text = null;
                    while ((text = reader.readLine()) != null) {
                        System.out.println(text);
                        if (text.equals("<stop>")) {
                            break;
                        }
                        publish(text);
                    }
                }
            } catch (IOException exp) {
                exp.printStackTrace();
                publish("Failed to establish connection to " + host + ":" + port + " - " + exp.getMessage());
            }
            return null;
        }
    }
    

    And then the actual UI client itself...

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    
    public class Main {
    
        public static void main(String[] args) {
            new Main();
        }
    
        //Constructor
        public Main() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                        ClientUI clientUI = new ClientUI();
    
                        ServerThread thread = new ServerThread("localhost", 4321, clientUI);
                        thread.execute();
    
                        JFrame frame = new JFrame("Client");
                        frame.add(clientUI);
                        frame.pack();
                        frame.setLocationRelativeTo(null);
                        frame.setVisible(true);
                }
            });
        }
    
        public class ClientUI extends JPanel implements Client {
    
            private JTextArea ta;
    
            public ClientUI() {
                setLayout(new BorderLayout());
                ta = new JTextArea(10, 20);
                add(new JScrollPane(ta));
            }
    
            @Override
            public void append(String message) {
                ta.append(message + "\n");
            }
    
        }
    }
    

    Not much going on here

    Finally, I wrote a simple Server test the code, which simply sends the current date/time as a String to the connected client.

    When I say simple, I mean simple. This is intended, by design, to tell with a single client connection and is meant only for testing the above code

    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.text.DateFormat;
    import java.util.Date;
    
    public class Server {
    
        public static void main(String[] args) {
            DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
            try (ServerSocket server = new ServerSocket(4321)) {
                Socket socket = server.accept();
                System.out.println("Connected");
                try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
                    while (true) {
                        System.out.println("Write >> ");
                        writer.write(format.format(new Date()));
                        writer.newLine();
                        writer.flush();
                        Thread.sleep(1000);
                    }
                }
            } catch (IOException | InterruptedException exp) {
                exp.printStackTrace();
            }
        }
    }
    

    To test it all, start the Server and then run the Main class

    0 讨论(0)
  • 2020-12-22 06:47

    You should pass Client into ServerThread via the constructor. The Client you are instantiating within run() is not the same reference to the Client you created in main(). So your ServerThread class would be something like

    ServerThread(Client client, Socket socket,  String userName) {
        this.client = client;
        this.socket = socket;
        this.userName = userName;
        messagesToSend = new LinkedList<String>();
    }
    
    public void run() {
        try
        {
            JTextArea test2 = this.client.getTextArea_Receive();
            String test3 = "Hello World";
            test2.append(test3);
        } 
        catch (IOException e)
        {}
    }
    

    Your startClient() method would be updated to something like this

    private void startClient(Client client, Scanner scan)
    {
        try
        {
            //Create new socket and wait for network communication
            Socket socket = new Socket(serverHost, serverPort);
            Thread.sleep(1000);
    
            //Create thread and start it
            ServerThread serverThread = new ServerThread(client, socket, userName);
            serverAccessThread.run();
        }
    }
    

    All that being said,

    I would recommend moving your main() out of Client and into a class that isn't so coupled to the Swing UI code. Something like this:

    public class MySwingApplication {
    
        private static final String host = "localhost";
        private static final int portNumber = 4444;
    
        public static void main(String[] args) {
            // Requests user to enter name
            // Start client
        }
    }
    

    Your Client is then built more like an instance object

    public class Client extends JFrame {
        public JTextArea getTextArea_Receive(){
            // Return the text area
        }
    
        // Constructor -- public to allow instantiation from main()
        public Client(String userName, String host, int portNumber) {
            // Do stuff
        }
    
        private void startClient(Scanner scan) {
            // Show the JFrame on screen
            // Spawn Server
        }
    }
    
    0 讨论(0)
提交回复
热议问题