I am writing a 'sketchPad' type program in Java. My FREEHAND and LINE implementation works fine, but when I do a RECT or an OVAL if I draw from top left to bottom right it works fine, but the opposite way doesn't function. It will draw from my starting point then down to the bottom right again depending on the size I try to draw. I have learned a little bit about Affine Transform and thought that may be a way to go, but I need help implementing it properly, or doing it a better way.
Here is the effected portion of the code:
public void paint(){
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
graphics2D.setPaint(toolBar.getCurrentColor());
repaint();
}
});
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
String currentPaintType = toolBar.getPaintType();
if(currentPaintType != "FREEHAND"){
currentX = e.getX();
currentY = e.getY();
if(currentPaintType == "LINE"){
if (graphics2D != null){
graphics2D.drawLine(oldX, oldY, currentX, currentY);
}
}else if(currentPaintType == "OVAL"){
if (graphics2D != null){
graphics2D.drawOval(oldX, oldY, getWidthHeight(oldX,currentX), getWidthHeight(oldY,currentY));
}
}else if(currentPaintType == "RECT"){
if (graphics2D != null){
graphics2D.drawRect(oldX, oldY, getWidthHeight(oldX,currentX), getWidthHeight(oldY,currentY));
}
}
repaint();
}
}
});
}
//Code to calculate the proper width and height based on X/Y points
public int getWidthHeight(int old, int current){
int i=0;
if(old>current){
i=old-current;
}else{
i=current-old;
}
return i;
}
Related
I'm relatively new to Java, but I've made a simple paint program that allows the user to draw, change the color and size of the pen, and clear the drawing area.
The user selects a color from the JColorChooser object 'c' and this is handed off to the Color variable 'selected' through c.getColor(). I want to be able to change the transparency of the selected color, but I don't know if there is a way to convert from Color to RGB so that I can use the setColor(r, g, b, a) method. My code is below. I really appreciate any help!
Color selected;
public class ColorTool extends JPanel {
public ColorTool() {
super(new BorderLayout());
b = new JLabel("Pen Color", JLabel.CENTER);
b.setForeground(Color.black);
c = new JColorChooser(b.getForeground());
c.getSelectionModel().addChangeListener(new ColorListener());
add(c, BorderLayout.PAGE_END);
}
}
public DrawPanel() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
for (int i = 0; i <= 100; i++) {
if (PS == i) {
oldX = (int)(e.getX() - Math.ceil(PS/2));
oldY = (int)(e.getY() - Math.ceil(PS/2));
if (graphics != null) {
graphics.setColor(selected);
graphics.fillOval(oldX, oldY, PS, PS);
}
repaint();
oldX = e.getX();
oldY = e.getY();
}
}
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
BasicStroke size = new BasicStroke(PS,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
currentX = e.getX();
currentY = e.getY();
if (graphics != null) {
graphics.setColor(selected);
graphics.setStroke(size);
graphics.drawLine(oldX, oldY, currentX, currentY);
}
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public class ColorListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
selected = c.getColor();
}
}
You can access that by calling the method getComponents on the instance of Color.
From the documentation:
public float[] getComponents(float[] compArray)
Returns a float array containing the color and alpha components of the Color, in the ColorSpace of the Color. If compArray is null, an array with length equal to the number of components in the associated ColorSpace plus one is created for the return value. Otherwise, compArray must have at least this length and it is filled in with the components and returned.
Parameters: compArray - an array that this method fills with the color and alpha components of this Color in its ColorSpace and returns
Returns:
the color and alpha components in a float array.
So I'm making a game, and the user controls a rectangle that moves left to right along a box at the bottom, but it falls of the edges and I don't know how to stop this, help would be appreciated. I have tried many things to stop this but nothing has worked and I really need some help to keep the rectangle actually on the screen.
public Rectangle character;
public Rectangle bottomBox;
public int charW = 100;
public int charH = 15;
public boolean right = false;
public boolean left = false;
public boolean up = false;
public boolean down = false;
public boolean mouseActive = false;
public Point mouse;
public Keying(Display f, Images i){
character = new Rectangle(180, 180, charW, charH);
bottomBox = new Rectangle (0, 350, 9000, 30);
f.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_D){
mouseActive = false;
right = true;
character.x += 1;
}
if(e.getKeyCode() == KeyEvent.VK_A){
mouseActive = false;
left = true;
character.x -= 1;
}
if(e.getKeyCode() == KeyEvent.VK_M){
mouseActive = false;
}
}
public void keyReleased(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_D){
right = false;
}
if(e.getKeyCode() == KeyEvent.VK_A){
left = false;
}
}
});
f.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e){
int mouseX = e.getX();
int mouseY = e.getY();
mouse = new Point(mouseX, mouseY);
if(mouseActive && character.x != Main.w - charW){
character.x = mouse.x;
character.y = mouse.y;
}
repaint();
}
});
f.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
mouse = new Point (e.getX(), e.getY());
if(e.getButton() == MouseEvent.NOBUTTON){
character.x = mouse.x;
character.y = mouse.y;
}
}
});
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Point pt1 = new Point(character.x, character.y + character.height);
if(!bottomBox.contains(pt1) && !mouseActive){
character.y++;
}
this.setBackground(Color.YELLOW);
{g.setColor(Color.BLACK);
g.fillRect(character.x, character.y, character.width, character.height);}
{g.setColor(Color.darkGray);
g.fillRect(bottomBox.x, bottomBox.y, bottomBox.width, bottomBox.height);
if(right && character.x != Main.w - charW){
character.x += 1;
}
if(left && character.x != 0){
character.x -= 1;
}
repaint();
}
}
}
I really need some help to keep the rectangle actually on the screen.
Well you need to do some basic logic check to see if the rectangle can be painted within the bounds of the panel.
You now the location of the rectangle and the width so just check if the sum is not greater than the width of the panel.
For example you can check out the logic found in Motion Using the Keyboard. All the code examples contain a move(...) method which does the boundary checking.
Also, note from the example that your painting code should NOT be calculation the location of the characters. A painting method should only paint the character based on the current properties of the character. Only a user action should change a property of the character because you can't control when the painting method is called.
Right now I am trying to get it so whenever I click inside of the oval that I have painted, and drag the mouse it will move positions by repainting. However, even though the MouseEvents are being detected correctly, the oval image is not updating. I am confused to why that is. Here is the code that deals with the oval, MouseEvents, and updating:
public class DrawOval extends JPanel {
private int size = 50;
private int locX = 0; //vector points
private int locY = 0;
private boolean isPressed = false;
private Shape oval = new Ellipse2D.Double(locX, locY, size, size * 2);
public DrawOval(int size){
this.size = size;
Dimension dims = new Dimension(size, size);
setPreferredSize(dims);
setMaximumSize(dims);
setMinimumSize(dims);
MouseAdapter m = new MouseAdapter(){
public void mouseReleased(MouseEvent e){
isPressed = false;
update(e);
System.out.println("Mouse is released!");
}
public void mousePressed(MouseEvent e){
isPressed = true;
update(e);
System.out.println("Mouse is pressed!");
}
public void mouseDragged(MouseEvent e){
if(isPressed){
update(e);
System.out.println("Mouse is dragged!");
}
}
public void update(MouseEvent e){
System.out.println("X: " + e.getX() + ", Y: " + e.getY());
if(oval.contains(e.getX(), e.getY())){
setX(e.getX()); setY(e.getY());
repaint();
}
//does not update if the mouses click coordinates are outside of the oval
}
};
addMouseListener(m); //for pressing and releasing
addMouseMotionListener(m); //for dragging
}
public void setX(int _x){
this.locX = _x;
}
public void setY(int _y){
this.locY = _y;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.fill(oval);
}
}
I cannot figure out why it is not updating correctly. I had it partially working before, but it would update all the time, even if where the user clicked was not within the oval.
I think doing setX and setY you forget to update x and y in your oval. You have at least three options:
1) recreate Ellipse2D.Double every time you change this.locX and this.locY.
2) expect that your oval is created with x=0, y=0 once and for all, check mouse event switching to relative coordinates (if(oval.contains(e.getX() - locX, e.getY() - locY)){...}) and draw your oval using AffineTransform by g2.transform(...).
3) Declare oval as Ellipse2D.Double oval = new Ellipse2D.Double(...); and then you can change its x and y directly cause they're public:
oval.x = this.locX;
oval.y = this.locY;
I have a combobox in my program, with three options CIRCLE, RECTANGLE, FREEHAND. Each option is connected to a mouselistener. If I swich between the three options the mouselisteners are causing me some problems. Therefore I would like to add a mouselistener only once (for example in the constructor or in the beginning of the method, or somewhere else). Is it even possible, and how would the code look like?
If it is not possible, is there any other way I can solve it?
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(comboBox)) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
contentPane.addMouseListener(new MouseAdapter() { //First mouseListener
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Rectangle r = new Rectangle(startX, startY, w, h, pickedColor, thickness);
shapeList.add(r);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Circle")) {
contentPane.addMouseListener(new MouseAdapter() { //Second
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Circle c = new Circle(startX, startY, w, h, pickedColor, thickness);
shapeList.add(c);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Freehand")) {
contentPane.addMouseListener(new MouseAdapter() { //Third
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseDragged(MouseEvent e) {
FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY(), pickedColor, thickness);
shapeList.add(fh);
repaint();
}
});
}
}
Instead of adding a different listener to the panel each time a selection is made in the combo box, you should add a single mouse listener to the panel, in the constructor. And this listener, when one of its methods is called, should first check which option is selected, and act accordingly (i.e. draw a rectangle, or a circle, or by free hand depending on the selection).
The simplest solution would be to store the last listener and remove that before adding a new one:
private MouseListener lastListener;
// ...
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
if (lastListener != null)
contentPane.removeMouseListener(lastListener);
lastListener = new MouseAdapter() { //First mouseListener
// ...
};
contentPane.addMouseListener(lastListener);
I am trying to complete the resizing of a shape task I almost got the result I wanted, only dragging after the mouse changes to a resize cursor first draws another shape of the same type and resizes this Second drawn shape. Resulting in such a picture :
This is my related code:
#Override
public void mouseMoved(MouseEvent e) {
if (e.isControlDown()) {
updateShapeUnderMouse(e.getX(), e.getY());
} // deals with drawing shape if control button held
//deals with identifying shape to resize
int x = e.getX();
int y = e.getY();
for (int i = myShapes.size() - 1; i >= 0; i--) {
Shape s = (Shape) myShapes.get(i);
if (s.isedgePoint(x, y)) {
ShapetoResize = s;
setCursor(crnw);
prevDragX = x;
prevDragY = y;
return;
}
}
#Override
public void mouseDragged(MouseEvent event) {
if (event.isControlDown()) {
if (shapeUnderMouse != null) {
shapeUnderMouse.setXPos(event.getX());
shapeUnderMouse.setYPos(event.getY());
repaint();
}
} // deals with moving the shape
//deals with identifying and resizing shape
int x = event.getX();
int y = event.getY();
if (ShapetoResize != null) {
if (ShapetoResize instanceof Square) {
ShapetoResize.resizeSE(x - prevDragX, y - prevDragY);
} else if (ShapetoResize instanceof Rectangle) { // SAME CODE FOR EACH SHAPE
}
repaint();
}
}
Any idea what might be happening?
public ArrayList<Shape> myShapes = new ArrayList();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int length = myShapes.size();
for (int i = 0; i < length; i++) {
myShapes.get(i).paint(g);
}
}
Without seeing this portion of the code, it's just a guess, but I'm thinking you're creating a new shape in your ShapetoResize.resizeSE(int x, int y); method, thus creating two shapes.
I'm assuming it's your own method, because there's no resizeSE available on the Rectangle or the interface Shape (the two built in shapes). Of course there's no paint method on the interface Shape, so you're probably using a custom interface as well (which would be confusing since you didn't provide code for this Shape interface). If you post the code for these methods we can confirm.
Here's an example of putting your code together in a working manner (and a SSCCE). I limited this only to Rectangles (since they're the only built in Shape) and stripped out a lot of stuff not related to resizing. If you're still having trouble, try recreating the problem using this example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
public class ShapeResizer extends Box{
Dimension preferredSize = new Dimension(400,300);
public ArrayList<Shape> myShapes = new ArrayList();
//Shape that's targeted for editing
Shape currentShape;
public ShapeResizer(){
super(BoxLayout.X_AXIS);
//Shapes (because I don't want to make write code for the user to make shapes)
myShapes.add(new Rectangle(100, 100, 20, 20));
myShapes.add(new Rectangle(200, 200, 30, 30));
addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
//deals with identifying shape to resize
int x = e.getX();
int y = e.getY();
boolean foundShape = false;
for (int i = myShapes.size() - 1; i >= 0; i--) {
Shape s = (Shape) myShapes.get(i);
if (s.contains(e.getPoint())) {
//We found a shape to target
currentShape = s;
foundShape = true;
}
}
if(!foundShape){
//Reset the shape and cursor only if needed
if(currentShape != null){
currentShape = null;
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
}
}
#Override
public void mouseDragged(MouseEvent event) {
if (currentShape != null) {
resizeShape(currentShape, event.getPoint());
}
repaint();
}
});
}
public void resizeShape(Shape s, Point p){
if(s instanceof Rectangle){
Rectangle r = (Rectangle)s;
r.setSize(p.x - r.x, p.y - r.y);
}
}
public void drawShape(Graphics g, Shape s){
if(s instanceof Rectangle){
Rectangle r = (Rectangle)s;
g.drawRect(r.x, r.y, r.width, r.height);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int length = myShapes.size();
for (int i = 0; i < length; i++) {
drawShape(g, myShapes.get(i));
}
}
public Dimension getPreferredSize(){
return preferredSize;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new ShapeResizer());
frame.validate();
frame.pack();
frame.setVisible(true);
}
}
What is the logic behind adding a shape? Is a shape added by left clicking the drawing canvas? If so, your problem is probably that a shape is being added on click and that's the one that's being resized. You can debug this by breaking execution after you drag an object. Your list would contain two shapes instead of one.