So basically I have some code I was working on a couple of days ago that is kind of like Paint, which allows you to essentially draw on the screen using the mouse. I kind of
Or we can try drawing for only java code , I think it's so easy and powerful.
package drawingbymouse;
import java.awt.*;
import java.awt.event.*;
public class DrawingByMouse extends Frame
implements MouseMotionListener{
DrawingByMouse(){
addMouseMotionListener(this);
setSize(400, 400);
setLayout(null);
setVisible(true);
}
@Override
public void mouseDragged(MouseEvent e){
Graphics g = getGraphics();
g.setColor(Color.BLACK);
g.fillOval(e.getX(), e.getY(), 10, 10);
}
public void mouseMoved(MouseEvent e){
}
public static void main (String[]args){
new DrawingByMouse();
}
}
You're current approach is basically breaking the requirements of the paint chain, by not calling super.paintComponent
. The paintComponent
method does a set of operations, which you are not taking over and which could result in some very weird paint artifacts which are difficult to replicate consistently.
Graphics
is a shared resource, so the Graphics
context which was used to paint some other control will be the same which is used to paint your component, unless you are "cleaning" the context before hand, what was previously painted to the context will remain (which is why you code currently "seems" to work).
Instead, you should use a MouseListener
to define a anchor point, which represents the point at which the mouse was pressed and then use the MouseMotionListener
to define the extent of the selection area, for example...
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SelectExample {
public static void main(String[] args) {
new SelectExample();
}
public SelectExample() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Rectangle selection;
public TestPane() {
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
@Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
selection = null;
}
@Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
int x = Math.min(clickPoint.x, dragPoint.x);
int y = Math.min(clickPoint.y, dragPoint.y);
int width = Math.max(clickPoint.x, dragPoint.x) - x;
int height = Math.max(clickPoint.y, dragPoint.y) - y;
if (selection == null) {
selection = new Rectangle(x, y, width, height);
} else {
selection.setBounds(x, y, width, height);
}
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
selection = null;
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (selection != null) {
g.setColor(UIManager.getColor("List.selectionBackground"));
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(selection);
g2d.dispose();
g2d = (Graphics2D) g.create();
g2d.draw(selection);
g2d.dispose();
}
}
}
}
Just to highlight the issue you will face if you continue to violate the requirements of the paintComponent
method, this is what happens when I don't call super.paintComponent
I simply added two JButton
's to the JFrame
(so not even directly to the panel). paintComponent
does a series of important jobs, which you neglected to perform, which is going to cause more problems and issues.
A free form line is actually a illusion, it's a series of (small) lines drawn between a series of points, the reason for this is because the MouseListener
won't report every mouse position it moves across, depending on the speed the mouse is moved, you might get lots of call backs or a few.
So, instead of drawing to just draw the points, we store the points in a List
and draw lines between them, for example...
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FreeFormLines {
public static void main(String[] args) {
new FreeFormLines();
}
public FreeFormLines() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<List<Point>> points;
public TestPane() {
points = new ArrayList<>(25);
MouseAdapter ma = new MouseAdapter() {
private List<Point> currentPath;
@Override
public void mousePressed(MouseEvent e) {
currentPath = new ArrayList<>(25);
currentPath.add(e.getPoint());
points.add(currentPath);
}
@Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
currentPath.add(dragPoint);
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
currentPath = null;
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (List<Point> path : points) {
Point from = null;
for (Point p : path) {
if (from != null) {
g2d.drawLine(from.x, from.y, p.x, p.y);
}
from = p;
}
}
g2d.dispose();
}
}
}
This is a simple example for a practical paint Application, where you can control and change the size and the Color of your drawing.
public class Main extends Application{
@Override
public void start(Stage stage){
try{
g = can.getGraphicsContext2D();
g.setStroke(Color.BLACK);
g.setLineWidth(1);
c.setValue(Color.BLACK);
c.setOnAction(e->{
g.setStroke(c.getValue());
});
sli.setMin(1);
sli.setMax(100);
sli.setShowTickLabels(true);
sli.setShowTickMarks(true);
sli.valueProperty().addListener(e->{
double val = sli.getValue();
String str = String.format("%.1f", val);
lab.setText(str);
g.setLineWidth(val);
});
gri.addRow(0, c, sli, lab);
gri.setHgap(20);
gri.setAlignement(Pos.TOP_CENTER);
gri.setPadding( new Insets( 20, 0, 0, 0));
scene.setOnMousePressed(e->{.
g.beginPath();
g.lineTo(e.getSceneX(), e.getSceneY());
g.stroke();
});
scene.setOnMoudrDragged(e->{.
g.lineTo(e.getSceneX(), e.getSceneY());
g.stroke();
});
pan.getChildren().addAll(can, gri);
stage.setScene(scene);
stage.show();
}catch(Exception e){
e.printStrackTrace();
}
Canvas can = new Canvas(760, 490);
GraphicsContext g ;
ColorPicker c = new ColorPicker();
Slider sli = new Slider();
Label lab = new Label("1.0");
GridPane gri = new GridPane();
StackPane pan = new StackPane();
Scene scene = new Scene(pan, 760, 490);
public static void main (String [] args){
launch(args);
}
}