Lines don't overlap when they should Java Swing - java

I'm drawing lines in a JFrame on a self made gridPanel.
Problem is, I draw the lines between 2 points. When I have a line that is between point 1 and point 2 and a line between point 2 and point 3, the lines should connect. This however isn,t the case, there is a small gap in between, no idea why. But it isn't drawing till the end of the specified point. (start point is correct.)
Here is the code of the JFrame:
public void initialize(){
this.setLayout(new BorderLayout());
this.setPreferredSize(new Dimension(500, 400));
gridPane = new GridPane();
gridPane.setBackground(Color.WHITE);
gridPane.setSize(this.getPreferredSize());
gridPane.setLocation(0, 0);
this.add(gridPane,BorderLayout.CENTER);
//createSampleLabyrinth();
drawWall(0,5,40,5); //These are the 2 lines that don't connect.
drawWall(40,5,80,5);
this.pack();
}
drawWall calls a method that calls a method in GridPane.
The relevant code in gridPane:
/**
* Draws a wall on this pane. With the starting point being x1, y1 and its end x2,y2.
* #param x1
* #param y1
* #param x2
* #param y2
*/
public void drawWall(int x1, int y1, int x2, int y2) {
Wall wall = new Wall(x1,y1,x2,y2, true);
wall.drawGraphic();
wall.setLocation(x1, y1);
wall.setSize(10000,10000);
this.add(wall, JLayeredPane.DEFAULT_LAYER);
this.repaint();
}
This method creates a wall and puts it in the Jframe.
The relevant code of the wall:
public class Wall extends JPanel {
private int x1;
private int x2;
private int y1;
private int y2;
private boolean black;
/**
* x1,y1 is the start point of the wall (line) end is x2,y2
*
* #param x1
* #param y1
* #param x2
* #param y2
*/
public Wall(int x1, int y1, int x2, int y2, boolean black) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.black = black;
setOpaque(false);
}
private static final long serialVersionUID = 1L;
public void drawGraphic() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if(black){
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(8));
} else {
g2.setColor(Color.YELLOW);
g2.setStroke(new BasicStroke(3));
}
g2.drawLine(x1, y1, x2, y2);
}
}
So, where am I going wrong? The true/false is to determine if the wall should be black or yellow, nothing to be concerned about.

You've set the main layout as BorderLayout using this.setLayout(new BorderLayout());
You then add the GridPane to the center position this.add(gridPane,BorderLayout.CENTER);
You then try and add the walls to the main layout using this.add(wall, JLayeredPane.DEFAULT_LAYER); ... But the main layout is a BorderLayout
This is going to cause you some issues
UPDATED
The other problem you have is in the Wall#paintComponent method.
You are drawing the lines offset from the x1 and y1 positions, but the component has already being positioned at this point.
The top, left corner of any component is always 0x0
The line g2.drawLine(x1, y1, x2, y2); should read more like...
int x = x2 - x1;
int y = y2 - y1;
g2.drawLine(0, 0, x, y);
UPDATED
You should also avoid setting the size of your components to some arbitary value (such 1000x1000) and rely more on the ability for your components to give you feedback...
public Dimension getPreferredSize() {
int width = Math.max(x1, x2) - Math.min(x1, x2);
int height = Math.max(y1, y2) - Math.min(y1, y2);
if (black) {
width += 8;
height += 8;
} else {
width += 3;
height += 3;
}
return new Dimension(width, height);
}
Then when adding the Wall, you can use wall.setSize(wall.getPreferredSize()) instead...

Related

Does anyone know an approximate text to pixel ratio? (Java String positioning)

Like you see in almost all text-editing softwares, css and more, I want to position my Text with java.awt. My test code for this is:
public class Test {
public static void main(String[] args) {
// creating the frame
JFrame frame = new JFrame("Test");
frame.setSize(1000, 800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
// variables
int x1 = 50;
int x2 = 500;
int y1 = 70;
int y2 = 150;
int y3 = 230;
int width = 400;
int height = 60;
int fontsize = 40;
String text = "This is a test";
frame.add(new JPanel() {
public void paint(Graphics g) {
g.setColor(Color.BLACK);
// borders
g.drawRect(x1, y1, width, height); // top
g.drawRect(x1, y2, width, height); // middle
g.drawRect(x1, y3, width, height); // bottom
g.drawRect(x2, y1, width, height); // left
g.drawRect(x2, y2, width, height); // center
g.drawRect(x2, y3, width, height); // right
g.setFont(new Font("arial", Font.PLAIN, fontsize));
// top
g.drawString(text, x1 + 10, y1 + fontsize); // x1 + 10 (10 is a buffer)
// center
g.drawString(text, x1 + 10, y2 + fontsize + (height - fontsize) / 2);
// bottom
g.drawString(text, x1 + 10, y3 + height);
// left
g.drawString(text, x2, y1 + fontsize);
// middle
g.drawString(text, x2 + width / 2 - text.length() * (fontsize/5), y2 + fontsize + (height - fontsize) / 2);
// right
g.drawString(text, x2 + (width - text.length() * (fontsize/5)), y3 + height);
}
});
frame.setVisible(true);
}
}
Of course it kind of looks messy, but I'm working on it in an API project where I'm implementing ux features atm.
You can use the FontMetrics object of the Graphics object to get information about the Font metrics to help with determining the size of the text:
FontMetrics fm = g.getFontMetrics();
See: Measuring Text tutorial.
Why are you doing custom painting? Why are you not using Swing components with layout managers to manage the UI? We can't give specific advice since we don't know what the goal of your posted code is.

Drawing a lanelist's members in cartesian coordinate system in java

I want to draw a lanelist's members in Cartesian coordinate system. But some of the lanes (including X&Y axis) axes do not appear. Tanx for your help.
public class Paint extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.orange);
g.drawLine(0, -10000, 0, 10000);// Y coordinate definition
g.setColor(Color.orange);
g.drawLine(-10000, 0, 10000, 0);// // X coordinate definition
for (int i1 = 0; i1 < Lanelist.size(); i1++) {// drawing lanes in the lanelist
int x1;
int y1;
int x2;
int y2;
x1 = (int) Math.round(Lanelist.get(i1).origNode.x);
y1 = (int) Math.round(Lanelist.get(i1).origNode.y);
x2 = (int) Math.round(.Lanelist.get(i1).destNode.x);
y2 = (int) Math.round(Lanelist.get(i1).origNode.y);
g.setColor(Color.white);
g.drawLine(x1, y1, x2, y2);
}
}
}
main class
public class Logistics{
public static void main(String[] args) throws IloException {
JFrame f2=new JFrame("Title");;
f2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Paint pl=new Paint();
f2.setSize(99999, 99999);
f2.setVisible(true);
f2.add(pl);
}
}

Number Line using Java Graphics API

I am trying to create a number line with labelled x-axis.Two problems:
Everything works fine for 0-9. But anything after that, the numbers get squashed together and not properly oriented on the scale.
My main axis line tends to disappear every time I try maximizing my window or at times it just wouldn't appear at all.Every time any of these happen, I have to re-compile my code and it works just fine.
Any help with the above problems will be greatly appreciated.
import java.awt.Graphics;
import javax.swing.JFrame;
/**
* #author Emil Shirima
*
*/
public class Drawing extends JFrame {
/**
* #param args
*/
int width = 300, height = 300, spacing = 10;
int x1 = 0, y1 = 150, x2 = 300, y2 = 150;
public Drawing() {
setTitle("Trial");
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
#Override
public void paint(Graphics brush) {
brush.drawLine(x1, y1, x2, y2);
x1 = 10;
y1 = 150;
x2 = 10;
y2 = 130;
// brush.drawLine(x1, y1, x2, y2);
for (int i = 0; i < 12; ++i) {
String ID = Integer.toString(i);
x1 = x2 += spacing;
brush.drawLine(x1, y1, x2, y2);
if (i < 10) {
brush.drawString(ID, x1 - 3, y2 + 40);
} else {
// With the below implementation, the numbers overlap each other
// and are not properly oriented on the axis
brush.drawString(ID, x1 - 3, y2 + 40);
// TODO: I need to resize the numbers after 10 so as they fit
// properly on the scale
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Drawing draw_object = new Drawing();
}
Current implementation:
Maximized GUI:
Your main problem:
You change x1, x2 within your paint method, and these changes will persist on the next painting. In other words, you're changing the state of the object within a rendering method, something that you must avoid doing.
You're using "magic" numbers making your program difficult to debug.
Other associated problems:
You're drawing directly in a JFrame, something that the Swing painting tutorials tell you exactly not to do since there are risks of significant side effects.
Instead draw in a JPanel's paintComponent method method.
You're not calling any super painting method, thus breaking the painting chain.
If you want the number line to extend through the component, get the component's size in the painting method (again, paintComponent) and use that to help determine the placement of the line.
Also consider sprinkling in a little FontMetrics to help place your numeric text. For example the following code creates a realizable number line:
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleNumberLinePanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 300;
private static final int GAP = 10;
private static final int START = 0;
private static final int END = 12;
private static final int VERT_LINE_HEIGHT = 20;
private static final Font FONT = new Font(Font.MONOSPACED, Font.BOLD, 14);
private static final int TEXT_GAP = 2;
#Override
protected void paintComponent(Graphics g) {
// call super method
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
// initialize these guys each time paintComponent is called
int x1 = GAP;
int y1 = height / 2;
int x2 = width - 2 * GAP;
int y2 = y1;
g.drawLine(x1, y1, x2, y2);
for (int i = START; i <= END; i++) {
int x = (i * (x2 - x1)) / (END - START) + GAP;
drawNumberAndLine(g, i, x, y1, VERT_LINE_HEIGHT);
}
}
private void drawNumberAndLine(Graphics g, int number, int x, int y,
int vertLineHeight) {
int x1 = x;
int y1 = y;
int x2 = x;
int y2 = y - vertLineHeight;
g.drawLine(x1, y1, x2, y2);
String text = String.valueOf(number);
g.setFont(FONT);
FontMetrics fontMetrics = g.getFontMetrics();
int textX = x - fontMetrics.stringWidth(text) / 2;
int textY = y + fontMetrics.getHeight() + TEXT_GAP;
g.drawString(text, textX, textY);
}
#Override // make GUI bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Number Line");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleNumberLinePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Resizing a square in Java

I am having an annoying problem trying to resize a draggable square in Java. To resize the square I am checking to see if the mouse cursor is inside a rectangular area surrounding the bottom right hand corner of the square - if it is, then the square resizes when I drag the mouse. This code works fine, BUT if I then click on the square to drag it around the screen, it jumps back to the default size of 100 x 100.
My class starts off like this:
public class DragPanel extends JPanel implements MouseListener,
MouseMotionListener, MouseWheelListener
{
Graphics2D g2;
Rectangle2D square;
Color colour;
double x1, y1, x2, y2, sizex, sizey;
double offsetX, offsetY;
double oldx, oldy;
boolean dragging = false;
boolean resizing = false;
public DragPanel()
{
x1 = 10.0;
y1 = 10.0;
sizex = 100.0;
sizey = 100.0;
x2 = x1 + sizex;
y2 = y1 + sizey;
square = new Rectangle2D.Double(x1, y1, sizex, sizey);
colour = Color.BLUE;
setFocusable(true);
addMouseListener(this);
addMouseMotionListener(this);
addMouseWheelListener(this);
this.requestFocus();
}
Here are my Mouse Pressed and Mouse Dragged Methods:
Mouse Pressed:
#Override
public void mousePressed(MouseEvent ev)
{
double mx = ev.getX();
double my = ev.getY();
if (mx > x1 && mx < x2 && my > y1 && my < y2)
{
dragging = true;
offsetX = mx - x1;
offsetY = my - y1;
}
if (mx > x2 - 3 && mx < x2 + 3 && my > y2 - 3 && my < y2 + 3)
{
oldx = mx;
oldy = my;
resizing = true;
}
}
Mouse Dragged:
#Override
public void mouseDragged(MouseEvent ev)
{
if (dragging)
{
double mx = ev.getX();
double my = ev.getY();
x1 = mx - offsetX;
y1 = my - offsetY;
x2 = x1 + sizex;
y2 = y1 + sizey;
square = new Rectangle2D.Double(x1, y1, sizex, sizey);
repaint();
}
if (resizing)
{
double mx = ev.getX();
double my = ev.getY();
double diffx, diffy;
diffx = oldx - mx;
diffy = oldy - my;
square = new Rectangle2D.Double(x1, y1, sizex - diffx, sizey - diffy);
repaint();
}
}
The code you see above does what I want it to do in terms of resizing, but as I already explained, DOESN'T work properly when I try and drag the square after resizing. And I know why - it is because of THIS line:
square = new Rectangle2D.Double(x1, y1, sizex - diffx, sizey - diffy);
So my solution was to change the last part of the if (resizing) block as follows:
diffx = oldx - mx;
diffy = oldy - my;
sizex -= diffx;
sizey -= diffy;
square = new Rectangle2D.Double(x1, y1, sizex, sizey);
repaint();
When I do this however, the thing stops working! I can still drag the square, but if I try and resize, the movement is erratic and extreme.
WHAT am I doing wrong?
Seems to me that the conditions for dragging and resizing are not mutually exclusive, particularly close to the borders. Assuming you are putting these two flags to false on mouse release, a single mouse click or move could still go into both modes at once.
I would put else if (mx > x2 - 3 && mx < x2 + 3 && my > y2 - 3 && my < y2 + 3) and else if (resizing) to avoid any intended consequences. This would make any dragging a priority over any resizing.
Being a graphical thing, hard to say if this is your problem (or part of it), but give it can't hurt to clear this up.
Edit: Of course, you might want to do the resize conditions take priority over (go before) the drag condition, since the area for resizing is much smaller than the area for dragging.
Edit 2: BTW, when you resize you are modifying your square, but not your sizex and sizey variables. Naturally, when you ask for those values when dragging they are the same as before (100). Store the changes and it should work. On that note, it is probably a bad idea to have multiple representations of the same information. It causes redundancies and synchronization issues like this one. If possible, remove these variables: double x1, y1, x2, y2, sizex, sizey; and read/write then from the current state of square (you probably don't need a new square every time either).
I treat these a two separate functions:
Check out the Component Mover
and the Component Resizer
The code in these classes is more complex than you need but you may want to consider the separation of the logic for each function in your final solution.
I found the solution, or rather, I found a solution. I changed my if (resizing) statement within the mouseDragged method as follows:
Old:
if (resizing)
{
double mx = ev.getX();
double my = ev.getY();
double diffx, diffy;
diffx = oldx - mx;
diffy = oldy - my;
square = new Rectangle2D.Double(x1, y1, sizex - diffx, sizey - diffy);
repaint();
}
New:
if (resizing)
{
double mx = ev.getX();
double my = ev.getY();
x2 = mx - rOffX;
y2 = my - rOffX;
sizex = x2 - x1;
sizey = sizex;
square.setRect(x1, y1, sizex, sizey);
repaint();
}

How can i display the distance of a line drawing randomly?

I'm trying to draw to filled circles, centered at random locations, with a line connecting the circles. The distance between the to centers is displayed on the line and whenever your resize the frame, the circles are redisplayed in new random locations.
I'm stuck in how to display the distance?
Any help is appreciated and thx for advance.
This's the code (what i managed to do):
public class Test extends JFrame {
public Test() {
add(new LineConnectingTheTwoCircles());
}
// Panel class
class LineConnectingTheTwoCircles extends JPanel {
//Default constructor
LineConnectingTheTwoCircles() {
}
/* Override paintComponent (getting access to the panel's Graphics
class) */
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int radius = 15;
// getting coordinates of circle 1
int x1 = (int) (Math.random() * (getWidth()));
int y1 = (int) (Math.random() * (getHeight()));
// getting coordinates of circle 2
int x2 = (int) (Math.random() * (getWidth()));
int y2 = (int) (Math.random() * (getWidth()));
// Setting color and drawing a filled circles (1 & 2)
g.setColor(Color.BLUE);
g.fillOval(x1 - radius, y1 - radius, 2 * radius, 2 * radius);
g.drawString("1", x1 - 25, y1);
g.setColor(Color.RED);
g.fillOval(x2 - radius, y2 - radius, 2 * radius, 2 * radius);
g.drawString("2", x2 - 25, y2);
connectingTheTwoCircles(g, x1, y1, x2, y2);
}
// Connecting the two circles from the center
private void connectingTheTwoCircles(Graphics g, int x1, int y1,
int x2, int y2) {
//Distance between the circles centered
double D = Math.sqrt((Math.pow((y2 - y1), 2))
+ (Math.pow((x2 - x1), 2)));
//Getting the coordinates for the line l
int x11 = x1;
int y11 = y1;
int x21 = x2;
int y21 = y2;
g.setColor(Color.BLACK);
g.drawLine(x11, y11, x21, y21);
}
public double getDistance(double x1, double y1, double x2, double y2) {
return Math.sqrt((Math.pow((y2 - y1), 2))
+ (Math.pow((x2 - x1), 2)));
}
}
public static void main(String[] args) {
// Frame declaration
Test frame = new Test();
/*
* Invoking some methods, to set a title on the title bar, to specifier
* the size of the frame to centre it on the screen, to tell the program
* to terminate when the frame is closed and finally to display it
*/
frame.setTitle("This is a test");
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Try next code draws distance at line center
double distance = getDistance(x11, y11, x21, y21);
g.drawString(distance+" ",
x11> x21 ? x21 + (x11-x21)/2 : x11 + (x21 - x11)/2 ,
y11> y21 ? y21 + (y11-y21)/2 : y11 + (y21 - y11)/2 );

Categories