这是我关于StackOverflow的第一个问题,所以我希望我的问题不是太模糊或格式错误。
我正在尝试使用Netbeans Swing GUI构建器使用Swing内置的GUI构建Java桌面聊天应用程序。有一个托管聊天的服务器,而多个客户端可以连接并离开聊天。对于连接到服务器的每个客户端,我创建一个新线程来处理与相应客户端的所有通信。当客户端发送消息时,它首先进入线程读取它的服务器,更新聊天记录(textarea),然后通过调用write()将消息写入所有其他客户端。
以下是服务器代码:
import java.io.*;
import java.net.*;
public class server extends javax.swing.JFrame implements Runnable
{
static Socket sock[]=new Socket[100]; //Array of sockets, 1 for each accept
static server obj[]=new server[100]; //Array of server objects, 1 for each thread
static Thread threads[]=new Thread[100]; //Array of threads, 1 for each client
static boolean conn_state[]=new boolean[100]; //Array of boolean values depicting whether connection is closed or not
static DataOutputStream dos[]=new DataOutputStream[100]; //Array of DataOutputStreams, 1 for each client
static InetAddress ipaddr[]=new InetAddress[100]; //Array to hold InetAddress objects of each client
static int port[]=new int[100]; //Array to hold port numbers
static int i=0; //No. of clients
static int except=0; //Marks client no. who sent last message
static int count=0; //Total no. of open connections at any time
static boolean flag=false; //Currently unused
static String str; //To hold message sent by a client
public server() {
initComponents();
setLocationRelativeTo(null);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
jButton2 = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
jLabel1.setText("Chat Log :");
jButton1.setBackground(new java.awt.Color(204, 204, 255));
jButton1.setText("Stop Server");
jButton1.setToolTipText("Stop the server hosting the chat.");
jButton1.setPreferredSize(new java.awt.Dimension(120, 25));
jButton2.setText("Print Chat Log");
jButton2.setPreferredSize(new java.awt.Dimension(120, 25));
jScrollPane1.setAutoscrolls(true);
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);
javax.swing.GroupLayout layout = new
javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(52, 52, 52)
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(52, 52, 52))
.addGroup(layout.createSequentialGroup()
.addGap(22, 22, 22)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 356, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 118, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(22, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 34, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(34, 34, 34))
);
pack();
}// </editor-fold>
public static void serve()
{
System.out.println("Server Program Running");
try
{
ServerSocket ss =new ServerSocket(50000);
while(true)
{
sock[i]=ss.accept();
System.out.println("Client with IP Address :- "+sock[i].getInetAddress().getHostAddress()+":"+sock[i].getPort()+" connected.");
obj[i]=new server();
threads[i]=new Thread(obj[i]);
conn_state[i]=true;
dos[i]=new DataOutputStream(sock[i].getOutputStream());
ipaddr[i]=sock[i].getInetAddress();
port[i]=sock[i].getPort();
count++;
i++;
threads[i-1].start(); //A new thread is created for each client to read all incoming messages and write it out to every other client
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
@Override
public void run()
{
try
{
int k=i-1; //Marks client no.
//TextArea does not get updated by the following lines
jTextArea1.append("Client with IP Address :- "+sock[k].getInetAddress().getHostAddress()+":"+sock[k].getPort()+" connected.");
jTextArea1.update(jTextArea1.getGraphics());
DataInputStream dis = new DataInputStream(sock[k].getInputStream());
while(true)
{
//System.out.println("k="+k);
str=dis.readUTF();
if(str.equalsIgnoreCase("exit"))
{
//If a client types exit, the server closes all socket and streams of that client and writes out thst the client has left
dis.close();
conn_state[k]=false;
sock[k].close();
count--;
str="Client with ip ="+(ipaddr[k].getHostAddress())+" and port no. = "+port[k]+" left the chat.";
flag=true;
write();
if(count!=0) //When open connections = 0, the server shuts down
return;
else
System.exit(0);
}
except=k;
str=ipaddr[k].getHostAddress()+":"+port[k]+" :- "+str;
System.out.println(str);
//The text area does not get updated
jTextArea1.setText(jTextArea1.getText()+str);
jTextArea1.repaint();
write(); //Function to write out "str" to all other clients
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void write()
{
int c;
for(c=0;c<i;c++)
{
//System.out.println(c);
if(c==except||conn_state[c]==false) //If c=current sender's client no. or connection is closed then do not write to it
continue;
try
{
/*if(!flag)
str="From IP Address :- "+ipaddr[except].getHostAddress()+":"+port[except]+"\nMessage : "+str;*/
dos[c].writeUTF(str); //Writing "str" to every client other than except
dos[c].flush();
//dos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see
http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(server.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(server.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(server.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(server.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new server().setVisible(true);
}
});
serve(); //Main job done by server
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
}
现在,当我作为客户端连接到服务器时,“客户端已连接”消息,客户端发送的所有消息都正确输出到控制台,但文本区域中没有任何内容。客户端代码只包括连接到服务器,然后运行2个线程,一个用于读取,一个用于写入。
当我在C中实现了这么多客户端 - 服务器模型时,没有任何GUI,它运行良好。当所有输出都打印到控制台而不是GUI时,我甚至设法用Java做同样的工作。当我尝试包含GUI时,GUI上没有任何内容。谷歌搜索我的问题引发了关于StackOverflow的问题,我从中了解到Swing组件只能被1个名为EDT的线程改变,而其他任何线程都无法改变它们。他们建议使用
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
JTextArea1.setText(jTextArea1.getText()+str);
}
});
但是我已经尝试了这个但它仍然不起作用。
如果您愿意调查此事,我将非常感激。如果代码过于集中,不洁或充满不良做法,我感到非常抱歉。我仍然是编码甚至是Java的新手,我欢迎任何反馈。
答案 0 :(得分:1)
对不起,我的第一次分析还没有完成。
您看到的JFrame
是在main
方法中创建的server
。然而,没有任何线程可以将某些东西写入它的textarea,因为你没有保留对框架或textarea的引用。
您创建的每个JFrame
实例都会在JTextArea
和setVisible(true);
上创建,但这些实例永远不会在屏幕上显示(您永远不会调用ServerCommunication
在这些框架上)。
要解决您的问题,最好创建两个类:
ServerGUI
)SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.setText(jTextArea1.getText()+str);
}
});
)更新textarea的正确方法来自您提供的片段:
SwingUtilities.invokeLater(() -> {
jTextArea1.setText(jTextArea1.getText()+str);
});
或者,使用Java 8及更高版本的lambdas:
jTextArea1.repaint();
请不要尝试拨打jTextArea1.update(jTextArea1.getGraphics());
或import pandas as pd
df = pd.DataFrame({'Group': ['A','A','A','B','B','B','B'], 'count': [1.1,11.2,1.1,3.3,3.40,3.3,100.0]})
print(pd.DataFrame(df.groupby('Group').quantile(.01)['count']))
- 在这种情况下,这些电话是无意义的,完全没必要。