I'm trying to wrap my head around some simple GUI operations using AWT. The point I'm stuck at right now is how to call the paint functions (I'm trying to create a method for each shape/object). I simply can't tell by reading the API what parameter "Graphics" refers to, that I need to pass the function on call. By looking at other examples, I feel like I don't even need to call it specifically. I'm confused..
Also, is it possible to pass the drawRect(int ... int) function the values in my actual object, or do I have to resort to hard coded values, the way it is defined in scope right now?
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics.*;
class AWTFigur extends Panel{
Figur f;
AWTFigur (Figur f){
this.f = f;
}
public void paint(Graphics g){
f.paint(g);
}
public Dimension getPreferredSize(){
return new Dimension (f.getWidth()+2, f.getHeight()+2);
}
public void paintRect(Graphics g){
super.paint(g);
g.drawRect(0, 0, 10, 10);
}
public static void main(String args[]){
Frame F=new Frame();
F.setLayout(new FlowLayout());
F.addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent we){System.exit(0);}});
AWTFigur P1=new AWTFigur(new Square(Integer.parseInt(args[0])));
F.add(P1);
AWTFigur P2=new AWTFigur(new Circle(Integer.parseInt(args[1])));
F.add(P2);
F.pack();
F.setVisible(true);
}
}
The code bit for the circle class:
public class Circle extends Figur{
private int radius;
private int diameter;
private final double pi = 3.14159265358979323846264338327950288419;
public Circle(int radius){
if (radius>0)
this.radius=radius;
else{
this.radius=2;
}
}
@Override
double getCircumference(){
return (this.radius*this.pi*2);
}
@Override
double getArea(){
return this.pi*this.radius*this.radius;
}
int getRadius(){
return this.radius;
}
int getDiameter(){
return this.diameter;
}
void setRadius(int radius){
if (radius > 0)
this.radius=radius;
else{
this.radius=2;
}
}
void setDiameter(int diameter){
if (diameter == (radius*2))
this.diameter=diameter;
else{
this.diameter=radius*2;
}
}
}
And for the square class:
public class Square extends Figur{
private int height;
private int width;
public Square(int height){
if (height >0){
this.height=height;
this.width=height;
}
else{
this.height=2;
this.width=2;
}
}
@Override
double getCircumference(){
return this.height*4;
}
@Override
double getArea(){
return this.width*2;
}
@Override
int getHeight(){
return this.height;
}
@Override
int getWidth(){
return this.width;
}
void setHeight(int height){
if (height > 0)
this.height=height;
else{
this.height=2;
}
}
void setWidth(int width){
if (width > 0)
this.width=width;
else{
this.width=2;
}
}
}
And the superclass Figur:
import java.awt.*;
class Figur{
double getCircumference(){return 0;}
double getArea(){return 0;}
int getHeight(){return 0;}
int getWidth(){return 0;}
public void paint(Graphics g){}
}
What value to pass the paint(Graphics) function? (AWT)
As hinted in your later words, you don't. Simply call repaint()
and the GUI toolkit of AWT/Swing will ensure that the paint(Graphics)
method is called with a valid Graphics
instance.
Also, is it possible to pass the drawRect(int ... int) function the values in my actual object, or do I have to resort to hard coded values, the way it is defined in scope right now?
The first class has this:
class AWTFigur extends Panel{
Figur f;
Here, f
is an attribute of the class that is of type Figure
, a class that specifies a method public void paint(Graphics g){}
which can be overridden by any any class that extends it. (But it would be better if it were an interface
or abstract
class - the reason being that then any other class that implements or extends it, is forced to provide an implementation.) So in the latter case, both Circle
and Square
would have a paint method that can be called be any class (such as AWTFigur
) which has an object of that type, when it wants / needs to paint that object.
You seem to have a tenuous understanding (at least) of this, given that class has:
public void paint(Graphics g){
f.paint(g);
}
Which will result in the Figure
being painted. But the main(..)
method shows where your understanding seems a bit hazy.
Frame F=new Frame();
F.setLayout(new FlowLayout());
F.addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent we){System.exit(0);}});
AWTFigur P1=new AWTFigur(new Square(Integer.parseInt(args[0])));
F.add(P1);
AWTFigur P2=new AWTFigur(new Circle(Integer.parseInt(args[1])));
F.add(P2);
This adds two instances of AWTFigur
to a frame that has (by default) a BorderLayout
. A Component
(like Panel
) can only be added to a single constraint of a BorderLayout
. Because no constraint was specified when adding either, they will both be added to the CENTER
(which can only display one of them).
That's not what is needed here.
What is needed, is a single instance of AWTFigur
that can draw any number of Figure
objects, so that opening code might be changed to:
class AWTFigur extends Panel{
ArrayList<Figur> f;
The ArrayList
can hold many Figur
objects. If then, in addition to (or perhaps instead of) the constructor that accepts a Figur
object, the class provides a method like this:
public void addFigur(Figur figur) {
f.addElement(figur); // add the new Figur to the existing collection
repaint(); // schedule a call to paint(Graphics)
}
That method might be called in the main(..)
to add a second or third figure to the collection held by the array list.
Then in the paint method, it would be possible to iterate the entire collection and paint each in turn. Something like:
public void paint(Graphics g){
for (Figure figur : f) {
g.paint(g);
}
}
This sort of stuff will be covered in Performing Custom Painting. Read the lesson carefully, go through the examples and try each one, it should be a lot more clear once completed.
A final note (or two):
EachWordUpperCaseClass
, firstWordLowerCaseMethod()
, firstWordLowerCaseAttribute
unless it is an UPPER_CASE_CONSTANT
) and use it consistently. private final double pi = 3.14159265358979323846264338327950288419;
use instead, Math.PI