diff --git a/examples/blocks-world/BlocksEnv/WorldModel.java b/examples/blocks-world/BlocksEnv/WorldModel.java index 0a5b3ac3..192517f1 100644 --- a/examples/blocks-world/BlocksEnv/WorldModel.java +++ b/examples/blocks-world/BlocksEnv/WorldModel.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Stack; import java.util.logging.Logger; +import javax.swing.SwingUtilities; public class WorldModel extends GridWorldModel { @@ -91,7 +92,9 @@ boolean move(String a, String b, List adds, List dels) throws Ex } modelToGrid(); if (view != null) - view.update(); + SwingUtilities.invokeLater(() -> { + view.update(); + }); return true; } @@ -155,16 +158,16 @@ static WorldModel world4() throws Exception { void modelToGrid() { for (int i=0; i s : stackList) { for (int j=1; j view.update(ux, uy)); + } } public void add(int value, Location l) { @@ -119,7 +123,10 @@ public void add(int value, Location l) { public void add(int value, int x, int y) { data[x][y] |= value; - if (view != null) view.update(x,y); + if (view != null) { + final int ux = x, uy = y; + SwingUtilities.invokeLater(() -> view.update(ux, uy)); + } } public void addWall(int x1, int y1, int x2, int y2) { @@ -130,13 +137,16 @@ public void addWall(int x1, int y1, int x2, int y2) { } } - public void remove(int value, Location l) { + public void remove(int value, Location l) { remove(value, l.x, l.y); } public void remove(int value, int x, int y) { data[x][y] &= ~value; - if (view != null) view.update(x,y); + if (view != null) { + final int ux = x, uy = y; + SwingUtilities.invokeLater(() -> view.update(ux, uy)); + } } public void removeAll(int value) { diff --git a/jason-interpreter/src/main/java/jason/environment/grid/GridWorldView.java b/jason-interpreter/src/main/java/jason/environment/grid/GridWorldView.java index d14fbc61..6b9c5367 100644 --- a/jason-interpreter/src/main/java/jason/environment/grid/GridWorldView.java +++ b/jason-interpreter/src/main/java/jason/environment/grid/GridWorldView.java @@ -1,13 +1,9 @@ package jason.environment.grid; -import java.awt.BorderLayout; -import java.awt.Canvas; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; +import java.awt.*; +import java.awt.image.BufferedImage; -import javax.swing.JFrame; +import javax.swing.*; /** * View component for a GirdWorldModel. @@ -23,6 +19,8 @@ public class GridWorldView extends JFrame { protected GridCanvas drawArea; protected GridWorldModel model; + protected BufferedImage backBuffer; + private Graphics2D backG; protected Font defaultFont = new Font("Arial", Font.BOLD, 10); @@ -46,20 +44,25 @@ public void repaint() { cellSizeW = drawArea.getWidth() / model.getWidth(); cellSizeH = drawArea.getHeight() / model.getHeight(); super.repaint(); - drawArea.repaint(); } /** updates all the frame */ public void update() { + ensureBackBuffer(); repaint(); } /** updates only one position of the grid */ public void update(int x, int y) { - Graphics g = drawArea.getGraphics(); - if (g == null) return; - drawEmpty(g, x, y); - draw(g, x, y); + if (!SwingUtilities.isEventDispatchThread()) { + // Only the event dispatch thread can update the GUI + SwingUtilities.invokeLater(this::update); + return; + } + + ensureBackBuffer(); + renderAllToBackBuffer(); + drawArea.repaint(); } public void drawObstacle(Graphics g, int x, int y) { @@ -100,25 +103,7 @@ public void draw(Graphics g, int x, int y, int object) { //drawString(g,x,y,defaultFont,String.valueOf(object)); } - private static int limit = (int)Math.pow(2,14); - - private void draw(Graphics g, int x, int y) { - if ((model.data[x][y] & GridWorldModel.OBSTACLE) != 0) { - drawObstacle(g, x, y); - } - - int vl = GridWorldModel.OBSTACLE*2; // the next object after OBSTACLE - while (vl < limit) { - if ((model.data[x][y] & vl) != 0) { - draw(g, x, y, vl); - } - vl *= 2; - } - - if ((model.data[x][y] & GridWorldModel.AGENT) != 0) { - drawAgent(drawArea.getGraphics(), x, y, Color.blue, model.getAgAtPos(x, y)); - } - } + private static final int limit = (int)Math.pow(2,14); public Canvas getCanvas() { return drawArea; @@ -130,27 +115,73 @@ public GridWorldModel getModel() { class GridCanvas extends Canvas { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; + + @Override + public void update(Graphics g) { + paint(g); + } public void paint(Graphics g) { - cellSizeW = drawArea.getWidth() / model.getWidth(); - cellSizeH = drawArea.getHeight() / model.getHeight(); - int mwidth = model.getWidth(); - int mheight = model.getHeight(); - - g.setColor(Color.lightGray); - for (int l = 1; l <= mheight; l++) { - g.drawLine(0, l * cellSizeH, mwidth * cellSizeW, l * cellSizeH); + ensureBackBuffer(); + g.drawImage(backBuffer, 0, 0, this); + Toolkit.getDefaultToolkit().sync(); + } + } + + private void ensureBackBuffer() { + int w = Math.max(1, drawArea.getWidth()); + int h = Math.max(1, drawArea.getHeight()); + if (backBuffer == null || backBuffer.getWidth() != w || backBuffer.getHeight() != h) { + if (backG != null) { + backG.dispose(); } - for (int c = 1; c <= mwidth; c++) { - g.drawLine(c * cellSizeW, 0, c * cellSizeW, mheight * cellSizeH); + backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + backG = backBuffer.createGraphics(); + backG.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + } + renderAllToBackBuffer(); + } + + private void renderAllToBackBuffer() { + cellSizeW = Math.max(1, backBuffer.getWidth() / model.getWidth()); + cellSizeH = Math.max(1, backBuffer.getHeight() / model.getHeight()); + + backG.setColor(Color.white); + backG.fillRect(0, 0, backBuffer.getWidth(), backBuffer.getHeight()); + + backG.setColor(Color.lightGray); + for (int l = 1; l <= backBuffer.getHeight(); l++) { + backG.drawLine(0, l * cellSizeH, model.getWidth() * cellSizeW, l * cellSizeH); + } + for (int c = 1; c <= backBuffer.getWidth(); c++) { + backG.drawLine(c * cellSizeW, 0, c * cellSizeW, model.getHeight() * cellSizeH); + } + + for (int x = 0; x < model.getWidth(); x++) { + for (int y = 0; y < model.getHeight(); y++) { + renderCell(backG, x, y); } + } + } + + private void renderCell(Graphics2D g, int x, int y) { + drawEmpty(g, x, y); - for (int x = 0; x < mwidth; x++) { - for (int y = 0; y < mheight; y++) { - draw(g,x,y); - } + if ((model.data[x][y] & GridWorldModel.OBSTACLE) != 0) { + drawObstacle(g, x, y); + } + + int vl = GridWorldModel.OBSTACLE*2; // the next object after OBSTACLE + while (vl < limit) { + if ((model.data[x][y] & vl) != 0) { + draw(g, x, y, vl); } + vl *= 2; + } + + if ((model.data[x][y] & GridWorldModel.AGENT) != 0) { + drawAgent(g, x, y, Color.blue, model.getAgAtPos(x, y)); } } }