使用来自另一个类的JFrame

时间:2018-03-08 17:14:37

标签: java swing jframe

嗨,我试图将一些文本从同一个包中的另一个类添加到JTextArea,这是一个小问题。以下是与JFrame相关的主要类:

  public class Client extends JFrame{

        //Static variables
        private static final String host = "localhost";
        private static final int portNumber = 4444;

        //Variables
        private String userName;

        //JFrame Variables
        private JPanel contentPanel;
        private JTabbedPane panel_Social;
        private JPanel jpanel_Social;
        private JPanel jpanel_Chat;
        private JTextArea textArea_Receive;
        private JTextField textField_Send;
        private JTextArea textArea_ClientList;
        private JButton btn_Enter;


        public JTextArea getTextArea_Receive(){
            return this.textArea_Receive;
        }

        //Constructor
        private Client(String userName, String host, int portNumber){
            this.userName = userName;
            this.serverHost = host;
            this.serverPort = portNumber;
        }

        public void main(String args[]){
            //Requests user to enter name
            String readName = null;
            Scanner scan = new Scanner(System.in);
            System.out.println("Please enter username");
            readName = scan.nextLine();

            //Start client
            Client client = new Client(readName, host, portNumber);
            client.startClient(scan);
        }

        private void startClient(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 = new ServerThread(socket, userName);
                Thread serverAccessThread = new Thread(serverThread);
                serverAccessThread.start();
            }
        }
    }


Below is the serverThread class

    public class ServerThread implements Runnable{

        private Socket socket;
        private String userName;
        private boolean isAlived;
        private final LinkedList<String> messagesToSend;
        private boolean hasMessages = false;

        //Constructor
        ServerThread(Socket socket,  String userName){
            this.socket = socket;
            this.userName = userName;
            messagesToSend = new LinkedList<String>();
        }

        public void run(){   
            try{
                Client test1 = new Client();
                JTextArea test2 = test1.getTextArea_Receive();
                String test3 = "Hello World";
                test2.append(test3);
            } catch (IOException e){
}
    }

我包含测试变量只是为了轻松地重新创建问题,但是无论何时运行追加功能,jFrame的文本区域都不会出现任何内容。在我的场景中,我让客户端从服务器接收文本,然后将其附加到文本框中。

BTW我正在为JFrame使用IntelliJ GUI设计器。我只包含了重新创建问题所需的代码。我仍在尝试创建MCVE问题,所以请随时告诉我我所犯的错误。

2 个答案:

答案 0 :(得分:1)

您应该通过构造函数将Client传递给ServerThread。您在Client内实例化的run()与您在Client中创建的main()的引用不同。所以你的ServerThread类就像

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)
    {}
}

您的startClient()方法会更新为此类

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();
    }
}

所有这一切,

我建议将main()Client移出并转移到与Swing UI代码不相关的类中。像这样:

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
    }
}

然后,您的Client更像是一个实例对象

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
    }
}

答案 1 :(得分:1)

  

追加功能在jFrame

的文本区域中不显示任何内容

您的问题中没有足够的信息可以确定为什么会发生这种情况,但是,您需要考虑许多重要的信息。

  1. Swing是单线程而非线程安全
  2. 您希望尽可能地解耦代码
  3. 基本上,第一点意味着您不应该在事件调度线程中运行任何长时间运行或阻塞进程,并且您不应该在上下文之外修改UI(或UI所依赖的任何状态)。事件调度线程

    首先查看Concurrency in Swing了解更多详情。

    第二点意味着,即使给定部分代码,您也想要问:“用其他实现替换它有多难?” - 如果工作量让你害怕,那么你的代码可能会紧密耦合。

    为此,我开始......

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

    这是非常基本的,但这意味着某些组件可以向其他组件发送消息,除此功能外,两者都不应该彼此关心。

    接下来,我查看了ServerThread。基本上,这个班负责管理Socket并将消息传递给Client。由于Swing的要求,我使用了SwingWorker。这允许我在后台线程上运行Socket代码,但确保在事件调度线程的上下文中将消息传递给Client

    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;
        }
    }
    

    然后是实际的UI客户端......

    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");
            }
    
        }
    }
    

    这里没多大意义

    最后,我写了一个简单的Server测试代码,它只是将当前日期/时间作为String发送到连接的客户端。

    当我说简单时,我的意思很简单。这是设计用于告知单个客户端连接,仅用于测试上述代码

    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();
            }
        }
    }
    

    要全部测试,请启动Server,然后运行Main