Currently I am using a JFrame that has a JPanel in it. In my JPanel I have overridden the paint component method, However, I want to "draw" a "Hero" class as a unit. Let me elaborate. The hero class as of right now has two parts: A health bar and an image. Originally, in the paint component method of my JPanel, I was drawing the character and health bar individually.
public void paintComponent(Graphics g){
g.drawImage(h.getImage(), h.getX(), h.getY(),null);
g.setColor(Color.red);
g.fillRect(h.getX()+7, h.getY()-16, 50, 10);
g.drawLine(h.getX() + (h.getImage().getWidth(getFocusOwner())/2), h.getY()-40, h.getX() + (h.getImage().getWidth(getFocusOwner())/2), h.getY()+40);
}
This properly aligned the health bar and character together, however, this seemed inefficient and messy. So, is there anyway I could draw the two together as a unit? I pondered making them a separate JPanel, but realized that was a silly idea. Is there anyway to do this more efficiently? One of the biggest reasons i am looking for a solution now is that i would like to be able to extend the character class with other classes IE: Monster, Knight, Goblin but when i draw them their respective health bars and images lined up. If you need any further explanation please ask. Thank you!
Also, to spark any ideas that you might have, I'm imagining something like this. Another thing: Would using canvas be of any use?
paint(Hero);
Thank you again!
In your Hero class define a drawing method which accepts a Graphics object:
public void drawHero(Graphics g)
{
// implementation
}
Then in your main JPanel subclass draw the Hero with this drawing method:
public void paintComponent(Graphics g)
{
// other drawing code
hero.drawHero(g);
}
Related
I am creating a java 2D game and have come to a point where I am thinking of creating "pop-up graphics" i.e graphics that will populate the screen when a certain event occurs. Say, you pick up a certain item, I want this item to be displayed in the middle of the screen in a box containing information about said item.
Currently I have one big paintComponent that paints all of the graphics for the game (tiles, entities, players etc (which has been done efficiently I might add)). I know that I can probably have a boolean value which checks if an item has been picked up in that method, but it feels wrong.
What I am wondering is, is there a way for items to have their own paintComponent so that when it is called, it will show say a bo for a brief period WITHOUT having a boolean value in the big paintComponent method that I currently use for everything?
Small code example (won't execute)
public class popUpGraphics extends (JComponent or JPanel or whatever works best for this scenario)
{
public popUpGraphics(){
}
#Override
protected void paintComponent(Graphics g){
//g.Draw(stuff);
}
}
and then somewhere in an event I instantiate this or somesuch.
I do not want this to override the other paintcomponent, I just want to add to it
(as if it was another layer) to the paintComponent
In short I want to know:
1. Is is possible to have brief graphics shown without including in the huge paintComponent method
2. What Swing library should be extended (JComponent, JPanel etc)
Thanks in advance!
I'm doing an assignment for school and I can't get my head around the logic I need to use to solve this. I hope some of you can point me in the right direction.
I have some classes to draw simple shapes:
Class Diagram 1
Extended Class Diagram
According to the assignment every deferred class under DrawingItem needs a paint() method to be able to paint the particular (Oval, Spline etc..) independent from GraphicsContext. For Oval, my guess is this method would be something like:
public void paint(Graphics g){
g.setColor(super.getColor());
g.drawOval(
(int) dw.getAnchor().getX(), (int) dw.getAnchor().getY(),
(int)this.width, (int)this.height
);`
}
Extended class diagram shows an interface IPaintable which I have created with a method for every shape. The JavaFX side (DrawingTool) implements this interface and all of its methods. These methods want the shape object as argument. I use these methods to draw the shapes in javaFX, again the oval example:
strokeOval(
oval.getHeight(), oval.getWidth(), oval.getAnchor().getX(), oval.getAnchor().getY()
);
The main questions I have are these:
Am I going in the right direction with the paint() methods in the shape subclasses and if so how do I call them from the JavaFX side?
How can I "implement" the paint(paintable:IPaintable) method in the Drawing and DrawingItem classes?
There are 2 design patterns easily identifiable in the class diagrams:
The IPaintable is supposed to be a wrapper(Facade) for the GUI drawing operations allowing you to use the classes in Class Diagram 1 independent from the GUI library used. You should only use the methods provided by IPaintable in the paint methods.
The classes in Class Diagram 1 are the command part of the Command Pattern; DrawingTool is the invoker/client and IPaintable is the receiver.
The DrawingTool class should contain code like this:
IPaintable paintable = new JavaFXPaintable(canvas.getGraphicsContext());
and use it like this, if the drawing needs to be redrawn:
drawing.paint(paintable);
Implementing the paint methods
Since a Oval can be drawn using IPaintable's methods, it should implement paint like this:
public void paint(IPaintable paintable) {
paintable.setColor(color);
paintable.paintOval(this);
}
Polygon would use the paintLine methods of the IPaintable passed to it's paint method for drawing itself, Drawing.paint would clear the IPaintable and draw all it's items ect.
In JavaFxPaintable the paintOval method would be implemented like this:
public void paintOval(Oval oval) {
Point anchor = oval.getAnchor();
graphics.strokeOval(anchor.getX(), anchor.getY(), oval.getWidth(), oval.getHeight());
}
You may need to modify this a bit, if anchor denotes the top-left instead of the the center.
Thanks fabian, pointing me in this direction realy helped a lot (as cleaning up my post for readability did too).
Now I have implemented these pointers and they seem to work. With the draw() method in Drawingtool I call the paint(IPaintable paintable) method in the Drawing class, which loops through the list of drawingitems in this class like so:
public void paint(IPaintable paintable){
for (DrawingItem test : drawingitems){
if (test instanceof Oval){
paintable.paintOval((Oval) paintable);
} else if (test instanceof Image){
paintable.paintImage((Image) paintable);
This should paint the shapes and seem to work. The last part is adding them to the canvas initialized in the DrawingTool class. I can't seem to figure out how to do this. I've tried to add them while going through the list with drawing items but this does not seem to work (or I'm handling it wrong).
So, lets say I have some game, take Pong for example. Obviously, you generally speaking don't want to mix game-logic into graphics classes, so the class for Ball or Paddle is sepearte from the JPanel which actually draws them. Ball has the movement logic for the ball, its current location, hit detection, etc. However, is it bad practice for me to use graphics classes from Swing and awt in my Ball class? For example, if I were to use a java.awt.Rectangle to determine the hitbox. Even though I am not drawing it in this class, I am using it. Or if I were to use Java.awt.Point to store coordinates.
By the way, the reason I am asking is because I have been told many times on this site not to mix graphics with other parts.
Using Rectangle in non-graphics class: (Is this bad practice?)
public class Ball {
static Rectangle hitbox = new Rectangle(0,10,20,20);
static void checkHit() {
if(hitbox.intersects(Paddle.hitbox) //do something
}
}
My Graphics class:
public class DrawMyStuff extends JPanel {
void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.BLACK);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(Ball.hitbox);
}
}
I'd say that for most part, you shouldn't do this.
Exceptions from the rule
There are however a (small) set of helper classes inside that package that are actually only data holders of a "nice" type. Why invent wheels when you already got them? These would be "okay to use" in my world.
Dimension
Insets
Point
Rectangle (and all other Shapes like Polygon, Area and so on)
These can be used to describe graphical problems while they are not directly coupled to on-screen-resources.
I'm really confused with the program flow for how the paintComponent function works within my JPanel. Ideally I'd like to have access to the Graphics object to draw stuff from other functions based on my program flow. I'm thinking along the lines of the following:
private Graphics myG;
public void paintComponent(Graphics g) {
super.paintComponent(g);
myG = g; //I want a graphics object that I can just draw with.
//Should I just initialize to myG = new Graphics(); or something?
//private Graphics myG = new Graphics(); does not seem to work
}
//this is what's getting called, where I want to call other functions that
//can use myG to draw graphics as I please
public void startPanelView() {
myG.drawRect(350, 20, 400, 300); //doesn't work
otherFunctionForGraphics(); //which will also use myG.
}
I hope I've made myself clear here. I just want to be able to do use the Graphics class as I please. Currently I can only do stuff like g.drawRect(...) inside of the paintComponent() function. This could work for my purposes but I'd like more flexibility.
Thanks.
EDIT - Alright, I understand that I should not try and reference a Graphics object outside. But how should I go about separating application logic from the paintComponent function? Right now this class is looking a little messy because I have the following:
public void paintComponent(Graphics g) {
if (flag1 == true) {
//do some graphics stuff, that I would prefer to be in another function
}
if (flag2 == true) {
//do some other graphics stuff, again, which I would prefer
//to be in another function
}
//... etc. More of these cases.
}
And basically the paintComponent function is getting stupidly long and complicated for me, so I would like to break it up in whatever ways possible.
Call repaint from your startPanelView method on the panel object. You should never act on the graphics object outside of the paint methods, nor should you maintain a reference to the graphics object for use outside of the paint method.
The others are right that you cannot keep the Graphics object as a member variable, but if the problem is that your paintComponent method is getting too long, you can still pass the Graphics Swing gives you as an argument to other methods:
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(350, 20, 400, 300);
doSomeStuff(g);
if (flag1) {
doMoreStuff(g);
} else {
doDifferentStuff(g);
}
}
I'd like to have access to the Graphics object to draw stuff from other functions based on my program flow. I'm thinking along the lines of the following:
No, you shouldn't do that in a standard Swing application as the Graphics object obtained will not persist and your drawings will disappear whenever the JVM or the operating system decide that a repaint is necessary. Consider creating Lists or other collections of objects to be drawn (such as from classes that implement Shape) and iterating through these collections in the paintComponent method. Another technique is to draw on a BufferedImage and then display it in your paintComponent method.
basic JComponent for Painting/Custom Painting/2D Graphics in Swing or for Image/ImageIcon too, is JLabel,
don't call another viod(s) or class(es) from 2D Graphics or CustomPainting, some valuable examples are here or here, search on this forum for excelent suggestions about Custom Painting and 2D Graphics
I'm having some troubles with setClip in Java. I have a class that extends JPanel. Within that class I have overridden the paintComponent method. My paintComponent method looks something like this:
paintComponent {
//draw some lines here
Rectangle whole = g2.getClipBounds();//g2 is my Graphics2D object
Rectangle part = <some rectangle that is a part of the whole paintable area>;
g2.setClip(part);
//draw some more stuff here
g2.setClip(whole);
}
The problem that I'm seeing is that the area in the clipped region seems to be painted repeatedly. For example, if I tell it to paint, it paints just fine. But then, if I switch windows or somehow else cause it to paint the same thing again, the clipped region isn't cleared while the rest is. This results in the painting on the clipped region to appear bolder than the rest of the paintable area.
I imagine that I'm missing something in how setClip works.
Any suggestions would be much appreciated. Thanks in advance for any help.
Creating a new Graphics object from the old one did the trick for me, as adviced by Tom.