this is the documentacion:
Causes doRun.run() to be executed asynchronously on the AWT event
dispatching thread. This will happen after all pending AWT events have
been processed. This method should be used when an application thread
needs to update the GUI. In the following example the invokeLater call
queues the Runnable object doHelloWorld on the event dispatching
thread and then prints a message.
but i want to know how it means in code
I always made a program like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.BufferedImage;
/**
*
* #author Robin
*/
public class Example {
JFrame Frame=new JFrame();
public Example() {
Frame.setTitle("Example");
Frame.setName("Example");
Frame.setSize(300, 300);
Frame.setResizable(false);
Frame.setUndecorated(false);
Frame.setLayout(null);
Frame.setLocationRelativeTo(null);
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.setIconImage(CrearIcono(Color.decode("#F4141D")).getImage());
Frame.getContentPane().setBackground(Color.WHITE);
Formato();
Accion();
Mover(Frame.getGlassPane());
Frame.setVisible(true);
}
private void Formato() {
}
private void Accion() {
}
public ImageIcon Imagen( String dir){return new ImageIcon(getClass().getResource("/lib/"+dir));}
public static void Mover(final Component objeto) {
MouseInputAdapter d=new MouseInputAdapter() {int x,X,y,Y;
#Override public void mousePressed(MouseEvent e){x=e.getXOnScreen();X=objeto.getLocation().x;y=e.getYOnScreen();Y=objeto.getLocation().y;}
#Override public void mouseDragged(MouseEvent e){objeto.setLocation(X+(e.getXOnScreen()-x), Y+(e.getYOnScreen()-y));}};
objeto.addMouseListener(d);objeto.addMouseMotionListener(d);
}
public int CentrarX(int AnchoObjeto, int AnchoRespectoA){return (AnchoRespectoA/2)-(AnchoObjeto/2);}
public int CentrarY(int LargoObjeto, int LargoRespectoA){return (LargoRespectoA/2)-(LargoObjeto/2);}
public int ImgA(JLabel imagen){return imagen.getIcon().getIconWidth();}
public int ImgL(JLabel imagen){return imagen.getIcon().getIconHeight();}
public static ImageIcon CrearIcono(Color color) {
int WIDTH = 32;
int HEIGHT = 32;
BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
int[] xPoints = {WIDTH, 0, 0, WIDTH / 2};
int[] yPoints = {0, WIDTH / 2, WIDTH, WIDTH};
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
g2.fillPolygon(xPoints, yPoints, xPoints.length);
g2.dispose();
ImageIcon icon = new ImageIcon(img);
return icon;
}
public static void main(String[] args) {
Example Ventana=new Example();
}
}
what is better? what is the difference?
SwingUtilities.invokeLater
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
pantalla principal=new pantalla();
Calendario s=new Calendario(1);
}
});
}
Without invokeLater
public static void main(String[] args) {
Example Ventana=new Example();
}
thanks for your advices
The first one using invokeLater(..) is better in that it is the correct way to create a GUI.
See Concurrency in Swing (and particularly 'Initial Threads') for more details.
Related
I'm quite new to swing, and I'm having an issue with graphics not showing up in my JFrame. What I should be seeing is a blue rectangle slowly moving downwards through the frame, and behind it is a plain white background. However, when I run my main class, all I see is a plain JFrame. This is my code:
Execute class
public class Execute {
public static void main (String[ ] args) {
GUI gui = new GUI();
gui.createFrame(800,600);
ElevatorOne e1 = new ElevatorOne();
e1.addElevatorOne();
}
}
ElevatorOne class (Where the graphics should be initialized and added)
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class ElevatorOne extends GUI{
int y = 100;
public void addElevatorOne() {
drawElevatorOne drawE1 = new drawElevatorOne();
frame.getContentPane().add(drawE1);
for(int i = 0; i < 130; i++) {
y++;
drawE1.repaint();
try {
Thread.sleep(50);
} catch (Exception ex) { }
}
}
#SuppressWarnings("serial")
class drawElevatorOne extends JPanel{
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLUE);
g.drawRect(200,y,40,60);
}
}
}
And finally, my GUI class (where frame is created)
import javax.swing.JFrame;
public class GUI {
JFrame frame = new JFrame();
public void createFrame(int x, int y) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.setSize(x, y);
}
}
While you've got an accepted answer, I do take issue with that answer and feel impelled to add my two cents:
I see no purpose to your having a GUI class and then having Elevator1 extend it. If you want Elevator1 to use a JFrame, then have it create a JFrame as there really is no need or benefit from your inheritance.
Myself, I'd have Elevator1 extend JPanel and then have it draw in its own paintComponent method, thus eliminating the need for drawElevatorOne inner class (which should be named DrawElevatorOne to adhere to Java naming conventions).
You are using Thread.sleep in a Swing GUI which is extremely risky to do. The only reason this works is because it is being called in the main thread. If your code were properly created and set up to start and create GUI components in the Swing event thread, this would and should fail since it would put the Swing event thread to sleep. Don't do this, don't call Thread.sleep in a method that has any risk of being called in the Swing event thread.
Instead use a Swing Timer to manage your delay.
Don't forget to (almost) always call the super.paintComponent(g) method within your oeverride. To not do this breaks the Swing painting chain and risks significant hard to debug side effects.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class ElevatorTest {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static void createAndShowGui() {
MyElevator mainPanel = new MyElevator(PREF_W, PREF_H);
JFrame frame = new JFrame("Elevator Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// start everything on the Swing event thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyElevator extends JPanel {
private static final Color BACKGROUND = Color.white;
private static final int ELEVATOR_X = 200;
private static final int ELEVATOR_W = 40;
private static final int ELEVATOR_H = 60;
private static final int TIMER_DELAY = 50;
public static final int MAX_ELEVATOR_Y = 130;
private static final Color ELEVATOR_COLOR = Color.blue;
private int prefW;
private int prefH;
private int elevatorY = 0;
public MyElevator(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
setBackground(BACKGROUND);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
// Don't forget to call the super method
super.paintComponent(g);
g.setColor(ELEVATOR_COLOR);
g.fillRect(ELEVATOR_X, elevatorY, ELEVATOR_W, ELEVATOR_H);
}
// to help size our GUI properly
#Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int w = Math.max(superSz.width, prefW);
int h = Math.max(superSz.height, prefH);
return new Dimension(w, h);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (elevatorY >= MAX_ELEVATOR_Y) {
// if elevator at max, stop thimer
((Timer) e.getSource()).stop();
} else {
// advance elevator and draw it
elevatorY++;
repaint();
}
}
}
}
Your ElevatorOne class extends GUI. Therefore it inherits all of the functionality of GUI, yet you create both of them. This is probably what you intended to do:
edit: I ran this code and indeed there is a box moving as you specify.
public class Execute {
public static void main (String[ ] args) {
// GUI gui = new GUI();
// gui.createFrame(800,600);
ElevatorOne e1 = new ElevatorOne();
e1.createFrame(800, 600);
e1.addElevatorOne();
}
}
I am making a game by java and it refreshes itself 60 times per second. Every time it executes a loop and I use g2d to draw images and strings. Things work fine if I do g2d.setFont(new Font("Arial", Font.PLAIN, 8)); and drawstring and it would be normal, but if I set the font to some "unfamiliar" fonts and do the same thing, the swing would show white screen in the first second of start up then paint everything correctly and it's apparently too slow (2 secs).
I put a jpanel in a jframe and override the paint() method of jpanel to draw everything I need. I've already used SwingUtilities.invokeLater in my code.
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
public Window(){
add(new Board());
setSize(800,600);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
private class Board extends JPanel {
Font font = new Font("Bitmap", Font.PLAIN, 64);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setFont(font);
g2d.drawString("This is slow", 220,200);
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
g.dispose();
}
}
}
This is not in a loop but it's very laggy.
http://fontsov.com/download-fonts/bitmap1159.html
This is the cutie font that slows our application down. "Arial" will load blazingly fast. How can I make this less laggy?
First and foremost, for best help, create and post your minimal code example program for us to review, test, and possibly fix. Without this, it will be hard for us to fully understand your problem.
Consider:
Overriding paintComponent not paint to get the advantage of double buffering.
Avoid using invokeLater unless you're sure that the code is being called off of the Swing event thread and you are making calls that need to be on the event thread.
Put slow running code in a background thread such as that which can be found using a SwingWorker.
Putting your text in a JLabel, not drawn on a component.
Draw all static images to a BufferedImage, and displaying that in paintComponent. Then draw all changing images, such as your moving sprites, directly in the paintComponent method.
Don't forget to call your super.paintCompmonent(g) within your paintComponent(Graphics g) method override.
Edit
A BufferedImage solution could look like,....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); //do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
paintGame(g2d);
// Toolkit.getDefaultToolkit().sync();
// g2d.dispose();
// g.dispose();
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
}
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Edit 2
Or with a SwingWorker background thread....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); // do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
paintGame(g2d);
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
imgWorker.addPropertyChangeListener(new ImgWorkerListener());
imgWorker.execute();
}
private class ImgWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
mainImage = imgWorker.get();
// repaint() here if you don't have a game loop running
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
return img;
}
};
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor.
and the font should be changed to some orthodox fonts (Arial,Calibri etc)
This is the smallest SSCCE,of my project, that I could implement to show you.
Can anyone explain why the square, that I create into Render, is not shown?
I APPRECIATE ANY HELP, IT IS VERY IMPORTANT
this code is compilable,and it runs,but as i said it don't show the square.
Loop Class
public class Foo {
public void update() {
for (int i = 0; i < 20; i++)
System.out.println("foo");
}
}
Render Class
import java.awt.Graphics2D;
public class Render {
private static Render renderManager = new Render();
public void setRenderState(Graphics2D graphic) {
showRender(graphic);
}
private void showRender(Graphics2D graphic) {
graphic.fillRect(4, 3, 40, 40);
}
public static Render getRenderManagerInstance() {
return renderManager;
}
}
Main class
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class Main {
private static final Main mainFrame = new Main();
private final JFrame frame;
private Main() {
frame = new JFrame();
frame.setUndecorated(true);
frame.add(new MyPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static Main getMainFrameInstance() {
return mainFrame;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Main.getMainFrameInstance();
}
});
}
}
MyPanel Class
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class MyPanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// thread and loop
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
private long start;
private long elapsed;
private long wait;
// image
public BufferedImage image;
// foo
private Foo foo;
private Render render = Render.getRenderManagerInstance();
public MyPanel() {
setPreferredSize(new Dimension(700, 700));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
// prevent to be done all method.
private synchronized void initGraphic() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
foo = new Foo();
running = true;
}
public void run() {
initGraphic();
// loop
while (running) {
start = System.nanoTime();
foo.update();
repaint();
elapsed = System.nanoTime() - start;
wait = (targetTime - elapsed / 1000000) - 8;
if (wait <= 0)
wait = 6;
try {
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics = (Graphics2D) image.getGraphics();
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState((Graphics2D) graphics);
}
Two problems:
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Check the values of WIDTH and HEIGHT at this point. I don't think they are what you expect. Presumably this is getting called before the component is realized.
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics = image.getGraphics();
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState((Graphics2D) graphics);
}
You are drawing into the image, but you are never drawing the image itself on to the component. Keep a reference to the original component's Graphics object and then, at the end, paint the image with that on to the component.
public void paintComponent(Graphics panelG2d) {
super.paintComponent(panelG2d);
Graphics2D imageG2d = (Graphics2D) image.getGraphics();
imageG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
imageG2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState(imageG2d);
panelG2d.drawImage(image, 0, 0, this);
}
You don't add image to the MyPanel. You need to add it. In initGraphic do something like the following:
private synchronized void initGraphic() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
this.add(image); //New.
foo = new Foo();
running = true;
}
I'm trying to draw two lines in a Canvas in Java, calling two methods separately, but when I draw the second line, the first one disapears (Java clears the screen). How can I avoid that? I want to see the two lines. I've seen paint tutorials (how to make a program like the Paint on Windows) where the user uses the mouse to draw lines and when one line is drawn, the other do not disappear. They just call the paint method and it does not clear the screen.
I'll be grateful if anyone can help me.
Thanks.
View Class
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class CircuitTracePlotView extends JFrame {
private CircuitTracePlot circuitTracePlot;
public CircuitTracePlotView() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.getContentPane().add(circuitTracePlot = new CircuitTracePlot(), BorderLayout.CENTER);
this.pack();
this.setSize(250,250);
this.setLocationRelativeTo(null);
this.setVisible(true);
circuitTracePlot.drawLine();
circuitTracePlot.drawOval();
}
}
class CircuitTracePlot extends Canvas {
private final static short LINE = 1;
private final static short OVAL = 2;
private int paintType;
private int x1;
private int y1;
private int x2;
private int y2;
public CircuitTracePlot() {
this.setSize(250,250);
this.setBackground(Color.WHITE);
}
private void setPaintType(int paintType) {
this.paintType = paintType;
}
private int getPaintType() {
return this.paintType;
}
public void drawLine() {
this.setPaintType(LINE);
this.paint(this.getGraphics());
}
public void drawOval() {
this.setPaintType(OVAL);
this.paint(this.getGraphics());
}
public void repaint() {
this.update(this.getGraphics());
}
public void update(Graphics g) {
this.paint(g);
}
public void paint(Graphics g) {
switch (paintType) {
case LINE:
this.getGraphics().drawLine(10, 10, 30, 30);
case OVAL:
this.getGraphics().drawLine(10, 20, 30, 30);
}
}
}
Main class
import javax.swing.SwingUtilities;
import view.CircuitTracePlotView;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CircuitTracePlotView cr = new CircuitTracePlotView();
}
});
}
}
You almost never should call paint(...) directly. I can count the times that I've needed to do this on one hand.
Do not get a Graphics object by calling getGraphics() on a component as that will return a non-durable Graphics object. Instead either draw in a BufferedImage and display that in the paint method or draw in the paint method (if AWT).
Since this is a Swing GUI, don't use an AWT component to draw in. Use a JPanel and override the paintComponent(...) method, not the paint(...) method. Otherwise you lose all benefits of Swing graphics including automatic double buffering.
The super.paintComponent(g) method should be called in the paintComponent(Graphics g) override, often as the first method call inside of this method. This lets the component do its own housekeeping painting, including erasing drawings that need to be erased.
Read the tutorials on Swing graphics as most of this is all well explained there. For e.g., please have a look here:
Lesson: Performing Custom Painting
Painting in AWT and Swing
Edit
To have your images persist, I suggest that you draw to a BufferedImage and then display that Image in your JPanel's paintComponent(...) method.
Or another option is to create a Collection of Shape objects, perhaps an ArrayList<Shape> and fill it with the Shapes you'd like to draw, and then in the paintComponent(...) method cast the Graphics object to a Graphics2D object and iterate through the Shape collection drawing each shape with g2d.draw(shape) as you iterate.
Since Trash posted his code,...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class CircuitTracePlot2 extends JPanel {
private static final int PREF_W = 250;
private static final int PREF_H = PREF_W;
private int drawWidth = 160;
private int drawHeight = drawWidth;
private int drawX = 10;
private int drawY = 10;
private PaintType paintType = PaintType.LINE;
public CircuitTracePlot2() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void setPaintType(PaintType paintType) {
this.paintType = paintType;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (paintType == null) {
return;
}
switch (paintType) {
case LINE:
g.drawLine(drawX, drawY, drawWidth, drawHeight);
break;
case OVAL:
g.drawOval(drawX, drawY, drawWidth, drawHeight);
break;
case SQUARE:
g.drawRect(drawX, drawY, drawWidth, drawHeight);
default:
break;
}
}
private static void createAndShowGui() {
final CircuitTracePlot2 circuitTracePlot = new CircuitTracePlot2();
JFrame frame = new JFrame("CircuitTracePlot2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(circuitTracePlot);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
int timerDelay = 2 * 1000;
new Timer(timerDelay , new ActionListener() {
private int paintTypeIndex = 0;
#Override
public void actionPerformed(ActionEvent arg0) {
paintTypeIndex++;
paintTypeIndex %= PaintType.values().length;
circuitTracePlot.setPaintType(PaintType.values()[paintTypeIndex]);
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum PaintType {
LINE, OVAL, SQUARE;
}
Here's a variation on your program that implements much of #Hovercraft's helpful advice. Try commenting out the call to setPaintType() to see the effect.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/** #see http://stackoverflow.com/a/15854246/230513 */
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CircuitTracePlotView cr = new CircuitTracePlotView();
}
});
}
private static class CircuitTracePlotView extends JFrame {
private CircuitTracePlot plot = new CircuitTracePlot();
public CircuitTracePlotView() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
plot.setPaintType(CircuitTracePlot.OVAL);
this.add(plot, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
private static class CircuitTracePlot extends JPanel {
public final static short LINE = 1;
public final static short OVAL = 2;
private int paintType;
public CircuitTracePlot() {
this.setBackground(Color.WHITE);
}
public void setPaintType(int paintType) {
this.paintType = paintType;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
switch (paintType) {
case LINE:
g.drawLine(10, 10, 30, 30);
case OVAL:
g.drawOval(10, 20, 30, 30);
default:
g.drawString("Huh?", 5, 16);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
}
I am a new learner of Java Swing. I am trying to draw some shapes.
But when I run the following codes, I can't see the graph at all.
Can't understanding why, Could someone help me with it? Thanks a lot!
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Draw
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
DrawFrame frame = new DrawFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class DrawFrame extends JFrame
{
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 400;
public DrawFrame()
{
setTitle("DrawTest");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
DrawComponent component = new DrawComponent();
add(component);
}
}
class DrawComponent extends JComponent
{
public void painComponent(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
Rectangle2D rec = new Rectangle2D.Double(100, 100, 200, 150);
g2.draw(rec);
Ellipse2D ellipse = new Ellipse2D.Double();
ellipse.setFrame(rec);
g2.draw(ellipse);
}
}
In the supplied code, the paintComponent method has an error in the name:
public void painComponent(Graphics g)
So it's not actually overriding the method from the superclass. You can add the #Override annotation so that the compiler will give an error if the method doesn't actually override anything, for example:
#Override
public void painComponent(Graphics g)