This is a current problem I am facing for a game. It is a game of Tic-Tac-Toe the user and a friend can play together. I'm not finished yet, but this is what I've got. Any time the window is minimized or covered up by another window the portion of the graphics drawn (X and O) get deleted. I don't really know what to do about this, it would be nice to have a way where the drawing does not get deleted. My paintComponent() method for my main class just sets up the design of the board.
Any help appreciated, thank you!
private class DrawXO implements MouseListener {
public void mousePressed(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
Graphics gContext = getGraphics();
Graphics2D graphics = (Graphics2D) gContext;
graphics.setStroke(new BasicStroke(8));
if (playerOneTurn) {
Player1.drawCircle(gContext, x, y );
checkForWinner();
if(playerOneWins) {
System.out.println("Player one wins");
}
playerTwoTurn = false;
} else {
// Still need to implement drawing for this ~
checkForWinner();
}
}
public void mouseExited(MouseEvent evt) {}
public void mouseEntered(MouseEvent evt) {}
public void mouseClicked(MouseEvent evt) {}
public void mouseReleased(MouseEvent evt) {}
}
Don't use getGraphics();
You need to learn how custom painting is done in Swing. Run through Performing Custom Painting. You will notice that paint required the use of a paintComponent method (in your JPanel or JComponent class) which takes in a Graphics (created for you) context that you use to perform your custom painting. All painting should be done within that context.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
// do painting here
}
Note: Never call this method explicitly, it is automatically called
To update the graphics, you will make some update to some paint variables, then call repaint(). Maybe something like:
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.fillRect(x, y, width, height);
}
If you want to add/draw multiple object, say with the click of a mouse, then keep a List of objects and iterate through the list int the paintComponent method. When the mouse is clicked, add another object to the list and repaint. Something like
List<Rectangle2D> rectangles;
...
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
rectangles.add(new Rectangle2d.Double(x, y, width, height);
repaint();
}
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (Rectangle2D rect: rectangles) {
g2.fill(rect);
}
}
Related
I faced the problem that I can't write an animation for color change at the Rectangle of JComponent. I use Java 8 and Swing. This animation is supposed to be slow, for any amount of seconds I would like to set. Nit: It feels like the base which I need to wrote his thing is definetly timer.
Here is the code snippet which describes my component's state:
class PBtn extends JComponent {
private LinkedList<MyBtn> myBtns = new LinkedList<>();
LinkedList<MyBtn> getMyBtns(){
return myBtns;
}
static class MyBtn extends Rectangle {
String name;
Color color;
MyBtn(int x, int y, int width, int height, String name, Color color) {
this.setBounds(x, y, width, height);
this.color = color;
}
}
void addBtn(int x, int y, int width, int height, String name, Color color) {
MyBtn myBtn = new MyBtn(x, y, width, height, name, color);
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {}
#Override
public void mouseMoved(MouseEvent e) {
if (myBtn.contains(e.getPoint())) {
setToolTipText(name);
}
ToolTipManager.sharedInstance().mouseMoved(e);
}
});
myBtns.add(myBtn);
repaint();
}
void clearBtns() {
myBtns.clear();
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics2D = (Graphics2D) g;
myBtns.forEach(n -> {
graphics2D.setColor(n.color);
graphics2D.draw(n);
graphics2D.fill(n);
});
}
I tried to use the interpolation-based animation library bu it didn't help. Can you please give me suggestions how to write this code from scratch? Thanks!
private class Board extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w=getWidth();
int h=getHeight();
Graphics2D g2d = (Graphics2D) g;
The following code draws the grid:
g2d.setPaint(Color.WHITE);
g2d.fill(new Rectangle2D.Double(0, 0, w, h));
g2d.setPaint(Color.BLACK);
g2d.setStroke(new BasicStroke(4));
g2d.draw(new Line2D.Double(0, h/3, w, h/3));
g2d.draw(new Line2D.Double(0, h*2/3, w, h*2/3));
g2d.draw(new Line2D.Double(w/3, 0, w/3, h));
g2d.draw(new Line2D.Double(w*2/3, 0, w*2/3, h));
The following code draws circles and xs by visiting elements in the array List:
for(Shape shape : shapes){
g2d.setPaint(Color.BLUE);
g2d.draw(shape);
}
}
}
public void addMouseListener(MouseListener ml){
// HOW CAN I ADD A MOUSE LISTENER HERE?
}
You can create a class that implements the MouseListener interface as so:
public class CustomMouseListener implements MouseListener{
public void mouseClicked(MouseEvent e) {
statusLabel.setText("Mouse Clicked: ("+e.getX()+", "+e.getY() +")");
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
You want define each of those methods based on the action the method represents (which are self explanatory). The MouseEvent object will have all the info you need related to the mouse (ex. x and y position of mouse).
Now you want to add this new MouseListener to a JPanel (which in this case is your Board class):
//JPanel panel = new JPanel();
Board panel = new Board();
panel.addMouseListener(new CustomMouseListener());
Source
Create your class which implements MouseListener, and pass it by addMouseListener method... ?
http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
you need to make the class implements MouseListener.
you need to add the unimplements methods.
and here you go :)
you got few new methods:
public void mouseClicked(MouseEvent e) // method calls when mouse clicked
public void mousePressed(MouseEvent e) // method calls when mouse pressed
public void mouseReleased(MouseEvent e) // method calls when mouse relesed
public void mouseEntered(MouseEvent e) // method calls when the mouse curser getting into the component's geometry
public void mouseExited(MouseEvent e) // method calls when mouse curser getting out of the component's geometry
hope it helped you :)
i'm trying to write a jigsaw puzzle application where an image is cut in pieces, scrambled, and the user have to rearrange them with drag&drop to reassemble the original image. (something like this: http://www.jigzone.com/puzzles/74055D549FF0?z=5).
i have to write this in java with Graphics2d.
so, at first i'm trying to make some kind of component which can show a part of the image (a rectangle for now), and can be dragged with mouse.
the code below works well when there is only one one such component. the problem is, when i add the second component, the first one is no longer visible.
i'm really stuck here. i have a feeling i'm missing something really basic. or maybe i'm on a wrong way. any help will be greatly appreciated.
edit: i changed a bit the code according to suggestions, however, still not working as expected.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
public class GraphicDragAndDrop extends JPanel {
Rectangle rect;
Image img;
public GraphicDragAndDrop(String imgFile, int x0, int y0){
rect = new Rectangle(x0, y0, 150, 75);
img = new ImageIcon(imgFile).getImage();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setClip(rect);
int x = rect.x;
int y = rect.y;
g2d.drawImage(img, x, y, this);
}
public void setRect(int x, int y) {
rect.setLocation(x, y);
repaint();
}
public static void main(String[] args) {
// first piece
GraphicDragAndDrop piece1 = new GraphicDragAndDrop("a.png", 0, 0);
piece1.setRect(0, 0);
new GraphicDragController(piece1);
// second piece --> only this will be visible
GraphicDragAndDrop piece2 = new GraphicDragAndDrop("a.png", 200, 200);
//GraphicDragAndDrop piece2 = new GraphicDragAndDrop("b.png", 200, 200); // does'n work either
piece2.setRect(150, 150);
new GraphicDragController(piece2);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(piece1);
f.add(piece2);
f.setSize(500,500);
f.setLocation(300,100);
f.setVisible(true);
}
}
class GraphicDragController extends MouseInputAdapter {
GraphicDragAndDrop component;
Point offset = new Point();
boolean dragging = false;
public GraphicDragController(GraphicDragAndDrop gdad) {
component = gdad;
component.addMouseListener(this);
component.addMouseMotionListener(this);
}
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
Rectangle r = component.rect;
if(r.contains(p)) {
offset.x = p.x - r.x;
offset.y = p.y - r.y;
dragging = true;
}
}
public void mouseReleased(MouseEvent e) {
dragging = false;
}
public void mouseDragged(MouseEvent e) {
if(dragging) {
int x = e.getX() - offset.x;
int y = e.getY() - offset.y;
component.setRect(x, y);
}
}
}
Your code above is written to draw only one image:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setClip(rect);
int x = rect.x;
int y = rect.y;
// here
g2d.drawImage(new ImageIcon("a.png").getImage(), x, y, this);
}
If you need to draw more than one image, then consider creating a collection of images and iterating through the collection in paintComponent using a for loop:
also, never read in the image from within paintComponent since this method should be lean, mean and fast, and should concern itself with painting only. Also, there's no need to read the image in each time your program has to draw it as that's very inefficient and will slow the program unnecessarily. Instead read the image in once in the constructor or a similar init method.
For example,
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Image img: myImageCollection) {
g2d.drawImage(img, 0, 0, this);
}
}
Edit
You state:
also, my plan was to have more objects of GraphicDragAndDrop class, each of them showing a different piece of the original image. is my approach wrong?
You could use components, but I have a feeling that it would be easy to drag images. I think it would be easier to rotate them for instance if you want your program to have this functionality. If not, though then sure use a component, but if you go this route, I would recommend using a JLabel and simply setting its ImageIcon rather than dragging JPanels.
I am trying to allow the user to select what shape they want to draw on my GUI. I have a selection of buttons: circle, square and rectangle. My actionListener works as it prints a string to my console, but it won't show the shape on my GUI. How can I use the actionCommand to draw that shape on my panel.
public void paintComponent(Graphics g) {
g2D = (Graphics2D) g;
//Rectangle2D rect = new Rectangle2D.Double(x, y, x2-x, y2-y);
//g2D.draw(rect);
repaint();
}
public void actionPerformed(ActionEvent arg0) {
if(arg0.getActionCommand().equals("Rect")){
System.out.println("hello");
Rectangle2D rect = new Rectangle2D.Double(x, y, x2-x, y2-y);
g2D.draw(rect); //can only be accessed within paintComponent method
repaint();
}
If you firstly paint your rectangle and then ask for a repaint the rectangle will disappear.
You should store your new shape in a temp variable and render it inside paintComponent.
private Rectangle2D temp;
// inside the actionPerformed
temp = new Rectangle2D.Double(x, y, x2-x, y2-y);
repaint();
// inside the paintComponent
if(temp != null) {
g2D.draw(temp);
}
Make the rect to be field nto local variable. In the actionPerformed create proper rect and call repaint(). Then paintComponent() will be called. It should be like this
public void paintComponent(Graphics g) {
g2D = (Graphics2D) g;
g2D.draw(rect);
}
I am using Graphics2D to draw shapes e.g. rectangles. However, I have got the code working and it draws rectangles on my GUI, but the accuracy is way off and not the size I drag it to be (the get methods return ints by default). Also it seems like the shape size and the number of shapes is random every time I click on the panel.
int a,b,a2,b2;
public void MyPaintMethod(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
Rectangle2D rectangle = new Rectangle2D.Double(a,b,a2,b2);
g2D.draw(rectangle);
repaint();
}
public void mousePressed(MouseEvent e) {
// ML
a = e.getX();
b = e.getY();
}
public void mouseReleased(MouseEvent e) {
// ML
a2 = e.getX();
b2 = e.getY();
}
Rectangle2D is constructed with (x,y,width,height). You're giving it (x1,y1,x2,y2). Try:
Rectangle2D rectangle = new Rectangle2D.Double(a, b, a2-a, b2-b);