使用来自另一个类的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 messagesToSend; private boolean hasMessages = false; //Constructor ServerThread(Socket socket, String userName){ this.socket = socket; this.userName = userName; messagesToSend = new LinkedList(); } public void run(){ try{ Client test1 = new Client(); JTextArea test2 = test1.getTextArea_Receive(); String test3 = "Hello World"; test2.append(test3); } catch (IOException e){ } }
我包含测试变量只是为了轻松地重新创建问题,但是只要运行追加function,jFrame的文本区域就不会出现任何内容。 在我的场景中,我让客户端从服务器接收文本,然后将其附加到文本框。
顺便说一下,我正在为JFrame使用IntelliJ GUI设计器。 我只包含了重新创建问题所需的代码。 我仍在尝试创建MCVE问题,所以请随时告诉我我所犯的错误。
您应该通过构造函数将Client
传递给ServerThread
。 您在run()
中实例化的Client
您在main()
创建的Client
引用不同。 所以你的ServerThread
类就像
ServerThread(Client client, Socket socket, String userName) { this.client = client; this.socket = socket; this.userName = userName; messagesToSend = new LinkedList(); } 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 } }
在jFrame的文本区域中没有出现附加function
您的问题中没有足够的信息可以确定为什么会发生这种情况,但是,您需要考虑许多重要的信息。
- Swing是单线程的,不是线程安全的
- 您希望尽可能地解耦代码
基本上,第一点意味着您不应该在事件调度线程中运行任何长时间运行或阻塞进程,并且您不应该在事件调度线程的上下文之外修改UI(或UI所依赖的任何状态)
首先来看看Swing中的Concurrency以获取更多详细信息。
第二点意味着,即使给出了部分代码,您也想要问:“用其他实现替换它有多难?” – 如果工作量让你害怕,那么你的代码可能是紧密耦合的。
为此,我开始……
public interface Client { public void append(String message); }
这是非常基本的,但这意味着某些组件可以向其他组件发送消息,除了此function之外,它们都不应该彼此关心。
接下来,我查看了ServerThread
。 基本上,这个类负责管理Socket
并将消息传递给Client
。 由于Swing的要求,我使用了SwingWorker
。 这允许我在后台线程上运行Socket
代码,但确保在Event Dispatching Thread的上下文中将消息传递给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 { 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 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("")) { 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
类