I'm trying to create a program that able the user to drag and drop the oval around in the space. I was able to drag and drop but after I tried do it again on the second run, the oval jump all over the places. I was wondering if anyone know why this happen? Am i missing something? Thank you
public class MoveOval extends JFrame {
private Ellipse2D node = new Ellipse2D.Float(200,200,80,120);
private Point offset;
private int preX,preY;
private Image dbImage;
private Graphics dbg;
Adapter ma = new Adapter();
public static void main(String args[]){
JFrame frame = new MoveOval();
frame.setSize(600,600);
frame.setVisible(true);
}
public MoveOval(){
super("Move Oval");
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(ma);
addMouseMotionListener(ma);
}
private class Adapter extends MouseAdapter{
public void mousePressed(MouseEvent e){
if(node.contains(e.getPoint())){
preX = node.getBounds().x-e.getX();
preY = node.getBounds().y-e.getX();
offset = new Point(preX, preY);
}
}
public void mouseDragged(MouseEvent e){
if(node.contains(e.getPoint())){
updateLocation(e);
}
}
public void mouseReleased(MouseEvent e) {
offset=null;
}
}
public void updateLocation(MouseEvent e){
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
Rectangle bounds = node.getBounds();
bounds.setLocation(to);
node.setFrame(bounds);
repaint();
}
public void paint(Graphics g){
dbImage=createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g){
Graphics2D gd = (Graphics2D)g.create();
gd.setColor(Color.blue);
gd.fill(node);
}
}
Actually a very simple mistake and easy to fix.
public void mousePressed(MouseEvent e){
if(node.contains(e.getPoint())){
preX = node.getBounds().x-e.getX();
preY = node.getBounds().y-e.getX(); // <- That's the bad guy.
offset = new Point(preX, preY);
}
}
It has to be -e.getY() not -e.getX().
Related
When i try to set value to BufferedImage called dinoImage in Dino.java in a constructor i just get a blank screen every time (second picture) because repaint() is not being called, but if i set it to null it is working just fine but without this image (first picture).
No exceptions, everything seems fine in this code, this problem appears when i try to set value to this field using static method getImage of Resource.java which uses this line of code ImageIO.read(new File(path)) and it causes that repaint() is not being called, i guess this line causes such weird behavior but i dont know how to solve it.
Main.java
public class Main {
public static void main(String[] args) {
GameWindow gameWindow = new GameWindow();
gameWindow.startGame();
}
}
GameWindow.java
public class GameWindow extends JFrame {
private GameScreen gameScreen;
public GameWindow() {
super("Runner");
setSize(1000, 500);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameScreen = new GameScreen();
add(gameScreen);
}
public void startGame() {
gameScreen.startThread();
}
}
GameScreen.java
public class GameScreen extends JPanel implements Runnable, KeyListener {
private Thread thread;
public static final double GRAVITY = 0.1;
public static final int GROUND_Y = 300;
private Dino dino;
public GameScreen() {
thread = new Thread(this);
dino = new Dino();
}
public void startThread() {
thread.start();
}
#Override
public void run() {
while(true) {
try {
Thread.sleep(20);
dino.updatePosition();
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// g.clearRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawLine(0, GROUND_Y, getWidth(), GROUND_Y);
dino.draw(g);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Key Pressed");
dino.jump();
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("Key Released");
}
}
Dino.java
public class Dino {
private double x = 100;
private double y = 100;
private double speedY = 0;
private BufferedImage dinoImage;
public Dino() {
dinoImage = getImage("data/dino.png");
}
public void updatePosition() {
if(y + speedY >= GROUND_Y - 100) {
speedY = 0;
y = GROUND_Y - 100;
} else {
speedY += GRAVITY;
y += speedY;
}
}
public void jump() {
if(y == GROUND_Y - 100) {
speedY = -5;
y += speedY;
}
}
public void draw(Graphics g) {
g.setColor(Color.BLACK);
g.drawRect((int)x, (int)y, 100, 100);
g.drawImage(dinoImage, (int)x, (int)y, null);
}
}
Resource.java
public class Resource {
public static BufferedImage getImage(String path) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
}
setSize(1000, 500);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameScreen = new GameScreen();
add(gameScreen);
Swing components need to be added to the frame BEFORE the frame is made visible. Otherwise the panel has a size of (0, 0) and there is nothing to paint.
The code should be something like:
gameScreen = new GameScreen();
add(gameScreen);
setSize(1000, 500);
setVisible(true);
So I'm painting a couple custom JComponets in a grid. like a simple battleship game. However I wanted to add a transparency to them. It renders in great the first time but if I call repaint then the alpha level goes away. I can then resize the frame and it automatically updates it and has the correct transparency.
public class Cell extends JComponent implements MouseListener{
public static int CELL_SIZE=50;
private boolean hit = false;
private boolean hasShip = false;
private GridPoint location;
private boolean highlighted = false;
private GameBoard parent;
public static final Color HIT = new Color(Color.RED.getRed(),Color.RED.getGreen(),Color.RED.getBlue(),123);
public static final Color MISS = new Color(80,100,200,123);
public static final Color DEFAULT = new Color(0,0,(150),123);
public static final Color HIGHLIGHT = new Color(255,255,255,50);
public static final Color BORDER = new Color(0,0,40,123);
public Cell()
{
setSize(Cell.CELL_SIZE,Cell.CELL_SIZE);
}
public Cell(GridPoint g, GameBoard p)
{
setOpaque(false);
addMouseListener(this);
parent = p;
setGridLocation(g);
setLocation(CELL_SIZE*location.getX(), CELL_SIZE*location.getY());
setSize(Cell.CELL_SIZE,Cell.CELL_SIZE);
}
public void paintComponent(Graphics g)
{
if(hit == false)
{
if(highlighted)
{
g.setColor(HIGHLIGHT);
g.fillRect(0, 0, Cell.CELL_SIZE, Cell.CELL_SIZE);
}
g.setColor(DEFAULT);
g.fillRect(0, 0, Cell.CELL_SIZE, Cell.CELL_SIZE);
}
else
{
if(hasShip)
{
g.setColor(Cell.HIT);
g.fillRect(0, 0, Cell.CELL_SIZE, Cell.CELL_SIZE);
}
else
{
g.setColor(Cell.MISS);
g.fillRect(0, 0, Cell.CELL_SIZE, Cell.CELL_SIZE);
}
}
g.setColor(Cell.BORDER);
g.drawRect(0, 0, Cell.CELL_SIZE, Cell.CELL_SIZE);
}
public GridPoint getGridLocation() {
return location;
}
public void setGridLocation(GridPoint location) {
this.location = location;
}
#Override
public void mouseClicked(MouseEvent e) {
hit = true;
repaint();
}
#Override
public void mouseEntered(MouseEvent e)
{
highlighted = true;
repaint();
}
#Override
public void mouseExited(MouseEvent e)
{
highlighted = false;
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
}
If you add the following lines to start of your paintComponent method, it should work.
float alpha = 0.2f;
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
alpha 0.0f means completely transparent, 1.0f means not transparent.
Okay I got the answer. Sorry it was a bug in some other area of code. for some reason the tiles were rendering under the JPanels Background Color. All I had to do was set the JPanel in the Back To Transparent.
I am only posting the relevant code. I am fairly new to java and right now I am building a program that will allow the user to use a draw method. However, when I click the button for drawing in the interface, it automatically generates a random line anywhere on the page and does not allow user interaction. I think the error is occurring in my mouseListener method, but I am not sure as this is my first time doing anything like this. Any help would be greatly appreciated. Thank you!
Also, the error that prints out is: Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
public class SimplePaint extends JFrame {
JButton drawing = new JButton();
Line2D draw = new Line2D.Float();
Point start = null;
Point end = null;
public SimplePaint() {
JPanel panel = new JPanel() {
{
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
start = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
start = e.getPoint();
//start = null;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
end = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
end = e.getPoint();
repaint();
}
});
}
};
drawing.setText("Draw");
panel.add(drawing);
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == drawing) {
draw = new Line2D.Float(start.x, start.y, end.x, end.y);
}
repaint();
}
};
drawing.addActionListener(actionListener);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
Line2D line = new Line2D.Float(0, 250, 2000, 300);
g2.draw(draw);
}
}
I've got a problem with connecting two classes:
This is the code with basic operations on JPanel:
public class Drawing extends JPanel {
Pencil pencil;
Tool lines;
Tool paintbrush;
public Drawing() {
setBackground(Color.WHITE);
pencil = new Pencil();
addMouseListener(pencil);
addMouseMotionListener(pencil);
addMouseListener(lines);
addMouseMotionListener(lines);
addMouseListener(paintbrush);
addMouseMotionListener(paintbrush);
this.repaint();
}
#Override
public void paintComponent(Graphics g) {
pencil.paintComponent(g);
super.paintComponent(g);
}
}
and this is a specific tool called Pencil, to draw on above JPanel:
public class Pencil implements MouseListener, MouseMotionListener {
private int x, y;
private ArrayList<ArrayList<Point>> pointsList = new ArrayList<ArrayList<Point>>();
private ArrayList<Color> Colors = new ArrayList<Color>();
public Pencil() {
System.out.println("PENCIL SELECTED!");
}
public void paintComponent(Graphics g) {
// super.paintComponent(g);
((Graphics2D) g).setStroke(new BasicStroke(2));
for(int i=0; i<pointsList.size(); i++) {
ArrayList<Point> Points = pointsList.get(i);
Color pencilColor = Colors.get(i);
g.setColor(pencilColor);
for(int j=0; j<Points.size()-1; j++) {
Point p1, p2 = null;
p1 = Points.get(j);
p2 = Points.get(j+1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
#Override
public void mousePressed(MouseEvent e) {
ArrayList<Point> Points = new ArrayList<Point>();
Color pencilColor = GUI.getColour();
Colors.add(pencilColor);
pointsList.add(Points);
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
Compiler says, Pencil class does not have repaint() method.
I have no idea, how to connect these two classes...
Thanks for help in advance! :)
As the error said, the Pencil class has no repaint() method and it doesn't inherit a repaint() method from a superclass, as the Drawing class does.
One way to solve this would be to pass the Drawing instance to the Pencil instance.
like this:
public Drawing() {
setBackground(Color.WHITE);
pencil = new Pencil(this); // send the instance to `Pencil` by constructor.
addMouseListener(pencil);
addMouseMotionListener(pencil);
addMouseListener(lines);
addMouseMotionListener(lines);
addMouseListener(paintbrush);
addMouseMotionListener(paintbrush);
this.repaint();
}
In Pencil :
private Drawing drawingBoard;
public Pencil(Drawing drawingBoard) {
System.out.println("PENCIL SELECTED!");
this.drawingBoard = drawingBoard;
}
Now when you call repaint(), call it like this: drawingBoard.repaint()
I have some code to draw rectangles. It's used to draw rectangles on a JPanel, to mark boundaries of widgets. Here the code first, after that I'll explain my problem cq. question.
First off, I have a class (WidgetDrawingPanel) which extends JPanel.
public WidgetDrawingPanel(int width, int height) {
/*To make things visible at least*/
widgets.add(new Widget(10,10,100,100, WidgetType.TextField));
widgets.add(new Widget(50,50,100,200, WidgetType.TextField));
this.width = width;
this.height = height;
this.setBackground(Color.BLUE);
addListener(); //adds both MouseMotionListener and MouseListener
}
Below you'll see me reference ch a lot. This is a CoordinateHolder, which holds start and current coordinates of my mouse movement.
private void addListener() {
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent arg0) {
ch.currentX = arg0.getX();
ch.currentY = arg0.getY();
System.out.println("dragging " + ch.currentX + ","+ch.currentY);
WidgetDrawingPanel.this.repaint();
}
});
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent event) {
ch.endX = event.getX();
ch.endY = event.getY();
try {
checkCoords();
} catch (OutsidePanelException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "drawn Outside Panel");
}
}
#Override
public void mousePressed(MouseEvent event) {
ch = new CoordinateHolder(event.getX(), event.getY());
}
});
}
and, finally, the paintComponent(Grapics) method. There's loop through Widgets, which are actually just already drawn Rects (x, y, w, h attributes), but which a little more information, which is not useful in the drawing part of the application. Everytime you release the mouse, the CoordinateHolder is converted into a Widget, and added to widgets.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Paint");
g.setColor(Color.BLUE);
g.fillRect(0, 0, width, height); //making the whole panel blue
g.setColor(Color.RED);
Graphics2D g2 = (Graphics2D)g;
g2.setStroke(new BasicStroke(3));
for (Widget w : widgets) {
g.drawRect(w.getX(), w.getY(), w.getW(), w.getH());
}
if (ch != null)
g.drawRect(ch.startX, ch.startY, ch.currentX - ch.startX, ch.currentY - ch.startY);
}
This code is working, but I suspect this is highly inefficient and inperformant, as above code continually refreshes the JPanel on mouse drag, which is, say, once every 10ms? I suppose it'll get slow really soon, especially when the user creates a heck of a lot rectangles (which are also continally redrawn, as seen in painComponent(Graphics)).
Question cq. Problem
Is there a better, less resource consuming method, where the user can drag rectangles smoothly?
I read an answer to this Drag rectangle on JFrame in Java, but the author of that answer seems to do it the same as me. But again, that's way inperformant, right? Or should computers be easily able to redraw the component continually, and is this actually a valid approach?
To show lots of non-changing background shapes, draw them to a BufferedImage and then show that BufferedImage in the paintComponent(...) method. So while a shape is being drawn, draw it in paintComponent(...) but once the shape is done being drawn, perhaps on mouseRelease, then draw it in the background BufferedImage.
Note that what will slow your current drawing code the most may be your debugging SOP statements, but I assume that these will be removed from the finished code.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color DRAWING_COLOR = new Color(255, 100, 200);
private static final Color FINAL_DRAWING_COLOR = Color.red;
private BufferedImage backgroundImg;
private Point startPt = null;
private Point endPt = null;
private Point currentPt = null;
public DrawingPanel() {
backgroundImg = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics g = backgroundImg.getGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, PREF_W, PREF_H);
g.dispose();
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
if (startPt != null && currentPt != null) {
g.setColor(DRAWING_COLOR);
int x = Math.min(startPt.x, currentPt.x);
int y = Math.min(startPt.y, currentPt.y);
int width = Math.abs(startPt.x - currentPt.x);
int height = Math.abs(startPt.y - currentPt.y);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void drawToBackground() {
Graphics g = backgroundImg.getGraphics();
g.setColor(FINAL_DRAWING_COLOR);
int x = Math.min(startPt.x, endPt.x);
int y = Math.min(startPt.y, endPt.y);
int width = Math.abs(startPt.x - endPt.x);
int height = Math.abs(startPt.y - endPt.y);
g.drawRect(x, y, width, height);
g.dispose();
startPt = null;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent mEvt) {
currentPt = mEvt.getPoint();
DrawingPanel.this.repaint();
}
#Override
public void mouseReleased(MouseEvent mEvt) {
endPt = mEvt.getPoint();
currentPt = null;
drawToBackground();
}
#Override
public void mousePressed(MouseEvent mEvt) {
startPt = mEvt.getPoint();
}
}
private static void createAndShowGui() {
DrawingPanel mainPanel = new DrawingPanel();
JFrame frame = new JFrame("Drawing Panel");
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();
}
});
}
}