First of all, here is the related code:
canvas = new CanvasPanel();
canvas.setBackground(Color.white);
canvas.addMouseListener(new PointListener());
canvas.addMouseMotionListener(new PointListener());
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, canvas);
class CanvasPanel extends JPanel
{
public void paintComponent(Graphics page)
{
super.paintComponent(page);
if (mouseDragged == true)
{
page.drawRect(x1, y1, x3, y3);
canvas.repaint();
}
}
}
class PointListener implements MouseListener, MouseMotionListener
{
public void mousePressed (MouseEvent event)
{
mouseDragged = true;
x1 = event.getX();
y1 = event.getY();
}
public void mouseReleased (MouseEvent event)
{
// some code
}
public void mouseDragged(MouseEvent event)
{
x3 = event.getX();
y3 = event.getY();
canvas.repaint();
}
So what this code is doing is when I click on the canvas component, it will draw an outline of a rectangle and the size changes as I drag the mouse
However, when I click and start to drag the mouse, there's an offset in the bottom right corner of the rectangle. It seems to jump to a bigger size the second I drag the mouse. Interestingly, the closer to the upper left corner of the canvas component I click, the closer the rectangle size is to the rectangle I draw with the mouse.
How can I fix this?
Remember, drawRect uses x, y, width, height as it's parameters, you should actually be using the delta between the click point and the drag point
Maybe something like...
public void paintComponent(Graphics page)
{
super.paintComponent(page);
if (mouseDragged == true)
{
int x = Math.min(x1, x3);
int y = Math.min(y1, y3);
int width = Math.max(x1, x3) - x;
int height = Math.max(y1, y3) - y;
page.drawRect(x, y, width, height);
}
}
And, don't call repaint from within the paint methods
Related
I'm trying to draw a rectangle to the screen based on mouse listeners. I'm having a few problems:
To start with the shape, it has an offset by a few pixels relative to the
release location of the mouse.
Secondly I can get only the shape to display if I set the screen to
visible each time after adding a JPanel component.
Could anyone tell me what I'm doing wrong or point me in the direction of some documentation? (I’ve read the Oracle documentation but I didn’t really understand it)
I know this isnt the greatest code but i just want to get it working for the moment.
This is my first time asking a question on stackoverflow so if I'm doing something wrong pls tell me.
This is my code
public class Frame {
private JFrame frame;
public Frame() {
this.frame = frameSetup("Graph");
this.frame.addMouseListener(new Mouse());
}
private JFrame frameSetup(String heading) {
JFrame f = new JFrame(heading);
f.setBackground(Color.WHITE);
f.setSize(800, 800);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
return f;
}
public void draw(int xIn, int yIn, int widthIn, int heightIn) {
int x = xIn;
int y = yIn;
int width = widthIn;
int height = heightIn;
this.frame.add(new Panel(x, y, width, height));
this.frame.pack();
//this.frame.setVisible(true);
}
private class Mouse implements MouseListener {
int x = 0;
int y = 0;
int height = 0;
int width = 0;
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == 1) {
x = e.getX();
y = e.getY();
System.out.println(x + ": " + y);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == 1) {
width = (e.getX() - x);
height = (e.getY() - y);
System.out.println(width + ": " + height);
draw(x - 7, y -30, width, height);
}
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
}
and
public class Panel extends JPanel {
private int x;
private int y;
private int width;
private int height;
public Panel(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
}
Welcome to the Site!
The offset is something I've had plenty of trouble with in the past aswell. It's caused by adding the MouseListener to the JFrame rather than it's contentPane. Basically, the JFrame is the thin border and the bar with the name, the icons and the buttons at the top. The content pane sits inside that, here it's the white surface. When you add the MouseListener to the JFrame, the coords are relative to this outline (the top left corner of the frame), rather than the white panel. This is fixed as follows:
// in the Frame constructor
this.frame.getContentPane().addMouseListener(new Mouse());
// in Mouse.mouseReleased(), remove the offset you added.
draw(x, y, width, height);
The Panel problem is a different story. I don't know how the code is doing what it does or how it works at all in the first place, but I can still give you some general tips.
Don't pack() the frame in the drawing method. It's used to calculate the window size while respecting the layout and the content of it. For me, it made the window as small as the OS allowed it to be.
Don't use JPanels like that! You'll run into weird problems like this, since they're made to be used in GUIs. For this reason, they're also way to heavy-weight to be used as a graphic. #user16320675 commented a tutorial on custom painting, I suggest you check that out.
Lastly, I suggest reworking the rectangle drawing. Right now, it only works when dragging from the top left to the bottom right.
I want to implement a Rectangle shape feature exactly as in Paint in JAVA. I have built a program as following. I have built a class MyPaint where buttons and frame are defined. I have built another class inside the same program PadDraw, where a drawing pad is created where I can draw with pencil like in Paint. Then I have another class outside the program DrawRect where the rectangle shape feature is created.
I want to know if there is a way to integrate the rectangle in a way that if I click a button "Rectangle", the way of drawing should change and instead of drawing with pencil, I should draw rectangle shapes exactly like in Paint when the rectangle shape is pressed.
The piece of code for PadDraw class is as following:
class PadDraw extends JComponent {
private Image image;
private Graphics2D graphics2D;
private int currentX , currentY , oldX , oldY ;
public PadDraw(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics2D != null)
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public void paintComponent(Graphics g){
if(image == null){
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 5, 5, null);
}
While the piece of code of DrawRect class that I want to integrate in the program where MyPaint and PadDraw class are located is as following:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawRect extends JPanel {
int x, y, x2, y2;
public static void main(String[] args) {
JFrame f = new JFrame("Draw Box Mouse 2");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new DrawRect());
f.setSize(300, 300);
f.setVisible(true);
}
DrawRect() {
x = y = x2 = y2 = 0; //
MyMouseListener listener = new MyMouseListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
public void setStartPoint(int x, int y) {
this.x = x;
this.y = y;
}
public void setEndPoint(int x, int y) {
x2 = (x);
y2 = (y);
}
public void drawPerfectRect(Graphics g, int x, int y, int x2, int y2) {
int px = Math.min(x,x2);
int py = Math.min(y,y2);
int pw=Math.abs(x-x2);
int ph=Math.abs(y-y2);
g.drawRect(px, py, pw, ph);
}
class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
setStartPoint(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
public void mouseReleased(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
drawPerfectRect(g, x, y, x2, y2);
}
}
I'm having issues attempting to draw a rectangle in the negative direction from a point clicked on a screen. I have the following class that simulates a screen capture software like Gyazo:
class DrawSquare extends JPanel implements MouseListener, MouseMotionListener {
// Components
public JDialog frame;
public Rectangle rectangle;
public BufferedImage bufferedImage;
public Point start, end;
// Variables
public String capturedImage;
public DrawSquare(JDialog frame) {
this.frame = frame;
// Read in crosshair image to replace mouse icon
Toolkit tool = Toolkit.getDefaultToolkit();
Image newImage = getToolkit().getImage("components/cursor.png");
Cursor cursor = tool.createCustomCursor(newImage, new Point (this.frame.getX(), this.frame.getY()), "img");
this.frame.setCursor(cursor);
this.frame.addMouseListener(this);
this.frame.addMouseMotionListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// draw background overlay
g2d.drawImage(bufferedImage, WIDTH, 0, this);
if (rectangle != null) {
//g2d.setColor(new Color(225, 225, 255, 128));
frame.setOpacity(0.6f);
//g2d.fill(rectangle);
System.out.println(rectangle);
g2d.setColor(new Color(72,119,205));
g2d.draw(rectangle);
}
g2d.dispose();
}
#Override
public void mouseDragged(MouseEvent e) {
this.end = e.getPoint();
int width = end.x - start.x;
int height = end.y - start.y;
rectangle.setSize(new Dimension(width, height));
frame.validate();
frame.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
this.start = e.getPoint();
frame.validate();
frame.repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// Get the X and Y point from the mouse pressed
rectangle = new Rectangle(start);
System.out.println(rectangle);
// Repaint the screen
frame.validate();
frame.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
Now the reason for the issue as mentioned already, is that when I attempt to draw the rectangle box in the opposition or negative direction of a point clicked on the screen, it doesn't draw, the rectangle information looks like this during such an attempt:
java.awt.Rectangle[x=635,y=395,width=-316,height=-194]
However, when I drag the rectnagle in the positive direction it works as it is supposed to:
What I'd like to know is how I can fix this using negative values for width/height, or doing it another way entirely.
You should actually have 2 Points - drag start Point and current drag Point.
The rectangle is calculated:
x=min(dragStartPoint.x, dragCurrentPoint.x)
y=min(dragStartPoint.y, dragCurrentPoint.y)
width=abs(dragStartPoint.x - dragCurrentPoint.x)
height=abs(dragStartPoint.y - dragCurrentPoint.y)
Increasing width and height are okay.
When they decrease, and reach 0, you need to decrease x and y.
Or otherwise seen: a rectangle is between two diagonal point topleft and bottomright. These roles change when for one coordinate (x or y) they cross.
Positive: you drag the bottom-right point (I guess).
Both coordinates zero: TL and BT cooincide, W and H zero.
Both coordinates negative: you leave the bottom-right point at the left-right position and drag the top-left point of the rectangle, W and H increasing from 0.
The easiest is:
Keep the mouse-down point from
Trag the mouse-drag point to
Calculate the rectangle between them:
Point min = new Point(Math.min(from.x, to.x), Math.min(from.y, to.y));
Point max = new Point(Math.max(from.x, to.x), Math.max(from.y, to.y));
Then the rectangle is calculated easily.
I've been trying to use mousePressed and mouseReleased but to no avail. The purpose of this program is to obtain an initial coordinate for the center of a circle from the mousepressed and to use the mousereleased to determine the radius of this circle. For some reason, I can't get the ball to repaint such that its center is the same position as the mousePressed(). I know that the first two parameters of the Ellipse2D object determine top-left corner of the ellipse, so if the radius length is subtracted from the x coordinate and the radius length is added to the y coordinate, shouldn't the ball appear at the first mouse click? I'm having difficulty understanding why it won't construct where I want it to.
Edit 1: Reformatted program for readability, made program compilable.
Here is the relevant portion of my program...
Main Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main{
public static void main(String[] args){
CircleComponent component = new CircleComponent();
JFrame frame = new JFrame("Bouncing Ball");
class mousePressedListener implements MouseListener
{
int x1, y1, x2, y2;
public void mouseClicked(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent e) { }
#Override
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
System.out.println(x1+ "|x1");
System.out.println(y1+ "|y1");
}
public void mouseReleased(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
System.out.println(x2 + "|x2");
System.out.println(y2 + "|y2");
frame.getHeight();
frame.getWidth();
component.moveBall(frame.getHeight(), frame.getWidth(), x1, y1, x2, y2);
}
}
class timeListener implements ActionListener{
public void actionPerformed(ActionEvent event)
{
frame.getHeight();
frame.getWidth();
component.moveBall(frame.getWidth(), frame.getHeight());
}
}
frame.add(component); //adds the ball to frame
frame.setVisible(true);
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//creates square panel with specific size and the default exit
ActionListener listener = new timeListener();
Timer timer = new Timer(500, listener);
timer.start();
frame.addMouseListener(new mousePressedListener());
}
}
CircleComponent Class
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import java.awt.Color;
public class CircleComponent extends JComponent{
private int x, y, a, b;
int radius = 50;
private Color color = Color.WHITE;
private int dx = 1, dy = 1;//initializes the speed of the ball
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(color);
Ellipse2D ball = new Ellipse2D.Double(x, y, 2*radius, 2*radius);
g2.fill(ball);
}
public void moveBall(int inWidth, int inHeight){
if(x<0 || x>inWidth-65){
dx = -dx;
}
if(y<0 || y>inHeight-150) {
dy = -dy;
}
x = x + dx;
y = y + dy;
repaint();
}
public void moveBall(int inWidth, int inHeight, int x1, int y1, int x2, int y2){
double r = (double) (Math.pow((x1-x2),2) + Math.pow((y1-y2),2));
radius = (int) Math.sqrt(r);
System.out.println(radius+"|radius");
if(x<0 || x>inWidth-65){
dx = -dx;
}
if(y<0 || y>inHeight-150) {
dy = -dy;
}
x = x1-radius;
y = y1+radius;
x = x + dx;
y = y + dy;
System.out.println(x+"X"+y+"Y");
repaint();
}
}
A MouseListener needs to be added to a viable GUI component for its magic to work, and you never seem to add your MouseListener to anything. You need to call .addMouseListener(...) on your CircleComponent object and pass in your created MouseListener.
As an aside, your code as formatted is very difficult to read. Please consider editing your post and fixing your indentation style so that it is uniform and consistent. I usually avoid using tabs for indenting (forum software often doesn't play well with tabs) and indent each code block 4 spaces.
Edit
Other suggestions:
Again, add the MouseListener to the CircleComponent instance, what you name "component".
I'd not make the MouseListener an inner class, but rather make it its own stand alone class.
You don't need a reference to the JFrame in the MouseListener, only the CircleComponent instance, which you can get by passing in a reference into the MouseListener's constructor, or by calling (CircleComponent) e.getSource()
In the MouseListener get the CircleComponent's width and height.
You will need to call the super's method inside of your paintComponent override.
Your calculations are off and you will need to debug these.
I'm having problem drawing rectangle to the left and upwards. They draw perfect to right and downwards.
An answer would be highly appreciated.
import acm.program.*;
import acm.graphics.*;
import java.awt.event.*;
public class Ch10_Ex04_Mouse_Dragged_Rectangle extends GraphicsProgram
{
public void init()
{
addMouseListeners();
}
public void mousePressed (MouseEvent e)
{
X = e.getX();
Y = e.getY();
rect = new GRect (e.getX(), e.getY(), 0, 0);
add (rect);
}
public void mouseDragged (MouseEvent e)
{
// if (e.getX() < X)
// rect.setBounds(X, Y, -e.getX() + X, e.getY() - Y);
rect.setBounds(X, Y, e.getX()-X, e.getY()-Y);
}
int X, Y;
private GRect rect;
}
I am making some assumptions here, but I think this is the mouseDragged function you are looking for (I did not validate this for syntax errors). This should draw the rectangle in all four possible drag directions (1) right/down, (2) right/up, (3) left/down, (4) left/up:
public void mouseDragged (MouseEvent e)
{
// Determine x-val and length
int xPos = X;
int xLen = Math.abs(X - e.getX());
if (e.getX() < X) {
xPos = e.getX();
}
// Determine y-val and length
int yPos = Y;
int yLen = Math.abs(Y - e.getY());
if (e.getY() < Y) {
yPos = e.getY();
}
// Set bounds on rectangle
rect.setBounds(xPos, yPos, xLen, yLen);
}