每次将点添加到Arraylist时运行循环(Java)
我目前在以下课程中工作,这是一个带有while循环的绘画程序,用于将包从客户端发送到服务器:每次将点添加到Arraylist时运行循环(Java),java,arraylist,Java,Arraylist,我目前在以下课程中工作,这是一个带有while循环的绘画程序,用于将包从客户端发送到服务器: public class TCPClient extends JPanel { public static ArrayList<Point> location = new ArrayList<>(); private JTextArea consoleOutput = new JTextArea(1,20); public void addComp
public class TCPClient extends JPanel {
public static ArrayList<Point> location = new ArrayList<>();
private JTextArea consoleOutput = new JTextArea(1,20);
public void addComponentToPane(Container pane) {
consoleOutput.setEditable(false);
}
public TCPClient() {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
location.add(e.getPoint());
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
location.add(e.getPoint());
repaint();
}
});
setPreferredSize(new Dimension(800, 500));
setBackground(Color.WHITE);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(location.isEmpty()){
return;
}
Point p = location.get(0);
for (int i = 1; i < location.size(); i++) {
Point q = location.get(i);
g.drawLine(p.x, p.y, q.x, q.y);
p = q;
}
}
public static void main(String argv[]) throws Exception {
InetAddress SERVERIP = InetAddress.getLocalHost();
JFrame frame = new JFrame("Drawing with friends");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TCPClient(), BorderLayout.CENTER);
JTextArea IPadress = new JTextArea(1,20);
IPadress.setEditable(false);
IPadress.append("DEVICE IP: " + SERVERIP.getHostAddress());
frame.add(IPadress, BorderLayout.SOUTH);
frame.setSize(new Dimension(800,600));
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
while(true) {
try {
//BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 9000);
ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
//ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());
outToServer.writeObject(location);
outToServer.flush();
clientSocket.close();
Thread.sleep(100);
} catch (SocketException e) {
System.err.println(e.toString());
}
}
}
}
不要让其他对象直接修改您的
ArrayList
,而是将其设置为私有,并创建一个getter、setter以及一个adder和remover方法(因为您使用的是集合)
在这些文件中,您可以通知程序的其他部分,
ArrayList
已更改,您需要发送一个数据包。您需要使用notify()将对变量位置的任何访问(read
和write
)包装到一个synchronized
块中
如果您对其进行了更新,然后在循环中用wait
替换sleep
,如下所示:
位置修改:
synchronized (location) {
location.add(e.getPoint());
location.notify();
}
synchronized (location) {
if(location.isEmpty()){
return;
}
Point p = location.get(0);
for (int i = 1; i < location.size(); i++) {
Point q = location.get(i);
g.drawLine(p.x, p.y, q.x, q.y);
p = q;
}
}
synchronized (location) {
while(true) {
//BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 9000);
ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
//ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());
outToServer.writeObject(location);
outToServer.flush();
clientSocket.close();
location.wait();
}
}
对位置的读取权限:
synchronized (location) {
location.add(e.getPoint());
location.notify();
}
synchronized (location) {
if(location.isEmpty()){
return;
}
Point p = location.get(0);
for (int i = 1; i < location.size(); i++) {
Point q = location.get(i);
g.drawLine(p.x, p.y, q.x, q.y);
p = q;
}
}
synchronized (location) {
while(true) {
//BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 9000);
ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
//ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());
outToServer.writeObject(location);
outToServer.flush();
clientSocket.close();
location.wait();
}
}
您可以创建自己的
CallbackArrayList
,它扩展了ArrayList
。
添加抽象回调方法,例如onAdded
和onRemoved
覆盖要监视的ArrayList
方法,并根据结果在其中调用回调方法
abstract class CallbackArrayList<T> extends ArrayList<T> {
public abstract void onAddSuccess(T object);
public abstract void onAddFailure(T object);
@Override
public boolean add(T object) {
boolean success = super.add(object);
if(success) {
onAddSuccess(object);
}
else {
onAddFailure(object);
}
return success;
}
}
抽象类CallbackArrayList扩展了ArrayList{
公开摘要无效(T对象);
公开摘要失效(T对象);
@凌驾
公共布尔加法(T对象){
布尔成功=super.add(对象);
如果(成功){
onAddSuccess(对象);
}
否则{
onAddFailure(对象);
}
回归成功;
}
}
然后在分配列表时,您可以执行以下操作
location = new CallbackArrayList<>() {
@Override
public void onAddSuccess(Point object) {
// handle send information to server
}
@Override
public void onAddFailure(Point object) {
// handle failure
}
};
location=newcallbackarraylist(){
@凌驾
公共无效onAddSuccess(点对象){
//句柄将信息发送到服务器
}
@凌驾
公共无效onAddFailure(点对象){
//处理失败
}
};
无论何时调用
location.add(e.getPoint())
,之后都会调用其中一个回调方法。基本上,您应该使用某种阻塞队列
,这将允许您的“套接字”线程在等待新的点
到达时“阻塞”
您不应该发送整个列表
,而应该单独发送每个点
,这样可以随着点数的增加节省时间
由于队列的性质,您可以不断向其添加更多点,“套接字”线程可以按自己的速度处理这些点,这将允许队列随着用户的绘制而增大,但允许“套接字”线程在用户停止时赶上,而无需您做任何特殊的操作
下面的示例使用Thread.sleep
在处理队列中的每个点之间生成一个人工延迟,用于演示,显然,您不应该使用它(Thread.sleep
),但它演示了上面的几点,停止绘图后,线程将继续将点从队列转储到标准输出
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
private BlockingQueue<Point> queue;
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
queue = new LinkedBlockingQueue<>();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TCPClient(queue));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Thread t = new Thread(new Consumer(queue));
t.setDaemon(true);
t.start();
}
});
}
public class TCPClient extends JPanel {
private JTextArea consoleOutput = new JTextArea(1, 20);
private Queue<Point> queue;
private List<Point> cache;
public TCPClient(Queue<Point> queue) {
this.queue = queue;
cache = new ArrayList<>(25);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
queue.add(e.getPoint());
cache.add(e.getPoint());
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
queue.add(e.getPoint());
cache.add(e.getPoint());
repaint();
}
});
setPreferredSize(new Dimension(800, 500));
setBackground(Color.WHITE);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (cache.isEmpty()) {
return;
}
Point p = cache.get(0);
for (int i = 1; i < cache.size(); i++) {
Point q = cache.get(i);
g.drawLine(p.x, p.y, q.x, q.y);
p = q;
}
}
}
public class Consumer implements Runnable {
private BlockingQueue<Point> queue;
public Consumer(BlockingQueue<Point> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
try {
Point p = queue.poll(Long.MAX_VALUE, TimeUnit.DAYS);
if (p != null) {
System.out.println("-> Got " + p);
Thread.sleep(125);
}
} catch (InterruptedException ex) {
}
}
}
}
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Point;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.awt.event.MouseMotionAdapter;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Queue;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.LinkedBlockingQueue;
导入java.util.concurrent.TimeUnit;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JTextArea;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公开课考试{
私有阻塞队列;
公共静态void main(字符串[]args){
新测试();
}
公开考试(){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
例如printStackTrace();
}
队列=新的LinkedBlockingQueue();
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(新的TCPClient(queue));
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
线程t=新线程(新使用者(队列));
t、 setDaemon(true);
t、 start();
}
});
}
公共类TCPClient扩展了JPanel{
专用JTextArea控制台输出=新的JTextArea(1,20);
专用队列;
私有列表缓存;
公共TCP客户端(队列){
this.queue=队列;
cache=newarraylist(25);
addMouseListener(新的MouseAdapter(){
@凌驾
公共无效鼠标按下(MouseEvent e){
添加(例如getPoint());
cache.add(如getPoint());
}
});
addMouseMotionListener(新的MouseMotionAdapter(){
@凌驾
公共无效鼠标标记(鼠标事件e){
添加(例如getPoint());
cache.add(如getPoint());
重新油漆();
}
});
设置首选尺寸(新尺寸(800500));
挫折地面(颜色:白色);
}
@凌驾
受保护组件(图形g){
超级组件(g);
if(cache.isEmpty()){
返回;
}
p点=cache.get(0);
对于(int i=1;i