I wrote a program that prints coordinates from GPS onto the screen as a scatter points.
here is the code:
class POSCanvas extends JPanel{
int cnt = 1;
private static final long serialVersionUID = 1L;
List<Vector2D> pnts = new ArrayList<Vector2D>();
public void getNewPoint (double xnew, double ynew){
Vector2D pnt = new Vector2D(cnt*xnew, cnt*ynew);
pnts.add(pnt);
cnt++;
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (!pnts.isEmpty()){
super.paintComponent(g);
g2.setColor(Color.white);
Dimension size = getSize();
Insets insets = getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
for (int i = 0; i < pnts.size(); i++ ){
Ellipse2D.Double OV = new Ellipse2D.Double(pnts.get(i).getX() % w, size.height - pnts.get(i).getY() % h, 5, 5);
g2.draw(OV);
repaint();
}
}
}
}
the problem with the drawing is that when the coordinates are bigger then the panel size the drawing makes no sense, the plotting starts from the left side again. here is an example:
I'd like to dynamically re-size the panel so the coordinates will always stay with its boundaries. How can I do that?
Related
I am new to programming and I've been trying to get and set the icon to circle but it's not being updated. I want to set every icon that was set to JLabel will become circular.
class CircleLabel extends JLabel {
private Icon icon;
private int borderSize;
#Override
protected void paintComponent(Graphics g) {
if (getIcon() != null) {
icon = getIcon();
int width = getWidth();
int height = getHeight();
int diameter = Math.min(width, height);
int x = width / 2 - diameter / 2;
int y = height / 2 - diameter / 2;
int border = borderSize * 2;
diameter -= border;
Dimension size = getAutoSize(icon, diameter);
BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2_img = img.createGraphics();
g2_img.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2_img.fillOval(0, 0, diameter, diameter);
Composite composite = g2_img.getComposite();
g2_img.setComposite(AlphaComposite.SrcIn);
g2_img.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2_img.drawImage(toImage(icon), 0, 0, size.width, size.height, null);
g2_img.setComposite(composite);
g2_img.dispose();
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(255, 255, 255));
diameter += border;
g2.fillOval(borderSize, borderSize, diameter, diameter);
g2.drawImage(img, x - borderSize, y + borderSize, null);
} else {
System.out.println("No Icon!");
}
super.paintComponent(g);
}
private Dimension getAutoSize(Icon image, int size) {
int w = size;
int h = size;
int iw = image.getIconWidth();
int ih = image.getIconHeight();
double xScale = (double) w / iw;
double yScale = (double) h / iw;
System.out.println(xScale);
System.out.println(yScale);
double scale = Math.max(xScale, yScale);
int width = (int) (scale * iw);
int height = (int) (scale * ih);
if (width < 1) {
width = 1;
}
if (height < 1) {
height = 1;
}
return new Dimension(width, height);
}
private Image toImage(Icon icon) {
return ((ImageIcon) icon).getImage();
}
}
If I set the icon manually and removed the icon from the label, it will work but when I add the icon to the label through properties, it will not work.
icon = new ImageIcon(getClass().getResource("/Attachments/user.png"));
I found this on YouTube and wanted to apply it to the application I'm trying to build.
I'm attempting to draw a line graph based on data held in array. I have managed to get the X and Y axis drawn. However when I draw the line with the data onto the graph it does not line up with the X and Y axis values. I am unsure of how this can be fixed. I have shown the code below:
public void drawLineG(Graphics g, int yCoords[]) {
String maxY = Integer.toString(getMax(yCoords));
String minY = Integer.toString(getMin(yCoords));
String maxX = Double.toString((xInterval * yCoords.length) - xInterval);
String minX = Double.toString(xStart);
g.setColor(Color.BLUE);
int height = (getHeight() / 2);
int x = 200; // start x point
// previous coord positions.
int prevX = x;
int prevY = yCoords[0];
g.setColor(Color.BLACK);
g.drawLine(prevX, getHeight() / 2, 500, getHeight() / 2);
g.drawLine(prevX, 200, 200, getHeight() / 2);
g.setColor(Color.BLUE);
g.drawString(minY, 190, (getHeight() / 2));
g.drawString(maxY, 180, (getHeight() / 2) - 255);
g.drawString(yLabel, 140, (getHeight() / 2) - 100);
g.drawString(minX, 192, (getHeight() / 2) + 20);
g.drawString(maxX, 500, (getHeight() / 2) + 20);
g.drawString(xLabel, 350, (getHeight() / 2) + 50);
for (int y : yCoords) {
g.setColor(Color.RED);
g.drawLine(prevX, height - prevY, x, height - y);
prevX = x;
prevY = y;
// add an increment to the X pos.
x = x + 50;
}
}
The array of data I have been testing contains the values: 0, 3, 4, 7, 5, 10, 3
However when this is plotted on the graph it doesn't line up with the values on the x and y axis.
Current: https://i.stack.imgur.com/Ju8BQ.jpg
What I am trying to achieve: https://i.stack.imgur.com/n9Aio.jpg
Any help?
Thanks
Your problem is your scale, you're trying to draw your yCoords as they're given, (3, 10 and so on) but they should be like: 30, 100 to fit the window's scale (Window = your program window).
For example in my code below, each "square" or each "unit" are of 30 x 30 pixels each, so I must convert yCoord = 3 to it's equivalent which would be 3 * 30 = 90 but as the axis is below starting at 400 I must substract it so I get the coord from the axis or from the bottom of the window to the real yCoord which would be 400 - 90 = 310, now this is my real point that I must paint.
However the painting should be done in the paintComponent method.
For my example I didn't draw the Strings for 0, 10, 0.0, 90.0 but you can do it later if you wish
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GraphSample {
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new GraphSample()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
GraphDrawer drawer = new GraphDrawer(new int[] {0, 3, 4, 7, 5, 10, 3});
frame.add(drawer);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#SuppressWarnings("serial")
class GraphDrawer extends JPanel {
private int[] yCoords;
private int startX = 100;
private int startY = 100;
private int endX = 400;
private int endY = 400;
private int unitX = (endX - startX) / 10;
private int unitY = (endY - startY) / 10;
private int prevX = startX;
private int prevY = endY;
public GraphDrawer(int[] yCoords) {
this.yCoords = yCoords;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//We draw in the following 2 loops the grid so it's visible what I explained before about each "unit"
g2d.setColor(Color.BLUE);
for (int i = startX; i <= endX; i += unitX) {
g2d.drawLine(i, startY, i, endY);
}
for (int i = startY; i <= endY; i += unitY) {
g2d.drawLine(startX, i, endX, i);
}
//We draw the axis here instead of before because otherwise they would become blue colored.
g2d.setColor(Color.BLACK);
g2d.drawLine(startX, startY, startX, endY);
g2d.drawLine(startX, endY, endX, endY);
//We draw each of our coords in red color
g2d.setColor(Color.RED);
for (int y : yCoords) {
g2d.drawLine(prevX, prevY, prevX += unitX, prevY = endY - (y * unitY));
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(endX + 100, endY + 100);
}
}
}
I hope it's clear what the error was.
This is a sample of what the output looks like with a 10 x 10 grid
I have a BufferedImage that I draw that doesn't show up unless I resize the window, and even then it only flickers:
// Remember, this is a JFrame class
#Override
public void paintComponents(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paint(g2d);
Graphics p = drawPanel.getGraphics();
for (int i = 0; i < images.length; i++) {
BufferedImage im = images[i];
int ciw = getWidth() / 3;
int cih = getHeight() / 2;
int xpos = i % 3;
int ypos = i / 3;
int ix = i * ciw * xpos;
int iy = i * cih * ypos;
int iw = ciw;
int ih = cih;
p.drawImage(im, ix, iy, iw, ih, null);
}
// drawPanel.paintComponents(p);
// drawPanel.repaint();
}
I have done drawPanel.setDoubleBuffered(true).
If you want to see the whole code: https://github.com/firestar115/BCMaker
This code contains several things you shouldn't do.
Don't override paint(). Override paintComponent() instead.
Don't do this:
Graphics2D p = (Graphics2D) drawPanel.getGraphics();
Instead, just use the Graphics that were passed into the paintComponent() method.
Don't call paint() or paintComponent() from your own painting code.
Instead, just call repaint() when you want your paintComponent() method to be called. If you want it to be called multiple times, then use a Timer. Don't call repaint() from inside your paintComponent() method either.
If you want more specific help, please provide an MCVE.
Make a BufferedImage to draw your images on. Then, draw that BufferedImage on to drawPanel.getGraphics(). Do not call repaint().
#Override
public void paintComponents(Graphics g) {
// Graphics2D g2d = (Graphics2D) g;
// super.paint(g2d);
Graphics p = bi.getGraphics();
for (int i = 0; i < images.length; i++) {
BufferedImage im = images[i];
int ciw = getWidth() / 3;
int cih = getHeight() / 2;
int xpos = i % 3;
int ypos = i / 3;
int ix = i * ciw * xpos;
int iy = i * cih * ypos;
int iw = ciw;
int ih = cih;
p.drawImage(im, ix, iy, iw, ih, null);
}
drawPanel.drawImage(bi, 0, 0, null);
// drawPanel.paintComponents(p);
// drawPanel.repaint();
}
I have painted a BufferedImage on a JPanel with the following code.
protected void paintComponent(Graphics g) {
if (image != null) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
double x = (getWidth() - scale * imageWidth) / 2;
double y = (getHeight() - scale * imageHeight) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
}
}
How can I add a mouse click listener to that image? Additionally, I want to get the click coordinate of the image, not the JPanel.
Add a MouseListener to the pane as per normal.
In the mouseClicked method check to see if the Point is within the rectangle of the image...
public void mouseClicked(MouseEvent evt) {
if (image != null) {
double width = scale * imageWidth;
double height = scale * imageHeight;
double x = (getWidth() - width) / 2;
double y = (getHeight() - height) / 2;
Rectangle2D.Double bounds = new Rectangle2D.Double(x, y, width, height);
if (bounds.contains(evt.getPoint()) {
// You clicked me...
}
}
}
So far I have a java app where I draw a circle(player) and then draw a green rectangle on top(gun barrel). I have it so when the player moves, the barrel follows with it. I want it to find where the mouse is pointing and then rotate the barrel accordingly. For an example of what I mean look at this video I found http://www.youtube.com/watch?v=8W7WSkQq5SU See how the player image reacts when he moves the mouse around?
Here's an image of what the game looks like so far:
So how do I rotate it like this? Btw I don't like using affinetransform or Graphics2D rotation. I was hoping for a better way. Thanks
Using the Graphics2D rotation method is indeed the easiest way. Here's a simple implementation:
int centerX = width / 2;
int centerY = height / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
g.fillRect(...); // draw your rectangle
If you want to remove the rotation when you're done so you can continue drawing normally, use:
Graphics2D g2d = (Graphics2D)g;
AffineTransform transform = g2d.getTransform();
g2d.rotate(angle, centerX, centerY);
g2d.fillRect(...); // draw your rectangle
g2d.setTransform(transform);
It's a good idea to just use Graphics2D anyway for anti-aliasing, etc.
Using AffineTransform, sorry, only way I know how :P
public class RotatePane extends javax.swing.JPanel {
private BufferedImage img;
private Point mousePoint;
/**
* Creates new form RotatePane
*/
public RotatePane() {
try {
img = ImageIO.read(getClass().getResource("/MT02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
int x = (width - img.getWidth()) / 2;
int y = (height - img.getHeight()) / 2;
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
g2d.drawImage(img, x, y, this);
x = width / 2;
y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
g2d.dispose();
}
}
Will produce this effect
The red line (point out from the center) will want to follow the cursor.