(The above image is taken from AutoCAD)
My application draws a line on a JPanel using two Point class variables: "startPoint" and "finishPoint".
"startPoint" is set from the first mouse click. Once a starting point has been established the finishPoint variable is set on the position of the cursor. Therefore the line moves/grows dynamically with the mouse movement until the "finishPoint" is finalised by a second mouse click.
During the period where a startPoint has been established and the line dynamically changes I would like to position a JTextField on the line midpoint (well... slightly off-center so it's not obscuring the line) if possible?
I know I'll get shouted at if I try and position a component without the use of a layout manager, but I can't see how a layout manager can help. I would like to position the JTextField using Coordinates. The only way I can think of doing that is to somehow add the textfield into a shape. Beyond that I'm at a loss.
Can someone put me in the right direction?
My code should anybody want to see it:
package Drawing;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
/*
* An extension to P2PLines. A line from point A to point B but with an animation.
*/
public class LineAnimation extends JPanel implements MouseListener, MouseMotionListener
{
private Graphics g;
private Point lineStart = new Point(0, 0);
private Point lineFinish = new Point(0, 0);
private boolean drawing;
int globalX = 0, globalY;
ArrayList<Line2D> edges = new ArrayList<>();
public LineAnimation()
{
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
drawing = false;
}
#Override public void mouseClicked(MouseEvent me) {}
#Override public void mousePressed(MouseEvent me)
{
if (drawing)
{
g = getGraphics(); // Get Graphics content
g.setColor(Color.black);
lineFinish.move(me.getX(), me.getY());
g.drawLine(lineStart.x, lineStart.y, me.getX(), me.getY());
edges.add(new Line2D.Float(lineStart.x, lineStart.y, lineFinish.x, lineFinish.y));
drawing = false;
g.dispose();
}
else
{
lineStart.move(me.getX(), me.getY());
drawing = true;
}
}
#Override public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawPreviousLine((Graphics2D)g);
if (drawing)
{g.drawLine(lineStart.x, lineStart.y, globalX, globalY);}
}
private void drawPreviousLine(Graphics2D g)
{
for(Line2D lines: edges)
{g.draw(lines);}
}
#Override
public void mouseMoved(MouseEvent me)
{
repaint();
globalX = me.getX();
globalY = me.getY();
}
#Override public void mouseReleased(MouseEvent me) {}
#Override public void mouseEntered(MouseEvent me) {}
#Override public void mouseExited(MouseEvent me) {}
#Override public void mouseDragged(MouseEvent me) {}
public static void main(String[] args)
{
JFrame frame = new JFrame("Drawing Frame");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
LineAnimation drawingFrame = new LineAnimation();
frame.add(drawingFrame);
frame.setVisible(true);
drawingFrame.addMouseListener(drawingFrame);
drawingFrame.addMouseMotionListener(drawingFrame);
}
}
Related
I am having an issue figuring out why my code isn't working for when I click to turn the drawing on/off. It should start as off initially but it doesn't. I also have an issue with my arraylist where I am not sure how to make it so that all the colors don't change when I click on a new color. This is my code so far, any help would be much appreciated.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import java.awt.event.MouseMotionAdapter;
public class Draw extends JPanel {
private Point startPoint, endPoint;
private ArrayList<Point> pointList;
private JButton clear;
private JRadioButton red, yellow, blue, eraser;
private boolean clicked;
private final static int SIZE = 30;
public Draw() {
// set the background color
setBackground(Color.WHITE);
// set starting point and end point of mouse click
startPoint = null;
endPoint = null;
this.addMouseListener(new MyMouseListener());
this.addMouseMotionListener(new MyMouseListener());
clicked = false;
pointList = new ArrayList<Point>();
this.addMouseMotionListener(new MyMouseListener());
clear = new JButton("Clear Drawing");
this.add(clear);
clear.addActionListener(new ButtonListener());
red = new JRadioButton("Red", true);
this.add(red);
red.addActionListener(new OptionListener());
yellow = new JRadioButton("Yellow", false);
this.add(yellow);
yellow.addActionListener(new OptionListener());
blue = new JRadioButton("Blue", false);
this.add(blue);
blue.addActionListener(new OptionListener());
eraser = new JRadioButton("Eraser",false);
this.add(eraser);
eraser.addActionListener(new OptionListener());
ButtonGroup group = new ButtonGroup();
group.add(red);
group.add(yellow);
group.add(blue);
group.add(eraser);
}
private class OptionListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
repaint();
}
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (event.getSource() == clear) {
pointList.clear();
repaint();
} else {
repaint();
}
}
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent event) {
if (clicked) {
pointList = new ArrayList<Point>();
pointList.add(event.getPoint());
endPoint = null;
} else {
endPoint = event.getPoint();
startPoint = null;
}
clicked = !clicked;
repaint();
}
#Override
public void mouseMoved(MouseEvent event) {
pointList.add(event.getPoint());
repaint();
}
}
#Override
public void paintComponent(Graphics pen) {
super.paintComponent(pen);
Graphics2D g2 = (Graphics2D) pen;
for (Point p : pointList) {
if (red.isSelected()) {
g2.setColor(Color.RED);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else if (yellow.isSelected()) {
g2.setColor(Color.YELLOW);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else if (blue.isSelected()) {
g2.setColor(Color.BLUE);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else {
}
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Drawing Time");
frame.setSize(500, 500);
// create an object of your class
Draw panel = new Draw();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
I also have an issue with my arraylist where I am not sure how to make it so that all the colors dont change when I click on a new color
There are two ways to do custom painting:
paint to a BufferedImage. Using this approach the object is painted and the currently selected color will be used to paint the object
(the approach you are using) - store the object you want to paint in an ArrayList. The problem is you are only storing the Point objects in the list so all Points get repainted with the same color. If you want each Point to have a different Color, then you need to store a custom Object that contains both the Color and the Point.
Check out Custom Painting Approaches for working examples of both of these approaches.
You need to associate the Color with each individual object that you paint.
Problem is specified in the title. I hit run, make a few lines here and there. When I resize or minimize the window, everything except the last line that was drawn is erased from the jframe window. This is part of a much larger photo album program. Eventually, I want to be able to save the drawing and add to the album. I believe the below code is where the issue lies. I've been scratching my head all night on this one. I figured if I created two arraylists and iterated through them, repaint() would re draw everything back, but that doesn't seem to be the case. Please help! Here's my code:
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Draw extends JPanel implements MouseListener, MouseMotionListener, ActionListener
{
private static final long serialVersionUID = 1L;
private ArrayList<ArrayList<Point>> lines;
private ArrayList<Point> points;
private Graphics g;
private Button clearButton;
public Draw()
{
clearButton = new Button("Clear slate");
g = getGraphics();
points = new ArrayList<Point>();
lines = new ArrayList<ArrayList<Point>>();
setPreferredSize(new Dimension(500, 500));
setBounds(0,0,500,500);
addMouseListener(this);
addMouseMotionListener(this);
clearButton.addActionListener(this);
this.add(clearButton, BorderLayout.SOUTH);
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseDragged(MouseEvent e)
{
// TODO Auto-generated method stub
points.add(e.getPoint());
lines.add(points);
repaint();
}
public void paint(Graphics g)
{
super.paintComponents(g);
for(ArrayList<Point> p : lines)
{
for(int i = 0; i < points.size()-1; i++)
g.drawLine(points.get(i).x, points.get(i).y, points.get(i+1).x, points.get(i+1).y);
}
}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e)
{
points = new ArrayList<Point>();
points.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void actionPerformed(ActionEvent evt)
{
if(evt.getSource()== clearButton)
{
lines.clear();
points.clear();
repaint();
}
}
}
Main method:
import javax.swing.JFrame;
public class MainDriver
{
public static void main(String a[])
{
JFrame frame = new JFrame();
Draw d = new Draw();
frame.add(d);
frame.pack();
frame.setVisible(true);
}
}
I extended the toolbar on a mac using a JPanel (see image), but the part that is the actualy toolbar (not the JPanel) is the only part that you can click and drag. How do I allow the user to click and drag the JPanel to move the window, just like they would the toolbar
The top mm or so of the image is the actual toolbar (with the text), the rest is the JPanel (with buttons).
Here is the code for the UnifiedToolPanel, which is set to the north of the border layout in the JFrame:
package gui;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowListener;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import com.jgoodies.forms.factories.Borders;
public class UnifiedToolbarPanel extends JPanel implements WindowFocusListener {
public static final Color OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR =
new Color(64, 64, 64);
public static final Color OS_X_UNIFIED_TOOLBAR_UNFOCUSED_BORDER_COLOR =
new Color(135, 135, 135);
public static final Color OS_X_TOP_FOCUSED_GRADIENT = new Color(214+8, 214+8, 214+8);
public static final Color OS_X_BOTTOM_FOCUSED_GRADIENT = new Color(217, 217, 217);
public static final Color OS_X_TOP_UNFOCUSED_GRADIENT = new Color(240+3, 240+3, 240+3);
public static final Color OS_X_BOTTOM_UNFOCUSED_GRADIENT = new Color(219, 219, 219);
public UnifiedToolbarPanel() {
// make the component transparent
setOpaque(true);
Window window = SwingUtilities.getWindowAncestor(this);
// create an empty border around the panel
// note the border below is created using JGoodies Forms
setBorder(Borders.createEmptyBorder("3dlu, 3dlu, 1dlu, 3dlu"));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Window window = SwingUtilities.getWindowAncestor(this);
Color color1 = window.isFocused() ? OS_X_TOP_FOCUSED_GRADIENT
: OS_X_TOP_UNFOCUSED_GRADIENT;
Color color2 = window.isFocused() ? color1.darker()
: OS_X_BOTTOM_UNFOCUSED_GRADIENT;
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(
0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
#Override
public Border getBorder() {
Window window = SwingUtilities.getWindowAncestor(this);
return window != null && window.isFocused()
? BorderFactory.createMatteBorder(0,0,1,0,
OS_X_UNIFIED_TOOLBAR_FOCUSED_BOTTOM_COLOR)
: BorderFactory.createMatteBorder(0,0,1,0,
OS_X_UNIFIED_TOOLBAR_UNFOCUSED_BORDER_COLOR);
}
#Override
public void windowGainedFocus(WindowEvent e) {
repaint();
}
#Override
public void windowLostFocus(WindowEvent e) {
repaint();
}
}
How do I allow the user to click and drag the JPanel to move the window
Here is the way :
private int x;
private int y;
//.....
//On mouse pressed:
jpanel.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent ev){
x = ev.getX ();
y = ev.getY();
}
});
//....
//on mouse dragged
jpanel.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent evt) {
int x = evt.getXOnScreen()-this.x;
int y = evt.getYOnScreen -this.y;
this.setLocation(x,y);
}
});
this.setLocation(x,y) will moves the Frame not the panel, I thought that your class extended JFrame.
However, you can create a method that returns a point (x,y) and set it to the window.
There wasn't really an answer with the Point class so I will be adding my contribution instead of storing the x, y cords of the MouseEvent, We store the Point
Here is show you can do it, Define a global Variable of the Class java.awt.Point
private Point currentLocation;
we then store the point to currentLocation once mouse is pressed using MouseListener
panel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
currentLocation = e.getPoint();
}
});
and we set the JFrame location when mouse is dragged using MouseMotionListener
panel.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
Point currentScreenLocation = e.getLocationOnScreen();
setLocation(currentScreenLocation.x - currentLocation.x, currentScreenLocation.y - currentLocation.y);
}
});
and we put all the code together inside a HelperMethod to be used anywhere
public void setDraggable(JPanel panel) {
panel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
currentLocation = e.getPoint();
}
});
panel.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
Point currentScreenLocation = e.getLocationOnScreen();
setLocation(currentScreenLocation.x - currentLocation.x, currentScreenLocation.y - currentLocation.y);
}
});
}
I store my HelperMethod in a class that extends JFrame Hence why I have access to setLocation that belongs to JFrame without a variable.
I have a simple class that draws a line when mouse dragging or a dot when mouse pressing(releasing).
When I minimize the application and then restore it, the content of the window disappears except the last dot (pixel). I understand that the method super.paint(g) repaints the background every time the window changes, but the result seems to be the same whether I use it or not. The difference between the two of them is that when I don't use it there's more than a pixel painted on the window, but not all my painting. How can I fix this?
Here is the class.
package painting;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
class CustomCanvas extends Canvas{
Point oldLocation= new Point(10, 10);
Point location= new Point(10, 10);
Dimension dimension = new Dimension(2, 2);
CustomCanvas(Dimension dimension){
this.dimension = dimension;
this.init();
addListeners();
}
private void init(){
oldLocation= new Point(0, 0);
location= new Point(0, 0);
}
public void paintLine(){
if ((location.x!=oldLocation.x) || (location.y!=oldLocation.y)) {
repaint(location.x,location.y,1,1);
}
}
private void addListeners(){
addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
#Override
public void mouseReleased(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
}
#Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.red);
g.drawLine(location.x, location.y, oldLocation.x, oldLocation.y);
}
#Override
public Dimension getMinimumSize() {
return dimension;
}
#Override
public Dimension getPreferredSize() {
return dimension;
}
}
class CustomFrame extends JPanel {
JPanel displayPanel = new JPanel(new BorderLayout());
CustomCanvas canvas = new CustomCanvas(new Dimension(200, 200));
public CustomFrame(String titlu) {
canvas.setBackground(Color.white);
displayPanel.add(canvas, BorderLayout.CENTER);
this.add(displayPanel);
}
}
public class CustomCanvasFrame {
public static void main(String args[]) {
CustomFrame panel = new CustomFrame("Test Paint");
JFrame f = new JFrame();
f.add(panel);
f.pack();
SwingConsole.run(f, 700, 700);
}
}
You are not storing the state of the points you are drawing. When the panel is repainted, it only has information for the last point it drew.
Response to comment:
You would need to have a collection of Points, for instance ArrayList<Point> location = new ArrayList<Point>();
Then, in your listeners: location.add(new Point(me.getX(), me.getY()));
Finally, in paintLine():
for (Point location : locations) {
repaint(location.x,location.y,1,1);
}
The collection locations is usually referred to as a Display List. Most graphics programs use them.
Response to comment:
Yes, I expect so. I just tossed off an idea based on your code to give you a starting point. It is almost certainly a bad idea to do exactly as I have described.
Doesn't that mean I will draw all the points(instead of one) everytime I press or drag the mouse?
Yes, but #Dave's approach is perfectly satisfactory for thousands of nodes, as may be seen in GraphPanel. Beyond that, consider the flyweight pattern, as used by JTable renderers and illustrated here.
Addendum: Focusing on your AWTPainting questions, the variation below may illustrate the difference between System- and App-triggered Painting. As the mouse is dragged, repaint() invokes update(), which calls paint(); this is app-triggered. As you resize the window, only paint() is called (no red numbers are drawn); this is system-triggered. Note that there is a flicker when the mouse is released after resizing.
Flickering typically occurs when the entire component's background is cleared and redrawn:
4. If the component did not override update(), the default implementation of update() clears the component's background (if it's not a lightweight component) and simply calls paint().
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
public class AWTPainting {
public static void main(String args[]) {
CustomPanel panel = new CustomPanel();
Frame f = new Frame();
f.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(panel);
f.pack();
f.setVisible(true);
}
}
class CustomPanel extends Panel {
public CustomPanel() {
this.add(new CustomCanvas(new Dimension(320, 240)));
}
}
class CustomCanvas extends Canvas {
private MouseAdapter handler = new MouseHandler();
private List<Point> locations = new ArrayList<Point>();
private Point sentinel = new Point();
private Dimension dimension;
CustomCanvas(Dimension dimension) {
this.dimension = dimension;
this.setBackground(Color.white);
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
this.locations.add(sentinel);
}
#Override
public void paint(Graphics g) {
g.setColor(Color.blue);
Point p1 = locations.get(0);
for (Point p2 : locations.subList(1, locations.size())) {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
p1 = p2;
}
}
#Override
public void update(Graphics g) {
paint(g);
g.clearRect(0, getHeight() - 24, 50, 20); // to background
g.setColor(Color.red);
g.drawString(String.valueOf(locations.size()), 8, getHeight() - 8);
}
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (locations.get(0) == sentinel) { // reference identity
locations.set(0, new Point(e.getX(), e.getY()));
}
}
#Override
public void mouseDragged(MouseEvent e) {
locations.add(new Point(e.getX(), e.getY()));
repaint();
}
}
#Override
public Dimension getPreferredSize() {
return dimension;
}
}
#Andrew, #Dave, #trashgod Hi,
I did some research on this and, finally, this is what I've got. Please correct me if I'm wrong. You cannot override paint() so you call repaint() everytime you need to do app-triggered painting.
Repaint() calls update() which its default behavior is to call paint().
update() is used for incremental painting; that explains the flickering screen when paint() was doing all the work, which practically means it was painting the whole image at every step.
However, my question is if I add "locationsAdded = 0" in the update method that means everytime I drag the mouse I paint the whole image(like in paint), so why doesn't it blink like before?
I've also read something about painting in swing and I didn't understand why update() is never invoked for swing. Can you explain me why?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
class CustomCanvas extends Canvas{
ArrayList<Point> locations;
int locationsAdded;
Point oldLocation;
Point location;
Dimension dimension;
CustomCanvas(Dimension dimension){
locations = new ArrayList<>();
this.dimension = dimension;
this.init();
addListeners();
}
private void init(){
oldLocation= new Point(0, 0);
location= new Point(0, 0);
}
public void paintLine(Graphics g, int x){
Point p1 = (Point)locations.get(x);
Point p2 = (Point)locations.get(x+1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
locationsAdded++;
}
#Override
public void paint(Graphics g){
locationsAdded = 0;
g.setColor(Color.red);
for(int i = locationsAdded; i < locations.size()-1; i++){
paintLine(g, i);
}
}
public void update(Graphics g) {
//locationsAdded = 0;
for (int i = locationsAdded; i < locations.size()-1; i++) {
paintLine(g, i);
}
}
private void addListeners(){
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
locations.add(location);
repaint();
}
});
}
#Override
public Dimension getMinimumSize() {
return dimension;
}
#Override
public Dimension getPreferredSize() {
return dimension;
}
}
class CustomFrame extends Panel {
Panel displayPanel = new Panel(new BorderLayout());
CustomCanvas canvas = new CustomCanvas(new Dimension(700, 700));
public CustomFrame(String titlu) {
canvas.setBackground(Color.white);
displayPanel.add(canvas, BorderLayout.CENTER);
this.add(displayPanel);
}
}
public class AWTPainting {
public static void main(String args[]) {
CustomFrame panel = new CustomFrame("Test Paint");
Frame f = new Frame();
f.add(panel);
f.pack();
f.setSize(700,700);
f.show();
}
}
set your layout to Null layout
I'm making a program in Java for my CS class. My teacher has little experience with graphics programing in Java so I've turned to you. I'm currently using the paintComponent method of my main panel to draw two things, one, a rectangle (my cannon, possibly replaced with a image later), and two, a .png file of a cannon ball. I use the Graphics g (which I convert to Graphics2D) to paint the cannon and Ball on to the screen. I then rotate, but, the cannon and ball rotate, not just the cannon. Any tips, suggestions, or helpful tutorials are greatly appreciated.
Here is my code (the commented out links are where I got certain code, ignore them):
package Cannon;
import java.awt.geom.Point2D;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class NewMain{
public static void main(String[] args) {
FraMainWindow frame = new FraMainWindow();
}
}
class FraMainWindow extends JFrame {
DrawCannon pnlCannon = new DrawCannon();
ButtonPannel pnlButtons = new ButtonPannel();
public FraMainWindow() {
this.setDefaultCloseOperation(JFrame.EXI…
this.setTitle("Super Mario Cannon Bro's");
this.setSize(900, 550);
this.setLayout(new BorderLayout());
this.add(pnlCannon, BorderLayout.CENTER);
this.add(pnlButtons, BorderLayout.SOUTH);
MouseMovement mouseMove = new MouseMovement();
MouseAction mouseClick = new MouseAction();
pnlCannon.addMouseMotionListener(mouseMo…
pnlCannon.addMouseListener(mouseClick);
FireButton actnFire = new FireButton();
pnlButtons.btnFire.addActionListener(act…
this.setVisible(true);
}
public class DrawCannon extends JPanel{
Rectangle.Float rectCannon = new Rectangle.Float(30, 450, 50, 10);
Image imgBall=new ImageIcon("ball.png").getImage();
double dAngle = 0;
boolean isFired = false;
public void addCannonBall(){
isFired=true;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_… RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_… RenderingHints.VALUE_RENDER_QUALITY);//A… Aliasing from http://www.java2s.com/Code/Java/2D-Graph…
g2d.rotate(0 - dAngle, rectCannon.getX(), rectCannon.getY() + 5);
g2d.fill(rectCannon);
if(isFired){
g2d.drawImage(imgBall, 0, 0, null);
}
//Dimension size = getSize();
}
}
public class ButtonPannel extends JPanel {
JButton btnFire = new JButton("Fire!");
ButtonPannel() {
this.add(btnFire);
}
}
public class FireButton implements ActionListener {
public void actionPerformed(ActionEvent e) {
pnlCannon.addCannonBall();
System.out.println("Fire ZE MISSILES");
}
}
public class MouseMovement implements MouseMotionListener {
public void mouseDragged(MouseEvent e) {
double dBase, dHeight, dAngle;
dBase = e.getX() - pnlCannon.rectCannon.getX();
dHeight = pnlCannon.rectCannon.getY() - 5 - e.getY() + 10;
dAngle = Math.atan2(dHeight, dBase);
pnlCannon.dAngle = dAngle;
pnlCannon.repaint();
}//http://download.oracle.com/javase/tutori…
public void mouseMoved(MouseEvent e) {
}
}
public class MouseAction implements MouseListener {
public void mousePressed(MouseEvent e) {
double dBase, dHeight, dAngle;
dBase = e.getX() - pnlCannon.rectCannon.getX();
dHeight = pnlCannon.rectCannon.getY() - 5 - e.getY() + 10;
dAngle = Math.atan2(dHeight, dBase);
pnlCannon.dAngle = dAngle;
pnlCannon.repaint();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
} // From http://www.rgagnon
Try moving this bit:
if(isFired){
g2d.drawImage(imgBall, 0, 0, null);
}
before this line:
g2d.rotate(0 - dAngle, rectCannon.getX(), rectCannon.getY() + 5);
Any transformations you apply to your Graphics2D will affect anything from that point, so you have to either be careful to apply transforms when you need them, or to "un-apply" them before you don't need them.
You have to unrotate after drawing the cannon and before drawing the ball :)
You could try to save the transform before you do a rotate and then set it back again. This example is from setTransform in the Java Docs:
// Get the current transform
AffineTransform saveAT = g2.getTransform();
// Perform transformation
g2d.transform(...);
// Render
g2d.draw(...);
// Restore original transform
g2d.setTransform(saveAT);