ここのどこかにバグがあります。何らかの理由で、メッセージをサーバーに送信すると、すべてのメッセージが 1 回のキーストロークで 2 回受信されます。たとえば、「a」と入力すると、サーバーは「INSERT 0 1 a」「INSERT 0 1 a」を受け取ります。なぜ2回起こるのかわかりませんか?
package client;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class JTextAreaListen extends JFrame implements KeyListener,
CaretListener {
private static final long serialVersionUID = 6950001634065526391L;
private JTextArea textArea;
protected final PrintWriter out;
protected final int id;
protected final BufferedReader in;
protected static int caretPos;
private static int cMark;
protected static boolean text_selected;
/*
* Connecting to server. (1337 is the port we are going to use).
*
* socket = new Socket(InetAddress.getByName("127.0.0.1"), 1337);
*
* (Open a new outStream, you can save this instead of opening on every time
* you want to send a message. If the connection is lost your should to
* out.close();
*
* out = new PrintWriter(socket.getOutputStream(), true);
*
* out.print("message"); to send something to the server.
*/
public JTextAreaListen(PrintWriter out, BufferedReader in, int id) {
super("JTextAreaListen");
this.id = id;
this.out = out;
this.in = in;
TextEditor.document.addCaretListener(this);
TextEditor.document.addKeyListener(this);
}
// Listener methods
public void changedUpdate(DocumentEvent ev) {
}
public void removeUpdate(DocumentEvent ev) {
}
public void insertUpdate(DocumentEvent ev) {
}
@Override
public void keyPressed(KeyEvent arg0) {
System.out.print("KeyPressedd");
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent ev) {
System.out.println(ev.KEY_PRESSED);
System.out.println("Sth happening!");
System.out.println(ev.getKeyCode());
int evID = ev.getID();
String keyString;
int keyCode;
if (evID == KeyEvent.KEY_TYPED) {
if (ev.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
keyCode = ev.getKeyCode();
if (keyCode == 8) {
if (text_selected) {
if (caretPos > cMark) {
for (int i = caretPos; i >= cMark; i--) {
System.out.println("sm1");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
} else if (caretPos < cMark) {
for (int i = caretPos; i >= cMark; i++) {
System.out.println("sm2");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
}
} else {
System.out.println("sm3");
sendMessage("DELETE" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos + 1));
}
}
} else {
char c = ev.getKeyChar();
boolean capital = ev.isShiftDown();
String charString = String.valueOf(c);
if (capital) {
charString.toUpperCase();
}
if (text_selected) {
if (caretPos > cMark) {
for (int i = caretPos; i >= cMark; i--) {
System.out.println("sm4");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(cMark + 1));
}
System.out.println("sm5");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(cMark) + " " + charString);
} else if (caretPos < cMark) {
for (int i = caretPos; i >= cMark; i++) {
System.out.println("sm6");
sendMessage("DELETE" + " " + String.valueOf(id)
+ " " + String.valueOf(caretPos + 1));
}
System.out.println("sm7");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos) + " " + charString);
}
} else {
System.out.println("sm8");
sendMessage("INSERT" + " " + String.valueOf(id) + " "
+ String.valueOf(caretPos) + " " + charString);
}
}
}
}
public void sendMessage(String s) {
System.out.println("smReal");
out.println(s);
}
@Override
public void caretUpdate(CaretEvent cev) {
int dot = cev.getDot();
int mark = cev.getMark();
caretPos = dot;
cMark = mark;
if (dot == mark) {
text_selected = false;
} else if ((dot < mark) | (dot > mark)) {
text_selected = true;
}
}
}
このリスナーを呼び出す TextArea を含むクライアントのコードを次に示します。
package client;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.text.DefaultEditorKit;
public class TextEditor extends JFrame {
private static final long serialVersionUID = 5991470239888613993L;
protected static JTextArea document = new JTextArea(20, 120);
private JFileChooser dialog = new JFileChooser(
System.getProperty("user.dir"));
private String currentFile = "Untitled";
private boolean changed = false;
private int id;
private final BufferedReader in;
private final PrintWriter out;
public TextEditor(final PrintWriter out, final BufferedReader in, int id) {
this.out = out;
this.in = in;
this.id = id;
document.setFont(new Font("Monospaced", Font.PLAIN, 12));
JScrollPane scroll = new JScrollPane(document,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
this.add(scroll, BorderLayout.CENTER);
JMenuBar JMB = new JMenuBar();
this.setJMenuBar(JMB);
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
JMB.add(file);
JMB.add(edit);
file.add(Open);
file.add(Save);
file.add(Quit);
file.add(SaveAs);
file.addSeparator();
for (int i = 0; i < 4; i++)
file.getItem(i).setIcon(null);
edit.add("Cut");
edit.add("Copy");
edit.add("Paste");
edit.getItem(0).setText("Cut");
edit.getItem(1).setText("Copy");
edit.getItem(2).setText("Paste");
JToolBar tool = new JToolBar();
this.add(tool, BorderLayout.NORTH);
tool.add(Open);
tool.add(Save);
tool.addSeparator();
JButton cut = tool.add(Cut), copy = tool.add(Copy), paste = tool
.add(Paste);
cut.setText(null);
cut.setIcon(new ImageIcon("cut.png"));
copy.setText(null);
copy.setIcon(new ImageIcon("copy.png"));
paste.setText(null);
paste.setIcon(new ImageIcon("paste.png"));
Save.setEnabled(false);
SaveAs.setEnabled(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
document.addKeyListener(new JTextAreaListen(out, in, id));
setTitle(currentFile);
setVisible(true);
final int id2 = id;
Thread t = new Thread(new Runnable() {
public void run() {
out.println("GET " + id2);
while (true) {
out.println("GET " + id2);
String line = null;
do {
try {
line = in.readLine();
} catch (IOException e) {
JOptionPane.showMessageDialog(null,
"Connection Lost", "Error",
JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
} while (line == null);
int temp = JTextAreaListen.caretPos;
document.setText(line);
document.setCaretPosition(temp);
}
}
});
t.start();
}
private KeyListener keyPressed = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
changed = true;
Save.setEnabled(true);
SaveAs.setEnabled(true);
}
};
Action Open = new AbstractAction("Open", new ImageIcon("open.png")) {
private static final long serialVersionUID = -474289105133169886L;
public void actionPerformed(ActionEvent e) {
saveOld();
if (dialog.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
readInFile(dialog.getSelectedFile().getAbsolutePath());
}
SaveAs.setEnabled(true);
}
};
Action Save = new AbstractAction("Save", new ImageIcon("save.png")) {
private static final long serialVersionUID = 2064233284536910855L;
public void actionPerformed(ActionEvent e) {
if (!currentFile.equals("Untitled"))
saveFile(currentFile);
else
saveFileAs();
}
};
Action SaveAs = new AbstractAction("Save as...") {
private static final long serialVersionUID = -5473532525926088880L;
public void actionPerformed(ActionEvent e) {
saveFileAs();
}
};
Action Quit = new AbstractAction("Quit") {
private static final long serialVersionUID = -5339245808869817726L;
public void actionPerformed(ActionEvent e) {
saveOld();
System.exit(0);
}
};
ActionMap m = document.getActionMap();
Action Cut = m.get(DefaultEditorKit.cutAction);
Action Copy = m.get(DefaultEditorKit.copyAction);
Action Paste = m.get(DefaultEditorKit.pasteAction);
private void saveFileAs() {
if (dialog.showSaveDialog(null) == JFileChooser.APPROVE_OPTION)
saveFile(dialog.getSelectedFile().getAbsolutePath());
}
private void saveOld() {
if (changed) {
if (JOptionPane.showConfirmDialog(this, "Save " + currentFile
+ " ?", "Save", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
saveFile(currentFile);
}
}
private void readInFile(String fileName) {
try {
FileReader r = new FileReader(fileName);
document.read(r, null);
r.close();
currentFile = fileName;
setTitle(currentFile);
changed = false;
} catch (IOException e) {
Toolkit.getDefaultToolkit().beep();
JOptionPane.showMessageDialog(this, "Could not find " + fileName);
}
}
private void saveFile(String fileName) {
try {
FileWriter w = new FileWriter(fileName);
document.write(w);
w.close();
currentFile = fileName;
setTitle(currentFile);
changed = false;
Save.setEnabled(false);
} catch (IOException e) {
JOptionPane
.showMessageDialog(this,
"An error has occurred. Your document may not have been saved");
}
}
}