We recently started using Applet and doing stuff with it, so the last class was on drawing lines. So after writing a successful code i changed a line of code for some reason unbeknownst to me and now it does not draw a line, rather draws a weird ray sort of.
Here is the code so any help would be appreciated.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class SimplePaint extends Applet {
private int lastx;
private int lasty;
#Override
public void init() {
this.setForeground(Color.BLUE);
this.addMouseListener(new PositionRecorder());
this.addMouseMotionListener(new LineDrawer());
}
public int getLastx() {
return lastx;
}
public void setLastx(int lastx) {
this.lastx = lastx;
}
public int getLasty() {
return lasty;
}
public void setLasty(int lasty) {
this.lasty = lasty;
}
private class PositionRecorder extends MouseAdapter{
public void mousePressed(MouseEvent e) {
setLastx(e.getX());
setLasty(e.getY());
}
}
private class LineDrawer extends MouseMotionAdapter{
public void mouseDragged(MouseEvent e) {
int x=e.getX();
int y=e.getY();
Graphics g;
g=getGraphics();
g.drawLine(lastx, lasty, x, y);
}
}
}
I distinctively remember messing with this part of code if that helps
private class PositionRecorder extends MouseAdapter{
public void mousePressed(MouseEvent e) {
setLastx(e.getX());
setLasty(e.getY());
Painting in AWT is a well documented process. You should start by reading through:
Painting in AWT and Swing, in particular, I suggest you read the section on The Paint Method
A Closer Look at the Paint Mechanism
Quoted from "A Closer Look at the Paint Mechanism"
the paint method (defined by java.awt.Component.) This method will be executed by the painting subsystem whenever you component needs to be rendered.
In AWT, painting is destructive, it is expected that any time paint is called, that you will completely repaint the component state. This raises a number of issue which you will need to solve.
For anything you need to paint, you need a reliable way to store those states and reapply them when paint is called. In you case, something as simple as an ArrayList would be suitable, but you could also use a BufferedImage as a backing buffer and draw the committed drawing elements to it.
The benefit of the first approach is to provides the ability to undo changes, but in terms of painting, isn't as fast as simply painting an image.
A more clever approach would be to use both. Maintaining the draw states in a ArrayList, rendering each one as it's committed to the BufferedImage and when you want to perform an undo, start with a new BufferedImage and paint all the states up to the point you don't need...but that's all beyond the scope of the question
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class SimplePaint extends Applet {
private Point clickPoint;
private Point dragPoint;
#Override
public void init() {
this.setForeground(Color.BLUE);
this.addMouseListener(new PositionRecorder());
this.addMouseMotionListener(new LineDrawer());
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (clickPoint != null && dragPoint != null) {
g.drawLine(clickPoint.x, clickPoint.y, dragPoint.x, dragPoint.y);
}
}
private class PositionRecorder extends MouseAdapter {
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
// This is where I'd reset the clickPoint and dragPoint
// to null and apply the line to some structure which can
// redraw it in the `paint` method, maybe something like
// a ArrayList
// Alternativly, you could render the result to a BufferedImage
// and paint that inside the paint method
}
}
private class LineDrawer extends MouseMotionAdapter {
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
repaint();
}
}
}
Related
so I have this project that I'm doing, which draws a circle and a square, and resizes them through buttons. Everything works great, however what I must do is put the circle inside the square, so that the circle is inscribed, and I can't seem to figure out how to put both swing elements on top of each other.
Here's a picture of how it currently is:
And here's a photoshop version of how it should look like:
Here's my Circle class:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
public class Picture extends Canvas implements VetoableChangeListener, PropertyChangeListener {
private final int SIZE = 100;
private int radius = 1;
public Picture() {
setSize(SIZE,SIZE);
}
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
if ((pce.getPropertyName()).equals("value")) {
int v = (Integer)pce.getNewValue();
if ((v <=0)||(v > SIZE/2))
throw new PropertyVetoException ("Value out of bounds!", pce);
}
}
public void propertyChange(PropertyChangeEvent pce) {
if ((pce.getPropertyName()).equals("value")) {
setRadius((Integer)pce.getNewValue());
repaint();
}
}
public void setRadius(int radius) {
this.radius = radius;
}
public int getRadius() {
return this.radius;
}
public void paint (Graphics g) {
Dimension d = getSize();
g.setColor(Color.GREEN);
g.fillOval(d.width/2 - radius, d.height/2 - radius, radius*2, radius*2);
}
}
And here's my Square class, which is similar:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
public class Square extends Canvas implements VetoableChangeListener, PropertyChangeListener {
private final int SIZE = 100;
private int side = 1;
public Square() {
setSize(SIZE,SIZE);
}
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
if ((pce.getPropertyName()).equals("value")) {
int v = (Integer)pce.getNewValue();
if ((v <=0)||(v > SIZE/2))
throw new PropertyVetoException ("Value out of bounds!", pce);
}
}
public void propertyChange(PropertyChangeEvent pce) {
if ((pce.getPropertyName()).equals("value")) {
setSide((Integer)pce.getNewValue());
repaint();
}
}
public void setSide(int side) {
this.side = side;
}
public int getSide() {
return this.side;
}
public void paint (Graphics g) {
Dimension d = getSize();
g.setColor(Color.BLUE);
g.drawRect(d.width/2 - side, d.height/2 - side, side*2, side*2);
}
}
I've added both of them to the palette. Would you please explain to me how to put those both elements on top of each other, I'm new to Swing and JavaBeans.
Thanks in advance!
First of all you should not be extending Canvas, that is an AWT component. In Swing you can extend JComponent (or JPanel) and then you add custom painting to the paintComponent(...) method. Read the section from the Swing tutorial on Custom Painting for more information.
Also you should make each component transparent (by using setOaque(false) in the constructor of the component so that the background of one component does not cover the other.
I've added both of them to the palette.
And they both display on top of the palette because of the rules of the layout manager being used:
So you have a couple of options:
Take advantage of Swings parent/child relationship. That is add the square to the palette and the circle to the square. This means you will need to set a layout manager on the square so you can add the circle to it. A BorderLayout might be easy to use.
Create a panel using the OverlayLayout. This layout manager allows you to add two components on top of one another in the same panel. You would add the square to the panel and the circle to the panel (in that order since Swing paints the last component added to a panel first).
A completely different (and probably easier) option is to have a single component and paint both the square and circle in the paintComponent() method.
You should at least override isOpaque to return false on both Circle and Square thus non-painted pixel will be considered as "show-through".
Next you also need to use a free layout in the container to be able to control exact location of your objects.
Note: don't use Canvas, it would be much better not to subclass any component to represent drawings, just implements some method (say draw) that would take a graphics to draw with, and override paintComponent of your container to call that method on every drawing object:
class Circle implements Drawable {
int x; int y; int radius;
public void draw(Graphics g) {
g.fillOval(x - radius, y - radius, radius*2, radius*2);
}
}
class MyContainer extends JPanel {
List<Drawable> ld = ...
public void paintComponent(Graphics g) {
for (Drawable d : ld) {
d.draw(g);
}
}
So, here is the thing. My lecturer taught us how to get mouse coordinates by clicking on an applet. Now, i was thinking that may be i can try drawing dynamic lines using mousemotionlistener class using the mousedrag method and the mouse coordinates. I tried it but couldn't really make it work. Can anyone please suggest me where i made the error. Thanks a lot.
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.applet.*;
public class drawing extends Applet
implements MouseMotionListener {
int mx,my;
Graphics2D g2;
public void init()
{
this.addMouseMotionListener(this);
}
public void paint(Graphics g)
{
this.setSize(800,600);
g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(10));
g2.drawLine(40,50,200,150); // I was experimenting to draw static lines using the drawLine() method.
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
mx = e.getX();
my = e.getY();
System.out.println(" "+ mx + " "+ my);
g2.setStroke(new BasicStroke(10));
g2.drawLine(mx,my,mx,my);
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
In order to draw a line, you need to know the start point (which would be the point the user clicked) and the end point (the point where the user dragged to), from there is a simple matter to simple use Graphics#drawLine.
Start by taking a look at How to Write a Mouse Listener, 2D Graphics and Painting in AWT and Swing for more details
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class Drawing extends Applet
implements MouseMotionListener, MouseListener {
private Point startPoint, endPoint;
public void init() {
this.addMouseMotionListener(this);
addMouseListener(this);
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (startPoint != null && endPoint != null) {
g.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
}
}
#Override
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
endPoint = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Now, my advice, don't use Applet or AWT directly. Instead, start with a JPanel and override it's paintComponent method and use it perform your custom painting. Then add this panel to a JFrame to display it on the screen.
AWT is more then 15 years out of date and applets have way to many gotchas which you just don't need to deal with right now.
Start by having a look at Creating a GUI With JFC/Swing or even do some research into JavaFX
Here is the code.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Robot;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;
public class Paint extends JPanel implements MouseMotionListener, MouseListener {
public Paint() {
setBackground(Color.RED);
addMouseMotionListener(this);
addMouseListener(this);
}
private boolean clicked = false;
public void paintComponent (Graphics g) {
super.paintComponent(g);
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int x = (int) b.getX() - 3;
int y = (int) b.getY() - 23;
if (clicked) {
g.drawLine(x, y-5000, x,y+5000);
g.drawLine(x+5000,y,x-5000,y);
g.setColor(Color.white);
}
g.drawLine(x, y-5000, x,y+5000);
g.drawLine(x+5000,y,x-5000,y);
g.setColor(Color.black);
// . . .
}
#Override
public void mouseDragged(MouseEvent e) {
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
clicked = true;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
clicked = false;
repaint();
}
}
public class Frame extends JFrame {
public Frame() {
this.setSize(500,500);
this.setTitle("Test painting");
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Paint panel = new Paint();
this.add(panel);
this.setVisible(true);
}
public static void main (String[] args) {
new Frame();
}
}
When I run the program, it looks like it works fine when the application is in the default position, but once I move the applet to where I like on the screen, the lines don't maintain the current mouse position on screen.
Can someone show me where I've gone wrong or how to fix this?
Painting is done from the context of the component. The Graphics context for any given component is translated so that the top, left corner is 0x0.
MouseInfo.getPointerInfo().getLocation() is returning the location of the mouse on the screen, not the position relative to the component.
While there is a way to fix it, a better solution would be to simply use a MouseMotionListener instead. The MouseEvent sent to this method has already been translated to the component coordinate space...
public void mouseMoved(MouseEvent me) {
myPoint = me.getPoint();
}
Then in you paintComponent method, simple refer to myPoint instead of trying to use MouseInfo
I think that you will be better off to change your class's state in the MouseAdapter, call repaint() and then have your paintComponent(...) method use this state to help it draw. This seems cleaner and safer to me than using MouseInfo in paintComponent(...).
Other than that, if you need more specific help, consider
telling us more about what it is exactly you're trying to do and how your program isn't working.
creating and posting an sscce, a small compilable and runnable program that demonstrates your problem for us.
Thanks for checking out this Question. I think I've just about scratched through my skull in frustration.
So what I've got is a 'JFrame' containing a 'JPanel'. The 'JPanel' contains a little colored Square which is supposed to move X pixels whenever I click the window.
Well, essentially everything behaves as it should, with one exception. When the blue square moves to the right, it leaves a trail of other squares behind it. It is not supposed to leave the trail, however, when I re-size the window, the trail vanishes.
Catalyst.java
package Prototype;
import java.awt.*;
public class Catalyst {
public static void main(String[] args){
World theWorldInstance = new World("Prototype", 100,100, 600,100); /*title,xpos,ypos,width,height*/
}
}
World.java
package Prototype;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class World extends JFrame {
Level mainPanel;
public World(String title, int x, int y, int width, int height) {
setTitle(title);
setBounds(x,y,width,height);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBackground(new Color(0x00000000));
initLevel();
}
public void initLevel(){
mainPanel = new Level();
Container visibleArea = getContentPane();
visibleArea.add(mainPanel);
setVisible(true);
add(mainPanel);
}
}
Level.java
package Prototype;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Level extends JPanel implements MouseListener, ActionListener {
Square x;
public Level() {
System.out.println("This is working correctly[JPANEL Cons]");
addMouseListener(this);
x = new Square();
}
public void paintComponent(Graphics g){
x.draw(g);
}
public void actionPerformed(ActionEvent e){
}
public void mousePressed(MouseEvent e){
requestFocus();
x.move();
repaint();
System.out.println("Focus Acquired");
}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
}
Square.java
package Prototype;
import java.awt.*;
public class Square {
private Point position;
private int size;
private final int displacement;
public Square(){
position = new Point(10,10);
size = 20;
displacement = 5;
}
public void draw(Graphics g){
g.setColor(Color.blue);
g.fillRect(position.x-(size/2), position.y-(size/2), size,size );
g.setColor(Color.black);
g.drawRect(position.x-(size/2), position.y-(size/2), size,size );
}
public void move() {
position.x += displacement;
}
}
Those are all my files. I hope I've phrased everything properly and provided all the content required. Whenever I've done something similar in the past this has never happened. I assume I'm missing something small, or I've done something stupid. If you can help me, thanks in advance!
There's another way of doing this. You can simply call the parent object's paintComponent method to clear the panel.
Add this to your constructor in Level :
this.setBackground(Color.BLACK);
And this as the first call in paintComponent:
super.paintComponent(g);
You can use g.clearRect(x, y, width, height), and provide the said coordinates, where you want the painting to be cleared from. Or you can give the dimensions of whole of the JPanel/JComponent where you are drawing, though doing this keep one thing in mind, that the said drawing is not a heavy work, else too much of cleaning will put extra burden on the painting calls.
I'm trying to make an applet which I can simply drag an image. And I want image object to listen events. So here is the applet code which simple run in a thread:
import java.awt.*;
import java.net.URL;
import javax.swing.JApplet;
public class Client extends JApplet implements Runnable {
private static final long serialVersionUID = 1L;
MediaTracker mediaTracker;
Image [] imgArray;
Tas t1;
public void init()
{
mediaTracker = new MediaTracker(this);
imgArray = new Image[1];
URL base = getCodeBase();
imgArray[0] = getImage(base,"okey.png");
mediaTracker.addImage(imgArray[0],1);
try {
mediaTracker.waitForAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
t1 = new Tas(this, new Rectangle(0, 0, imgArray[0].getWidth(this), imgArray[0].getHeight(this)), imgArray[0]);
Thread t = new Thread(this);
t.start();
}
public void paint(Graphics g)
{
t1.paint(g);
}
#Override
public void run() {
while(true){
//System.out.println("run");
repaint();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the class of object which holds image is:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Movable extends JPanel implements MouseListener {
public Client mainObj;
public Rectangle rect;
public Image image;
public Movable(Client mainObj, Rectangle rect, Image image) {
this.mainObj = mainObj;
this.rect = rect;
this.image = image;
addMouseListener(this);
}
public void paint(Graphics g) {
g.drawImage(image, rect.x, rect.y, rect.width, rect.height, this);
}
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("clicked");
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
System.out.println("pressed");
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
#SuppressWarnings("serial")
class Tas extends Movable{
public String name = "";
public Tas(Client mainObj, Rectangle rect, Image image) {
super(mainObj, rect, image);
}
}
I can see the image in my applet but nothing happens when I click in or out of the image. So what's wrong with this code.
Assuming that Tas in code #1 is Moveable in code #2...
You don't actually use the Moveable as a Component, but instead ask it to paint itself onto the Applet's graphics context, here:
public void paint(Graphics g)
{
t1.paint(g);
}
Instead you should add an instance of Moveable onto the Applet's container, wherein painting will become automatic, and it will start to receive mouse events. You can also remove that paint() method then too.
First of all you should never override the paint method of a top level container (JApplet, JFrame, JDialog).
Then to do custom painting on other Swing components you override the paintComponent() method of the component, NOT the paint() method. Read the Swing tutorial on Custom Painting. So first fix those problems.
I'm not sure what the point of the Thread is but remove it from your code until you solve your other problems. If you are trying to do animation, then you should be using a Swing Timer, not a Thread.
If you want to see some code for dragging components you can take a look at Moving Windows for some generic code.
This is a working solution. It is not an applet but you can easily convert that. Hope it helps :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class ImagePanel extends JPanel {
Image image;
Point2D axis = new Point2D.Double();
boolean drag = false;
Point2D dragPoint = new Point2D.Double();
public ImagePanel(Image image) {
this.image = image;
setPreferredSize(new Dimension(300,300));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drag = true;
dragPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (drag) {
axis.setLocation(axis.getX()
+ (e.getPoint().x - dragPoint.getX()), axis.getY()
+ (e.getPoint().y - dragPoint.getY()));
dragPoint = e.getPoint();
repaint();
}
}
});
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(image, (int) axis.getX(), (int) axis.getY(), null);
}
public static void main(String[] args) {
try {
JFrame f = new JFrame();
f.getContentPane().add(
new ImagePanel(ImageIO.read(new File("image.jpg"))));
f.pack();
f.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The simple answer is - you don't have code to do anything in mousePressed() or mouseReleased().
There are lots of other problems in the code though...
Simplest solution I could come up with -
public class Client extends JApplet {
private MouseInputAdapter myMouseListener = new MyMouseListener();
public void init() {
// usually a very bad idea, but needed here
// since you want to move things around manually
setLayout(null);
// assuming this will get used often, so making it a method.
addLabelForImage(getImage(getCodeBase(), "okay.png"));
}
private void addLabelForImage(Image image) {
ImageIcon icon = new ImageIcon(image);
JLabel l = new JLabel(icon);
add(l);
l.setSize(l.getPreferredSize());
// you'll probably want some way to calculate initial position
// of each label based on number of images, size of images,
// size of applet, etc. - just defaulting to 100,100 now.
l.setLocation(100, 100);
l.addMouseListener(myMouseListener);
l.addMouseMotionListener(myMouseListener);
}
// Made this a MouseInputAdapter because I assume you may want to handle
// other types of mouse events later...
private static class MyMouseListener extends MouseInputAdapter {
#Override
public void mouseDragged(MouseEvent e) {
// when the mouse is dragged over a the component this listener is
// attached to (ie - one of the labels) convert the point of the mouse
// event from the internal component coordinates (0,0 is upper right
// corner of each label), to it's parent's coordinates (0,0 is upper
// right corner of the applet), and set the components location to
// that point.
Component theLabel = e.getComponent();
Container theApplet = theLabel.getParent();
Point labelPoint = e.getPoint();
Point appletPoint = SwingUtilities.convertPoint(
theLabel, labelPoint, theApplet );
theLabel.setLocation(appletPoint);
}
}
}