Usage of object attribute in swing paint methods - java

I've been trying to create a maze using swing.
For now, I just want to create a 10x10 grid using lines, which would be all around my cells (a 40x40 square, from the "w"). I'm trying to create each lines of my square depending of my boolean[] walls tab ( walls[0] is top, walls[1] is right, walls[2] is bottom and walls[3] is left).
If the value is true, then we have a wall, if not, the passage is opened and no line on this side.
I'm using an ArrayList<Cell> for collecting the differents cells of my grid.
All of this is working (it seems) but I've came across a problem.
Indeed I would like to use my object's (Cell) attributes in paintComponent(Graphics g) for doing custom dimensions of cells.
But, I don't know really how to do this. I've tried to separate my Cell class and do another class for my graphic interface but it didn't worked out as well.
public class Cell {
int i,j;
int w = 40;
ArrayList<Cell> grid = new ArrayList<Cell>();
boolean[] walls = new boolean[4];
boolean visited;
public Cell () {
this.setup();
}
public Cell(int i, int j) {
this.i = i;
this.j = j;
this.walls[0] = true;
this.walls[1] = true;
this.walls[2] = true;
this.walls[3] = true;
this.visited = false;
}
public int getI() {
return i;
}
public int getJ() {
return j;
}
public void setup() {
JFrame f = new JFrame("Maze");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400);
f.setVisible(true);
JPanel panel = new JPanel();
f.getContentPane().add(panel);
int cols = (int) f.getWidth()/w;
int rows = (int) f.getHeight()/w;
for (int j = 0; j < rows; j++)
{
for (int i = 0; i < cols; i++)
{
Cell cell = new Cell(i,j);
grid.add(cell);
}
}
}
public void paintComponent(Graphics g) {
int x = i*w;
int y = j*w;
g.setColor(Color.black);
if (this.walls[0])
g.drawLine(x , y , x + w, y );
if (this.walls[1])
g.drawLine(x + w, y , x + w, y + w);
if (this.walls[2])
g.drawLine(x + w, y + w, x , y + w);
if (this.walls[3])
g.drawLine(x , y + w, x , y );
}
public static void main(String[] args) {
new Cell();
}
}

You can't just add a paintComponent(...) method to a class and expect that method to be invoked.
To do custom painting you override the paintComponent() method of a JPanel. So you need a custom panel. The panel would contain the ArrayList of Cell objects and in the paintComponent() method you iterate through each Cell object and paint it.
So first you need to start by reading the section from the Swing tutorial on Custom Painting to learn the basics of painting a single object.
Once you understand that you can check out Custom Painting Approaches which shows how to paint from a List of objects.

Related

Java Code not working. Using loops to draw stripes on the US Flag

I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.

Which Swing layout should i use for moving JButtons

I have a Board 14x14 which has JButtons and every Jbutton has a different color. When you click one of those buttons, it checks the neighbors with the same color and removes them. When it removes them, theres a blank space between the board so the above buttons, should move down to fill the blank space. I tried with GridLayout but I don't know how to move the above buttons.
This actually is a case where you can hardly use a layout manager at all.
A LayoutManager is supposed to compute the layout of all components at once. It is triggered by certain events (e.g. when the parent component is resized). Then it computes the layout and arranges the child components accordingly.
In your case, the situation is quite different. There is no layout manager that can sensibly represent the "intermediate" state that appears while the upper buttons are falling down. While the components are animated, they cannot be part of a proper layout.
The animation itself may also be a bit tricky, but can fortunately be solved generically. But you still have to keep track of the information about where each component (i.e. each button) is currently located in the grid. When one button is removed, you have to compute the buttons that are affected by that (namely, the ones directly above it). These have to be animated. After the animation, you have to assign the new grid coordinates to these buttons.
The following is a MCVE that shows one basic approach. It simply removes the button that was clicked, but it should be easy to generalize it to remove other buttons, based on other conditions.
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FallingButtons
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int rows = 8;
int cols = 8;
GridPanel gridPanel = new GridPanel(rows, cols);
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
JButton button = new JButton(r+","+c);
gridPanel.addComponentInGrid(r, c, button);
button.addActionListener(e ->
{
Point coordinates = gridPanel.getCoordinatesInGrid(button);
if (coordinates != null)
{
gridPanel.removeComponentInGrid(
coordinates.x, coordinates.y);
}
});
}
}
f.getContentPane().add(gridPanel);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class GridPanel extends JPanel
{
private final int rows;
private final int cols;
private final JComponent components[][];
GridPanel(int rows, int cols)
{
super(null);
this.rows = rows;
this.cols = cols;
this.components = new JComponent[rows][cols];
addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
layoutGrid();
}
});
}
private void layoutGrid()
{
int cellWidth = getWidth() / cols;
int cellHeight = getHeight() / rows;
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
JComponent component = components[r][c];
if (component != null)
{
component.setBounds(
c * cellWidth, r * cellHeight, cellWidth, cellHeight);
}
}
}
}
Point getCoordinatesInGrid(JComponent component)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
if (components[r][c] == component)
{
return new Point(r, c);
}
}
}
return null;
}
void addComponentInGrid(int row, int col, JComponent component)
{
add(component);
components[row][col] = component;
layoutGrid();
}
JComponent getComponentInGrid(int row, int col)
{
return components[row][col];
}
void removeComponentInGrid(int row, int col)
{
remove(components[row][col]);
components[row][col] = null;
List<Runnable> animations = new ArrayList<Runnable>();
for (int r=row-1; r>=0; r--)
{
JComponent component = components[r][col];
if (component != null)
{
Runnable animation =
createAnimation(component, r, col, r + 1, col);
animations.add(animation);
}
}
for (Runnable animation : animations)
{
Thread t = new Thread(animation);
t.setDaemon(true);
t.start();
}
repaint();
}
private Runnable createAnimation(JComponent component,
int sourceRow, int sourceCol, int targetRow, int targetCol)
{
int cellWidth = getWidth() / cols;
int cellHeight = getHeight() / rows;
Rectangle sourceBounds = new Rectangle(
sourceCol * cellWidth, sourceRow * cellHeight,
cellWidth, cellHeight);
Rectangle targetBounds = new Rectangle(
targetCol * cellWidth, targetRow * cellHeight,
cellWidth, cellHeight);
Runnable movement = createAnimation(
component, sourceBounds, targetBounds);
return () ->
{
components[sourceRow][sourceCol] = null;
movement.run();
components[targetRow][targetCol] = component;
repaint();
};
}
private static Runnable createAnimation(JComponent component,
Rectangle sourceBounds, Rectangle targetBounds)
{
int delayMs = 10;
int steps = 20;
Runnable r = () ->
{
int x0 = sourceBounds.x;
int y0 = sourceBounds.y;
int w0 = sourceBounds.width;
int h0 = sourceBounds.height;
int x1 = targetBounds.x;
int y1 = targetBounds.y;
int w1 = targetBounds.width;
int h1 = targetBounds.height;
int dx = x1 - x0;
int dy = y1 - y0;
int dw = w1 - w0;
int dh = h1 - h0;
for (int i=0; i<steps; i++)
{
double alpha = (double)i / (steps - 1);
int x = (int)(x0 + dx * alpha);
int y = (int)(y0 + dy * alpha);
int w = (int)(w0 + dw * alpha);
int h = (int)(h0 + dh * alpha);
SwingUtilities.invokeLater(() ->
{
component.setBounds(x, y, w, h);
});
try
{
Thread.sleep(delayMs);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
SwingUtilities.invokeLater(() ->
{
component.setBounds(x1, y1, w1, h1);
});
};
return r;
}
}
You could try using a 2-dimensional array of JButtons
JButton[][] buttons = new JButton[14][14];
for (int i=0; i < buttons.length; i++) {
for (int j=0; j < buttons[i].length; j++) {
buttons[i][j] = new JButton("Button [" + i + "][" + j + "]");
}
}
// Then do whatever,remove,change color,check next element in array
// and compare colors etc
buttons[2][3].setText("changed text");
If you want the above buttons to take more space to fill the empty space when you remove a component well, this is not possible using GridLayout, but you can add some empty components like JLabels to fill the space.
You can add a component in a container at a specific index for this purpose, by using Container's add (Component comp, int index) method.
This code snippet will replace a button at a specified index (45, just for example) with a blank component in a panel which has a GridLayout set:
JPanel boardPanel = new JPanel (new GridLayout (14, 14));
// ... add your buttons ...
// This code could be invoked inside an ActionListener ...
boardPanel.remove (45);
boardPanel.add (new JLabel (""), 45);
boardPanel.revalidate ();
boardPanel.repaint ();
This way, the rest of the components will not move, and you will just see a blank space replacing your button.
You can achieve more: if you add the empty label at index = 0, all the buttons will move to the right (remember that the number of components should not change, else the components will resize and you could obtain bad behaviour), and so on, you can "move" a single component by simply removing it and adding it at a different index.
Another way to go would be to store a 2-dimensional array of objects representing your model logic (you can store color and all the stuff you need), and painting them on your own by overriding paintComponent method.
For an example of a custom painting approach, take a look at this MadProgrammer's answer, where he shows how to highlight a specific cell in a grid (in this case he uses a List to store objects, but a 2d array will work as well).

Loading tile-based maps using text files (2D Java Engine) Standard Libraries

So I can load a 2D map using tiles using a text file, which is great and all. However, one issue I have met with this method is that I can't add objects/actors to my map since the file is a 2D grid. (The game is similar to games like zelda and pokemon.) I've tried creating an object layer so I can overlap images, but it doesn't seem to work for me. To give an example of what I want, have objects such as trees to be solid and on top of the background grass.
I am also looking for better methods to creating these tile based maps if you want to pitch some ideas to me.
**Note: I am about beginner/intermediate at Java.
Here is my constructor for the GameState class that calls the Map.
public GameState(Game game) {
super(game);
player = new Player(game, 0, 0, 64, 64);
map = new Map(game, "res/saves/save1.txt");
}
Here is the Map class (which works) that also calls the object (2nd) layer.
private int width, height;
public static int spawnX, spawnY;
private int[][] mapTiles;
MapObjects mapObjects;
Game game;
public Map(Game game, String path) {
this.game = game;
mapObjects = new MapObjects(game, "res/saves/save1_obj.txt", width, height);
loadMap(path);
}
private void loadMap(String path) {
String file = Utils.loadFileAsString(path);
//Token is which number it is out of the total
String[] tokens = file.split("\\s+");
//Sets what is what
width = Utils.parseInt(tokens[0]);
height = Utils.parseInt(tokens[1]);
spawnX = Utils.parseInt(tokens[2]);
spawnY = Utils.parseInt(tokens[3]);
mapTiles = new int[width][height];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// (x+y*width) : calculates the nth token (+4) : The 4 prior tokens before the graph
mapTiles[x][y] = Utils.parseInt(tokens[(x + y *width) + 4]);
}
}
}
public void render(Graphics g) {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//Only renders what is seen.
getMapTile(x, y).render(g, (int)(x*Tile.TILE_WIDTH-game.getCamera().getxOffset()), (int)(y*Tile.TILE_HEIGHT-game.getCamera().getyOffset()));
}
}
}
public void tick() {
}
//Gets the specific tile at specific coordinates.
private Tile getMapTile(int x, int y) {
Tile t = Tile.tiles[mapTiles[x][y]];
if(t == null) {
return Tile.grassTile;
}
return t;
}
And lastly, the object layer that doesn't work. It does not give an error, just the overlapping objects aren't visible. I've made sure to load the object layer before the Map layer, but that doesn't seem to be the issue.
private int width, height;
private int[][] objTiles;
Game game;
public MapObjects(Game game, String path, int width, int height) {
this.game = game;
loadObjects(path, width, height);
}
public void loadObjects(String path, int width, int height) {
this.width = width;
this.height = height;
String file = Utils.loadFileAsString(path);
String[] tokens = file.split("\\s+");
objTiles = new int[width][height];
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
objTiles[x][y] = Utils.parseInt(tokens[(x + y *width)]);
}
}
}
public void render(Graphics g) {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
//Only renders what is seen.
getObjTile(x, y).render(g, (int)(x*Tile.TILE_WIDTH-game.getCamera().getxOffset()), (int)(y*Tile.TILE_HEIGHT-game.getCamera().getyOffset()));
}
}
}
public void tick() {
}
//Gets the specific object tile at specific coordinates.
private Tile getObjTile(int x, int y) {
Tile t = Tile.tiles[objTiles[x][y]];
if(t == null) {
return Tile.nothingTile;
}
return t;
}
We may need a bit more info from you.
Do you use a different "container/component" to draw map tiles than you do for your objects? Because if you render objects first then they will disappear as soon as you render the map. You should draw the map first, and then do objects like so:
public Map(Game game, String path) {
this.game = game;
//swapped the order of the lines below so the map loads first:
loadMap(path);
mapObjects = new MapObjects(game, "res/saves/save1_obj.txt", width, height);
}
From what you have said then this does not work either, however if you use the same component to draw your map and objects then one will always override the other, and something will always be missing. To fix this you need to crease two separate panes, one for the map, and a transparent one that sits on top of the map that you can use to render your objects.
See this illustration as an example:
You basically need to add a new transparent "content plane" similar to the way that glass pane shown above.

(Java) Drawn Rectangles do not appear

So am working on a School Project, and I want to draw a game board made out of Rectangles which are saved in an array. I managed to do that, but only the last drawn Rectangle Stays on the Panel. I'm really desperate and i don't know where my mistake is.
The Field is a 4x5 field. The Coordinates saved in the Tile Class:
the first two represent the upper left Corner
the last two represent the bottom right corner of it
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class quoVadis{
public static void main(String[] args) {
new Frame();
}
}
class Tile {
Random rGen = new Random();
int sX,sY,eX,eY;
Color farbe;
public Tile(int sX, int sY,int eX,int eY){
this.sX = sX;
this.sY = sY;
this.eX = eX;
this.eY = eY;
farbe = new Color(rGen.nextInt(156)+100,rGen.nextInt(156)+100,rGen.nextInt(156)+100);
}
}
class Frame extends JFrame{
private Game game;
final int GAMESIZE = 400;
final int PANELSIZE = GAMESIZE/5;
public Frame() {
super("Quo Vadis");
this.setSize(GAMESIZE, GAMESIZE*5/4);
this.setLocation(50, 50);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game = new Game(GAMESIZE, PANELSIZE);
game.setLayout(null);
game.setBackground(Color.WHITE);
this.getContentPane().add(game);
this.setVisible(true);
}
}
class Game extends JPanel{
int GAMESIZE;
int PANELSIZE;
private Tile field[][]=new Tile[4][5];
Random rGen = new Random(4711);
Tile stein;
public Game(int g, int p) {
GAMESIZE = g;
PANELSIZE = p;
// The Mistake has to be in this following Part:
int idx=0;
for(Tile i:levels){
for(int j = i.sX; j <= i.eX; j++){
for(int k = i.sY; k <= i.eY; k++){
field[j][k] = levels[idx];
}
}
idx++;
}
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
draw((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
this.setVisible(true);
}
int rx, ry,rdx,rdy;
private void draw(int a, int b, int c, int d){
rx=a;
ry=b;
rdx=c;
rdy=d;
repaint(rx,ry,rdx,rdy);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(stein.farbe);
g.fillRect(rx, ry, rdx, rdy);
}
Tile[] levels = {
new Tile(1,0,2,1),
new Tile(0,0,0,1),
new Tile(3,0,3,1),
new Tile(0,2,0,3),
new Tile(1,2,2,2),
new Tile(3,2,3,3),
new Tile(0,4,0,4),
new Tile(1,3,1,3),
new Tile(2,3,2,3),
new Tile(3,4,3,4),
};
}
I already checked the Position of the Rectangles in numbers and they are correct in every way so they do not overlap or something like that.
Sorry for my bad english, it's not my primary language.
You need to draw each rectangle inside of your paintComponent method every time.
Currently you are calling your draw method for one rectangle then you call repaint and draw that single rectangle. paintComponent will redraw the entire panel each time it is called. This means that it will on preserve the last rectangle (the rest were "repainted over".
You want to loop through all of your tiles and use the drawRect method to draw them inside of your paintComponent method so they will be drawn every time.
public void paintComponent(Graphics g) {
super.paintComponent(g)
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
g.setColor(stein.farbe);
g.fillRect((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
}

Swing auto repaints JPanel after button clicked

I'm having this weird issue with Swing.
I am drawing few points and lines between them, directly on JPanel.
I'm just calling:
g.drawLine(pointAX, pointAY, pointBX, pointBY);
Where g is Graphics object taken from panel.getGraphics()
And this works alright, gives me nice output.
But then I'm trying to move it and I use ActionListener on my button, which does:
panel.revalidate();
panel.repaint();
drawPanel();
moveVector(moveX, moveY);
drawPoints();
drawConnections(connections);
The other methods:
drawPanel just draws some lines, so it's easier to see:
private void drawPanel(){
Graphics g = panel.getGraphics();
zeroX = panel.getWidth() / 2;
zeroY = panel.getHeight() / 2;
g.setColor(Color.GRAY);
for(int i = zeroX + 10; i < panel.getWidth(); i += 10){
g.drawLine(i, 0, i, panel.getHeight());
}
for(int i = zeroX + 10; i > 0; i -= 10){
g.drawLine(i, 0, i, panel.getHeight());
}
for(int j = zeroY - 10; j < panel.getHeight(); j += 10){
g.drawLine(0, j, panel.getWidth(), j);
}
for(int j = zeroY - 10; j > 0; j -= 10){
g.drawLine(0, j, panel.getWidth(), j);
}
g.setColor(Color.BLACK);
g.drawLine(zeroX, 0, zeroX, panel.getHeight());
g.drawLine(0, zeroY, panel.getWidth(), zeroY);
panel.paintComponents(g);
}
drawPoints looks like this
private void drawPoints() {
for(int i = 0; i < points.size(); i++){
int x = Integer.parseInt(points.get(i)[1]);
int y = Integer.parseInt(points.get(i)[2]);
drawPoint(x, y);
}
}
private void drawPoint(int x, int y) {
Graphics g = panel.getGraphics();
for (int i = -1; i < 2; i++) {
g.drawLine(zeroX + x + i, zeroY + y - 1, zeroX + x + i, zeroY + y);
}
panel.paintComponents(g);
}
g.setColor(Color.BLACK);
g.drawLine(zeroX, 0, zeroX, panel.getHeight());
g.drawLine(0, zeroY, panel.getWidth(), zeroY);
panel.paintComponents(g);
}
and drawConnections:
private void drawConnections(ArrayList<String[]> lines) {
for (String[] arr : lines) {
String x = arr[1];
String y = arr[2];
drawConnection(x, y);
}
}
private void drawConnection(String pointA, String pointB) {
int pointAX = 0, pointAY = 0, pointBX = 0, pointBY = 0;
Graphics g = panel.getGraphics();
for (String[] arr : points) {
if (arr[0].equals(pointA)) {
pointAX = Integer.parseInt(arr[1]);
pointAY = Integer.parseInt(arr[2]);
} else if (arr[0].equals(pointB)) {
pointBX = Integer.parseInt(arr[1]);
pointBY = Integer.parseInt(arr[2]);
}
}
g.drawLine(zeroX + pointAX, zeroY + pointAY, zeroX + pointBX, zeroY + pointBY);
panel.paintComponents(g);
}
What I don't understand here is that everything looks OK. I did debug and it looks ok and at the end of listener call, when everything is painted (although it paints over the old one instead of clearing it) it suddenly clears everything and nothing is visible at all.
You need to implement all the drawing in paintComponent(Graphics) in your JPanel class (or methods that are called from it). Calling getGraphics on the panel instance and using the Graphics object is not always guaranteed to work. It's also strange that you call panel.repaint() and immediately afterwards try to do additional drawing using the graphics object from the panel, that additional drawing should just be done in paintComponent(Graphics).
Using paintComponent(Graphics) will ensure your painting is done at the right time, and that the panel's graphics will be cleared (if you call the super method at least).
panel.repaint does not immediately repaint the panel, but it tells Swing that this panel should be repainted in the near future (see API docs: https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#repaint(long,%20int,%20int,%20int,%20int). So your custom painting will be cleared once the panel repaints itself.
Create a custom component by inheriting from JPanel and overwriting the method paintComponent with your custom painting code. Then, whenever the panel needs to be repainted, your code is called, and not only the user pressed a button.

Categories

Resources