简体   繁体   English

从另一个类使用JFrame

[英]Using JFrame from another class

Hi I'm small a little issue trying to append some text to a JTextArea from another class within the same package. 嗨,我有一个小问题,试图从同一包中的另一个类向JTextArea附加一些文本。 Below is the main class that pertains to the JFrame: 以下是与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){
}
    }

I included test variables just to easily recreate the issue but whenever the append function is run nothing appears in the text area of the jFrame. 我包括测试变量只是为了轻松地重新创建问题,但是无论何时运行append函数,jFrame的文本区域中都不会出现任何内容。 In my scenario I'm having the client receive text from a server then append it to the text box. 在我的方案中,我让客户端从服务器接收文本,然后将其附加到文本框中。

BTW I'm using the IntelliJ GUI designer for the JFrame. 顺便说一句,我正在为JFrame使用IntelliJ GUI设计器。 I've only included code needed to recreate the problem. 我只包含了重新创建问题所需的代码。 I'm still trying to create MCVE questions so feel free to let me know mistakes I made. 我仍在尝试提出MCVE问题,因此随时让我知道自己犯的错误。

You should pass Client into ServerThread via the constructor. 您应该通过构造函数将Client传递到ServerThread The Client you are instantiating within run() is not the same reference to the Client you created in main() . Client你中具体使用run()是不一样的参考Client你创建main() So your ServerThread class would be something like 因此,您的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)
    {}
}

Your startClient() method would be updated to something like this 您的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();
    }
}

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. 我建议将main()移出Client并移至与Swing UI代码不太相关的类中。 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 然后,您的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
    }
}

the append function is run nothing appears in the text area of the jFrame 运行append函数时,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 基本上,第一点意味着您不应在事件调度线程内运行任何长时间运行或阻塞的进程,并且不应从事件调度线程的上下文外部修改UI(或UI依赖的任何状态)

Start by taking a look at Concurrency in Swing for more details. 首先查看Swing中的并发以获取更多详细信息。

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 . 接下来,我查看了ServerThread Basically this class becomes responsible for the management of the Socket and delivery of the messages to the Client . 基本上,该类负责管理Socket和将消息传递给Client Because of the requirements of Swing, I've used a SwingWorker . 由于Swing的要求,我使用了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 这使我可以在后台线程上运行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;
    }
}

And then the actual UI client itself... 然后是实际的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");
        }

    }
}

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. 最后,我编写了一个简单的Server测试代码,该代码只是将当前日期/时间作为String发送给连接的客户端。

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 要进行全部测试,请启动Server ,然后运行Main

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM