好吧,朋友和我一直在尝试制作我们自己的服务器客户端,并且只需键盘扫描程序和println语句就可以正常工作......直到我们尝试实现gui才开始工作变得怪异......
有时它会起作用......有时它会冻结,有时候什么都不会发生......
我们非常肯定问题出现在ask()方法中,因为它没有发生任何事情,
public String ask(String string)
{
println(string);
hasInput = false;
while(true)
{
//System.out.println("working");
if(hasInput)
{
println("done");
return processLastInput();//removes the carot ">" from the input and returns it
}
}
}
但是如果你取消注释println语句呢 不一致的工作 ...这是您要查看的其余代码
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
public class ConsoleGUI
{
private JFrame FRAME;
private JPanel PANEL;
private JTextArea CMD_TEXT;
private JTextArea CMD_HISTORY;
private JScrollPane CMD_HISTORY_SCROLLER;
private String LAST_INPUT = "";
private boolean hasInput = false;
private final int screenX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
private final int screenY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();
public ConsoleGUI(String terminalHeader)
{
FRAME = new JFrame(terminalHeader);
PANEL = new JPanel();
CMD_TEXT = new JTextArea(">");
CMD_HISTORY = new JTextArea();
CMD_HISTORY_SCROLLER = new JScrollPane(CMD_HISTORY_SCROLLER);
FRAME.setBounds(screenX/2-250,screenY/2-150,500,300);
FRAME.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FRAME.getContentPane().add(PANEL);
FRAME.setResizable(false);
CMD_TEXT.setBackground(Color.BLACK);
CMD_TEXT.setForeground(Color.GREEN);
CMD_TEXT.setFont(new Font("courier new",Font.PLAIN,15));
CMD_TEXT.setBorder(BorderFactory.createTitledBorder("COMMAND:"));
CMD_TEXT.setBounds(0,220,490,50);
CMD_TEXT.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "NEXT");
CMD_TEXT.getActionMap().put("NEXT",new ActivateInputAction());
CMD_HISTORY.setEditable(false);
CMD_HISTORY.setBackground(Color.BLACK);
CMD_HISTORY.setForeground(Color.GREEN);
CMD_HISTORY.setFont(new Font("courier new",Font.PLAIN,20));
CMD_HISTORY.setBorder(BorderFactory.createTitledBorder("CONSOLE:"));
CMD_HISTORY_SCROLLER = new JScrollPane(CMD_HISTORY);
CMD_HISTORY_SCROLLER.setBounds(0,0,490,220);
PANEL.setBackground(Color.GRAY);
PANEL.setFocusable(true);
PANEL.setLayout(null);
PANEL.add(CMD_HISTORY_SCROLLER);
PANEL.add(CMD_TEXT);
FRAME.setVisible(true);
}
public void print(Object ob)
{
CMD_HISTORY.append(ob.toString());
}
public void println(Object ob)
{
CMD_HISTORY.append(ob.toString()+"\n");
}
public String getLastInput(){return LAST_INPUT;}
public String processLastInput()
{
String newString = LAST_INPUT.replace(">","");
return newString;
}
public boolean hasInput(){return hasInput;}
public String ask(String string)
{
println(string);
hasInput = false;
while(true)
{
if(hasInput)
{
println("done");
return processLastInput();
}
}
}
class ActivateInputAction extends AbstractAction
{
@Override
public void actionPerformed(ActionEvent e)
{
LAST_INPUT = CMD_TEXT.getText();
println(LAST_INPUT);
CMD_TEXT.setText(">");
CMD_HISTORY.setCaretPosition(CMD_HISTORY.getText().length());
hasInput = true;
}
}
}
如果您愿意,服务器代码也在下面
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Server
{
private static ServerSocket service = null;
private static String line;
private static BufferedReader input;
private static PrintStream output;
private static Socket clientSocket = null;
//private static final Scanner keyboard = new Scanner(System.in);
private static ConsoleGUI Console = new ConsoleGUI("SERVER");
public static void main(String[] args)
{
try
{
int port = Integer.parseInt(Console.ask("PORT:"));
Console.println("PORT = "+port);
service = new ServerSocket(port);
Console.println(service.getLocalSocketAddress());
Console.println("WAITING FOR CLIENT TO CONNECT");
clientSocket = service.accept();
input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
output = new PrintStream(clientSocket.getOutputStream());
Console.println("CLIENT CONNECTED");
Console.println(service.getInetAddress());
while(true)
{
line = input.readLine();
output.println(line);
}
}
catch(Exception e)
{
Console.println(e);
}
}
}
答案 0 :(得分:3)
Swing是一个单线程环境,也就是说,期望与UI的所有交互都是从事件调度线程完成的。任何阻止EDT的东西都会阻止UI响应用户或处理新事件
你似乎正在犯这样的错误,试图在EDT的上下文之外更新textarea,这似乎是导致某种线程锁定(至少在Java 8下)
所以,我首先更新了您的print
方法,以便在EDT的上下文中更新内容
public void print(final Object ob) {
Runnable run = new Runnable() {
@Override
public void run() {
CMD_HISTORY.append(ob.toString());
}
};
if (EventQueue.isDispatchThread()) {
run.run();
} else {
EventQueue.invokeLater(run);
}
}
public void println(Object ob) {
Runnable run = new Runnable() {
@Override
public void run() {
CMD_HISTORY.append(ob.toString() + "\n");
}
};
if (EventQueue.isDispatchThread()) {
run.run();
} else {
EventQueue.invokeLater(run);
}
}
我还将您的LAST_INPUT
和hasInput
变量更新为volatile
...
private volatile String LAST_INPUT = "";
private volatile boolean hasInput = false;
这将确保它们在线程边界之间正确更新......
不是尝试使用boolean
标志作为更多信息的指示器,而是使用对象监视器锁定更好,主要原因是它会使等待线程进入休眠状态,因此它赢了“消耗任何CPU ......
private final Object inputLock = new Object();
//...
public String ask(String string) {
println(string);
hasInput = false;
do {
synchronized (inputLock) {
try {
System.out.println("Wait");
inputLock.wait();
} catch (InterruptedException ex) {
}
}
} while (!hasInput);
println("done");
return processLastInput();
}
我强烈建议您在继续前进之前阅读Concurrency in Swing。上面的例子充其量只是黑客......
答案 1 :(得分:0)
在ask()中,hasInput初始化为false,因此您将立即进入无限循环。这将导致奇怪的行为,因为它吸收任何可用的周期。