Repaint doesn't erase the background (sometimes) - java

I put a aintComponent() method in a JPanel. This method draws a tree using Graphics.drawLine().
I put a JButton from which a Listener is used to zoom on this tree. At the end I use the repaint() method, and my tree is repainted bigger, so no problem there.
// Add Listeners on Zooming buttons
bPlus.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
Node.setZoom(1);
repaint();
}
});
However, I used a MouseMotionListener for moving this tree inside its JPanel.
Then when I call repaint(), it does not erase the previous printed trees, so I end up with duplicated trees.
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
if(mouseHolded) {
x += e.getX() - mouseX;
mouseX = e.getX();
y += e.getY() - mouseY;
mouseY = e.getY();
repaint(); // <===
}
}
}
);
What am I doing wrong ? While the previous trees will be erased when I use the repaint() for zooming, why wont it do so when I move the tree?

Related

Java - Issues with MouseListener Coordinates

This is a sample of a larger program used to draw rectangles. A rectangle object is drawn on screen already. what I am attempting to do with the mousedPressed object is get the coordinates of the mouse, and compare it with that of the rectangle's (which are initially set to (100, 100, 200, 200)). The mouseDragged event should take the coordinates obtained in the mousePressed section and run code with them; however, it seems that no matter what, the coordinates are always 0 in the mouseDragged event. I added test code (as marked) to each event to simply change the color of the square when the coordinates are at a certain point. The test code in mousedPressed works just fine, but the test code in mouseDragged can never run. I have tried with many, many different values, and determined that the coordinates will always equal 0 in the mouseDragged event. If someone could help me understand why the int values are not being passed, despite referencing the same variable, I would appreciate it.
public class PointListener implements MouseListener, MouseMotionListener {
private int mousex, mousey;
//in case that a user presses using a mouse,
//record the point where it was pressed.
public void mousePressed (MouseEvent event) {
//getPoint() returns a Point object containing the x & y-coordinates
currentPoint = event.getPoint();
mousex = event.getPoint().x;
mousey = event.getPoint().y;
repaint();
if (mousex > 250) {
currentColor = Color.GREEN;
repaint();
} //The test, which can easily be triggered as expected
}
public void mouseClicked(MouseEvent event) {}
public void mouseReleased(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mouseMoved(MouseEvent event) {}
public void mouseDragged(MouseEvent event) {
if (95 < mousex && mousex < 105) {
currentColor = Color.BLUE;
repaint();
}
if (mousex > 150) {
currentColor = Color.RED;
repaint();
} // The test, which can never be triggered
} //mouseDragged()
} //PointListener

Drawing a straight line drag and drop in class Graphics2D

How can I draw a straight line on a drag and drop, that there was only one line and moved around?
My code:
panelPaint.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
point1 = e.getPoint();
}
});
panelPaint.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
point2 = e.getPoint();
g2.draw(new Line2D.Double(point1, point2));
panelPaint.repaint();
}
});
Current effect:
Looks like you are drawing to a BufferedImage or something. You should not be doing painting using a Graphics object in the mouse event.
Instead you should be doing custom painting on a panel and override the paintCompnent(...) method. Your paintComponent() method should look like:
#Override
protected void paintComponent(Grapahics g)
{
super.paintComponent(g);
// custom painting here
g.drawLine(...);
}
The first statement will clear the background. The next statement will draw the line between your starting/ending points.
Check out Custom Painting Approaches for more information and examples. The example will dynamically draw a Rectangle as you drag the mouse, but the concept is the same for a single line.

Keep mousePressed active after one click

So what I want to do is after one click is keep the mousePressed method 'on' even though im not holding it down myself. Then after another click it will turn it 'off'
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// save coord x,y when mouse is pressed
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
// coord x,y when drag mouse
currentX = e.getX();
currentY = e.getY();
if (g2 != null) {
// draw oval if g2 context not null
g2.drawOval(oldX, oldY, width, height);
g2.fillOval(oldX, oldY, width, height);
// refresh draw area to repaint
repaint();
// store current coords x,y as olds x,y
oldX = currentX;
oldY = currentY;
}
}
});
Handle the mousePressed() event. Then keep a variable in your class (lets say "clickCounter") that you increment every time the event is generated.
Then you will need to handle the mouseMoved() event to know when the mouse is moving.
So now your logic in the mouseMoved() event can check if the variable is odd, which would indicate the mouse has just been clicked:
if (clickCounter % 2 == 1)
{
add your logic here
}
Or you could keep a boolean variable that you toggle off/on for every mouse click.

How to draw lines (segments) using the arrow keys?

I'm trying to resolve an excercise about drawing lines using the arrow keys. The line starts from the center and draws toward east, west, north or south when one of the arrow keys is pressed. The code works only in east or west direction and not in a north or south and that is my problem!!
Could someone give me an idea about this matter? Thanks.
Here's the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawingLinesUsingTheArrowKeys extends JFrame {
// Create a panel
private LinesUsingTheArrowKeys LinesUsingTheArrowKeys = new LinesUsingTheArrowKeys();
public DrawingLinesUsingTheArrowKeys() {
add(LinesUsingTheArrowKeys);
/*
* A component (keyboard) must be focused for its can receive the
* KeyEvent To make a component focusable , set its focusable property
* to true
*/
LinesUsingTheArrowKeys.setFocusable(true);
}
public static void main(String[] args) {
JFrame frame = new DrawingLinesUsingTheArrowKeys();
frame.setTitle("Drawing Lines Using The Arrow Keys");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setVisible(true);
}
// Inner class: LinesUsingTheArrowKeys (keyboardPanel) for receiving key
// input
static class LinesUsingTheArrowKeys extends JPanel {
private int x = 200;
private int y = 100;
private int x1 = x + 10;
private int y1 = y;
// register listener
public LinesUsingTheArrowKeys() {
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
// x1 += y1;
y1 += 10;
repaint();
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
y1 -= 10;
repaint();
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x1 += 10;
repaint();
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
x1 -= 10;
repaint();
}
}
});
}
// Draw the line(s)
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(x, y, x1, y1);
}
}
}
Your first mistake is using a KeyListener. KeyListener will only respond to key events when the component is registered to is focusable AND has focus.
Your second mistake is not providing size hints for your LinesUsingTheArrowKeys class, so the layout manager has some idea of how big your component should be.
You third mistake is assuming that painting in Swing is accumative, which it is not. Painting in Swing is destructive. That is, each time paintComponent is called, the expectation is that the Graphics context will be cleared and what ever needs to be painted will be completely regenerated.
Take a look at:
How to use Key Bindings
Performing Custom Painting
2D Graphics
Painting in AWT and Swing...because every body that wants to do painting in Swing should know how this works
Basically, a better solution would be to have a List of Point, which the paintComponent would simply either generate a Line between them or even maybe some kind of Polygon or Shape. You would then simply add a new Point to this List as you require and then repaint the component

how to draw rectangle on java applet using mouse drag event

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.

Categories

Resources