I'm trying to draw in JPANEL using getgraphics but it still doesn't work, I don't understand why, I don't know where the error is.
maybe it happens because i'm using threads,also this part of code is based on a game made with java swing (Dragon tale).
my code
public class GamePanel extends JPanel implements Runnable {
private BufferedImage image;
private Graphics2D g;
private Thread thread;
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D)image.getGraphics();
}
#Override
public void run() {
init();
draw(g);
drawToScreen();
}
public void draw(Graphics2D g) {
g.drawRect(0, 0, 100, 1);
}
private void drawToScreen() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0, WIDTH * 2, HEIGHT * SCALE, null);
g2.dispose();
}
}
Related
I'm trying to make it when you click the cameraButton, the graphics show, but when clicked again, it closes.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int camButtonWidth = 500;
int camButtonHeight = 33;
int camButtonX = (width - camButtonWidth) / 2;
int camButtonY = (height - camButtonHeight) - 5;
int camWidth = width - 50;
int camHeight = (height - (camButtonHeight * 2)) - 10;
int camX = (width - camWidth) / 2;
int camY = ((height - camHeight) - camButtonHeight) / 2;
Graphics2D g1 = (Graphics2D) g;
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
RoundRectangle2D camButton = new RoundRectangle2D.Double(camButtonX, camButtonY, camButtonWidth, camButtonHeight, 25, 25);
RoundRectangle2D cameras = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
// Background
g1.setColor(Color.BLACK);
g1.fillRect(0, 0, width, height);
addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (camButton.contains(e.getPoint())) {
camUp = !camUp;
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
// Camera Button
g2.setColor(camColor);
g2.fill(camButton);
paintCameras = camUp;
// Cameras
g3.setColor(camColor);
if (paintCameras) {
g3.fill(cameras);
}
repaint();
}
Try to change make it when you click the camera button, a graphics object shows, but when clicked again, it closes.
To get this sort of program to work you should:
Create your MouseListener in code that is only called once, such as within a constructor
Create an instance field in the class to represent the camera button, such as a Rectangle or RoundRectangle2D and give it a viable object reference
In the mouse listener, toggle the state of a boolean variable if a click occurs within the shape that represents the camera button, e.g., camUp = !camUp; as you're doing
And then call repaint().
In the paintComponent method, check the state of the boolearn variable with an if statement, and if true, draw the image inside the if statement.
Keep the mouse listener and the painting code separate and in separate methods (or constructor).
Never call repaint() within a painting method as that will cause an uncontrolled animation. If you need a Swing animation, then use a Swing Timer so that you can fully control it. I don't see the need for it here.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class GraphicsExample extends JPanel {
private static final int IMG_WIDTH = 400;
private static final int PREF_W = (3 * IMG_WIDTH) / 2;
private static final int PREF_H = PREF_W;
private static final Color BTN_COLOR = Color.RED;
private static final Color HOVER_COLOR = new Color(255, 100, 100);
private static final Color BTN_CLK_COLOR = new Color(180, 0, 0);
private static final int IMG_X = IMG_WIDTH / 2;
private static final int IMG_Y = IMG_X;
private double camX = 10;
private double camY = camX;
private double camWidth = 200;
private double camHeight = 80;
private Color buttonColor = Color.RED;
private RoundRectangle2D cameraButton = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
private Image img;
private boolean showImage = false;
private JCheckBox toggleModeChkBox = new JCheckBox("Toggle Mode");
// private boolean toggleMode = true;
public GraphicsExample() {
add(toggleModeChkBox);
setPreferredSize(new Dimension(PREF_W, PREF_H));
img = createMyImage();
MouseAdapt mouseAdapt = new MouseAdapt();
addMouseListener(mouseAdapt);
addMouseMotionListener(mouseAdapt);
}
private Image createMyImage() {
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setPaint(new GradientPaint(0, 0, Color.RED, 100, 100, Color.BLUE, true));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int gap = 10;
g2.fillOval(gap, gap, IMG_WIDTH - 2 * gap, IMG_WIDTH - 2 * gap);
g2.dispose();
return img;
}
private class MouseAdapt extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = BTN_CLK_COLOR;
if (toggleModeChkBox.isSelected()) {
showImage = !showImage;
} else {
showImage = true;
}
} else {
buttonColor = BTN_COLOR;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(buttonColor);
g2.fill(cameraButton);
if (showImage) {
int x = (getWidth() - IMG_WIDTH) / 2;
int y = (getHeight() - IMG_WIDTH) / 2;
g2.drawImage(img, x, y, this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GraphicsExample mainPanel = new GraphicsExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
The program draws completely fine if the border layout is Center, but not for any other direction. Here is the code below.
public class MainVisualizer {
public static void main(String[] args) {
int windowWidth = 1000;
int windowHeight = 850;
JFrame mainFrame = new JFrame("Plotter and Integration Visualizer ");
mainFrame.setSize(windowWidth, windowHeight);
mainFrame.add(new GraphComponent(windowWidth, windowHeight), BorderLayout.EAST);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
}
public class GraphComponent extends JComponent {
private ArrayList<String> textFunctions;
private int frameWidth;
private int frameHeight;
public GraphComponent(int width, int height) {
this.textFunctions = new ArrayList<>();
this.frameHeight = height;
this.frameWidth = width;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.drawLine(0, frameHeight/2, frameWidth, frameHeight/2);//X axis
g2.drawLine(frameWidth/2, 0, frameWidth/2, frameHeight);//Y axis
System.out.println( this.getX()+" "+ this.getY());
g2.drawString("X", frameWidth/2, frameHeight/2);
}
}
I believe what you are seeing is because you haIven't set preferred size. The default is 0, and so that's what you get when you add not to the center
public class GraphComponent extends JComponent {
private ArrayList<String> textFunctions;
private int frameWidth;
private int frameHeight;
public GraphComponent(int width, int height) {
this.textFunctions = new ArrayList<>();
this.frameHeight = height;
this.frameWidth = width;
//Set preferredSize right here
setPreferredSize(new Dimension(width, height));
///////////////
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.drawLine(0, frameHeight/2, frameWidth, frameHeight/2);//X axis
g2.drawLine(frameWidth/2, 0, frameWidth/2, frameHeight);//Y axis
System.out.println( this.getX()+" "+ this.getY());
g2.drawString("X", frameWidth/2, frameHeight/2);
}
}
For my game, I paint to a java.awt.Image then draw the Image onto a JPanel. I do this for a couple of reasons, mainly because I didn't want game rendering to hog up cpu cycles on the EDT, and for portability.
A problem arised which caused flickering on the java.awt.JPanel when using
graphics#drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer)
.
However,
graphics#drawImage(Image img, int x, int y, ImageObserver observer)
did not cause this issue.
Here is my code:
Sandbox.java
public class Sandbox implements Paintable {
public static void main(String[] args) throws Exception {
GameWindow window = new GameWindow("Test", 800, 600);
GameScreen screen = new GameScreen(800, 600);
Sandbox sandbox = new Sandbox();
window.add(screen);
window.setVisible(true);
boolean running = true;
while(running) {
sandbox.update();
screen.getPaintBuffer().clear();
screen.getPaintBuffer().paint(sandbox);
screen.repaint();
Thread.sleep(1000 / 60);
}
}
private int x = 0, y = 0;
public void update() {
x++;
y++;
}
public void paint(Graphics g) {
g.drawRect(x, y, 50, 50);
}
}
GameWindow.java
public class GameWindow extends JFrame {
public GameWindow(String title, int width, int height) {
setTitle(title);
setSize(width, height);
setResizable(false);
setLocationByPlatform(true);
setDefaultCloseOperation(3);
}
}
GameScreen.java
public class GameScreen extends JPanel {
private ImageBuffer buffer;
public GameScreen(int width, int height) {
buffer = new ImageBuffer(width, height);
}
public void paint(Graphics g) {
g.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), null);
}
public ImageBuffer getPaintBuffer() {
return buffer;
}
}
Paintable.java
public interface Paintable {
public void paint(Graphics g);
}
ImageBuffer.java
public class ImageBuffer {
private final Image buffer;
private int width, height;
public ImageBuffer(int width, int height) {
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
this.width = width;
this.height = height;
}
public void paint(Paintable paintable) {
paintable.paint(buffer.getGraphics());
}
public void clear() {
buffer.getGraphics().clearRect(0, 0, width, height);
}
public Image getBuffer() {
return buffer;
}
}
Change the GameScreen's paint method to...
Override paintComponent instead
Call super.paintComponent in order to maintain the paint chain's contract
Pass this as the ImageObsever parameter to drawImage
For example...
public class GameScreen extends JPanel {
private ImageBuffer buffer;
public GameScreen(int width, int height) {
buffer = new ImageBuffer(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), this);
}
public ImageBuffer getPaintBuffer() {
return buffer;
}
}
Have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works
Updated
The basic problem is a scaling issue...
The image you're using to draw with is 800x600, but the GameScreen is actually 794x572 (on my PC), this causes the image to be scaled. Now, Swing's default scaling isn't pretty and is based on speed over quality generally.
Now, there are a number of ways you could improve this, but a quick way would be to apply some higher rendering hints, for example
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.drawImage(getPaintBuffer().getBuffer(), 0, 0, getWidth(), getHeight(), this);
g2d.dispose();
}
Now, I've gone overboard with this, so you might want to remove some and see what changes
Updated
Rendering hints could slow the rendering process down, so a better solution might to override the getPreferredSize method of GameScreen and return the expected size
public static class GameScreen extends JPanel {
private ImageBuffer buffer;
private Dimension size;
public GameScreen(int width, int height) {
buffer = new ImageBuffer(width, height);
this.size = new Dimension(width, height);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
Then, rather then passing the size to GameWindow, simply call pack
GameWindow window = new GameWindow("Test");
GameScreen screen = new GameScreen(800, 600);
Sandbox sandbox = new Sandbox();
window.add(screen);
window.pack();
window.setVisible(true);
This way, everybody's on the same size
I am creating a simulation type application, I want one background layer and another layer on top for all of the animations. Im currently using JlayeredPanes but i cannot get the background on the top layer to show as transparent so I can see the background, any help is much appreciated, heres the code:
Background layer
public class SimBackground extends JLayeredPane{
private Model theModel;
private SimulationArea simulationArea;
public SimBackground(Model theModel){
this.theModel=theModel;
setBackground(new Color(0, 230, 0));
setOpaque(true);
setPreferredSize(new Dimension(500,500));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(int x=0;x<50;x++){
for(int y=0;y<50;y++){
g.drawRect((x*10), (y*10), 10, 10);
}
}
}
Top layer
public class SimulationArea extends JLayeredPane {
private int SPEED = 100;
private Model theModel;
Timer timer;
public SimulationArea(Model theModel){
this.theModel = theModel;
setPreferredSize(new Dimension(500,500));
setLocation(0,0);
setOpaque(false);
setBackground(new Color(0,0,0,0));
setVisible(true);
//Swing Timer
timer = new Timer(SPEED,new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
revalidate();
}
});
}
private void update() {
theModel.update();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
//test get 1 active object
ArrayList<ActiveObject> activeObjects = theModel.getActiveObjects();
//System.out.println(activeObjects.size());
for(int i=0; i<activeObjects.size(); i++){
ActiveObject activeObject = theModel.getActiveObjects().get(i);
int x = activeObject.getCoordinates().getX();
int y = activeObject.getCoordinates().getY();
int size = activeObject.getSize();
g2d.fillRect (x ,y , size, size);
}
}
Can someone please tell me what i'm missing here?
Don't use a JLayeredPane, but if you do need to use JLayeredPane in the future, you will want to read the tutorial here since as per my comment you're not using them correctly at all. Instead I recommend that you simplify by doing all drawing in a single JPanel, drawing your background into a BufferedImage perhaps in the constructor, and then drawing that image and your sprites within the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SimExample extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color BKGD_COLOR = new Color(0, 230, 0);
private BufferedImage bkgrnd = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
public SimExample() {
Graphics2D g = bkgrnd.createGraphics();
g.setBackground(BKGD_COLOR);
g.clearRect(0, 0, PREF_W, PREF_H);
g.setColor(Color.black);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
g.drawRect((x * 10), (y * 10), 10, 10);
}
}
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (bkgrnd != null) {
g.drawImage(bkgrnd, 0, 0, null);
}
// draw sprites here
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SimExample mainPanel = new SimExample();
JFrame frame = new JFrame("SimExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
}
});
}
}
I'e been learning java for a while and I've just started a project to make a functional drawing program. However the code below is supposed to draw a rectangle on a bufferedimage but it does not work.
Code for drawing rectangle
public class DrawRectangle extends Panel {
public void drawRect(int x, int y, int width, int height) {
System.out.println("new Rectangle = X:" + x + " Y:" + y + " Width:" + width + " height:" + height);
canvas.createGraphics().draw(new Rectangle2D.Double(x, y, width, height));
}}
public class Panel extends JPanel {
BufferedImage canvas = new BufferedImage(400,400, BufferedImage.TYPE_INT_ARGB);
......
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Repainting");
g.drawImage(canvas, 25, 25, null);
}}
Note: All the methods are going off correctly so it is not simply me neglecting to initiate drawRectangle()
Edit my bad: you're not setting color properly. To wit:
e.g.,
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
public class FunnyDraw {
private static void createAndShowGui() {
DrawRectangle mainPanel = new DrawRectangle();
mainPanel.drawRect(10, 10, 100, 100);
mainPanel.betterDrawRect(200, 200, 200, 200);
JFrame frame = new JFrame("FunnyDraw");
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();
}
});
}
}
class HisPanel extends JPanel {
private static final Color COLOR = Color.black;
private static final int PREF_W = 600;
private static final int PREF_H = 450;
protected BufferedImage canvas = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Repainting");
g.drawImage(canvas, 25, 25, null);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void draw(Shape shape) {
Graphics2D g2 = canvas.createGraphics();
g2.setColor(COLOR);
g2.draw(shape);
g2.dispose();
repaint();
}
}
class DrawRectangle extends HisPanel {
public void drawRect(int x, int y, int width, int height) {
Graphics2D g2 = canvas.createGraphics();
g2.setColor(Color.black);
g2.draw(new Rectangle2D.Double(x, y, width, height));
g2.dispose();
repaint();
}
public void betterDrawRect(int x, int y, int width, int height) {
draw(new Rectangle2D.Double(x, y, width, height));
}
}