I have got problem with my project:/
Why drawPac isn't working correctly. Black rect is drawing, but my image not:/ why
I made 4 classes, here is cod of 3 classes, without main class which extends JFrame, and there is added JPanel Game.
File #1
package pacman;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Game extends JPanel {
Pac pacman = new Pac();
public void Game() {
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.black);
g2d.fillRect(0, 0,this.getWidth(),this.getHeight());
drawPac(g2d);
}
public void drawPac(Graphics2D g2d){
g2d.drawImage(pacman.image, pacman.x, pacman.y, 100, 100, this);
}
}
File #2
package pacman;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Actor {
int x,y;
int dv;
Image image;
public void Actor(){
}
}
File #3
package pacman;
import pacman.Game;
import javax.swing.ImageIcon;
import java.awt.Graphics2D;
public class Pac extends Actor {
public void Pac(){
try{
image = new ImageIcon(Pac.class.getResource("../img/Pac00.gif")).getImage();
x=0;
y=0;
}
catch (Exception e){
System.out.println("Blad prz otwieraniu");
System.exit(0); }
}
}
1 - The "Pac" class should be responsible for draw itself, don't you agree?
2 - For JPanels and every JComponent's sons, you should override the paintComponent method, not paint, that is responsible to delegate the painting work to paintComponent, paintBorder and paintChildren. You should call the super version of paintComponent too, as you are doing in paint. Take a look at the documentation.
3 - In most of the cases, is recomended to create a new graphics context (based on the original). So, your line:
Graphics2D g2d = (Graphics2D) g;
Should be replaced to:
Graphics2D g2d = (Graphics2D) g.create();
And you need to dispose (g2d.dispose()) this new context after using it (at the last line of the paintComponent).
4 - Is the code of the Pac class correct? Is it compiling? The image field is a member of Actor?
I think you have some problems in your code that you not showed in your question...
Ok #lechniak update Game class
public class Game extends JPanel {
Pac pacman = new Pac();
public Game() {
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.black);
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
drawPac(g2d);
}
public void drawPac(Graphics2D g2d){
g2d.drawImage(pacman.image, pacman.x, pacman.y, 200, 200, this);
}
public static void main(String[] args) {
JFrame f = new JFrame("Image Draw");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new Game());
f.setSize(350,300);
f.setLocation(300,300);
f.setVisible(true);
}
}
And Pac class
//import javax.swing.ImageIcon;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import javax.imageio.ImageIO;
import java.io.*;
public class Pac /*extends Actor*/ {
int x = 0;
int y = 0;
BufferedImage image;
public Pac() {
try {
image = ImageIO.read(new File("/Users/hlozano/java/swing/programmerBorn.jpg"));
//new ImageIcon(Pac.class.getResource("../img/Pac00.gif")).getImage();
x = 0;
y = 0;
} catch (Exception e) {
System.out.println("Blad prz otwieraniu " + e);
System.exit(0);
}
}
}
And image output
I hope these helps.
Related
Basically I have a (width x height) size of pixels in a buffered image and would like to draw simple horizontal BLACK lines, one after another into the Buffered Image / JPanel. Each click of the button should create a new horizontal line.
Although the button event reaches the updateImage() function, AND the Log output indicates that paintComponent(Graphics g) is called by the system. There is no update happening. The only time a Line is drawn is on the constructor initialisation. Nothing is being updated to the screen on each button click; only the initial one line is drawn from a test call in the constructor.
The end product is to simulate a printer.
Thank You.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class ViewPaper extends JPanel {
private BufferedImage buffer = null;
private final int width = 384;
private int height = 500;
private final static Logger LOG = Logger.getLogger(ViewPaper.class
.getName());
public ViewPaper() {
super();
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
printDotLine(50);
LOG.log(Level.INFO, "ViewPaper: Load Successful.");
}
/* Update BufferedImage then repaint to screen.
* Note. A Top Level repaint() is also called
* and according to log the paintComponent is
* called but nothing is happening!
*/
public void updateImage(int y) {
printDotLine(y);
repaint();
LOG.log(Level.INFO, "ViewPaper: updateImage(); Called.");
}
/* Update JPanel with updated buffer. */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(buffer, 0, 0, this);
g2d.dispose();
LOG.log(Level.INFO, "ViewPaper: paintComponent(); Called.");
}
/* Sets row of pixels in buffer to black.*/
public void printDotLine(int y) {
for (int x = 0; x < width; x++) {
buffer.setRGB(x, y, Color.BLACK.getRGB());
}
LOG.log(Level.INFO, "ViewPaper: printDotLine(); Called.");
}
}
You almost answered your own question but forgot to include actual button.
Here is how it should be (almost - no static should be used -it's just simple example/improvement of your code):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ViewPaper extends JPanel {
static ViewPaper viewPaper;
static int line=50;
public static void main(String args[])
{
JFrame frame=new JFrame("View Paper");
viewPaper=new ViewPaper();
frame.add(viewPaper);
JButton button=new JButton("Click Me!");
frame.add(button,BorderLayout.SOUTH);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
viewPaper.updateImage(line++);
}
});
frame.setSize(300,500);
frame.setVisible(true);
}
private BufferedImage buffer = null;
private final int width = 384;
private int height = 500;
private final static Logger LOG = Logger.getLogger(ViewPaper.class
.getName());
public ViewPaper() {
super();
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
printDotLine(50);
LOG.log(Level.INFO, "ViewPaper: Load Successful.");
}
/* Update BufferedImage then repaint to screen.
* Note. A Top Level repaint() is also called
* and according to log the paintComponent is
* called but nothing is happening!
*/
public void updateImage(int y) {
printDotLine(y);
repaint();
}
/* Update JPanel with updated buffer. */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(buffer, 0, 0, this);
g2d.dispose();
LOG.log(Level.INFO, "ViewPaper: paintComponent(); Called.");
}
/* Sets row of pixels in buffer to black.*/
public void printDotLine(int y) {
for (int x = 0; x < width; x++) {
buffer.setRGB(x, y, Color.BLACK.getRGB());
}
LOG.log(Level.INFO, "ViewPaper: Update Received.");
}
}
Language: Java.
Hi, I need to prevent drawing over the same location of a Graphics2D more than once. For example, if the user draws using a BasicStroke with a round cap and a width of 10 over a certain area, that same area cannot be drawn on a second time.
The reason I want to do this is so that the user can draw (free-hand) translucent colours over an image without drawing over the same stroke (thus increasing the density of the colour and reducing its translucency).
I've tried storing the shapes of all the strokes made by the user (as Area objects that subtract the shape) and then clipping the Graphics2D by the intersection of all those Area objects.
This almost works, but the 'shape' obtained by the clip is not quite the same as the 'shape' drawn by the stroke - it is out by a couple of pixels.
Does anyone have any other ideas that might work?
The concept is relatively simple, you need to have multiple layers onto which you can render...
There are multiple different ways to approach the problem. You could maintain a list of Points and on each paint cycle, render these points to a backing buffer, which you would then draw over the main content using a AlphaComposite.
You could (as this example does) draw directly to the backing buffer and repaint the content, again, using a AlphaComposite to render the higher layer.
You could have any number of layers...
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class PaintOver {
public static void main(String[] args) {
new PaintOver();
}
public PaintOver() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MapPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MapPane extends JPanel {
private BufferedImage background;
private BufferedImage foreground;
public MapPane() {
try {
background = ImageIO.read(getClass().getResource("/TreasureMap.png"));
foreground = new BufferedImage(background.getWidth(), background.getHeight(), BufferedImage.TYPE_INT_ARGB);
} catch (Exception e) {
e.printStackTrace();
}
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint;
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
startPoint = null;
}
#Override
public void mouseDragged(MouseEvent e) {
Point endPoint = e.getPoint();
Graphics2D g2d = foreground.createGraphics();
Point offset = getOffset();
Point from = new Point(startPoint);
from.translate(-offset.x, -offset.y);
Point to = new Point(endPoint);
to.translate(-offset.x, -offset.y);
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.draw(new Line2D.Float(from, to));
g2d.dispose();
startPoint = endPoint;
repaint();
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
protected Point getOffset() {
Point p = new Point();
if (background != null) {
p.x = (getWidth() - background.getWidth()) / 2;
p.y = (getHeight() - background.getHeight()) / 2;
}
return p;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
Point offset = getOffset();
g2d.drawImage(background, offset.x, offset.y, this);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.drawImage(foreground, offset.x, offset.y, this);
g2d.dispose();
}
}
}
}
I want to use graphics2D but I can't get I get it to display my graphics. Is there a better way to go about this that would allow me to use repaint()? Eventually I want to make have a image set as a background and be able to draw on it then save the contents of the frame as a image.
import java.awt.image.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.swing.JApplet;
import java.awt.*;
// assume that the drawing area is 150 by 150
public class test extends JApplet
{
final int radius = 25;
int width = 200, height = 200;
BufferedImage img = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
public void paint ( )
{
Graphics2D g = img.createGraphics();
g.setColor( Color.orange );
g.fillRect( 0, 0, 150, 150 );
g.setColor( Color.black );
g.drawOval( (150/2 - radius), (150/2 - radius), radius*2, radius*2 );
}
}
Ok so,
You have public void paint( ) what the hell is this doing lol? You need a graphics object. public void paint(Graphics g) is like the default method which gets called automatically when your applet is initialised.
You have Graphics2D g = img.createGraphics(); when you need to use your default Graphics g object and cast it into a Graphics2D object like so Graphics2D g2d = (Graphics2D) g;
You should search for a little more information on double buffering too :)
anyway... This code works so take from it what you want :)
P.S Note how I implemented Runnable; You do not need to do this if you only want to use the Graphics2D code. It is just making the class a thread and is used for game frame rates :)
Hope this helped.
import java.applet.*;
import java.awt.*;
public class Test extends Applet implements Runnable{
public boolean isRunning = false;
public int radius = 25;
public void start() {
isRunning = true;
new Thread(this).start();
}
public void stop() {
isRunning = false;
}
public void paint(Graphics g) {
//Create Graphics2D object, cast g as a Graphics2D
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.ORANGE);
g2d.fillRect(0, 0, 150, 150);
g2d.setColor(Color.BLACK);
g2d.drawOval((150/2 - radius), (150/2 - radius), radius * 2, radius * 2);
}
public void run() {
while (isRunning) {
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I've tried the add() method but nothing is displayed when I try to add Test to GraphicsTest. How should I be adding it? Can someone show me? I've included the code I'm using.
This is my way and it's not working. Can someone show me or make me aware of what the problem actually is?
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class Test extends JComponent
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.red);
g2d.drawString("Hello", 50, 50);
g2d.dispose();
}
}
Here is the other class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public class GraphicsTest extends JPanel
{
private Graphics2D g2d;
private String state;
private int x, y;
GraphicsTest()
{
Test t = new Test();
t.setVisible(true);
add(t);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.drawString("STATE: " + state, 5, 15);
g2d.drawString("Mouse Position: " + x + ", " + y, 5, 30);
g2d.setColor(Color.red);
Rectangle2D r2d = new Rectangle2D.Double(x, y, 10, 10);
g2d.draw(r2d);
g2d.dispose();
}
public void setState(String state) { this.state = state; }
public String getState() { return state; }
public void setX(int x) { this.x = x; repaint(); }
public void setY(int y) { this.y = y; repaint(); }
}
Your problem is g2d.dispose(). Take those out and it should work. I suspect this may cause different behavior on different jvms. It appears what is happening is the g2d object is used to draw stuff on the GraphicsTest object. Then the same g2d object tries to draw stuff on on the Test object, but it has been disposed so it can't draw anything. There are cases where you want to call g2d.dispose() but this is not one of them.
The other thing I did to make your code work was I changed the layout manager:
setLayout(new BorderLayout());
add(t, BorderLayout.CENTER);
The default layout should be Flow Layout. I'm not sure off hand why it wouldn't work with Flow Layout.
I have checked similarly named questions, but they don't answer this use case.
Basically, I was to overlay some text (text) at a given coordinate (x,y) I have the below function in a package;
protected BufferedImage Process2(BufferedImage image){
Graphics2D gO = image.createGraphics();
gO.setColor(Color.red);
gO.setFont(new Font( "SansSerif", Font.BOLD, 12 ));
gO.drawString(this.text, this.x, this.y);
System.err.println(this.text+this.x+this.y);
return image;
}
I feel like im missing something patently obvious; every reference to Graphics2D I can find is dealing with either games or writing directly to a file but I just want a BufferedImage returned. with the overlay 'rendered'
In the current code, the image appears out the end unchanged.
Thanks!
The method drawString() uses x and y for the leftmost character's baseline. Numbers typically have no descenders; if the same is true of text, a string drawn at position (0,0) will be rendered entirely outside the image. See this example.
Addendum: You may be having trouble with an incompatible color model in your image. One simple expedient is to render the image and then modify it in situ.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/questions/2658663
*/
public class TextOverlay extends JPanel {
private BufferedImage image;
public TextOverlay() {
try {
image = ImageIO.read(new URL(
"http://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png"));
} catch (IOException e) {
e.printStackTrace();
}
image = process(image);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
private BufferedImage process(BufferedImage old) {
int w = old.getWidth() / 3;
int h = old.getHeight() / 3;
BufferedImage img = new BufferedImage(
w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(old, 0, 0, w, h, this);
g2d.setPaint(Color.red);
g2d.setFont(new Font("Serif", Font.BOLD, 20));
String s = "Hello, world!";
FontMetrics fm = g2d.getFontMetrics();
int x = img.getWidth() - fm.stringWidth(s) - 5;
int y = fm.getHeight();
g2d.drawString(s, x, y);
g2d.dispose();
return img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TextOverlay());
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
}