I'm trying to draw objects onto a canvas from an array, but the thing is, I have no clue how to? This must include the position and sizes of the shapes, and there will be more than one type of shape. The code I've got so far(It's inefficient/bad though)
public class MCanvas extends Canvas {
private Object[] world = {};
public void paint(Graphics g){
try{
// How to paint all the shapes from world here?
} catch (NullPointerException e) {
System.out.println(e.toString());
}
}
}
Any ideas? Thanks.
If your using objects that extend from java.awt.Shape, you can translate and draw them by using a Graphics2D context
Since (some whe around Java 1.3/4), the paint engine is guaranteed to use Graphics2D instance.
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
for (Object o : world) {
if (o instanceof Shape) {
Shape shape = (Shape)o;
//if the shape isn't created with
// a location, you can translate them
shape.translate(...,...);
g2d.setColor(....);
g2d.draw(shape);
//g2d.fill(...);
}
}
}
You might like to take a look at 2D Graphics for more details.
Also, use a JPanel instead of Canvas and then override its paintComponent method
Have a look at Custom Painting for more details
Related
Can you render components swing through a Graphics object?
I have a structure like this in my class:
public void render(Graphics g) {
//Render stuff
}
Is it possible to create an object swing, and for that object to render i using the Graphics object?
sure, absolutely possible.
public class MyClass extends JComponent {
//...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
render(g);
}
}
I take it, you want to draw, but not to the screen.
One can create a BufferedImage (or read a background image) and create a Graphics2D object with which to draw.
File imgFile = new File("scenery.png");
BufferedImage img = ImageIO.read(imgFile);
Graphics2D g = img.createGraphics();
render(g);
g.dispose();
ImageIO.write(img, "png", imgFile);
Not to forget the g.dispose() to releast native drawing state.
I am trying to make a program with a simple grid of rectangles where, if the user clicks on a rectangle, it is filled black. The problem I am having is that my mouseClicked method cannot access my paintComponent method, so I get an error.
Here is relevant code:
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g2);
g2.setColor(Color.BLACK);
for(Rectangle2D rect : squares) {
g2.draw(rect);
}
}
public void mouseClicked(MouseEvent e) {
if((e.getX()>RECT_WIDTH && e.getX()<RECT_WIDTH+(game.getSize()-1)*BOX_DIM) && (e.getY()>RECT_HEIGHT && e.getY()<RECT_HEIGHT+(game.getSize()-1)*BOX_DIM)) {
Point2D point = new Point2D.Double(e.getX(), e.getY());
Rectangle2D rect = findRect(point);
g.setColor(Color.BLACK);
g.fill(rect);
repaint();
}
}
public Rectangle2D findRect(Point2D p) {
for(Rectangle2D rect : squares) {
if(rect.contains(p)) {
return rect;
}
}
return null;
}
"squares" is an arraylist of rectangle2Ds. The error is in the mouseClicked method on 'g' because eclipse cannot find g. Thanks for any help!
In your List object you need to store an object that contains two pieces of information:
The Rectangle
the Color of the Rectangle
When you click on the Rectangle you iterate through the List to find the Rectangle that was clicked and then you update the Color property of that Rectangle and invoke repaint().
You will also need to change the painting code to set the Color of the Rectangle before you invoke the draw() method.
Check out the DrawOnComponent example found in Custom Painting Approaches. It shows how to create the custom object to store two properties and how to paint this object in the paintComponent() method.
I've extended the JPanel class to draw a graph. The problem that I've got is that I need a global graphics object in order to call it in multiple methods... As an example, here's what I'm trying to do:
public class Graph extends JPanel {
private Graphics2D g2d;
public void paintComponent(Graphics g){
g2d = (Graphics2D)g;
}
public void drawGridLines(int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
This returns a null pointer exception - so my question is: how do I create a global graphics object? What's the best practice in this situation?
My suggestion would be this:
public class Graph extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d = (Graphics2D) g;
drawGridLines(g2d, ......);
}
private void drawGridLines(Graphics2D g2d, int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
i.e. keep all the uses of your graphics context inside the paintComponent call.
How would I pass in the graphics object externally?
Don't. The graphics context is only valid during the invocation of paintComponent(). Instead, use the MVC pattern, discussed here, to update a model that notifies any listening view to render itself. JFreeChart is a complete example.
I've extended the JPanel class to draw a graph. The problem that I've got is that I need a global graphics object in order to call it in multiple methods... As an example, here's what I'm trying to do:
public class Graph extends JPanel {
private Graphics2D g2d;
public void paintComponent(Graphics g){
g2d = (Graphics2D)g;
}
public void drawGridLines(int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
This returns a null pointer exception - so my question is: how do I create a global graphics object? What's the best practice in this situation?
My suggestion would be this:
public class Graph extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d = (Graphics2D) g;
drawGridLines(g2d, ......);
}
private void drawGridLines(Graphics2D g2d, int hor, int vert){
g2d.someLogicToDrawMyGridLines(someparams);
}
}
i.e. keep all the uses of your graphics context inside the paintComponent call.
How would I pass in the graphics object externally?
Don't. The graphics context is only valid during the invocation of paintComponent(). Instead, use the MVC pattern, discussed here, to update a model that notifies any listening view to render itself. JFreeChart is a complete example.
how to turn several graphics objects in to one?
(this part of code should generate tetris figure, where generate() create a figure)
public void paint(Graphics g){
Figure f = generate();
int length = f.getX()[0].length;
for(int j =0; j<f.getX().length;j++){
int xr=xs+10;
ys = 0;
for(int i=0;i<length;i++){
if (f.getX()[j][i] == 1){
int yr = ys+10;
Rectangle p = new Rectangle(xs,ys,xr,yr);
g.setColor(f.getY());
g.drawRect(p.x, p.y, p.width, p.height);
g.fillRect(p.x, p.y, p.width, p.height);
//g.translate(xs+40, ys+40);
}
ys+=10;
}
xs+=10;
}
xs=0;
ys=0;
//g.setColor(Color.white);
//g.drawRect(45, 95, 55, 105);
}
Well, I think you are starting with Java 2D, since your code has some problems.
First of all, you always need to call the paint version of the super class. This should be done because the component needs to have a chance to render itself properly. Take a look.
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
// continue here...
}
If you are dealing with a JFrame you will override the paint method. If you are working with some JComponent child, like JPanel, you need to override the paintComponent method, which has the same signature of paint, but it is protected, not public. You can override paint too, but in these cases (JComponent and its children), paint is a method that delegates the paint work to three methods (paintComponent, paintBorder, and paintChildren), so the best option is to override paintComponent.
Another detail. The best way to work with graphics is to create a new graphics context based in the current one and dispose of it after using it. Take a look:
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
Graphics newG = g.create();
// or Graphics2D newG2d = (Graphics2D) g.create();
// do your work here...
newG.dispose(); // disposes the graphics context
}
The graphics context that is created using the create method is a copy of the current graphics context (with the same states), but changing it does not affect the original one, so doing this, you will not mess with the state of the original graphics context.
To finish, I think that you need to have a draw method in your figure that receives the graphics context. So, the Figure instance will be responsible to draw itself. Something like:
public class Figure {
// figure's members...
public void drawMe( Graphics2D g2d ) {
// do the draw work here...
}
}
public class MyFrame extends JFrame {
#Override
public void paint( Graphics g ) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g.create();
// let's suppose that figureList is a List<Figure> or a Figure[]
for ( Figure f : figureList ) {
f.drawMe( g2d );
}
g2d.dispose();
}
}
Of course, you can create a new graphics context for each Figure if its draw method changes the graphics context too "deeply", like doing translations and rotations. You just need to dispose the new ones after using them.
I assume you are trying to put multiple components inside of an enclosing component so that you can move/manipulate them together.
One suggestion would be to add each of your objects to a panel object, like JPanel.
However it is somewhat unclear what you are trying to achieve exactly.