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.
Related
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 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.
So basically I'm writing a program where the user clicks and drags the mouse to a size he/she wants, and lets go, filling in a rectangle based on the choice from the JComboBox.
What I have implemented is MouseListener and MouseMotionListener to track the location of the mouse, and draw a rectangle based on where the user first clicked, to where it was let go.
When the user clicks and drags (but does not let go), there is a drawRect() but not a fillRect() (as in, the rectangle does not fill - only when the user releases the mouse does the rectangle fill with the color).
This class creates a Rect object that has another part in the constructor, which is the color that is selected (which is determined in the ColorListener class below).
This is where I included my instance variables, and everything is instantiated in the constructor below:
private ArrayList<Rect> rectList;
private Color currentColor;
private Canvas canvas;
private JPanel controlPanel;
private JButton undo, erase;
private JComboBox comboBox;
private int xStart, yStart, xEnd, yEnd;
private Graphics page;
private Point pt = null;
private PointListener pointListener;
private ColorListener colorListener;
public WholePanel()
{
// here we use black to draw a rectangle
currentColor = Color.black;
pointListener = new PointListener();
addMouseListener(pointListener);
addMouseMotionListener(pointListener);
String[] listOfColors = {"black", "red", "blue", "green", "orange"};
comboBox = new JComboBox(listOfColors);
comboBox.setSelectedIndex(0);
rectList = new ArrayList<Rect>();
controlPanel = new JPanel(new GridLayout(1,3));
undo = new JButton("Undo");
erase = new JButton("Erase");
controlPanel.add(comboBox);
controlPanel.add(undo);
controlPanel.add(erase);
undo.addActionListener(new ButtonListener());
erase.addActionListener(new ButtonListener());
canvas = new Canvas();
JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, controlPanel, canvas);
setLayout(new BorderLayout());
add(sp);
}
The Rect class can create a Rect object used later.
public class Rect
{
private int x1, y1, width1, height1;
private Color color1;
public Rect(int x, int y, int width, int height, Color color)
{
x1 = x;
y1 = y;
width1 = width;
height1 = height;
color1 = color;
}
public void draw(Graphics page)
{
page.setColor(color1);
page.drawRect(x1,y1,width1,height1);
}
}
The Canvas class creates the space that allows for drawing of an object.
private class Canvas extends JPanel
{
public void paintComponent(Graphics page)
{
super.paintComponent(page);
setBackground(Color.white);
if (pt != null)
{
Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
rect.draw(page);
}
}
}
The PointListener class finds all the points that are there, as in where the user clicks, to where the user drags, and also to where the user releases.
private class PointListener implements MouseListener, MouseMotionListener
{
public void mousePressed(MouseEvent event)
{
pt = event.getPoint();
xStart = pt.x;
yStart = pt.y;
}
public void mouseReleased(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
}
}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mouseDragged(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
rect.draw(page);
}
repaint();
}
public void mouseMoved(MouseEvent event) {}
}
ColorListener finds the type of object that is selected in the JComboBox determined in the main() method, and sets the currentColor to it (it is put back as the color in the Rect constructor above).
private class ColorListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource().equals("black"))
{
currentColor = Color.black;
comboBox.setSelectedIndex(0);
}
else if (event.getSource().equals("red"))
{
currentColor = Color.red;
comboBox.setSelectedIndex(1);
}
else if (event.getSource().equals("blue"))
{
currentColor = Color.blue;
comboBox.setSelectedIndex(2);
}
else if (event.getSource().equals("green"))
{
currentColor = Color.green;
comboBox.setSelectedIndex(3);
}
else if (event.getSource().equals("orange"))
{
currentColor = Color.orange;
comboBox.setSelectedIndex(4);
}
}
}
So what I am having trouble with is being able to draw it. I don't see any flaws in logic in the program so far above, and nothing is being able to be drawn onto the Canvas (don't worry about the JButtons Undo and Erase, as they are easy to work with with an ArrayList and remove() and clear() and things like that).
Your program should have no Graphics field that is a class field (your page class field). I'm surprised your not seeing a NullPointException with the way you're attempting to use it above in say your Mouse Listener class:
public void mouseReleased(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
// !!!! don't do this !!!!
page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
}
}
Instead the Graphics object should only be obtained from the JVM, should only exist within the paintComponent method and should only be used within the same paintComponent method (exceptions being any methods called from with paintComponent that are passed this object and of course a Graphics object obtained from a BufferedImage). The MouseListener/MouseMotionListener should fill in your x-start, y-start, x-end, and y-end variables during mouseDragged, and then on mouseRelease these variables should be used to create a new Rect object that is placed in the rectList, and then repaint called.
Then paintComponent should iterate through rectList, filling each Rect object it finds there.
I've been searching for a way to draw a black-and-white array on screen. It's a simple array, just 20x20. What I plan to do is to draw on an array with the mouse so that each pixel "toggles" from black to white and back when clicked, then pass the array as a set of booleans (or integers) to another function. Currently I'm using Swing. I do remember to have used Swing for drawing on a canvas, but I still can't find the actual usage. Should I use a canvas, or instead rely on JToggleButtons?
You can simply use a JFrame (or other Swing component) and override the paint(Graphics) method to draw a representation of the boolean matrix (note that in the case of a lightweight component such as JPanel you should override paintComponent(Graphics). This will give you the click-and-drag capability you require (which is very difficult to achieve using a grid of individual Swing components).
As other people have commented, AWT Canvas doesn't give you anything not provided by Swing components and you'll see in the example below that I've used the createBufferStrategy method also present on JFrame to ensure a non-flicker display.
Note that my example is fairly simple in that it toggles every pixel you drag across rather than the click operation establishing whether you're in "paint" mode or "erase" mode and then exclusively applying black or white pixels for the duration of the drag.
public class Grid extends JFrame {
private static final int SCALE = 10; // 1 boolean value == 10 x 10 pixels.
private static final int SIZE = 20;
private boolean[][] matrix = new boolean[SIZE][SIZE];
private boolean painting;
private int lastX = -1;
private int lastY = -1;
public Grid() throws HeadlessException {
setPreferredSize(new Dimension(SIZE * SCALE, SIZE * SCALE));
setResizable(false);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBackground(Color.WHITE);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
painting = true;
tryAdjustValue(e.getPoint());
}
public void mouseReleased(MouseEvent e) {
painting = false;
lastX = -1;
lastY = -1;
}
});
addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
tryAdjustValue(e.getPoint());
}
public void mouseMoved(MouseEvent e) {
tryAdjustValue(e.getPoint());
}
});
}
private void tryAdjustValue(Point pt) {
int newX = pt.x / SCALE;
int newY = pt.y / SCALE;
if (painting && isInRange(newX) && isInRange(newY) && (newX != lastX || newY != lastY)) {
// Only invert "pixel" if we're currently in painting mode, both array indices are valid
// and we're not attempting to adjust the same "pixel" as before (important for drag operations).
matrix[newX][newY] = !matrix[newX][newY];
lastX = newX;
lastY = newY;
repaint();
}
}
private boolean isInRange(int val) {
return val >= 0 && val < SIZE;
}
public void paint(Graphics g) {
super.paint(g);
for (int x=0; x<SIZE; ++x) {
for (int y=0; y<SIZE; ++y) {
if (matrix[x][y]) {
g.fillRect(x * SCALE, y * SCALE, SCALE, SCALE);
}
}
}
}
public static void main(String[] args) {
Grid grid = new Grid();
grid.pack();
grid.setLocationRelativeTo(null);
grid.createBufferStrategy(2);
grid.setVisible(true);
}
}
Why not a simple 20 x 20 grid of JPanel held in a GridLayout(20, 20), and flip the panel's background color if clicked via a MouseListener's mousePressed method. You could hold the panels in a 2D array and query their background color whenever the need arises.
You could also use JLabels for this, but you'd have to remember to turn their opaque properties to true. A JButton would work as well or a JToggleButton, ... the options are almost limitless. I do not recommend though that you use AWT (Canvas) as their's no need to step backwards in functionality since Swing handles this so well.
If you get stuck on this, why not come back and show us your code and we'll better be able to give you more specific help.
Another way to solve this is to use a single JPanel and override its paintComponent method. You could give it an int[][] array to serve as its model, and then in the paintComponent method draw rectangles of whatever color desired based on the state of the model. Then give it a MouseListener that changes the state of the model and calls repaint.
e.g.,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class BlackWhiteGridPanel extends JPanel {
// can have multiple colors if desired
// public static final Color[] COLORS = {Color.black, Color.red, Color.blue, Color.white};
public static final Color[] COLORS = {Color.black, Color.white};
public static final int SIDE = 20;
private static final int BWG_WIDTH = 400;
private static final int BWG_HEIGHT = BWG_WIDTH;
private int[][] model = new int[SIDE][SIDE]; // filled with 0's.
public BlackWhiteGridPanel() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
myMousePressed(e);
}
});
}
private void myMousePressed(MouseEvent e) {
// find relative position of mouse press on grid.
int i = (e.getX() * SIDE) / getWidth();
int j = (e.getY() * SIDE) / getHeight();
int value = model[i][j];
// the model can only hold states allowed by the COLORS array.
// So if only two colors, then value can only be 0 or 1.
value = (value + 1) % COLORS.length;
model[i][j] = value;
repaint();
}
public int[][] getModel() {
// return a copy of model so as not to risk corruption from outside classes
int[][] copy = new int[model.length][model[0].length];
for (int i = 0; i < copy.length; i++) {
System.arraycopy(model[i], 0, copy[i], 0, model[i].length);
}
return copy;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int ht = getHeight();
for (int i = 0; i < model.length; i++) {
for (int j = 0; j < model[i].length; j++) {
Color c = COLORS[model[i][j]];
g.setColor(c);
int x = (i * width) / SIDE;
int y = (j * ht) / SIDE;
int w = ((i + 1) * width) / SIDE - x;
int h = ((j + 1) * ht) / SIDE - y;
g.fillRect(x, y, w, h);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BWG_WIDTH, BWG_HEIGHT);
}
private static void createAndShowGui() {
BlackWhiteGridPanel mainPanel = new BlackWhiteGridPanel();
JFrame frame = new JFrame("BlackWhiteGrid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
i am using java.
i want to draw rectangle based on mousedrag event. if user dragging the mouse, then the rectangle on the applet should increase or decrease basing on current mouse coordinates.
i have the following code.
in the following code i am using [b]SelectionArea[/b] class which extends a canvas on which i am performing drawing operation. i am using [b]image[/b] variable in this class for double buffering to reduce flickering and to save the applet's previous state(i.e drawing content of applet)
but the code is working fine if i draw first rectangle. if i start to draw second rectangle the previously drawn rectangle is disappearing. i want the previously drawn rectangle to be on the screen
can any one tell me how to solve this.
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
/*
* This displays a framed area. When the user drags within
* the area, this program displays a rectangle extending from
* where the user first pressed the mouse button to the current
* cursor location.
*/
public class RectangleDemo extends Applet {
SelectionArea drawingPanel;
Label label;
public void init() {
GridBagLayout gridBag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
setLayout(gridBag);
drawingPanel = new SelectionArea(this);
c.fill = GridBagConstraints.BOTH;
c.weighty = 1.0;
c.gridwidth = GridBagConstraints.REMAINDER; //end row
gridBag.setConstraints(drawingPanel, c);
add(drawingPanel);
label = new Label("Drag within the framed area.");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
gridBag.setConstraints(label, c);
add(label);
drawingPanel.setVisible(true);
validate();
}
public void paint(Graphics g){
drawingPanel.repaint();
}
public void update(Graphics g){
paint(g);
}
}
class SelectionArea extends Canvas implements ActionListener, MouseListener, MouseMotionListener{
Rectangle currentRect;
RectangleDemo controller;
//for double buffering
Image image;
Graphics offscreen;
public SelectionArea(RectangleDemo controller) {
super();
this.controller = controller;
addMouseListener(this);
addMouseMotionListener(this);
}
public void actionPerformed(ActionEvent ae){
repaintoffscreen();
}
public void repaintoffscreen(){
image = createImage(this.getWidth(), this.getHeight());
offscreen = image.getGraphics();
Dimension d = getSize();
if(currentRect != null){
Rectangle box = getDrawableRect(currentRect, d);
//Draw the box outline.
offscreen.drawRect(box.x, box.y, box.width - 1, box.height - 1);
//repaint();
}
}
public void mouseEntered(MouseEvent me) {}
public void mouseExited(MouseEvent me){ }
public void mouseClicked(MouseEvent me){}
public void mouseMoved(MouseEvent me){}
public void mousePressed(MouseEvent me) {
currentRect = new Rectangle(me.getX(), me.getY(), 0, 0);
repaintoffscreen();
}
public void mouseDragged(MouseEvent me) {
System.out.println("here in dragged()");
currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
repaintoffscreen();
repaint();
}
public void mouseReleased(MouseEvent me) {
currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
repaintoffscreen();
repaint();
}
public void update(Graphics g){
paint(g);
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
}
Rectangle getDrawableRect(Rectangle originalRect, Dimension drawingArea) {
int x = originalRect.x;
int y = originalRect.y;
int width = originalRect.width;
int height = originalRect.height;
//Make sure rectangle width and height are positive.
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
//The rectangle shouldn't extend past the drawing area.
if ((x + width) > drawingArea.width) {
width = drawingArea.width - x;
}
if ((y + height) > drawingArea.height) {
height = drawingArea.height - y;
}
return new Rectangle(x, y, width, height);
}
}
also if i run this code on full screen mode then i am seeing that the rectangle is appering on screen only after i released the mouse. but i want the rectangle to be on the screen while dragging the mouse and it should change it's dimension according to the current mouse coordinates.
can any one help me pls.
homework?
basically what you need to do is:
on mouse down keep the mouse-down coordinates and repaint
on mouse move keep current mouse coordinates and repaint
on mouse up, nullify the mouse-down coordinates to indicate there is no rect, and repaint.
on paint, draw background and then rect between mousedown and cur-mouse coordinates.
if you don't want to keep a background image, you can do a trick with the Graphics xor function, drawing the same rect twice will erase the old rect, so you can use it to restore the old image straight on the graphics object.
Edit: code xor usage sample:
public void paint(Graphics g)
{
g.setXORMode(Color.black);
// draw old rect if there is one. this will erase it
// draw new rect, this will draw xored
g.setDrawMode(); // restore normal draw mode
}
Xor has the an interesting property:
xor(xor(x)) = x
so xoring the same pixel twice restores it's original color.
There are a couple issues that need to be addressed.
First, regarding only one rectangle can be drawn, this is due to the design of your program. In your code, whenever the repaintoffscreen method is called, the currectRect field is used to draw a rectangle. However, there is no provision to keep holding onto rectangles which were made in the past.
One way to keep a hold of past rectangles would be perhaps to make another field which is, for example, a List<Rectangle> which is used to store past rectangles. Then, when the mouse is released, add the current rectangle to that list.
Then, in order for all rectangles, currentRect and past rectangles to appear, repaintoffscreen will need to not only perform getDrawableRect and offscreen.drawRect using the currentRect but also with the past rectangles which are stored in the List<Rectangle>. (Hint, use a for loop to iterate through the list.)
Second, regarding the rectangle not appearing until after releasing the mouse button, rather than using the mouseDragged method, maybe using the mouseMoved method along with a check to see that the mouse button is depressed may be a workaround. (I think I've also had trouble dealing with the mouseDragged method in the past.)
The MouseEvent passed into the mouseMoved method can be used to check if a button is depressed by the getButton method:
public void mouseMoved(MouseEvent e)
{
// Check if button1 is pressed.
if (e.getButton() == MouseEvent.BUTTON1)
{
// Perform sizing of rectangle and off-screen drawing, and repaint.
}
}
My question was about create a select rectangle invert mouse click position, but, in the end I got make this with this method:
... //to set the selection area
private int iniSelX;
private int iniSelY;
private int endSelX;
private int endSelY;
private JPanel myJPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.drawLine(260, 5, 260, 260);
g.setColor(Color.BLUE);
//verify if go draw the rectangle
if (iniSelX != 0 || endSelX != 0) {
boolean revertX = iniSelX < endSelX;
boolean revertY = iniSelY < endSelY;
//Simple way
//g.drawRect(iniSelX, iniSelY, endSelX - iniSelX, endSelY - iniSelY);
//reverse way
g.drawRect(revertX ? iniSelX : endSelX, revertY ? iniSelY : endSelY,
revertX ? endSelX - iniSelX : iniSelX - endSelX, revertY ? endSelY - iniSelY : iniSelY - endSelY);
}
}
}; ...
addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent m) {
//update selection area
endSelX = m.getX();
endSelY = m.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent m) {
repaint();
}
});
addMouseListener(new MouseListener() {
...
#Override
public void mousePressed(MouseEvent e) {
//start drawing the selection
iniSelX = e.getX() - 15;
iniSelY = e.getY() - 20;
}
#Override
public void mouseReleased(MouseEvent e) {
//start drawing the selection
iniSelX = 0;
iniSelY = 0;
endSelX = 0;
endSelY = 0;
}
...
});
}
public void log() {
System.out.println("iniSelX" + iniSelX);
System.out.println("iniSelY" + iniSelY);
System.out.println("endSelX" + endSelX);
System.out.println("endSelY" + endSelY);
} ...
I hope this is useful.