Questions about drawing on Canvas

Z

Zerex71

Greetings,

I am attempting for the first time to do some drawing on a canvas.
What I would like to do is draw a standard set of three orthogonal
axes and then superimpose a line (vector) on the canvas as well, to
aid in visualizing some rotations. The questions I have are as
follows:

1. If I want the vectors to have any thickness, it sounds like I am
going to have to call drawRect() instead of drawLine() - true or
false?
2. In my reading, I have seen code examples where they seem to extend
JPanel (I don't know why such a graphical object would subclass from a
panel, so I'm a bit puzzled by that) and override its paintComponent()
method. Why do you subclass from JPanel to draw rectangles, etc.?
3. Must you do everything to each thing you want to draw that you
would do to other container components (e.g. my canvas) such as
frame.add(canvas) and canvas.setVisible(true), etc.?
4. When you do a setColor(color), it seems like it's just telling the
Graphics object "you're about to do something and I want you to do it
with this color). Is that correct? Why can you get away with not
specifying the fg and bg colors each time (for example, if you want to
draw a red rectangle with a black border, I have seen in that example
where they make two calls to setColor())?
5. Is there a specific order to packing and adding things before
showing them? I'm a little confused on what the absolute last thing
is that you need to do when you want to show your combined UI. (In
other words, I have a frame which contains the canvas, the axes, and
the vector, and so far I can only get the canvas to be drawn.)

I am hoping there are some simple answers here but unfortunately none
of the Java tutorials I have seen on Sun or in my manuals I printed
seem to provide any concrete answers. If you know of any good
websites that really explain the graphics paradigm well, I'm open to
hearing about them.

Thanks in advance,
Mike
 
K

Knute Johnson

Zerex71 said:
Greetings,

I am attempting for the first time to do some drawing on a canvas.
What I would like to do is draw a standard set of three orthogonal
axes and then superimpose a line (vector) on the canvas as well, to
aid in visualizing some rotations. The questions I have are as
follows:

1. If I want the vectors to have any thickness, it sounds like I am
going to have to call drawRect() instead of drawLine() - true or
false?

See Stroke.
2. In my reading, I have seen code examples where they seem to extend
JPanel (I don't know why such a graphical object would subclass from a
panel, so I'm a bit puzzled by that) and override its paintComponent()
method. Why do you subclass from JPanel to draw rectangles, etc.?

Convention. You can use JComponent and some people recommend you do.
JComponent and JPanel which extends it are both Containers as well.
Sometimes you want to be able to add components to your GUI. Canvas is
not a Container. Be sure to read the docs for Canvas.
3. Must you do everything to each thing you want to draw that you
would do to other container components (e.g. my canvas) such as
frame.add(canvas) and canvas.setVisible(true), etc.?

You can add the Canvas to a Container (eg. Frame or Panel) before you
set the primary Frame visible. You should pack() or setSize() on the
container to get it to layout before you set it visible.
4. When you do a setColor(color), it seems like it's just telling the
Graphics object "you're about to do something and I want you to do it
with this color). Is that correct?

Yes.

Why can you get away with not
specifying the fg and bg colors each time (for example, if you want to
draw a red rectangle with a black border, I have seen in that example
where they make two calls to setColor())?

Because that's not the way it works. In your paint() method you set the
color you wish to draw with and then call the drawing method. If you
want to change colors, set a new color and draw again.
5. Is there a specific order to packing and adding things before
showing them? I'm a little confused on what the absolute last thing
is that you need to do when you want to show your combined UI. (In
other words, I have a frame which contains the canvas, the axes, and
the vector, and so far I can only get the canvas to be drawn.)

setVisible(true) is the last call on your GUI container. Are you
drawing in the paint() method? For AWT components (Frame, Panel, Canvas
etc.) all drawing must occur in the paint() method. For Swing
components it is the paintComponent() method.
I am hoping there are some simple answers here but unfortunately none
of the Java tutorials I have seen on Sun or in my manuals I printed
seem to provide any concrete answers. If you know of any good
websites that really explain the graphics paradigm well, I'm open to
hearing about them.

Post some simple code that demonstrates the problem you are having. It
must be compilable (unless you are asking about compile errors).
 
Z

Zerex71

See Stroke.


Convention. You can use JComponent and some people recommend you do.
JComponent and JPanel which extends it are both Containers as well.
Sometimes you want to be able to add components to your GUI. Canvas is
not a Container. Be sure to read the docs for Canvas.


You can add the Canvas to a Container (eg. Frame or Panel) before you
set the primary Frame visible. You should pack() or setSize() on the
container to get it to layout before you set it visible.


Yes.

Why can you get away with not


Because that's not the way it works. In your paint() method you set the
color you wish to draw with and then call the drawing method. If you
want to change colors, set a new color and draw again.


setVisible(true) is the last call on your GUI container. Are you
drawing in the paint() method? For AWT components (Frame, Panel, Canvas
etc.) all drawing must occur in the paint() method. For Swing
components it is the paintComponent() method.


Post some simple code that demonstrates the problem you are having. It
must be compilable (unless you are asking about compile errors).

You asked for it! :)

*** BEGIN CODE ***

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class Visualizer
{
// The purpose of this class is to provide a Swing-based
visualization
// capability for our rotations to show the user a graphical
representation
// of what happens during the transformation process.

// Default constructor (required but not used)
public Visualizer() {}

public Visualizer(final Vector start,
final Vector end) {
// In this constructor, we should try to instantiate a canvas
// (drawing window), a set of axes, and an initial vector.
// Also, we should customize the view to show a "perspective
// view" of the scene before performing the rotation.

// Good resource for how to use the frame properly is located
at:
// http://java.sun.com/docs/books/tutorial/uiswing/components/frame.html

// Create the drawing canvas; customize its background and
// foreground colors. Make the window appear right away.
String title = "OneTESS Transformation Algorithm Visualizer";
Color bg = new Color(17, 54, 171); // Background color (dark
blue)
Color fg = Color.white; // Foreground color (white)
Canvas canvas = new Canvas(); // The drawing canvas
// Set the colors on the canvas, and force it to be a certain
size
canvas.setBackground(bg);
canvas.setForeground(fg);
Dimension canvasSize = new Dimension(400, 400);
// Set the max and min sizes to attempt to "lock" the
container to a fixed size
// NOTE By themselves, these two calls do NOT limit the size.
// They also make the initial size zero height.
// TODO Find out what effect removing these LOC will have.
// Setting the frame size seems to be just fine.
canvas.setMaximumSize(canvasSize);
canvas.setMinimumSize(canvasSize);
canvas.setSize(canvasSize);
// TODO Do we need to make the frame an explicit size or is
// some layout manager handling that for us because we are
sizing
// something contained by the frame?
// Seems dumb and obvious but we better make sure it's visible
too
canvas.setVisible(true);

JFrame frame = new JFrame(title, null); // Use default GC
// Ensure the window closes with the app
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// Set the frame size - the canvas never changes size but it's
the
// frame that we want to lock
// frame.setMaximumSize(canvasSize);
frame.setMinimumSize(canvasSize);
frame.setSize(canvasSize);
// NOTE These three lines don't work in locking the frame,
// so find another way...
// NOTE Here's that way:
frame.setResizable(false);

// Add the canvas to the frame
frame.add(canvas);

// Size the frame
// frame.setSize(400, 400); // Rough guess at size, had no
effect

// Create axes and draw them
// VisualAxes axes = new
VisualAxes(canvas.getForeground(), // Use the canvas fg
color
// new Vector(100.0, 100.0,
100), // May need to check to see if these coords will fit on the
canvas
//
100.0); // Set a reasonable length for each
axis

// NOTE This type of code can ONLY go into a paintComponent()
method.
// This is because g is of type Graphics which CANNOT be
instantiated,
// and must be passed down by the painting infrastructure to
your overridden
// paintComponent() method.
// g.setColor(canvas.getForeground());
// g.drawRect(10, 20, 30-1, 5-1);
// g.setColor(canvas.getForeground());
// g.fillRect(10+1, 20+1, 30-2, 5-2);

// Create the vector to be rotated
// DEBUG Try drawing just one axis and see what happens
VisualVector vv = new VisualVector(new Vector(10.0, 0.0, 0.0),
Color.orange);
// TODO Pass in a real vector at some point

// Duh, set the vector to be visible too...sheesh, Java makes
// you do everything like a baby
vv.setVisible(true);
// TODO Do we even need to do this?

// TODO Did we even add the vector to the frame? Do we need
to do that?
// If so, in what order?
frame.add(vv);
// QUESTION Do we add the vector to the frame or to the
canvas? Hmm...
// NOTE We cannot add the vector to the canvas, so to the
frame it is...

// TODO Ensure that when this app is ready to rock and roll,
// that you can port it to the conference room and run it
frame.pack();

// Show the frame
frame.setVisible(true);

// Hmm, maybe we need to force a repaint of ALL components
(top-down)...
frame.repaint();
// TODO Do we need to set opacity on some object?

// Draw the initial vector
// TODO Figure out the proper way to force the object(s) to
// paint themselves. I haven't been able to find a way to
// do this but maybe there's hope in repaint()...
// vv.repaint();

// Shall we try to animate the rotation to the final vector?
animateRotation();

// QUESTION Do we want to show the guntube as a vector, or
// just show the effect of the initial muzzle vector rotating?

// TODO If you want to get slick, see if you can allow the
// user to see the rotation quaternion on there as the unit
// vector plus twist angle.

// TODO Somehow we have to define a "perspective view" such
// that our coordinates (axes), when drawn, appear as "tilted"
// (perspective) rather than side-on and thus losing one DOF.

// TODO Figure out how to put arrowheads on the axes

// TODO Investigate making the axes have some thickness
// enough for the user to see
// NOTE To answer this to-do, consider using drawRect()
}

private void animateRotation() {
// This method will perform the animation of the vector
// NOTE We may need some form of slerp to do this...
// We assume, as novice Java Swing programmers, that we will
// have to on every cycle draw a vector, then erase it, and
// draw a new vector based on the interpolated position over
// the total length of the vector divided by dt, the time
increment
// of animation.

// TODO When we animate the rotation, we should be using a
// repaint scheme - but only the vector to be rotated should
// be repainted. The axes should stay fixed.
}

private final double dt = 0.0; // Parameter to govern speed of
animation
// Set to positive number for gradual motion
// Set to zero for "snap-to" animation

private Timer animationTimer; // Timer used to control animation

// The amount of twist around the z-axis that we will rotate our
// geometry for better viewability
private final double perspectiveTwist = 0.0;
// The amount of tilt away from vertical (pitch down) that we
// will rotate our geometry for better viewability
private final double perspectiveTilt = 0.0;
}

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class VisualAxes extends JPanel // TODO Figure out why we must
use JPanel
{
// This class will provide a visual set of axes on the drawing
// canvas so the user can see where their vectors are being
rotated.

// Default constructor
public VisualAxes(Color color,
Vector O,
double length) {
// Initialize the attributes of this class
axesColor = color;
origin = O;
axisLength = length;

// With this starting information, set up each axis.
// Once this is done, we can try to draw them.
// The x-axis will be (length, 0, 0) offset from the origin.
// The y-axis will be (0, length, 0) offset from the origin.
// The z-axis will be (0, 0, length) offset from the origin.

xAxis = new VisualVector(origin.add(new Vector(axisLength,
0.0, 0.0)), axesColor); // Or something like this
yAxis = new VisualVector(origin.add(new Vector(0.0,
axisLength, 0.0)), axesColor); // Or something like this
zAxis = new VisualVector(origin.add(new Vector(0.0, 0.0,
axisLength)), axesColor); // Or something like this

// TODO Ensure mathematically that the axes adhere to the
right-
// hand rule.

// Theoretically at this point we have three orthogonal axes
// starting at a common origin and having the same length, but
// pointing in three different directions orthogonal to each
// other.

// TODO Consider adding an axis indicator character to the
// screen for each axis such as "x", "y", and "z".
// NOTE drawString() might do this for you

// TODO May want to add some debug code to ensure the math
// part is correct, by printing out the origin and axes
values.
}

public void show() {
// Method to draw the axes

// Draw the x-axis

// Draw the y-axis

// Draw the z-axis

// TODO Do we need some kind of reference to the canvas
// we're trying to draw on?
}

public void hide() {
// Method to hide the axes

// Hide the x-axis

// Hide the y-axis

// Hide the z-axis
}

// Required method to implement drawing of the axes
public void paintComponent(Graphics g) {
// First call the superclass to paint the background
super.paintComponent(g);

// Set the color
g.setColor(axesColor);
// Draw each axis
}

private Color axesColor; // Color of each axis
private Vector origin; // The origin of the axes
private double axisLength; // The length of each axis
private VisualVector xAxis; // The x-axis
private VisualVector yAxis; // The y-axis
private VisualVector zAxis; // The z-axis
}

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class VisualVector extends JPanel
{
// This class represents a vector which we can show to the user.
// A visual vector is a graphical class which extends a normal
// mathematical vector.

public VisualVector(Vector v,
Color c) {
// Default constructor

// Set up the visual vector's characteristics
theVector = v;
vectorColor = c;
// Now convert the math vector into an appropriate visual
vector
x = (int) Math.round(v.x);
y = (int) Math.round(v.y);
z = (int) Math.round(v.z);

// DEBUG Print out the coordinates for grins
System.out.println("Original vector to be drawn:");
System.out.println(v.toString());
System.out.println("Original vector converted to graphics
vector:");
System.out.println("x = " + x + " y= " + y + " z= " + z);
// NOTE Z-coordinates not used
// NOTE I read something in the Java API documentation
explaining
// something to the effect of how "user space" drawing got
mapped
// to "system space" (?) coordinates. I believe this is
simply
// the 2D representation as the user/programmer would think of
// an object as opposed to the "upper-left-corner-across-and-
down"
// graphics space, not the math conversion of 3D objects to 2D
// objects. This latter process is probably what we will have
to do
// explicitly.

// TODO Figure out if we'll need this or even use it
thickness = 0;

// TODO Do we draw the vector now, or make an explicit call?
}

public void show() {
// Show (draw) the vector
// TODO Do we need a canvas or graphics object to do this?
}

public void hide() {
// Hide the vector
// TODO Do we need a canvas or graphics object to do this?
}

// Required method to implement drawing of the axes
public void paintComponent(Graphics g) {
// First call the superclass to paint the background
super.paintComponent(g);

System.out.println("Attempting to paint a vector!");

// Set the color
// g.setColor(vectorColor);
// TODO Examples make it seem like you only call setColor()
// but maybe you need to set the bg and the fg explicitly to
ensure
// your graphics will show up
setForeground(vectorColor);
setBackground(new Color(17, 54, 171)); // TODO Find a way to
pass in the bg color from the canvas

// Draw the vector
// For now, just draw a line
// g.drawLine(10, 20, 30, 40); // DEBUG
g.drawLine(0, 0, x, y); // The actual line we're given
// Somehow we need to pass the origin
into here
// TODO This is not showing our line - do we need to use the
// frame's origin instead?
// TODO Do we need to set it to opaque?
}

public Vector theVector; // The mathematical vector to be rotated
private Color vectorColor; // The color of the vector
private int x; // The integral value of the x-coordinate
private int y; // The integral value of the y-coordinate
private int z; // The integral value of the z-coordinate
private int thickness; // Thickness of the vector to draw
// Assume zero means a line will be drawn
}
 
K

Knute Johnson

Zerex71 said:
You asked for it! :)

This isn't exactly what I meant when I said simple. There are too many
comments that exceed the line length of my news reader for me to fix
them so this is compilable. Strip all the comments out and post again
if you want. See my comments in the code below for some starting points.
*** BEGIN CODE ***

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class Visualizer
{
// The purpose of this class is to provide a Swing-based
visualization
// capability for our rotations to show the user a graphical
representation
// of what happens during the transformation process.

// Default constructor (required but not used)
public Visualizer() {}

public Visualizer(final Vector start,
final Vector end) {
// In this constructor, we should try to instantiate a canvas
// (drawing window), a set of axes, and an initial vector.
// Also, we should customize the view to show a "perspective
// view" of the scene before performing the rotation.

// Good resource for how to use the frame properly is located
at:
// http://java.sun.com/docs/books/tutorial/uiswing/components/frame.html

// Create the drawing canvas; customize its background and
// foreground colors. Make the window appear right away.
String title = "OneTESS Transformation Algorithm Visualizer";
Color bg = new Color(17, 54, 171); // Background color (dark
blue)
Color fg = Color.white; // Foreground color (white)
Canvas canvas = new Canvas(); // The drawing canvas

Canvas is an AWT component. You don't want to mix AWT and Swing
components. If you are going to put your GUI in a JFrame, use a
JComponent or JPanel as your drawing surface.

// Set the colors on the canvas, and force it to be a certain
size
canvas.setBackground(bg);
canvas.setForeground(fg);
Dimension canvasSize = new Dimension(400, 400);
// Set the max and min sizes to attempt to "lock" the
container to a fixed size
// NOTE By themselves, these two calls do NOT limit the size.
// They also make the initial size zero height.
// TODO Find out what effect removing these LOC will have.
// Setting the frame size seems to be just fine.
canvas.setMaximumSize(canvasSize);
canvas.setMinimumSize(canvasSize);
canvas.setSize(canvasSize);
// TODO Do we need to make the frame an explicit size or is
// some layout manager handling that for us because we are
sizing
// something contained by the frame?
// Seems dumb and obvious but we better make sure it's visible
too

Size your component by setting its preferredSize and then use a layout
manager that will respect that size.
canvas.setVisible(true);

Unless you are trying to hide and un-hide components you don't want to
set individual components visible.
JFrame frame = new JFrame(title, null); // Use default GC
// Ensure the window closes with the app
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// Set the frame size - the canvas never changes size but it's
the
// frame that we want to lock
// frame.setMaximumSize(canvasSize);
frame.setMinimumSize(canvasSize);
frame.setSize(canvasSize);
// NOTE These three lines don't work in locking the frame,
// so find another way...
// NOTE Here's that way:
frame.setResizable(false);

// Add the canvas to the frame
frame.add(canvas);

// Size the frame
// frame.setSize(400, 400); // Rough guess at size, had no
effect

See my comments about sizing above.
// Create axes and draw them
// VisualAxes axes = new
VisualAxes(canvas.getForeground(), // Use the canvas fg
color
// new Vector(100.0, 100.0,
100), // May need to check to see if these coords will fit on the
canvas
//
100.0); // Set a reasonable length for each
axis

// NOTE This type of code can ONLY go into a paintComponent()
method.
// This is because g is of type Graphics which CANNOT be
instantiated,
// and must be passed down by the painting infrastructure to
your overridden
// paintComponent() method.
// g.setColor(canvas.getForeground());
// g.drawRect(10, 20, 30-1, 5-1);
// g.setColor(canvas.getForeground());
// g.fillRect(10+1, 20+1, 30-2, 5-2);

You may store the colors into the component but it is not all that
useful and hardly convenient especially if you want to change colors.
// Create the vector to be rotated
// DEBUG Try drawing just one axis and see what happens
VisualVector vv = new VisualVector(new Vector(10.0, 0.0, 0.0),
Color.orange);
// TODO Pass in a real vector at some point

// Duh, set the vector to be visible too...sheesh, Java makes
// you do everything like a baby
vv.setVisible(true);
// TODO Do we even need to do this?

No. See comments above
// TODO Did we even add the vector to the frame? Do we need
to do that?
// If so, in what order?
frame.add(vv);
// QUESTION Do we add the vector to the frame or to the
canvas? Hmm...
// NOTE We cannot add the vector to the canvas, so to the
frame it is...

Add all your components to the JFrame then pack() or setSize() on the
JFrame, then set it visible.
// TODO Ensure that when this app is ready to rock and roll,
// that you can port it to the conference room and run it
frame.pack();

// Show the frame
frame.setVisible(true);

// Hmm, maybe we need to force a repaint of ALL components
(top-down)...
frame.repaint();

Not needed.
// TODO Do we need to set opacity on some object?

Probably not.
// Draw the initial vector
// TODO Figure out the proper way to force the object(s) to
// paint themselves. I haven't been able to find a way to
// do this but maybe there's hope in repaint()...
// vv.repaint();

If you want to draw different things on one component depending on
conditions, use a flag or some data structure to set the conditions so
that when paintComponent() is called you can draw the appropriate
information.

boolean circleFlag;

paintComponent(Graphics g) {
if (circleFlag)
drawOval(0,0,10,10);
else
drawRect(0,0,10,10);
// Shall we try to animate the rotation to the final vector?
animateRotation();

// QUESTION Do we want to show the guntube as a vector, or
// just show the effect of the initial muzzle vector rotating?

// TODO If you want to get slick, see if you can allow the
// user to see the rotation quaternion on there as the unit
// vector plus twist angle.

// TODO Somehow we have to define a "perspective view" such
// that our coordinates (axes), when drawn, appear as "tilted"
// (perspective) rather than side-on and thus losing one DOF.

// TODO Figure out how to put arrowheads on the axes

// TODO Investigate making the axes have some thickness
// enough for the user to see
// NOTE To answer this to-do, consider using drawRect()
}

private void animateRotation() {
// This method will perform the animation of the vector
// NOTE We may need some form of slerp to do this...
// We assume, as novice Java Swing programmers, that we will
// have to on every cycle draw a vector, then erase it, and
// draw a new vector based on the interpolated position over
// the total length of the vector divided by dt, the time
increment
// of animation.

// TODO When we animate the rotation, we should be using a
// repaint scheme - but only the vector to be rotated should
// be repainted. The axes should stay fixed.
}

private final double dt = 0.0; // Parameter to govern speed of
animation
// Set to positive number for gradual motion
// Set to zero for "snap-to" animation

private Timer animationTimer; // Timer used to control animation

// The amount of twist around the z-axis that we will rotate our
// geometry for better viewability
private final double perspectiveTwist = 0.0;
// The amount of tilt away from vertical (pitch down) that we
// will rotate our geometry for better viewability
private final double perspectiveTilt = 0.0;
}

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class VisualAxes extends JPanel // TODO Figure out why we must
use JPanel
{
// This class will provide a visual set of axes on the drawing
// canvas so the user can see where their vectors are being
rotated.

// Default constructor
public VisualAxes(Color color,
Vector O,
double length) {
// Initialize the attributes of this class
axesColor = color;
origin = O;
axisLength = length;

// With this starting information, set up each axis.
// Once this is done, we can try to draw them.
// The x-axis will be (length, 0, 0) offset from the origin.
// The y-axis will be (0, length, 0) offset from the origin.
// The z-axis will be (0, 0, length) offset from the origin.

xAxis = new VisualVector(origin.add(new Vector(axisLength,
0.0, 0.0)), axesColor); // Or something like this
yAxis = new VisualVector(origin.add(new Vector(0.0,
axisLength, 0.0)), axesColor); // Or something like this
zAxis = new VisualVector(origin.add(new Vector(0.0, 0.0,
axisLength)), axesColor); // Or something like this

// TODO Ensure mathematically that the axes adhere to the
right-
// hand rule.

// Theoretically at this point we have three orthogonal axes
// starting at a common origin and having the same length, but
// pointing in three different directions orthogonal to each
// other.

// TODO Consider adding an axis indicator character to the
// screen for each axis such as "x", "y", and "z".
// NOTE drawString() might do this for you

// TODO May want to add some debug code to ensure the math
// part is correct, by printing out the origin and axes
values.
}

public void show() {
// Method to draw the axes

// Draw the x-axis

// Draw the y-axis

// Draw the z-axis

// TODO Do we need some kind of reference to the canvas
// we're trying to draw on?
}

public void hide() {
// Method to hide the axes

// Hide the x-axis

// Hide the y-axis

// Hide the z-axis
}

// Required method to implement drawing of the axes
public void paintComponent(Graphics g) {
// First call the superclass to paint the background
super.paintComponent(g);

// Set the color
g.setColor(axesColor);
// Draw each axis
}

private Color axesColor; // Color of each axis
private Vector origin; // The origin of the axes
private double axisLength; // The length of each axis
private VisualVector xAxis; // The x-axis
private VisualVector yAxis; // The y-axis
private VisualVector zAxis; // The z-axis
}

package transformation;

import javax.swing.*;
import java.awt.*;

/**
* @author mfeher
*
*/
public class VisualVector extends JPanel
{
// This class represents a vector which we can show to the user.
// A visual vector is a graphical class which extends a normal
// mathematical vector.

public VisualVector(Vector v,
Color c) {
// Default constructor

// Set up the visual vector's characteristics
theVector = v;
vectorColor = c;
// Now convert the math vector into an appropriate visual
vector
x = (int) Math.round(v.x);
y = (int) Math.round(v.y);
z = (int) Math.round(v.z);

// DEBUG Print out the coordinates for grins
System.out.println("Original vector to be drawn:");
System.out.println(v.toString());
System.out.println("Original vector converted to graphics
vector:");
System.out.println("x = " + x + " y= " + y + " z= " + z);
// NOTE Z-coordinates not used
// NOTE I read something in the Java API documentation
explaining
// something to the effect of how "user space" drawing got
mapped
// to "system space" (?) coordinates. I believe this is
simply
// the 2D representation as the user/programmer would think of
// an object as opposed to the "upper-left-corner-across-and-
down"
// graphics space, not the math conversion of 3D objects to 2D
// objects. This latter process is probably what we will have
to do
// explicitly.

// TODO Figure out if we'll need this or even use it
thickness = 0;

// TODO Do we draw the vector now, or make an explicit call?
}

public void show() {
// Show (draw) the vector
// TODO Do we need a canvas or graphics object to do this?
}

public void hide() {
// Hide the vector
// TODO Do we need a canvas or graphics object to do this?
}

// Required method to implement drawing of the axes
public void paintComponent(Graphics g) {
// First call the superclass to paint the background
super.paintComponent(g);

System.out.println("Attempting to paint a vector!");

// Set the color
// g.setColor(vectorColor);
// TODO Examples make it seem like you only call setColor()
// but maybe you need to set the bg and the fg explicitly to
ensure
// your graphics will show up
setForeground(vectorColor);
setBackground(new Color(17, 54, 171)); // TODO Find a way to
pass in the bg color from the canvas

// Draw the vector
// For now, just draw a line
// g.drawLine(10, 20, 30, 40); // DEBUG
g.drawLine(0, 0, x, y); // The actual line we're given
// Somehow we need to pass the origin
into here
// TODO This is not showing our line - do we need to use the
// frame's origin instead?
// TODO Do we need to set it to opaque?
}

public Vector theVector; // The mathematical vector to be rotated
private Color vectorColor; // The color of the vector
private int x; // The integral value of the x-coordinate
private int y; // The integral value of the y-coordinate
private int z; // The integral value of the z-coordinate
private int thickness; // Thickness of the vector to draw
// Assume zero means a line will be drawn
}

If you would like to see an example of how to code an animation, please
see my Asteroids game;

http://rabbitbrush.frazmtn.com/asteroids.html

A link to the source code is available at the bottom of that page.
 
Z

Zerex71

This isn't exactly what I meant when I said simple. There are too many
comments that exceed the line length of my news reader for me to fix
them so this is compilable. Strip all the comments out and post again
if you want. See my comments in the code below for some starting points.













Canvas is an AWT component. You don't want to mix AWT and Swing
components. If you are going to put your GUI in a JFrame, use a
JComponent or JPanel as your drawing surface.




Size your component by setting its preferredSize and then use a layout
manager that will respect that size.


Unless you are trying to hide and un-hide components you don't want to
set individual components visible.









See my comments about sizing above.





You may store the colors into the component but it is not all that
useful and hardly convenient especially if you want to change colors.



No. See comments above




Add all your components to the JFrame then pack() or setSize() on the
JFrame, then set it visible.






Not needed.


Probably not.




...

read more »

I finally got some things to draw today, and realized that I never
needed Canvas in the first place, (a) because there was no canvas in
the two examples I was looking at and (b) I overlooked the fact that
Canvas is AWT and not Swing. I'm still getting reacclimated to the
AWT-vs-Swing paradigm.

My new problem is probably somewhat simpler: I am drawing a set of
visual axes (VisualAxes being an extension of JPanel) and I also want
to add another vector/line to the drawing area (VisualVector which is
an extension of JPanel). I have code to new the VisualAxes and add
them to the frame, then new the VisualVector and add it to the frame.
The result however is that I cover up the axes with the subsequently-
added VisualVector. (Incidentally, VisualAxes is composed of three
VisualVectors, which I am finally able to draw appropriately on the
screen at a desired origin.)

For the snippet folks:

...
frame.setResizable(false);
frame.setSize(canvasSize);
Vector origin = new Vector(350.0, 350.0, 0.0);
double axisLength = 50.0; // Set a reasonable length for each
axis
VisualAxes axes = new VisualAxes(fg, origin, axisLength);
axes.setBackground(bg);
frame.add(axes);
VisualVector vv = new VisualVector(new Vector(100.0, 200.0,
50.0), Color.orange, origin);
vv.setBackground(bg);
vv.setOpaque(false); // See if this allows us to not cover up
the axes
frame.add(vv);
frame.pack(); // ALWAYS the second-to-last thing to do
frame.setVisible(true); // ALWAYS the last thing to do
...

Mike
 
K

Knute Johnson

Zerex71 said:
I finally got some things to draw today, and realized that I never
needed Canvas in the first place, (a) because there was no canvas in
the two examples I was looking at and (b) I overlooked the fact that
Canvas is AWT and not Swing. I'm still getting reacclimated to the
AWT-vs-Swing paradigm.

My new problem is probably somewhat simpler: I am drawing a set of
visual axes (VisualAxes being an extension of JPanel) and I also want
to add another vector/line to the drawing area (VisualVector which is
an extension of JPanel). I have code to new the VisualAxes and add
them to the frame, then new the VisualVector and add it to the frame.
The result however is that I cover up the axes with the subsequently-
added VisualVector. (Incidentally, VisualAxes is composed of three
VisualVectors, which I am finally able to draw appropriately on the
screen at a desired origin.)

For the snippet folks:

...
frame.setResizable(false);
frame.setSize(canvasSize);
Vector origin = new Vector(350.0, 350.0, 0.0);
double axisLength = 50.0; // Set a reasonable length for each
axis
VisualAxes axes = new VisualAxes(fg, origin, axisLength);
axes.setBackground(bg);
frame.add(axes);
VisualVector vv = new VisualVector(new Vector(100.0, 200.0,
50.0), Color.orange, origin);
vv.setBackground(bg);
vv.setOpaque(false); // See if this allows us to not cover up
the axes
frame.add(vv);
frame.pack(); // ALWAYS the second-to-last thing to do
frame.setVisible(true); // ALWAYS the last thing to do
...

Mike

Mike:

You are adding two components to the JFrame, a VisualVector and
VisualAxes, without specifying any constraints. I don't know what
layout manager you are using but depending on which one it could cause
both of those components to occupy the same space on the JFrame and make
that first one not visible.

I have a suggestion and that is to use a JPanel as your drawing surface
and draw your axes and vectors directly onto it. Don't create
components for your drawing elements.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class test extends JPanel implements ActionListener {
int shape = 0;

public test() {
setPreferredSize(new Dimension(400,300));
}

public void actionPerformed(ActionEvent ae) {
String ac = ae.getActionCommand();
if (ac.equals("Circle")) {
shape = 1;
repaint();
} else if (ac.equals("Square")) {
shape = 2;
repaint();
}
}

public void paintComponent(Graphics g) {
// fill background with gray
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0,0,getWidth(),getHeight());

// draw xy axis
g.setColor(Color.BLUE);
g.drawLine(10,10,10,290);
g.drawLine(10,290,380,290);

// draw the appropriate shape
g.setColor(Color.RED);
switch (shape) {
case 1: g.drawOval(10,10,280,280);
break;
case 2: g.drawRect(10,190,100,100);
break;
}
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final test t = new test();
f.add(t,BorderLayout.CENTER);

JPanel p = new JPanel(new FlowLayout());
JButton b = new JButton("Circle");
b.addActionListener(t);
p.add(b);

b = new JButton("Square");
b.addActionListener(t);
p.add(b);

f.add(p,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
});
}
}

Again I suggest that you look at the code for my Asteroids game to give
you an idea how to do drawing and animation.

http://rabbitbrush.frazmtn.com/asteroids.html
 
Z

Zerex71

Zerex71 said:
I finally got some things to draw today, and realized that I never
needed Canvas in the first place, (a) because there was no canvas in
the two examples I was looking at and (b) I overlooked the fact that
Canvas is AWT and not Swing. I'm still getting reacclimated to the
AWT-vs-Swing paradigm.
My new problem is probably somewhat simpler: I am drawing a set of
visual axes (VisualAxes being an extension of JPanel) and I also want
to add another vector/line to the drawing area (VisualVector which is
an extension of JPanel). I have code to new the VisualAxes and add
them to the frame, then new the VisualVector and add it to the frame.
The result however is that I cover up the axes with the subsequently-
added VisualVector. (Incidentally, VisualAxes is composed of three
VisualVectors, which I am finally able to draw appropriately on the
screen at a desired origin.)
For the snippet folks:
...
frame.setResizable(false);
frame.setSize(canvasSize);
Vector origin = new Vector(350.0, 350.0, 0.0);
double axisLength = 50.0; // Set a reasonable length for each
axis
VisualAxes axes = new VisualAxes(fg, origin, axisLength);
axes.setBackground(bg);
frame.add(axes);
VisualVector vv = new VisualVector(new Vector(100.0, 200.0,
50.0), Color.orange, origin);
vv.setBackground(bg);
vv.setOpaque(false); // See if this allows us to not cover up
the axes
frame.add(vv);
frame.pack(); // ALWAYS the second-to-last thing to do
frame.setVisible(true); // ALWAYS the last thing to do
...

Mike:

You are adding two components to the JFrame, a VisualVector and
VisualAxes, without specifying any constraints. I don't know what
layout manager you are using but depending on which one it could cause
both of those components to occupy the same space on the JFrame and make
that first one not visible.

I have a suggestion and that is to use a JPanel as your drawing surface
and draw your axes and vectors directly onto it. Don't create
components for your drawing elements.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class test extends JPanel implements ActionListener {
int shape = 0;

public test() {
setPreferredSize(new Dimension(400,300));
}

public void actionPerformed(ActionEvent ae) {
String ac = ae.getActionCommand();
if (ac.equals("Circle")) {
shape = 1;
repaint();
} else if (ac.equals("Square")) {
shape = 2;
repaint();
}
}

public void paintComponent(Graphics g) {
// fill background with gray
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0,0,getWidth(),getHeight());

// draw xy axis
g.setColor(Color.BLUE);
g.drawLine(10,10,10,290);
g.drawLine(10,290,380,290);

// draw the appropriate shape
g.setColor(Color.RED);
switch (shape) {
case 1: g.drawOval(10,10,280,280);
break;
case 2: g.drawRect(10,190,100,100);
break;
}
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final test t = new test();
f.add(t,BorderLayout.CENTER);

JPanel p = new JPanel(new FlowLayout());
JButton b = new JButton("Circle");
b.addActionListener(t);
p.add(b);

b = new JButton("Square");
b.addActionListener(t);
p.add(b);

f.add(p,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
});
}

}

Again I suggest that you look at the code for my Asteroids game to give
you an idea how to do drawing and animation.

http://rabbitbrush.frazmtn.com/asteroids.html

Excellent and thank you. I solved part of my problem by creating the
vector on the VisualAxes component instead of adding it separately to
the frame as I had been doing. I now get the the axes (white) and the
vector (orange) on the same surface, following the outline of the Java
tutorial sample program. The other thing is I decided to refactor
VisualAxes as VectorCanvas since that's more in line with what it does
now - acting as a canvas for things I might want to draw on it.

Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top