java - 在 Swing 事件中启动线程

标签 java multithreading swing sockets client-server

我正在开发客户端/服务器聊天的客户端应用程序,这是为了学习经验。我的问题是我似乎无法让 socket 和 Swing 同时运行。

我想要的是,当用户打开 JOpionsPane 并输入主机名和端口号时,单击“确定”,然后它们就会连接。当套接字信息被硬编码时,它工作得很好,但现在我正在尝试获取用户的输入。

应该发生的是, Action 监听器应该创建处理通信的新 SocketManager 对象。事件虽然说已连接,但并未运行。当我创建新的 SocketManager 对象并在新线程上运行它时,它会连接并恢复来自服务器的消息,但随后 Swing 会卡住,我必须结束该进程才能将其关闭。

我应该在新的工作线程或其他线程上启动它吗?也许只是因为我累了,但我没有想法。

编辑 我更新了 ActLis.class 和 SocketManager.class,建议为我的 SocketManager 对象“网络”添加一个新线程。当我尝试使用“网络”时,尽管它由于某种原因返回 null。

ActLis.clss

package com.client.core;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class ActLis implements ActionListener {

private Main main = new Main();;
private JTextField ipadress = new JTextField(),
        portnumber = new JTextField(),
        actionField;

private String username;

final JComponent[] ipinp = new JComponent[]{new JLabel("Enter Hostname (IP Adress): "),
        ipadress,
        new JLabel("Enter Port number: "), portnumber};
private SocketManager network;
private Window win;

public ActLis(){

}

public ActLis(JTextField t, Window w){
    actionField = t;
    win = w;

}

@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();


if(cmd == "Exit"){
    System.exit(0);
} else if(cmd == "Connect to IP"){
    try{
        JOptionPane.showMessageDialog(null, ipinp, "Connect to IP", JOptionPane.PLAIN_MESSAGE);
        if(network != null){
            network.close();
        }
        network = new SocketManager(ipadress.getText(),Integer.parseInt(portnumber.getText()));
        network.setGUI(win);
        Thread t = new Thread(network);
        t.start();
        JOptionPane.showMessageDialog(null, "Connected to chat host successfully!","Connected", JOptionPane.INFORMATION_MESSAGE);
    }catch(Exception ee){
        JOptionPane.showMessageDialog(null, "Could not connect. Check IP adress or internet connection","Error - Could not connect", JOptionPane.ERROR_MESSAGE);
        ee.printStackTrace();
    }

} else if (cmd == "chatWriter"){

    if( actionField.getText() != ""){   
        try{
            network.send(actionField.getText());
            win.updateChat(actionField.getText());
            actionField.setText("");
            actionField.requestFocus();
        }catch(Exception ex){
            JOptionPane.showMessageDialog(null, "You are not connected to a host. (File -> Connect to IP)","Error - Not Connected", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
        }

    }

} else if (cmd == "setUsername"){
    username = actionField.getText();
    network.send("USERNAME:" + username);


}


}
}

Main.class

package com.client.core;

import javax.swing.JFrame;

public class Main extends JFrame{

private SocketManager network;

public static void main(String[] args){     
    Main main = new Main();
    main.run();

}

private void run(){
    Window win = new Window();
    win.setVisible(true);
}
}

SocketManager.class

package com.client.core;

import java.io.*;
import java.net.*;

public class SocketManager implements Runnable {

private Socket sock;
private PrintWriter output;
private BufferedReader input;
private String hostname;
private int portnumber;
private String message;
private Window gui;

public SocketManager(String ip, int port){
    try{
        hostname = ip;
        portnumber = port;
    }catch(Exception e){
        System.out.println("Client: Socket failed to connect.");
    }
}



public synchronized void send(String data){
    try{
        //System.out.println("Attempting to send: " + data);
        output.println(data);
        output.flush();
        //System.out.println("Message sent.");
    }catch(Exception e){
        System.out.println("Message could not send.");
    }
}

public synchronized void setGUI(Window w){
    gui = w;
}

public synchronized void connect(){
    try{
        sock = new Socket(hostname,portnumber);
    }catch(Exception e){

    }
}

public synchronized Socket getSocket(){
    return sock;
}

public synchronized void setSocket(SocketManager s){
    sock = s.getSocket();
}

public synchronized void close(){
    try{
        sock.close();
    }catch(Exception e){
        System.out.println("Could not close connection.");
    }
    output = null;
    input = null;
    System.gc();
}

public synchronized boolean isConnected(){
    return (sock == null) ? false : (sock.isConnected() && !sock.isClosed());
}

public synchronized void listenStream(){
    try {
        while((message = input.readLine()) != null){        
            System.out.println("Server: " + message);
            gui.updateChat(message);
        }
    } catch (Exception e) {

    }
}

@Override
public void run() {
    try {
        sock = new Socket(hostname,portnumber);
        output = new PrintWriter(sock.getOutputStream(),true);
        input = new BufferedReader(
                new InputStreamReader(sock.getInputStream()));
        while(true){
            listenStream();
        }
    } catch (Exception e) {
        System.out.println("Run method fail. -> SocketManager.run()");
    }finally{
        try {
            sock.close();
        } catch (Exception e) {

        }
    }

}

}

Window.class

package com.client.core;

import java.awt.*;
import javax.swing.*;


public class Window extends JFrame{

private int screenWidth = 800;
private int screenHeight = 600;

private SocketManager network;

private JPanel window = new JPanel(new BorderLayout()),
        center = new JPanel(new BorderLayout()),
        right = new JPanel(new BorderLayout()),
        display = new JPanel( new BorderLayout()),
        chat = new JPanel(),
        users = new JPanel(new BorderLayout());

private JTextArea chatBox = new JTextArea("Welcome to the chat!", 7,50),
        listOfUsers = new JTextArea("None Online");

private JTextField chatWrite = new JTextField(),
        userSearch = new JTextField(10),
        username = new JTextField();

private JScrollPane userList = new JScrollPane(listOfUsers),
        currentChat = new JScrollPane(chatBox);

private JMenuBar menu = new JMenuBar();

private JMenu file = new JMenu("File");

private JMenuItem exit = new JMenuItem("Exit"),
        ipconnect = new JMenuItem("Connect to IP");
private JComponent[] login = new JComponent[]{new JLabel("Username:"), username};

public Window(){

    //Initial Setup
    super("NAMEHERE - Chat Client Alpha v0.0.1");
    setResizable(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(screenWidth,screenHeight);


    //Panels
    listOfUsers.setLineWrap(true);
    listOfUsers.setEditable(false);
    display.setBackground(Color.black);
    chat.setLayout(new BoxLayout(chat, BoxLayout.Y_AXIS));
    chat.setBackground(Color.blue);
    users.setBackground(Color.green);       

    //TextFields
    addChatArea();

    //Menu bar
    addMenuBar();   

    //Adding the main panels. 
    addPanels();

    //Listeners
    addListeners();

    for(int x = 0; x < 1; x++){
        login();
    }
}

private void login(){
    JOptionPane.showMessageDialog(null, login, "Log in", JOptionPane.PLAIN_MESSAGE);
}

private void addChatArea(){
    chatBox.setEditable(false);     
    userList.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    currentChat.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    users.add(userList);
    users.add(userSearch, BorderLayout.NORTH);
    chat.add(currentChat);
    chat.add(chatWrite);
    chat.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
}

private void addMenuBar(){
    file.add(ipconnect);
    file.add(exit);
    menu.add(file); 
}

private void addPanels(){
    right.add(users);
    center.add(display, BorderLayout.CENTER);
    center.add(chat, BorderLayout.SOUTH);
    window.add(center, BorderLayout.CENTER);
    window.add(right, BorderLayout.EAST);
    window.add(menu, BorderLayout.NORTH);
    add(window);
}

private void addListeners(){
    username.addActionListener(new ActLis(username, this));
    chatWrite.addActionListener(new ActLis(chatWrite, this));
    username.setActionCommand("setUsername");
    chatWrite.setActionCommand("chatWriter");
    ipconnect.addActionListener(new ActLis());
    exit.addActionListener(new ActLis());
}

public void setNetwork(SocketManager n){
    network = n;
}

public void updateChat(String s){
    chatBox.setText(chatBox.getText() + "\n" + s);
}

}

最佳答案

好的@Zexanima,您已经为套接字管理器创建了一个 Socket 类。像这样的事情:

public class YouSocketClass {
   static public Socket socket = null;
   static public InputStream in = null;
   static public OutputStream out = null;

   public YouSocketClass() {
     super();
   }
   public static final Socket getConnection(final String ip, final int port, final int timeout) {
    try {
        socket = new Socket(ip, port);
        try {
            socket.setSoTimeout(timeout);
        } catch(SocketException se) {
            log("Server Timeout");
        }
        in = socket.getInputStream();
        out = socket.getOutputStream();
    } catch(ConnectException e) {
        log("Server name or server ip is failed. " + e.getMessage());
        e.printStackTrace();
    } catch(Exception e) {
        log("ERROR Socket: " + e.getMessage() + " " + e.getCause());
        e.printStackTrace();
    }
    return socket;
}

public static void closeConnection() {
    try {
        if(socket != null) {
            if(in != null) {
                if(out != null) {
                    socket.close();
                    in.close();
                    out.close();
                }
            }
        }
    } catch(Exception e2) {
        e2.printStackTrace();
    }
}

private static Object log(Object sms) {
    System.out.println("Test Socket1.0: " + sms);
    return sms;
}
}

我希望能提供服务。 :)

关于java - 在 Swing 事件中启动线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10594772/

相关文章:

java - 当按钮失去焦点时出现默认按钮

java - 将数据从数据库加载到每个字段的 Jcheckboxes

java - Spring MVC项目无法使用Hibernate

java - 在另一个类中使用数组并停止随机数据

c++ - Qt 多线程通信

android - 服务和处理程序之间的关系

java - 我应该在 netbeans 中创建 Images 文件夹吗

java - 如何使用java + spring代码连接MFT服务器与其余暴露的执行上传,下载和列出文件等操作

java - MySQL 中的字段由 LOAD DATA INFILE 终止

c# - 为什么这个消费者-生产者线程被卡住了?