This question already has an answer here:
Java: mouseDragged and moving around in a graphical interface
(1 answer)
Closed 5 years ago.
I have to draw a simple crosshair. All I am seeing is a blank panel.
class ChartPanel extends JPanel implements MouseMotionListener{
Graphics2D g;
Dimension dimFrame;
ChartPanel() {
addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e) {
drawCrosshair(e.getX(),e.getY());
}
public void mouseDragged(MouseEvent e) {}
protected void paintComponent(Graphics g2) {
g = (Graphics2D)g2;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
dimFrame = getSize();
setBackground(Color.WHITE);
}
public Dimension getPreferredSize() {
return new Dimension(700, 500);
}
void drawCrosshair(double x, double y) {
double maxx = dimFrame.getWidth();
double maxy = dimFrame.getHeight();
g.setPaint(Color.BLACK);
g.draw(new Line2D.Double(0, y, maxx, y));
g.draw(new Line2D.Double(x, 0, x, maxy));
}
}
public class pra {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
ChartPanel chartPanel = new ChartPanel();
jFrame.add(chartPanel);
jFrame.pack();
jFrame.setVisible(true);
jFrame.setExtendedState(Frame.MAXIMIZED_BOTH);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
And it is getting into drawCrosshair() method with correct value. I have no clue what I am doing wrong.
You can just dispose of drawCrosshair(), and draw the crosshair in the paint method, which would replace the paintComponent method (Actually I think that you shouldn't ever override paintComponent):
Graphics2D g;
Dimension dimFrame;
int x, y;
ChartPanel() {
addMouseMotionListener(this);
setPreferredSize(new Dimension(700, 500));
}
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
public void mouseDragged(MouseEvent e) {
}
public void paint(Graphics g2) {
super.paint(g2);
g = (Graphics2D) g2;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
dimFrame = getSize();
g.clearRect(0, 0, dimFrame.width, dimFrame.height);//clears previous drawings
g.setColor(Color.BLACK);
g.drawLine(x - 10, y, x + 10, y);
g.drawLine(x, y - 10, x, y + 10);
}
And this should do it (actually it does, as I've tested it ;) )
Related
I want to implement a Rectangle shape feature exactly as in Paint in JAVA. I have built a program as following. I have built a class MyPaint where buttons and frame are defined. I have built another class inside the same program PadDraw, where a drawing pad is created where I can draw with pencil like in Paint. Then I have another class outside the program DrawRect where the rectangle shape feature is created.
I want to know if there is a way to integrate the rectangle in a way that if I click a button "Rectangle", the way of drawing should change and instead of drawing with pencil, I should draw rectangle shapes exactly like in Paint when the rectangle shape is pressed.
The piece of code for PadDraw class is as following:
class PadDraw extends JComponent {
private Image image;
private Graphics2D graphics2D;
private int currentX , currentY , oldX , oldY ;
public PadDraw(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics2D != null)
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public void paintComponent(Graphics g){
if(image == null){
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 5, 5, null);
}
While the piece of code of DrawRect class that I want to integrate in the program where MyPaint and PadDraw class are located is as following:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawRect extends JPanel {
int x, y, x2, y2;
public static void main(String[] args) {
JFrame f = new JFrame("Draw Box Mouse 2");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new DrawRect());
f.setSize(300, 300);
f.setVisible(true);
}
DrawRect() {
x = y = x2 = y2 = 0; //
MyMouseListener listener = new MyMouseListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
public void setStartPoint(int x, int y) {
this.x = x;
this.y = y;
}
public void setEndPoint(int x, int y) {
x2 = (x);
y2 = (y);
}
public void drawPerfectRect(Graphics g, int x, int y, int x2, int y2) {
int px = Math.min(x,x2);
int py = Math.min(y,y2);
int pw=Math.abs(x-x2);
int ph=Math.abs(y-y2);
g.drawRect(px, py, pw, ph);
}
class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
setStartPoint(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
public void mouseReleased(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
drawPerfectRect(g, x, y, x2, y2);
}
}
I am trying to draw a rectangle over Image using java.awt classes. For that I used below sample code:
public class DrawRectangle {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
}
class TestPane extends JPanel {
private BufferedImage myImage;
private Rectangle myOffice = new Rectangle(150, 50, 30, 20);
public TestPane() {
try {
File image = new File("C:\\Users\\NNaphade\\work\\ImageDetection\\Trial_Pascal_VOC\\test_image\\IMG_20180327_110210.jpg");
if(image.exists())
myImage = ImageIO.read(image);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
System.out.println("image exist!!!!!!");
return myImage == null ? new Dimension(200, 200) : new Dimension(
myImage.getWidth(), myImage.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (myImage != null) {
g2d.drawImage(myImage, 0, 0, 1000, 1000, this);
g2d.setColor(Color.RED);
g2d.translate(0, 0);
g2d.draw(myOffice);
}
g2d.dispose();
}
}
This works correct and output is displayed as expected. Here I am fixing the parameters for rectangle as:
private Rectangle myOffice = new Rectangle(150, 50, 30, 20);
However, in my application, I want to pass these parameters from another method. I want to pass these x1, y1, w and h to TestPane class given above. I tried changing the TestPane constructor by passing these 4 parameters, but I am not able to set them as instance variables. E.g. the following code doesn't work.
private void markWithBoundingBox(INDArray testData, int gridWidth, int gridHeight, double w, double h, DetectedObject obj) {
double[] xy1 = obj.getTopLeftXY();
int predictedClass = obj.getPredictedClass();
int x1 = (int) Math.round(w * xy1[0] / gridWidth);
int y1 = (int) Math.round(h * xy1[1] / gridHeight);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane(x1, y1, w, h));
frame.pack();
frame.setVisible(true);
}
});
}
class TestPane extends JPanel {
private BufferedImage myImage;
//private Rectangle myOffice = new Rectangle(50, 50, 3, 20);
public TestPane(int x, int y, double w, double h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
try {
File file = new File("C:\\Users\\NNaphade\\work\\ImageDetection\\Trial_Pascal_VOC\\test_image\\IMG_20180327_110210.jpg");
if(file.exists()) {
myImage = ImageIO.read(file);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return myImage == null ? new Dimension(100, 100) : new Dimension(
myImage.getWidth(), myImage.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (myImage != null) {
g2d.drawImage(myImage, 0, 0, 2000, 2000, this);
g2d.setColor(Color.RED);
g2d.translate(0, 0);
g2d.draw(new Rectangle(this.x, this.y, this.w, this.h));
}
g2d.dispose();
}
}
It seems to me that TestPane here is not a class but the component. because Java compiler doesn't let me declare the instance variables in the constructor and all the available methods there are of component. How can I get rid of this issue?
I've got two classes: Connection extends JComponent and PostMachineView extends JPanel implements MouseListener.
What I'm trying to do is fire a method whenever the mouse button is pressed inside the Connection component.
I'm using SwingUtilities.convertPointToScreen so that the mouse event coordinates will be relative to where I am drawing. The problem is that it returns slightly different numbers for x and y than it should.
Code below:
public class PostMachineView extends JPanel implements MouseListener {
ArrayList<Connection> connections;
public PostMachineView() {
connections = new ArrayList<>();
setSize(new Dimension(800, 800));
setBackground(Color.white);
//here i create the points i'll need for the connection and instantiate it
Point p1 = new Point(100, 100);
Point p2 = new Point(100, 200);
Connection conn = new Connection(p1, p2);
//add the connection component to this panel
add(conn);
//set the connection mouse listener
conn.addMouseListener(this);
connections.add(conn);
}
#Override
public void paint(Graphics g) {
super.paint(g);
//this will be done in a different way, just trying to get it to work first
Point p1 = new Point(100, 100);
Point p2 = new Point(100, 200);
((Connection)getComponent(0)).paintComponent(g, p1, p2);
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("clicked in the component");
}
#Override
public void mouseReleased(MouseEvent e) {}
}
public class Connection extends JComponent {
private Rectangle2D.Double curveControl;
private GeneralPath path;
public Connection(Point p1, Point p2) {
path = new GeneralPath();
path.moveTo(p1.getX(), p1.getY());
int[] mid = getMidPointCoords(p1, p2);
curveControl = new Rectangle2D.Double(mid[0] - 5, mid[1] - 5, 10, 10);
path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
curveControl.getCenterX(), curveControl.getCenterY(),
p2.getX(), p2.getY());
}
public int[] getMidPointCoords(Point p1, Point p2) {
int[] v = { 0, 0 };
v[0] = (int) ((p1.getX() + p2.getX()) / 2);
v[1] = (int) ((p1.getY() + p2.getY()) / 2);
return v;
}
public void paintComponent(Graphics g, Point p1, Point p2) {
path.moveTo(p1.getX(), p1.getY());
path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
curveControl.getCenterX(), curveControl.getCenterY(),
p2.getX(), p2.getY());
Graphics2D g2d = (Graphics2D) g;
g2d.draw(path);
g2d.setColor(Color.red);
g2d.fill(curveControl);
g2d.setColor(Color.black);
}
#Override
public boolean contains(int x, int y) {
//here is where i use swingutilities to convert the coordinates
Point p = new Point(x, y);
SwingUtilities.convertPointToScreen(p, this);
return curveControl.contains(p.getX(), p.getY());
}
}
I also have a Teste class, which simply instantiates a JFrame and adds a PostMachineView to it:
public class Teste {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(new Dimension(800,800));
f.add(new PostMachineView());
f.setResizable(false);
f.setVisible(true);
}
}
This...
public void paint(Graphics g) {
super.paint(g);
//this will be done in a different way, just trying to get it to work first
Point p1 = new Point(100, 100);
Point p2 = new Point(100, 200);
((Connection)getComponent(0)).paintComponent(g, p1, p2);
}
Is a VERY bad idea. The Connection component is already a child of the PostMachineView component. You should simply be updating the state of Connection (maybe through a mouseClicked event) and calling repaint to update it.
In Connection, this...
public void paintComponent(Graphics g, Point p1, Point p2) {
path.moveTo(p1.getX(), p1.getY());
path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
curveControl.getCenterX(), curveControl.getCenterY(),
p2.getX(), p2.getY());
Graphics2D g2d = (Graphics2D) g;
g2d.draw(path);
g2d.setColor(Color.red);
g2d.fill(curveControl);
g2d.setColor(Color.black);
}
Should be slit into two methods, one that adds the new point and one that draws it...
public void add(Point p1, Point p2) {
path.moveTo(p1.getX(), p1.getY());
path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
curveControl.getCenterX(), curveControl.getCenterY(),
p2.getX(), p2.getY());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(path);
g2d.setColor(Color.red);
g2d.fill(curveControl);
g2d.setColor(Color.black);
g2d.dispose();
}
Because the MouseListener is attached to the Connection component, this...
#Override
public boolean contains(int x, int y) {
//here is where i use swingutilities to convert the coordinates
Point p = new Point(x, y);
SwingUtilities.convertPointToScreen(p, this);
return curveControl.contains(p.getX(), p.getY());
}
No longer makes sense and, to be honest, I'd be VERY careful with messing around with this
At best it should be more like...
public boolean contains(int x, int y) {
return curveControl.contains(x, y);
}
But remember, the MouseListener will no longer generate events unless the x/y coordinates are WITHIN the curveControl, which might not really be what you want.
Oh and this ArrayList<Connection> connections; scares me...but then, I don't have the context to your problem to really know what you're intentions are for this...
Basically I want to draw an ellipse which its size is relative to JPanel in Java.
for example: Ellipse2D e = new Ellipse2D.Double(0, 0, w, h)
Which w and h is the size of the panel. So by doing this, the ellipse will automatically resize when the panel is changing its size.
I have tried this but actually it doesn't work, I wrote this code for testing only.
public class Help extends JFrame{
public static void main(String [] agrs){
Help h = new Help();
h.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
h.init();
}
public void init(){
this.setLayout(new FlowLayout());
this.setSize(2000, 1000);
JPanel a = new JPanel();
a.setPreferredSize(new Dimension(1000, 500));
a.setBorder(BorderFactory.createLineBorder(Color.yellow, 3));
Help_Option k = new Help_Option(a.getPreferredSize().width/2, a.getPreferredSize().height/4);
k.setPreferredSize(new Dimension(1000, 400));
a.add(k);
this.add(a);
this.validate();
this.setVisible(true);
}
}
class Help_Option extends JComponent implements MouseMotionListener{
private static int x, y;
private Ellipse2D ellipse = new Ellipse2D.Double(0, 0, x, y);
private Color c = Color.MAGENTA;
public Help_Option(int x, int y){
Help_Option.x = x;
Help_Option.y = y;
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.draw(ellipse);
g2d.setColor(c);
g2d.fill(ellipse);
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("TimesRoman", Font.BOLD, 20));
g2d.drawString("Here I am", 250, 100);
}
public void setColor(Color c){
this.c = c;
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if(ellipse.contains(e.getX(), e.getY())){
setColor(Color.GREEN);
repaint();
}else{
setColor(Color.MAGENTA);
repaint();
}
}
}
Thank you for your code snippet. In order to make it work, you need to initalize the ellipse in the Help_Option-Constructor otherwise it is draw at 0, 0 with the widht and height of 0 and 0.
...
private Ellipse2D ellipse = null; //also works w/o this assignment.
private Color c = Color.MAGENTA;
public Help_Option(int x, int y){
Help_Option.x = x;
Help_Option.y = y;
ellipse = new Ellipse2D.Double(0, 0, x, y);
this.addMouseMotionListener(this);
}
...
If I change the code accordingly, the ellipse stays at its size even though I resize the window.
Please give me a hint (screenshot) what you mean.
I want to draw an ellipse which its size is relative to JPanel in Java.
Then you need to create the Ellipse object in the paintComponent() method. You can use the getWidth() and getHeight() methods to get the current size of the panel.
Here is the problem I am currently facing: I want to draw a String on a JPanel using Java2D. The String has to be rotated of a user-defined angle.
Under that String, I also paint the background in a given color to facilitate reading (plenty of other things are drawn on my JPanel).
What I did, in the overridden paint method of my JPanel, is the following:
final Graphics2D g2 = (Graphics2D) g.create();
final int textWidth = g.getFontMetrics().stringWidth(textToDraw);
final int textHeight = g.getFontMetrics().getHeight();
g2.translate(pointToDraw.x, pointToDraw.y);
g2.rotate(angle);
g2.setColor(textBackground);
g2.fillRect(deltaX, -textHeight, textWidth, textHeight);
g2.setColor(drawColor);
g2.setFont(font);
g2.drawString(textToDraw, deltaX, deltaY);
g2.dispose();
This works very well on linux, but on Mac OS X (with Java 1.6), the text is not displayed properly: the text is correctly rotated but after each character, there is a line break.
How can I make it work on both platforms?
I don't think this is the solution you will want, but from everything I've been able to read, there doesn't seem to be a better solution...
The problem seems to be that the Mac is rotating each character, not just the String
Basically, I've cheated. This renders the text to a BufferedImage (you should create the image only when the properties change, unlike me, which I've done it within the paint method) and then rotates the image...
public class RotateText {
public static void main(String[] args) {
new RotateText();
}
public RotateText() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private String textToDraw = "Stack Overflow";
private double angle = 90;
private Color drawColor = Color.BLACK;
public TestPane() {
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle += 2;
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g.create();
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(textToDraw);
int textHeight = fm.getHeight();
BufferedImage img = new BufferedImage(textWidth, textHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D ig = img.createGraphics();
ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ig.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
ig.setColor(drawColor);
ig.drawString(textToDraw, 0, fm.getAscent());
ig.dispose();
int x = (getWidth() - textWidth) / 2;
int y = (getHeight() - textHeight) / 2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), getWidth() / 2, getHeight() / 2));
g2.drawImage(img, x, y, this);
g2.dispose();
}
}
}