簡體   English   中英

如何在每個並發線程中在 Java Swing 中繪畫?

[英]How to paint in Java Swing in every concurrent thread?

我的程序的目標是從隨機生成的點中繪制正方形。 我想在每個線程生成一組方塊后立即顯示它們。 但是,一旦所有線程都運行完畢,只會顯示一組方塊。 我使用過swinginvoke,並且很好奇,好像repaint() 有問題,因為所有線程都達到了重繪但在最后一個線程完成之前不會繪制,並最終相互重疊。 我也不希望在每個線程之間共享“storedata”變量,但它的每個實例都將數據保存在其中。 我試圖通過清除它來解決這個問題,但它沒有奏效。 該程序由自定義線程類、線程啟動的主類、GUI 類和繪制正方形的自定義 jpanel 組成。

import java.awt.*;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

class Action extends Thread {

        private Random rand = new Random();
        private static CopyOnWriteArrayList<Point> storedata = new CopyOnWriteArrayList<>();
        static volatile CopyOnWriteArrayList<CopyOnWriteArrayList<Point>> finallist = new CopyOnWriteArrayList<>();
        private GUI g;

        Action(GUI g) {
            this.g = g;

        }

    private void generatePoint() {
        int x = rand.nextInt(500);
        int y = rand.nextInt(500);
        Point p = new Point(x,y);
        storedata.add(p);

    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            generatePoint();
        }
        CopyOnWriteArrayList<Point> copy = new CopyOnWriteArrayList<>(storedata);
        finallist.add(copy);
        SwingUtilities.invokeLater(() -> {
            try {
                Thread.sleep(500);
                System.out.println("ARRAY = " + copy.toString());
                g.setSolution(copy);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        storedata.clear();
    }
}

public class Main {
    public static void main(String[] args) {
        GUI g = new GUI();
        g.setVisible(true);

        Thread[] threads = new Thread[5];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Action(g);
            threads[i].start();
        }

    }


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;

public class GUI extends JFrame implements ActionListener  {
    private CustomPanel c;
    GUI()  {
        initialize();
    }


    private void initialize()  {
        this.setLayout(new FlowLayout());
        c = new CustomPanel(500,500);
        this.setSize(1000,1000);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(c);
        this.setTitle("Seat Placement Program");
    }

    @Override
    public void actionPerformed(ActionEvent e) {

    }

    public void setSolution(CopyOnWriteArrayList<Point> room) {
        c.setRoom(room);
        c.setPaint(true);
        c.repaint();
    }

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;

public class CustomPanel extends JPanel implements ActionListener {

    private Border blackline = BorderFactory.createLineBorder(Color.black);
    private boolean paint;
    private CopyOnWriteArrayList<Point> room;

    public CustomPanel(int h, int w) {
        room = new CopyOnWriteArrayList<>();
        paint = false;
        this.setPreferredSize(new Dimension(w,h));
        this.setBorder(blackline);
    }

    @Override
    public void actionPerformed (ActionEvent e) {

    }


    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(paint) {
            for(Point p : room) {
                g.drawRect((int) p.getX(),(int) p.getY(),20,20);
            }
        }
    }

    void setPaint(boolean b) {
        paint = b;
    }

    public void setRoom(CopyOnWriteArrayList<Point> room) {
        this.room = room;
    }


}

在 Swing 中,繪制只能在Event Dispatching Thread 中完成 實現您想要的方法是當線程完成時,將形狀(可能連同顏色)添加到您想要它的 JComponent 集合中(您需要創建一個具有此類集合的自定義 JComponent,並且您應該在添加形狀時和在繪制形狀時在paintComponent 中同步它)。 然后在您的非 EDT 線程中,調用 myJComponent.repaint()。 可以在所有非 EDT 線程中調用它。

例子:

public class MyPanel extends JPanel {
  Collection<Shape> myShapes = ...;
  public void paintComponent(Graphics g) {
    ... // do any other non-shape related painting
    Graphics2D g2 = (Graphics2D) g;
    synchronized (myShapes) {
      for (Shape s : myShapes) {
        //TODO: do you want to set a color?
        g.draw(s);
        //TODO: do you want to fill the shapes?
        g.fill(s);
      }
    }
  }
}

然后在你的線程中:

public void run() {
  ...
  Shape newShape = ...;
  synchronized (myPanel.myShapes) {
    //add newShape to the collection
  }
  myPanel.repaint();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM