Related
BACKGROUND
I'm currently working on a project where I want to be able to draw a triangle, circle and a rectangle on a JPanel and move them around.
When a figure is moved, it should end up "at the top" so that it covers other figures that are in an overlapping position and when a figure is moved, the "top" is selected; if several figures cover the position of the mouse pointer, the top one is selected.
MY PROBLEM
I cannot figure out how to fix the issue of my shapes not ending up on top of each other if I drag them to the same position. They just stay in the same layers and if i stack them all on top of each other I still pick up the rectangle first.
They just stay in the same layers...
That's because of the order in which you are drawing them:
drawRec.paintComponent(g);
drawCirc.paintComponent(g);
drawTri.paintComponent(g);
Which will result in the drawTri to always be painted on top of the others (because you always paint it last). In a similar way, drawRec will be painted on the bottom of the others (since you are painting it always first). Then drawCirc will be painted in the middle. There is no dynamic order (let me put it) of the painting here. It doesn't matter what you drag or not, they are always going to be painted in that sequence.
A solution might be to have them in a list or array of some sort where when you drag one shape, you put it last in the list, and move the others before it. If you combine that with painting all shapes sequentialy from the list, then you will have your desired result.
...if i stack them all on top of each other I still pick up the rectangle first.
That's because of how your mousePressed in the ClickListener class works: it first of all checks if the rectangle is clicked and then the others. That means that if the rectangle overlaps another shape, then the rectangle is always going to be prioritized.
One solution might again be putting all your shapes in a data structure where you can modify their selection order. For example a list or array where let's say that the closer to the top is a shape then the later it will appear in the list. Then, when the user clicks somewhere, you will check the shapes starting from the last one in the list going to first one. If you find something, you immediately break the loop and select what you found. If you don't find anything, then the user clicked the panel somewhere where there are no shapes currently.
I am almost certain there must be more efficient data structures than a list or array for this problem (because you have to iterate in linear time all shapes to find the one clicked), but I am not an expert on collision detection, so, in order to keep things simple, I am going to stick with it. But there is also one other operation we want to do: change the painting and the selection order of the clicked shape. Long story short, we can use a LinkedHashSet for the job, because:
It maintains an order of the shapes.
We can quickly and efficiently change the order by first removing the clicked shape from its current postion (constant time) and then adding it back to the LinkedHashSet (also constant time), essentialy placing it last in the insertion order. So that automatically means that we have to use the last element in the set as the top most one. And that's good, because when painting we can iterate over all shapes in the set in the order in which they are found in it, so the last shape will be painted last (which means on top of all others). The same stands for the selection of a shape when clicking: we iterate over all elements, and select the last one which we found containing the user's click point. If LinkedHashSet had a descending iterator (by insertion order) then we could also optimize a little the searching of shapes at a given click point, but it doesn't (at least for Java 8 in which the following demonstration/example code applies), so I will stick with iterating from the start, checking all shapes every time and keeping the last one found containing the click point.
Finally, I would advise you to use the API class java.awt.Shape for the shapes since this enables you to create arbitrary shapes and get the contains method to check if a point lies inside them, the drawing/filling capability, the bounds, the path iterator, and so on...
Summarizing all the above, with an example code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class NonComponentMain {
public static Shape createRectangle(final double width,
final double height) {
return new Rectangle2D.Double(0, 0, width, height);
}
public static Shape createEllipse(final double width,
final double height) {
return new Ellipse2D.Double(0, 0, width, height);
}
public static Shape createCircle(final double radius) {
return createEllipse(radius + radius, radius + radius);
}
public static class MoveableShapeHolder {
private final Shape shape;
private final Paint paint;
private final Rectangle2D originalBounds;
private double offsetX, offsetY;
public MoveableShapeHolder(final Shape shape,
final Paint paint) {
this.shape = Objects.requireNonNull(shape);
this.paint = paint;
offsetX = offsetY = 0;
originalBounds = shape.getBounds2D();
}
public void paint(final Graphics2D g2d) {
final AffineTransform originalAffineTransform = g2d.getTransform();
final Paint originalPaint = g2d.getPaint();
g2d.translate(offsetX, offsetY);
if (paint != null)
g2d.setPaint(paint);
g2d.fill(shape);
g2d.setPaint(originalPaint);
g2d.setTransform(originalAffineTransform);
}
public void moveTo(final double newBoundsCenterX,
final double newBoundsCenterY) {
offsetX = newBoundsCenterX - originalBounds.getCenterX();
offsetY = newBoundsCenterY - originalBounds.getCenterY();
}
public void moveBy(final double dx,
final double dy) {
offsetX += dx;
offsetY += dy;
}
public boolean contains(final Point2D pt) {
return shape.contains(pt.getX() - offsetX, pt.getY() - offsetY);
}
public Point2D getTopLeft() {
return new Point2D.Double(offsetX + originalBounds.getX(), offsetY + originalBounds.getY());
}
public Point2D getCenter() {
return new Point2D.Double(offsetX + originalBounds.getCenterX(), offsetY + originalBounds.getCenterY()); //Like 'getTopLeft' but with adding half the size.
}
public Point2D getBottomRight() {
return new Point2D.Double(offsetX + originalBounds.getMaxX(), offsetY + originalBounds.getMaxY()); //Like 'getTopLeft' but with adding the size of the bounds.
}
}
public static class DrawPanel extends JPanel {
private class MouseDrag extends MouseAdapter {
private MoveableShapeHolder current;
private Point origin;
private Point2D center;
#Override
public void mousePressed(final MouseEvent e) {
current = null;
center = null;
final Point evtLoc = e.getPoint();
for (final MoveableShapeHolder moveable: moveables)
if (moveable.contains(evtLoc))
current = moveable; //Keep the last moveable found to contain the click point! It's important to be the last one, because the later the moveable appears in the collection, the closer to top its layer.
if (current != null) { //If a shape was clicked...
//Initialize MouseDrag's state:
origin = e.getPoint();
center = current.getCenter();
//Move to topmost layer:
moveables.remove(current); //Remove from its current position.
moveables.add(current); //Move to last (topmost layer).
//Rapaint panel:
repaint();
}
}
#Override
public void mouseDragged(final MouseEvent e) {
if (current != null) { //If we are dragging something (and not empty space), then:
current.moveTo(center.getX() + e.getX() - origin.x, center.getY() + e.getY() - origin.y);
repaint();
}
}
#Override
public void mouseReleased(final MouseEvent e) {
current = null;
origin = null;
center = null;
}
}
private final LinkedHashSet<MoveableShapeHolder> moveables;
public DrawPanel() {
moveables = new LinkedHashSet<>();
final MouseAdapter ma = new MouseDrag();
super.addMouseMotionListener(ma);
super.addMouseListener(ma);
}
/**
* Warning: all operations on the returned value must be made on the EDT.
* #return
*/
public Collection<MoveableShapeHolder> getMoveables() {
return moveables;
}
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
moveables.forEach(moveable -> moveable.paint((Graphics2D) g)); //Topmost moveable is painted last.
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet())
return super.getPreferredSize();
final Dimension preferredSize = new Dimension();
moveables.forEach(moveable -> {
final Point2D max = moveable.getBottomRight();
preferredSize.width = Math.max(preferredSize.width, (int) Math.ceil(max.getX()));
preferredSize.height = Math.max(preferredSize.height, (int) Math.ceil(max.getY()));
});
return preferredSize;
}
}
private static void createAndShowGUI() {
final DrawPanel drawPanel = new DrawPanel();
final Collection<MoveableShapeHolder> moveables = drawPanel.getMoveables();
MoveableShapeHolder moveable = new MoveableShapeHolder(createRectangle(100, 50), Color.RED);
moveable.moveTo(100, 75);
moveables.add(moveable);
moveable = new MoveableShapeHolder(createCircle(40), Color.GREEN);
moveable.moveTo(125, 100);
moveables.add(moveable);
moveable = new MoveableShapeHolder(createRectangle(25, 75), Color.BLUE);
moveable.moveTo(125, 75);
moveables.add(moveable);
final JFrame frame = new JFrame("Click to drag");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(NonComponentMain::createAndShowGUI);
}
}
All the above apply in the case you want to work with a single custom component painting all shapes. If instead you want, you can create a custom component for each shape and use a JLayeredPane for positioning them on top of each other. But then you would probably need a custom LayoutManager too (in order to handle the location of each component).
I created the following GUI.
I created a Shape class. I used a java.awt.Point to hold the center point and a java.awt.Polygon to hold the actual shape. I was able to use the Polygon contains method to see if I was mouse clicking inside the polygon.
I created a ShapeModel class to hold a java.util.List of Shape instances. Creating the proper application model is so important when creating a Swing GUI.
I created a JFrame and a drawing JPanel. The drawing JPanel draws the List of Shape instances. Period. The MouseAdapter will take care of recalculating the polygon and repainting the JPanel.
The trick is in the MouseAdapter mousePressed method. I delete the selected Shape instance and add the selected Shape instance back to the List. This moves the selected shape to the top of the Z-order.
Here's the complete runnable code. I made all the classes inner classes so I could post this code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MoveShapes implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MoveShapes());
}
private final DrawingPanel drawingPanel;
private final ShapeModel shapeModel;
public MoveShapes() {
this.shapeModel = new ShapeModel();
this.drawingPanel = new DrawingPanel();
}
#Override
public void run() {
JFrame frame = new JFrame("Move Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void repaint() {
drawingPanel.repaint();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(600, 500));
MoveListener listener = new MoveListener();
this.addMouseListener(listener);
this.addMouseMotionListener(listener);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Shape shape : shapeModel.getShapes()) {
g2d.setColor(shape.getColor());
g2d.fillPolygon(shape.getShape());
}
}
}
public class MoveListener extends MouseAdapter {
private Point pressedPoint;
private Shape selectedShape;
#Override
public void mousePressed(MouseEvent event) {
this.pressedPoint = event.getPoint();
this.selectedShape = null;
List<Shape> shapes = shapeModel.getShapes();
for (int i = shapes.size() - 1; i >= 0; i--) {
Shape shape = shapes.get(i);
if (shape.getShape().contains(pressedPoint)) {
selectedShape = shape;
break;
}
}
if (selectedShape != null) {
shapes.remove(selectedShape);
shapes.add(selectedShape);
}
}
#Override
public void mouseReleased(MouseEvent event) {
moveShape(event.getPoint());
}
#Override
public void mouseDragged(MouseEvent event) {
moveShape(event.getPoint());
}
private void moveShape(Point point) {
if (selectedShape != null) {
int x = point.x - pressedPoint.x;
int y = point.y - pressedPoint.y;
selectedShape.incrementCenterPoint(x, y);
drawingPanel.repaint();
pressedPoint = point;
}
}
}
public class ShapeModel {
private final List<Shape> shapes;
public ShapeModel() {
this.shapes = new ArrayList<>();
this.shapes.add(new Shape(100, 250, Color.BLUE, ShapeType.TRIANGLE));
this.shapes.add(new Shape(300, 250, Color.RED, ShapeType.RECTANGLE));
this.shapes.add(new Shape(500, 250, Color.BLACK, ShapeType.CIRCLE));
}
public List<Shape> getShapes() {
return shapes;
}
}
public class Shape {
private final Color color;
private Point centerPoint;
private Polygon shape;
private final ShapeType shapeType;
public Shape(int x, int y, Color color, ShapeType shapeType) {
this.centerPoint = new Point(x, y);
this.color = color;
this.shapeType = shapeType;
createPolygon(shapeType);
}
public void incrementCenterPoint(int x, int y) {
centerPoint.x += x;
centerPoint.y += y;
createPolygon(shapeType);
}
private void createPolygon(ShapeType shapeType) {
this.shape = new Polygon();
switch (shapeType) {
case TRIANGLE:
int angle = 30;
int radius = 100;
for (int i = 0; i < 3; i++) {
Point point = toCartesianCoordinates(angle, radius);
shape.addPoint(point.x, point.y);
angle += 120;
}
break;
case RECTANGLE:
angle = 45;
radius = 100;
for (int i = 0; i < 4; i++) {
Point point = toCartesianCoordinates(angle, radius);
shape.addPoint(point.x, point.y);
angle += 90;
}
break;
case CIRCLE:
radius = 75;
for (angle = 0; angle < 360; angle++) {
Point point = toCartesianCoordinates(angle, radius);
shape.addPoint(point.x, point.y);
}
break;
}
}
private Point toCartesianCoordinates(int angle, int radius) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
return new Point(x, y);
}
public Color getColor() {
return color;
}
public Point getCenterPoint() {
return centerPoint;
}
public Polygon getShape() {
return shape;
}
}
public enum ShapeType {
TRIANGLE, RECTANGLE, CIRCLE
}
}
I cannot figure out how to fix the issue of my shapes not ending up on top of each other if I drag them to the same position
Components on a panel are painted based on the components ZOrder. The component with the lowest ZOrder is painted last.
So in the mousePressed metthod of your MouseListener when you select a component to drag you can change its ZOrder:
Component child = e.getComponent();
child.getParent().setComponentZOrder(child, 0);
Edit:
drawRec.paintComponent(g);
drawCirc.paintComponent(g);
drawTri.paintComponent(g);
I didn't notice that code before.
Never invoke paintComponent() directly.
Swing has a parent/child relationship. You just need to add each of the 3 shape panels to the parent panel. The parent panel will then paint the child components based on the ZOrder I described above. Get rid of those 3 lines of code.
im using the Canvas class to make a screensaver as a schoolproject.
But the window generated by Canvas doesnt show my objects on it (current time)
until i minimize it an resize it again. After that all things works fine.
so what is wrong?
thank you for coming answers!
with kind regards
leon
those are the classes, i peronally think that the problem is in the class Start or BufferedCanvas
import java.awt.*;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Start
{
int fensterX = 900;
int fensterY = 700;
Farbengenerator fg = new Farbengenerator();
BufferedCanvas c =newBufferedCanvas("Bild",fensterX,fensterY);
Zeit z = new Zeit();
SchriftParameter sp = new SchriftParameter();
public void zeichneText(){
double x = 100;
double y = 100;
double fy =0.01;
double fx =0.02;
int red=0;
int green=0;
int blue=0;
double colourGrowRate=0.05;
String uhr;
c.setFont(sp.setzteSchrift());
c.setForegroundColour(Color.BLACK);
c.setBackgroundColour(Color.WHITE);
for(int i=0;i<100;i++){
c.drawString("Starting...",(int)x,(int)y);
c.updateAndShow();
try{Thread.sleep(50);}
catch(Exception e){};
c.updateAndShow();
}
CreateButton d = new CreateButton();
d.run();
while(true) {
c.erase();
uhr = z.erstelleZeit();
c.drawString(uhr,(int)x,(int)y);
if((int)x >fensterX-93 || (int)x <5){
fx = fx * (-1);
red=fg.gibROT();
green=fg.gibGRUEN();
blue=fg.gibBLAU();
Color colour = new Color(red,green,blue);
c.setForegroundColour(colour);
}
if((int)y > fensterY-1 || (int)y < 46){
fy = fy * (-1);
red=fg.gibROT();
green=fg.gibGRUEN();
blue=fg.gibBLAU();
Color colour = new Color(red,green,blue);
c.setForegroundColour(colour);
}
if((int)colourGrowRate>=1){
fg.generiereFarbe();
colourGrowRate = 0.05;
}
colourGrowRate=colourGrowRate+colourGrowRate;
x = x + fx;
y = y + fy;
c.updateAndShow();
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class BufferedCanvas
{
private JFrame frame;
private CanvasPane canvas;
private Graphics2D graphic;
private Color backgroundColour;
private Image canvasImage;
BufferStrategy buff;
/**
* Create a BufferedCanvas with default height,
width and background colour
* (300, 300, white).
* #param title title to appear in Canvas Frame
*/
public BufferedCanvas(String title)
{
this(title, 300, 300, Color.white);
}
/**
* Create a BufferedCanvas with default background colour (white).
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
*/
public BufferedCanvas(String title, int width, int height)
{
this(title, width, height, Color.white);
}
/**
* Create a BufferedCanvas.
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
* #param bgClour the desired background colour of the canvas
*/
public BufferedCanvas(String title, int width, int height, Color bgColour)
{
frame = new JFrame();
canvas = new CanvasPane();
frame.setContentPane(canvas);
frame.setTitle(title);
canvas.setPreferredSize(new Dimension(width, height));
backgroundColour = bgColour;
frame.pack();
frame.createBufferStrategy(2);
buff = frame.getBufferStrategy();
graphic = (Graphics2D)buff.getDrawGraphics();
setVisible(true);
}
/**
* Set the canvas visibility and brings canvas to the front of screen
* when made visible. This method can also be used to bring an already
* visible canvas to the front of other windows.
* #param visible boolean value representing the desired visibility of
* the canvas (true or false)
*/
public void setVisible(boolean visible)
{
if(graphic == null) {
// first time: instantiate the offscreen image and fill it with
// the background colour
Dimension size = canvas.getSize();
canvasImage = canvas.createImage(size.width, size.height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.setColor(backgroundColour);
graphic.fillRect(0, 0, size.width, size.height);
graphic.setColor(Color.black);
}
frame.setVisible(true);
}
/**
* Update the canvas and show the new image.
*/
public void updateAndShow(){
buff.show();
}
/**
* Provide information on visibility of the Canvas.
* #return true if canvas is visible, false otherwise
*/
public boolean isVisible()
{
return frame.isVisible();
}
/**
* Draw a given shape onto the canvas.
* #param shape the shape object to be drawn on the canvas
*/
public void draw(Shape shape)
{
graphic.draw(shape);
//canvas.repaint();
}
/**
* Fill the internal dimensions of a given shape with the current
* foreground colour of the canvas.
* #param shape the shape object to be filled
*/
public void fill(Shape shape)
{
graphic.fill(shape);
//canvas.repaint();
}
/**
* Erase the whole canvas.
*/
public void erase()
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
Dimension size = canvas.getSize();
graphic.fill(new Rectangle(0, 0, size.width, size.height));
graphic.setColor(original);
//canvas.repaint();
}
/**
* Erase a given shape's interior on the screen.
* #param shape the shape object to be erased
*/
public void erase(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.fill(shape); // erase by filling background colour
graphic.setColor(original);
//canvas.repaint();
}
/**
* Erases a given shape's outline on the screen.
* #param shape the shape object to be erased
*/
public void eraseOutline(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.draw(shape); // erase by drawing background colour
graphic.setColor(original);
//canvas.repaint();
}
/**
* Draws an image onto the canvas.
* #param image the Image object to be displayed
* #param x x co-ordinate for Image placement
* #param y y co-ordinate for Image placement
* #return returns boolean value representing whether the image was
* completely loaded
*/
public boolean drawImage(Image image, int x, int y)
{
boolean result = graphic.drawImage(image, x, y, null);
//canvas.repaint();
return result;
}
/**
* Draws a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void drawString(String text, int x, int y)
{
graphic.drawString(text, x, y);
//canvas.repaint();
}
/**
* Erases a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void eraseString(String text, int x, int y)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColour);
graphic.drawString(text, x, y);
graphic.setColor(original);
//canvas.repaint();
}
/**
* Draws a line on the Canvas.
* #param x1 x co-ordinate of start of line
* #param y1 y co-ordinate of start of line
* #param x2 x co-ordinate of end of line
* #param y2 y co-ordinate of end of line
*/
public void drawLine(int x1, int y1, int x2, int y2)
{
graphic.drawLine(x1, y1, x2, y2);
//canvas.repaint();
}
/**
* Draws a dot/pixel on the Canvas.
* #param x x co-ordinate of dot
* #param y y co-ordinate of dot
*/
public void drawDot(int x, int y)
{
graphic.drawLine(x, y, x, y);
//canvas.repaint();
}
/**
* Sets the foreground colour of the Canvas.
* #param newColour the new colour for the foreground of the Canvas
*/
public void setForegroundColour(Color newColour)
{
graphic.setColor(newColour);
}
/**
* Returns the current colour of the foreground.
* #return the colour of the foreground of the Canvas
*/
public Color getForegroundColour()
{
return graphic.getColor();
}
/**
* Sets the background colour of the Canvas.
* #param newColour the new colour for the background of the Canvas
*/
public void setBackgroundColour(Color newColour)
{
backgroundColour = newColour;
graphic.setBackground(newColour);
}
/**
* Returns the current colour of the background
* #return the colour of the background of the Canvas
*/
public Color getBackgroundColour()
{
return backgroundColour;
}
/**
* changes the current Font used on the Canvas
* #param newFont new font to be used for String output
*/
public void setFont(Font newFont)
{
graphic.setFont(newFont);
}
/**
* Returns the current font of the canvas.
* #return the font currently in use
**/
public Font getFont()
{
return graphic.getFont();
}
/**
* Sets the size of the canvas.
* #param width new width
* #param height new height
*/
public void setSize(int width, int height)
{
canvas.setPreferredSize(new Dimension(width, height));
Image oldImage = canvasImage;
canvasImage = canvas.createImage(width, height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.drawImage(oldImage, 0, 0, null);
frame.pack();
}
/**
* Returns the size of the canvas.
* #return The current dimension of the canvas
*/
public Dimension getSize()
{
return canvas.getSize();
}
/**
* Waits for a specified number of milliseconds before finishing.
* This provides an easy way to specify a small delay which can be
* used when producing animations.
* #param milliseconds the number
*/
public void wait(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (Exception e)
{
// ignoring exception at the moment
}
}
/************************************************************************
* Nested class CanvasPane - the actual canvas component contained in the
* Canvas frame. This is essentially a JPanel with added capability to
* refresh the image drawn on it.
*/
private class CanvasPane extends JPanel
{
public void paint(Graphics g)
{
g.drawImage(canvasImage, 0, 0, null);
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
public class CreateButton extends JFrame implements ActionListener{
public void run() {
createAndShowGUI();
}
public CreateButton() {
// set layout for the frame
this.getContentPane().setLayout(new FlowLayout());
JButton button1 = new JButton();
button1.setText("closeApp");
//set actionlisteners for the buttons
button1.addActionListener(this);
// define a custom short action command for the button
button1.setActionCommand("closeApp");
// add buttons to frame
add(button1);
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new CreateButton();
//Display the window.
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent ae) {
String action = ae.getActionCommand();
if (action.equals("closeApp")) {
System.exit(1);
}
}
}
import java.awt.*;
public class SchriftParameter
{
public Font setzteSchrift(){
Font f = new Font("Fixed",1,24);
return (f);
}
}
public class Farbengenerator
{
int r=0;
int g=0;
int b=0;
public void generiereFarbe(){
if (r<255&&g==0&&b==0){
r++;
}
else if (r==255&&g<255&&b==0){
g++;
}
else if (r>0&&g==255&&b==0){
r= r-1;
}
else if (r==0&&g==255&&b<255){
b++;
}
else if (r==0&&g>0&&b==255){
g=g-1;
}
else if (r<255&&g==0&&b==255){
r++;
}
else if (r==255&&g==0&&b>0){
b=b-1;
}
}
public int gibROT () {
return(r);
}
public int gibGRUEN () {
return(g);
}
public int gibBLAU () {
return(b);
}
}
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class Zeit
{
public String erstelleZeit(){
DateFormat df = new SimpleDateFormat("HH:mm:ss");
Date d = new Date();
String uhr = df.format(d);
return (uhr);
}
}
How do I draw the unique rectangle(cube) inside the oval:
http://i.stack.imgur.com/pmHTl.jpg
For me it is tricky to use graphics to draw a rectangle such as the one shown. Any advice on what to do.
Ok. I will try to make myself as clear as I can. What I have so far are the orange ovals and the slim gray oval that is behind it. I only need to create one of these "dots" in a class and i will make many objects of them. The Task I need help in is drawing the "rectangle" shape you see that is in the orange dot using J Component possibly. By request I will add a picture of what I have so far if this edit does not fulfill the need for you to understand my problem.
Thanks
Edit : Here is the Code that I have for creating the ovals if that is of interest to you-
public void paint(Graphics g) {
Color c = (Color.orange);
g.setColor(Color.gray);
g.fillOval(3,3,60,60);
g.setColor(c);
g.fillOval(0,0,60,60);
}
Edit: My Attempt at an SSCCE -->
NanoBot Class(Where I am Creating the Bot in paint)
/**
* #author (Omar Ahmed)
*/
import javax.swing.*;
import java.awt.*;
public class NanoBot extends Image
{
public NanoBot(int x, int y, int w, int h)
{
super(x,y,w,h);
}
public void paint(Graphics g) {
Color c = (Color.orange);
g.setColor(Color.gray);
g.fillOval(3,3,60,60);
g.setColor(c);
g.fillOval(0,0,60,60);
//g.setColor(Color.black);
//g.fillOval(10,20,10,10);
//g.fillOval(40,20,10,10);
}
}
And The Driver:
/** Bot Swarm
* Date: May, 2013
* Author: Omar Ahmed
*/
import java.awt.*;
import javax.swing.*;
public class Driver {
private JFrame win;
private NanoBot bot1;
public Driver() {
win = new JFrame(" Swarm ");
win.setLayout(null);
win.setVisible(true);
win.setBounds( 20, 20, 800, 700);
win.getContentPane().setBackground(Color.white);
bot1=new NanoBot(50,50,70,70);
win.add(bot1,0);
}
Hope This Helps
Your first step is to break down your requirements...
You need to draw 3 shapes, front, top, side.
The front's y position is offset by 0.412 of the overall height. It's width is 0.77 of the overall width.
The top's height is 0.412 of the overall height, and it has a horizontal inset of 0.2 of the overall width...
The side's x position is offset by 0.77 of the overall width and has an inset of 0.47 of the over all width.
This is all very important, as you want to ensure that the shapes can resize reasonably well...
Now, you could simply use Graphics#drawLine and Graphics#drawRectangle to build the shape, but that, to me, is a lot of work...
Instead the 2D Graphics is very powerful and contains many wonderful things, the one of interest today is the Shape API, which allows you to define many different shapes, which can be drawn or filled.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestChip {
public static void main(String[] args) {
new TestChip();
}
public TestChip() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = 44;
int height = 17;
Front front = new Front(width, height);
Top top = new Top(width, height);
Side side = new Side(width, height);
draw(g2d, front, Color.BLACK, Color.YELLOW);
draw(g2d, top, Color.BLACK, Color.GRAY);
draw(g2d, side, Color.BLACK, Color.DARK_GRAY);
g2d.dispose();
}
protected void draw(Graphics2D g2d, Shape shape, Color foreground, Color background) {
g2d.setColor(background);
g2d.fill(shape);
g2d.setColor(foreground);
g2d.draw(shape);
}
}
public class Front extends Path2D.Float {
public Front(float width, float height) {
float frontWidth = width * 0.77f;
float yOffset = height * 0.412f;
moveTo(0, yOffset);
lineTo(frontWidth, yOffset);
lineTo(frontWidth, height);
lineTo(0, height);
closePath();
}
}
public class Side extends Path2D.Float {
public Side(float width, float height) {
float xOffset = width * 0.77f;
float inset = height * 0.47f;
moveTo(xOffset, inset);
lineTo(width, 0);
lineTo(width, inset);
lineTo(xOffset, height);
closePath();
}
}
public class Top extends Path2D.Float {
public Top(float width, float height) {
float inset = width * 0.2f;
float shapeHeight = height * 0.412f;
moveTo(inset, 0);
lineTo(width, 0);
lineTo(width - inset, shapeHeight);
lineTo(0, shapeHeight);
closePath();
}
}
}
Your job is to now go away, study the example, study the referenced tutorials, study the associated API docs and figure out how to align the above shape within you circle and draw it's legs...
A hint. Make a "Bug" class that knows how to renderer all this and simply translate the position of the Graphics as required...
I have some shapes created by class Rectangle and I want to surround them with a thick border. However the methods drawRect and drawOval form Graphics class create a thin line as the border of the shape. How can I adjust them so as me to able to manipulate the thickness of the border line? If this is not possible or quite effective, what is another way to assign an adjustable border on the shapes? May I need Rectangle2D or Graphics2D?
After that, do you know how I can “round” the angles of the border of a square so as not to be sharp?
To make the border thicker, use Graphics2D.setStroke(...). And to draw "rounded" rectangles, use Graphics.drawRoundRect(...).
Look into Graphics2D strokes:
Graphics2D.setStroke()
BasicStroke
If a round join in your stroke isn't soft enough, look into RoundRectangle2D.
I implemented custom rounded shape for icons.
1) The thick border can be painted by :
BasicStroke dashed =new BasicStroke(3.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0f);
2) Rounded shape could be painted by:
Ellipse2D.Double circle = new Ellipse2D.Double(x+1, y+1, 14, 14);
Ellipse2D.Double circleBorder = new Ellipse2D.Double(x, y, 15, 15);
All code is here:
public class ColorIcon implements Icon {
private Color color = Color.WHITE;
/**
* Constructor for implement custom colored icon
* #param color - custom parameter for creating colored icon.
*/
public ColorIcon(#Nonnull Color color) {
this.color = color;
}
/**
* Default constructor for implement default icon.
*/
public ColorIcon() {
}
#Override
public void paintIcon(#Nonnull Component c, #Nonnull Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
BasicStroke dashed =new BasicStroke(3.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0f);
Ellipse2D.Double circle = new Ellipse2D.Double(x+1, y+1, 14, 14);
Ellipse2D.Double circleBorder = new Ellipse2D.Double(x, y, 15, 15);
g2.setColor(getColor());
g2.setRenderingHints(hints);
g2.fill(circle);
Composite oldComposite=g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0));
g2.setColor(new Color(1,1,1,1));
g2.setStroke(dashed);
g2.draw(circleBorder);
g2.setComposite(oldComposite);
}
#Override
public int getIconWidth() {
return 15;
}
#Override
public int getIconHeight() {
return 15;
}
public Color getColor() {
return color;
}
public void setColor(#Nonnull Color color) {
this.color = color;
}
}
** Why is the class CanvasPane not included in the Java API?.
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
/**
* Class Canvas - a class to allow for simple graphical
* drawing on a canvas.
*
* #author Michael Kolling (mik)
* #author Bruce Quig
*
* #version 2008.03.30
*/
public class Canvas
{
private JFrame frame;
private CanvasPane canvas;
private Graphics2D graphic;
private Color backgroundColor;
private Image canvasImage;
/**
* Create a Canvas with default height, width and background color
* (300, 300, white)
* #param title title to appear in Canvas Frame
*/
public Canvas(String title)
{
this(title, 300, 300, Color.white);
}
/**
* Create a Canvas with default background color (white).
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
*/
public Canvas(String title, int width, int height)
{
this(title, width, height, Color.white);
}
/**
* Create a Canvas.
* #param title title to appear in Canvas Frame
* #param width the desired width for the canvas
* #param height the desired height for the canvas
* #param bgClour the desired background color of the canvas
*/
public Canvas(String title, int width, int height, Color bgColor)
{
frame = new JFrame();
canvas = new CanvasPane();
frame.setContentPane(canvas);
frame.setTitle(title);
canvas.setPreferredSize(new Dimension(width, height));
backgroundColor = bgColor;
frame.pack();
}
/**
* Set the canvas visibility and brings canvas to the front of screen
* when made visible. This method can also be used to bring an already
* visible canvas to the front of other windows.
* #param visible boolean value representing the desired visibility of
* the canvas (true or false)
*/
public void setVisible(boolean visible)
{
if(graphic == null) {
// first time: instantiate the offscreen image and fill it with
// the background color
Dimension size = canvas.getSize();
canvasImage = canvas.createImage(size.width, size.height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.setColor(backgroundColor);
graphic.fillRect(0, 0, size.width, size.height);
graphic.setColor(Color.black);
}
frame.setVisible(true);
}
/**
* Provide information on visibility of the Canvas.
* #return true if canvas is visible, false otherwise
*/
public boolean isVisible()
{
return frame.isVisible();
}
/**
* Draw the outline of a given shape onto the canvas.
* #param shape the shape object to be drawn on the canvas
*/
public void draw(Shape shape)
{
graphic.draw(shape);
canvas.repaint();
}
/**
* Fill the internal dimensions of a given shape with the current
* foreground color of the canvas.
* #param shape the shape object to be filled
*/
public void fill(Shape shape)
{
graphic.fill(shape);
canvas.repaint();
}
/**
* Fill the internal dimensions of the given circle with the current
* foreground color of the canvas.
*/
public void fillCircle(int xPos, int yPos, int diameter)
{
Ellipse2D.Double circle = new Ellipse2D.Double(xPos, yPos, diameter, diameter);
fill(circle);
}
/**
* Fill the internal dimensions of the given rectangle with the current
* foreground color of the canvas. This is a convenience method. A similar
* effect can be achieved with the "fill" method.
*/
public void fillRectangle(int xPos, int yPos, int width, int height)
{
fill(new Rectangle(xPos, yPos, width, height));
}
/**
* Erase the whole canvas.
*/
public void erase()
{
Color original = graphic.getColor();
graphic.setColor(backgroundColor);
Dimension size = canvas.getSize();
graphic.fill(new Rectangle(0, 0, size.width, size.height));
graphic.setColor(original);
canvas.repaint();
}
/**
* Erase the internal dimensions of the given circle. This is a
* convenience method. A similar effect can be achieved with
* the "erase" method.
*/
public void eraseCircle(int xPos, int yPos, int diameter)
{
Ellipse2D.Double circle = new Ellipse2D.Double(xPos, yPos, diameter, diameter);
erase(circle);
}
/**
* Erase the internal dimensions of the given rectangle. This is a
* convenience method. A similar effect can be achieved with
* the "erase" method.
*/
public void eraseRectangle(int xPos, int yPos, int width, int height)
{
erase(new Rectangle(xPos, yPos, width, height));
}
/**
* Erase a given shape's interior on the screen.
* #param shape the shape object to be erased
*/
public void erase(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColor);
graphic.fill(shape); // erase by filling background color
graphic.setColor(original);
canvas.repaint();
}
/**
* Erases a given shape's outline on the screen.
* #param shape the shape object to be erased
*/
public void eraseOutline(Shape shape)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColor);
graphic.draw(shape); // erase by drawing background color
graphic.setColor(original);
canvas.repaint();
}
/**
* Draws an image onto the canvas.
* #param image the Image object to be displayed
* #param x x co-ordinate for Image placement
* #param y y co-ordinate for Image placement
* #return returns boolean value representing whether the image was
* completely loaded
*/
public boolean drawImage(Image image, int x, int y)
{
boolean result = graphic.drawImage(image, x, y, null);
canvas.repaint();
return result;
}
/**
* Draws a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void drawString(String text, int x, int y)
{
graphic.drawString(text, x, y);
canvas.repaint();
}
/**
* Erases a String on the Canvas.
* #param text the String to be displayed
* #param x x co-ordinate for text placement
* #param y y co-ordinate for text placement
*/
public void eraseString(String text, int x, int y)
{
Color original = graphic.getColor();
graphic.setColor(backgroundColor);
graphic.drawString(text, x, y);
graphic.setColor(original);
canvas.repaint();
}
/**
* Draws a line on the Canvas.
* #param x1 x co-ordinate of start of line
* #param y1 y co-ordinate of start of line
* #param x2 x co-ordinate of end of line
* #param y2 y co-ordinate of end of line
*/
public void drawLine(int x1, int y1, int x2, int y2)
{
graphic.drawLine(x1, y1, x2, y2);
canvas.repaint();
}
/**
* Sets the foreground color of the Canvas.
* #param newColor the new color for the foreground of the Canvas
*/
public void setForegroundColor(Color newColor)
{
graphic.setColor(newColor);
}
/**
* Returns the current color of the foreground.
* #return the color of the foreground of the Canvas
*/
public Color getForegroundColor()
{
return graphic.getColor();
}
/**
* Sets the background color of the Canvas.
* #param newColor the new color for the background of the Canvas
*/
public void setBackgroundColor(Color newColor)
{
backgroundColor = newColor;
graphic.setBackground(newColor);
}
/**
* Returns the current color of the background
* #return the color of the background of the Canvas
*/
public Color getBackgroundColor()
{
return backgroundColor;
}
/**
* changes the current Font used on the Canvas
* #param newFont new font to be used for String output
*/
public void setFont(Font newFont)
{
graphic.setFont(newFont);
}
/**
* Returns the current font of the canvas.
* #return the font currently in use
**/
public Font getFont()
{
return graphic.getFont();
}
/**
* Sets the size of the canvas.
* #param width new width
* #param height new height
*/
public void setSize(int width, int height)
{
canvas.setPreferredSize(new Dimension(width, height));
Image oldImage = canvasImage;
canvasImage = canvas.createImage(width, height);
graphic = (Graphics2D)canvasImage.getGraphics();
graphic.drawImage(oldImage, 0, 0, null);
frame.pack();
}
/**
* Returns the size of the canvas.
* #return The current dimension of the canvas
*/
public Dimension getSize()
{
return canvas.getSize();
}
/**
* Waits for a specified number of milliseconds before finishing.
* This provides an easy way to specify a small delay which can be
* used when producing animations.
* #param milliseconds the number
*/
public void wait(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
// ignoring exception at the moment
}
}
/************************************************************************
* Inner class CanvasPane - the actual canvas component contained in the
* Canvas frame. This is essentially a JPanel with added capability to
* refresh the image drawn on it.
*/
private class CanvasPane extends JPanel
{
public void paint(Graphics g)
{
g.drawImage(canvasImage, 0, 0, null);
}
}
}
Why it should be? I mean its a BlueJ extension class, AFAIK. Similar questions may come to the mind regarding StringUtils, or NumberUtils. IMHO, these two really qualifies to be there in the original Java API. :)
One huge reason is that it has one of the worst named methods I have ever seen in a Java class:
public void wait(int milliseconds)
Try calling wait(100) on it and watch it work without synchronisation and obviously do something completely different from java.lang.Object.wait(long). This would be a nightmare to do in production.
What on earth is such a method doing in a class named Canvas?