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
}