i have an arraylist RecArray of objects with each object containing two int values, one for the width and for the height of a rectangle. Each rectangle's height and width are a multiple of ten. the rectangles have to be passed on to the surface as in the given order in RecArray from left to right and from top to bottom. my problem is i can not find the x,y coordinates of the next rectangle. what im trying to do is, starting at the coordinate (0,0) i generate the first rectangle, add it to an arraylist RecList. Then i set the x and y coordinates. x becomes x = x+RecArray.get(0).getLength1() + 1. if x is greater than the width of the jpanel surface then it becomes 0 and y becomes y = y + 10 . starting from the second object in the RecArray i try to generate rectangles with the given coordinates and width&height. Then i try to compare them with all the previous rectangles to see if there is any overlapping. if there is no overlapping, the rectangle will be drawn, if there is overlapping, the x coordinate of the rec becomes x = RecList.get(j).width+1 and if that exceeds the width x becomes 0 and y is y=y+10. Then i regenate the current rectangle with the new coordinates and compare with the other rectangles in RecList again till i find the right spot for the current rectangle.ive been dealing with that issue for the last 5 days and am really fed up now. i would greatly appreciate any tipps. and Please be patient with me. im still learning programming.
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle rec = new Rectangle(x, y, RecArray.get(0).getWidth(),
RecArray.get(0).getHeight());
RecList.add(rec);
recPaint(g2,RecArray.get(0));
x = x + RecArray.get(0).getWidth() + 1;
int i;
for (i = 1; i < RecArray.size(); i++) {
if (x >= this.getArea().getWidth()) {
x = 0;
y = y + 10;
}
Rectangle rec1 = new Rectangle(x, y, RecArray.get(i)
.getWidth(), RecArray.get(i).getheight());
for (int j= 0; j < RecList.size(); j++) {
if (!recIntersect(rec1, RecList.get(j))) {
RecList.add(rec1);
recPaint(g2,RecArray.get(i));
break;
}
else {
x = RecList.get(j).width;
if (x >= this.getFlaeche().getLength1()) {
x = 0;
y = y + 10;
}
rec1 = new Rectangle(x, y,RecArray.get(i). .getWidth(),
RecArray.get(i).getHeight());
}
x = x + RecArray.get(i).getWidth();
}
//With this method using the given rec parameter a rectangle will be drawn on the g2 and filled in blue colour
private void recPaint (Graphics2D g2, RecType rec){
g2.setColor(Color.BLUE);
g2.fillRect(x, y, rec.getWidth(),
rec.getLength2());
g2.setColor(Color.BLACK);
g2.drawRect(x, y, rec.getHeight(),
rec.getLength2());
}
// returns true, if two rectangles overlap
private boolean recIntersect(Rectangle rec1, Rectangle rec2) {
if( rec1.intersects(rec2)){
return true;
}
return false;
}
Edit: apparently i haven't stated clearly what my problem is. my problem is, that the way i generate (x,y) coordinates of the rectangles is obviously wrong. the way my algorithm works doesnt get the results i want. i want my rectangles to be placed neatly next to/above/below each other WITHOUT overlapping, which is not the case.
Separate out your List of Rectangles. Calculate the X, Y coordinates once.
Since I didn't have your object class, I used the Dimension class, which holds a width and a length. I used the Rectangle class to hold the objects that will eventually be drawn in your Swing GUI.
Divide and conquer. Separate out your GUI model, view, and controller(s). This way, you can focus on one piece of the puzzle at a time.
Here are the results of my test code when I ran it with a drawing area of 500, 400.
java.awt.Rectangle[x=0,y=0,width=100,height=100]
java.awt.Rectangle[x=100,y=0,width=20,height=10]
java.awt.Rectangle[x=120,y=0,width=40,height=20]
java.awt.Rectangle[x=160,y=0,width=60,height=40]
java.awt.Rectangle[x=220,y=0,width=80,height=60]
java.awt.Rectangle[x=300,y=0,width=20,height=10]
java.awt.Rectangle[x=320,y=0,width=120,height=110]
Here are the results of my test code when I ran it with a drawing area of 200, 200.
java.awt.Rectangle[x=0,y=0,width=100,height=100]
java.awt.Rectangle[x=100,y=0,width=20,height=10]
java.awt.Rectangle[x=120,y=0,width=40,height=20]
java.awt.Rectangle[x=0,y=100,width=60,height=40]
java.awt.Rectangle[x=60,y=100,width=80,height=60]
java.awt.Rectangle[x=140,y=100,width=20,height=10]
And here's the code. I fit rectangles on the X axis until I can't fit another rectangle. Then I add the maximum height to Y, reset the X to zero, reset the maximum height and fit the next row of rectangles.
Create test applications like I did here and make sure that you can create the GUI model long before you create the GUI view and GUI controller.
package com.ggl.testing;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
public class CalculatingRectangles {
public static void main(String[] args) {
CalculatingRectangles calculatingRectangles = new CalculatingRectangles();
Dimension drawingArea = new Dimension(200, 200);
List<Dimension> dimensions = new ArrayList<>();
dimensions.add(new Dimension(100, 100));
dimensions.add(new Dimension(20, 10));
dimensions.add(new Dimension(40, 20));
dimensions.add(new Dimension(60, 40));
dimensions.add(new Dimension(80, 60));
dimensions.add(new Dimension(20, 10));
dimensions.add(new Dimension(120, 110));
List<Rectangle> rectangles = calculatingRectangles
.calculatingRectangles(drawingArea, dimensions);
System.out.println(displayRectangles(rectangles));
}
private static String displayRectangles(List<Rectangle> rectangles) {
StringBuilder builder = new StringBuilder();
for (Rectangle r : rectangles) {
builder.append(r);
builder.append(System.getProperty("line.separator"));
}
return builder.toString();
}
public List<Rectangle> calculatingRectangles(Dimension drawingArea,
List<Dimension> dimensions) {
int width = drawingArea.width;
int height = drawingArea.height;
int x = 0;
int y = 0;
int index = 0;
int maxHeight = 0;
boolean hasRoom = dimensions.size() > index;
List<Rectangle> rectangles = new ArrayList<>();
while (hasRoom) {
Dimension d = dimensions.get(index);
maxHeight = Math.max(maxHeight, d.height);
if ((x + d.width) <= width && (y + maxHeight) <= height) {
Rectangle r = new Rectangle(x, y, d.width, d.height);
x += d.width;
rectangles.add(r);
index++;
if (index >= dimensions.size()) {
hasRoom = false;
}
} else {
y += maxHeight;
if (y > height) {
hasRoom = false;
}
x = 0;
}
}
return rectangles;
}
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am making a star using a draw line. I want to run a for loop to expand a star into multiple stars in a grid-like pattern. I am fairly new to java and could use some help with my code. The gride pattern that I would like the stars to open up too isn't too specific as far as columns x rows go. even making 6 stars or 9 stars is fine, as long as they are in a grid-like pattern.
So far, I have the star drawn with drawLine. At one point I got two stars but they were to close to each other. When I run the code it looks like I have a whole bunch of stars sort of staggered on top of each other and being able to get two stars on Star Field, I would like to get more in such 5x6 pattern or something close. I believe I might be having a hard time computing the math in the for loops to get this to happen.
Should I run, multiple nested for loops or is there a way to do this with using a minimal amount of for loops?
public static void drawFlag(int stars, int stripes, java.awt.Graphics
g, int x, int y, int width, int height) {
// Sets backround rectangle color to white
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
// Draw filled red rectangles *stripes*
int stripeHeight = height/stripes;
g.setColor(Color.RED);
int lastStripeDrawnY = 0;
// For loop runs red stripes
for (int i = y; i < y + height - 2*stripeHeight; i = i + 2*stripeHeight)
{
g.fillRect(x, i, width, stripeHeight);
lastStripeDrawnY = i;
}
// expands strips across the rectangle
int lastStripeY = lastStripeDrawnY+2*stripeHeight;
int lastStripeHeight = y + height - lastStripeY;
if (stripes%2 != 0) {
g.fillRect(x, lastStripeY, width, lastStripeHeight);
}
int stars1 = 15;
for (int cols = 1; cols <= stars1; cols++) {
int rows = stars1/cols;
if (cols > rows && cols <2*rows && cols*rows == stars1) {
}
}
// Draws the starField
int numberOfRedStripes = (int)Math.ceil(stripes/2.0);
int starFieldHeight = numberOfRedStripes*stripeHeight;
int starFieldWidth = starFieldHeight*width/height;
g.setColor(Color.BLUE);
g.fillRect(x, y, starFieldWidth, starFieldHeight);
for (int x1 = 0; x1+100 <+ starFieldWidth-5; x1++) {
if(x1/5*4 == stars) {
drawStar(g,x1,y,50);
for(int y1 = 0; y1 <=starFieldHeight-5;y1++) {
if(y1/4*2 == stars) {
drawStar(g,x,y1,50);
}
}
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.setColor(Color.WHITE);
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
Expand one star into a checkered grid-like pattern.
There are a number of ways you can approach this problem, you can, as you've started, simply try and build each star individually based on the required x/y position.
You could make a single star that was always at 0x0 and translate the Graphics context to the desire x/y position
Or, you could take advantage of the Shape API.
This allows you to define a self contained object which describes the shape you are trying to create.
public class StarShape extends Path2D.Double {
public StarShape(double size) {
double mid = size / 2d;
moveTo(mid, 0);
lineTo((size * 0.6d), (size * 0.4d));
lineTo(size, (size * 0.4d));
lineTo((size * 0.72d), (size * 0.58d));
lineTo((size * 0.85d), size);
lineTo((size * 0.5d), (size * 0.72d));
lineTo((size * 0.2), size);
lineTo((size * 0.325d), (size * 0.58d));
lineTo(0, (size * 0.4d));
lineTo((size * 0.4d), (size * 0.4d));
closePath();
}
}
There are lots of side benefits to this, but the immediate benefit is that it's "paintable". You can pass an instance of it directly to Graphics2D and have it painted and/or filled based on your needs.
Now, with that in hand, you can do something like...
public class TestPane extends JPanel {
private StarShape star;
private double starSize = 10;;
public TestPane() {
star = new StarShape(starSize);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
PathIterator path = star.getPathIterator(at);
GeneralPath p = new GeneralPath();
p.append(path, true);
g2d.fill(p);
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
}
The reason I'd prefer this method, is it doesn't affect the origin of the original starShape. You could also use the technique to cache the results, so you're not repeatedly doing it in the paintComponent method.
You could also do something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
Graphics2D starg = (Graphics2D) g2d.create();
starg.translate(x, y);
starg.fill(star);
starg.dispose();
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
Which changes the origin of the Graphics context instead or something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double xCount = getWidth() / starSize;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
g2d.fill(star);
star.transform(AffineTransform.getTranslateInstance(starSize, 0));
}
star.transform(AffineTransform.getTranslateInstance(-(starSize) * xCount, starSize));
}
g2d.dispose();
}
which changes the origin of the star itself.
Personally, I prefer not to affect the original and instead simply change the context in how it's painted, but which method you use will come down to your needs.
Okay, that might seem like a lot of work for little gain, but the Shapes API is extremely powerful. Because it's point based (instead of pixel based), it can be more easily resized, without generating pixilation. It's very simple to rotate, through the use of AffineTransform and makes for a much simpler point of re-use.
Want to make the stars bigger? Simply change starStar, for example...
private double starSize = 50;
and the API takes care of the rest...
I used your drawStar() function and built this StarPanel. Try it and see if it gives you some hints for what you are trying to achieve.
Note that I removed g.setColor(Color.WHITE); line from your drawStar() function. We need to be careful when we set color of Graphics object. In many cases, this is the reason why we don't see what we draw.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
public class StarPanel extends JPanel
{
private int xStarting;
private int yStarting;
private int numberOfRows;
private int numberOfColumns;
private int xDisplacement;
private int yDisplacement;
public StarPanel(int xStarting, int yStarting,
int numberOfRows, int numberOfColumns,
int xDisplacement, int yDisplacement)
{
this.xStarting = xStarting;
this.yStarting = yStarting;
this.numberOfRows = numberOfRows;
this.numberOfColumns = numberOfColumns;
this.xDisplacement = xDisplacement;
this.yDisplacement = yDisplacement;
}
public static void main(String[] args)
{
StarPanel starPanel = new StarPanel(50, 50, 5, 6, 75, 75);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(starPanel);
frame.setBounds(300, 200, 500, 600);
frame.setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int row = 0; row < numberOfRows; row++) {
for (int column = 0; column < numberOfColumns; column++) {
drawStar(g, xStarting + (row * xDisplacement), yStarting + (column * yDisplacement), 50);
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.
I have a set of two dimensions points. Their X and Y are greater than -2 and lesser than 2. Such point could be : (-0.00012 ; 1.2334 ).
I would want to display these points on a graph, using rectangles (a rectangle illustrates a point, and has its coordinates set to its point's ones - moreover, it has a size of 10*10).
Rectangles like (... ; Y) should be displayed above any rectangles like (... ; Y-1) (positive Y direction is up). Thus, I must set the graph's origin not at the top-left hand-corner, but somewhere else.
I'm trying to use Graphics2D's AffineTransform to do that.
I get the minimal value for all the X coordinates
I get the minimal value for all the Y coordinates
I get the maximal value for all the X coordinates
I get the maximal value for all the Y coordinates
I get the distance xmax-xmin and ymax-ymin
Then, I wrote the code I give you below.
Screenshots
Some days ago, using my own method to scale, I had this graph:
(so as I explained, Y are inverted and that's not a good thing)
For the moment, i.e., with the code I give you below, I have only one point that takes all the graph's place! Not good at all.
I would want to have:
(without lines, and without graph's axis. The important here is that points are correctly displayed, according to their coordinates).
Code
To get min and max coordinates value:
x_min = Double.parseDouble((String) list_all_points.get(0).get(0));
x_max = Double.parseDouble((String) list_all_points.get(0).get(0));
y_min = Double.parseDouble((String) list_all_points.get(0).get(1));
y_max = Double.parseDouble((String) list_all_points.get(0).get(1));
for(StorableData s : list_all_points) {
if(Double.parseDouble((String) s.get(0)) < x_min) {
x_min = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(0)) > x_max) {
x_max = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(1)) < y_min) {
y_min = Double.parseDouble((String) s.get(1));
}
if(Double.parseDouble((String) s.get(1)) > y_max) {
y_max = Double.parseDouble((String) s.get(1));
}
}
To draw a point:
int x, y;
private void drawPoint(Cupple storable_data) {
//x = (int) (storable_data.getNumber(0) * scaling_coef + move_x);
//y = (int) (storable_data.getNumber(1) * scaling_coef + move_y);
x = storable_data.getNumber(0).intValue();
y = storable_data.getNumber(1).intValue();
graphics.fillRect(x, y, 10, 10);
graphics.drawString(storable_data.toString(), x - 5, y - 5);
}
To paint the graph:
#Override
public void paint(Graphics graphics) {
this.graphics = graphics;
Graphics2D graphics_2d = ((Graphics2D) this.graphics);
AffineTransform affine_transform = graphics_2d.getTransform();
affine_transform.scale(getWidth()/(x_max - x_min), getHeight()/(y_max - y_min));
affine_transform.translate(x_min, y_min);
graphics_2d.transform(affine_transform);
for(StorableData storable_data : list_all_points) {
graphics_2d.setColor(Color.WHITE);
this.drawPoint((Cupple) storable_data);
}
I suggest you map each data point to a point on the screen, thus avoiding the following coordinate system pitfalls. Take your list of points and create from them a list of points to draw. Take into account that:
The drawing is pixel-based, so you will want to scale your points (or you would have rectangles 1 to 4 pixels wide...).
You will need to translate all your points because negative values will be outside the boundaries of the component on which you draw.
The direction of the y axis is reversed in the drawing coordinates.
Once that is done, use the new list of points for the drawing and the initial one for calculations. Here is an example:
public class Graph extends JPanel {
private static int gridSize = 6;
private static int scale = 100;
private static int size = gridSize * scale;
private static int translate = size / 2;
private static int pointSize = 10;
List<Point> dataPoints, scaledPoints;
Graph() {
setBackground(Color.WHITE);
// points taken from your example
Point p1 = new Point(-1, -2);
Point p2 = new Point(-1, 0);
Point p3 = new Point(1, 0);
Point p4 = new Point(1, -2);
dataPoints = Arrays.asList(p1, p2, p3, p4);
scaledPoints = dataPoints.stream()
.map(p -> new Point(p.x * scale + translate, -p.y * scale + translate))
.collect(Collectors.toList());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// draw a grid
for (int i = 0; i < gridSize; i++) {
g2d.drawLine(i * scale, 0, i * scale, size);
g2d.drawLine(0, i * scale, size, i * scale);
}
// draw the rectangle
g2d.setPaint(Color.RED);
g2d.drawPolygon(scaledPoints.stream().mapToInt(p -> p.x).toArray(),
scaledPoints.stream().mapToInt(p -> p.y).toArray(),
scaledPoints.size());
// draw the points
g2d.setPaint(Color.BLUE);
// origin
g2d.fillRect(translate, translate, pointSize, pointSize);
g2d.drawString("(0, 0)", translate, translate);
// data
for (int i = 0; i < dataPoints.size(); i++) {
Point sp = scaledPoints.get(i);
Point dp = dataPoints.get(i);
g2d.fillRect(sp.x, sp.y, pointSize, pointSize);
g2d.drawString("(" + dp.x + ", " + dp.y + ")", sp.x, sp.y);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setContentPane(new Graph());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
And another:
You might want to have the points aligned on the grid intersections and not below and to the right of them. I trust you will figure this one out.
Also, I ordered the points so that drawPolygon will paint the lines in the correct order. If your points are arbitrarily arranged, look for ways to find the outline. If you want lines between all points like in your example, iterate over all combinations of them with drawLine.
I need to:
1.) move the origin and also rotate the coordinate plane so that x-values progress rightward and y-values progress upward from the new origin(which needs to be the bottom left corner of the inner, blue rectangle in the code below). This will enable me to plot points at x,y coordinate pairs in the code below.
2.) plot rotated labels for the tic marks on the y-axis of the data plot.
The code below sets up this problem. It works, except for two problems:
1.) the data points are being plotted with the upper left hand corner as the origin and y-values descending downward
2.) the labels for the tic marks on the y-axis are not being drawn on the screen
Can anyone show me how to fix the code below so that it fixes these two problems and does what the first paragraph above describes?
The code is in the following two java files:
DataGUI.java
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
class DataGUI extends JFrame{
DataGUI() {
super("X,Y Plot");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(800, 400));
this.pack();
this.setSize(new Dimension(800, 600));
this.setLocationRelativeTo(null);
setLayout(new GridLayout());
ArrayList<Double> myDiffs = new ArrayList<Double>();
myDiffs.add(25.0);
myDiffs.add(9.0);
myDiffs.add(7.0);
myDiffs.add(16.0);
myDiffs.add(15.0);
myDiffs.add(6.0);
myDiffs.add(2.0);
myDiffs.add(8.0);
myDiffs.add(2.0);
myDiffs.add(27.0);
myDiffs.add(14.0);
myDiffs.add(12.0);
myDiffs.add(19.0);
myDiffs.add(10.0);
myDiffs.add(11.0);
myDiffs.add(8.0);
myDiffs.add(19.0);
myDiffs.add(2.0);
myDiffs.add(16.0);
myDiffs.add(5.0);
myDiffs.add(18.0);
myDiffs.add(23.0);
myDiffs.add(9.0);
myDiffs.add(4.0);
myDiffs.add(8.0);
myDiffs.add(9.0);
myDiffs.add(3.0);
myDiffs.add(3.0);
myDiffs.add(9.0);
myDiffs.add(13.0);
myDiffs.add(17.0);
myDiffs.add(7.0);
myDiffs.add(0.0);
myDiffs.add(2.0);
myDiffs.add(3.0);
myDiffs.add(33.0);
myDiffs.add(23.0);
myDiffs.add(26.0);
myDiffs.add(12.0);
myDiffs.add(12.0);
myDiffs.add(19.0);
myDiffs.add(14.0);
myDiffs.add(9.0);
myDiffs.add(26.0);
myDiffs.add(24.0);
myDiffs.add(13.0);
myDiffs.add(19.0);
myDiffs.add(2.0);
myDiffs.add(7.0);
myDiffs.add(28.0);
myDiffs.add(15.0);
myDiffs.add(2.0);
myDiffs.add(5.0);
myDiffs.add(17.0);
myDiffs.add(2.0);
myDiffs.add(16.0);
myDiffs.add(19.0);
myDiffs.add(2.0);
myDiffs.add(31.0);
DataPanel myPP = new DataPanel(myDiffs,this.getHeight(),this.getWidth());
this.add(myPP);
this.setVisible(true);// Display the panel.
}
public static void main(String[] args){
DataGUI myDataGUI = new DataGUI();
myDataGUI.setVisible(true);
}
}
DataPanel.java (Note: I edited the code below to include trashgod's suggestions, but it still does not work.)
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
class DataPanel extends JPanel {
Insets ins; // holds the panel's insets
ArrayList<Double> myDiffs;
double maxDiff = Double.NEGATIVE_INFINITY;
double minDiff = Double.POSITIVE_INFINITY;
double maxPlot;
DataPanel(ArrayList<Double> Diffs, int h, int w){
setOpaque(true);// Ensure that panel is opaque.
setPreferredSize(new Dimension(w, h));
setMinimumSize(new Dimension(w, h));
setMaximumSize(new Dimension(w, h));
myDiffs = Diffs;
repaint();
this.setVisible(true);
}
protected void paintComponent(Graphics g){// Override paintComponent() method.
super.paintComponent(g);
//get data about plotting environment and about text
int height = getHeight();
int width = getWidth();
ins = getInsets();
Graphics2D g2d = (Graphics2D)g;
FontMetrics fontMetrics = g2d.getFontMetrics();
String xString = ("x-axis label");
int xStrWidth = fontMetrics.stringWidth(xString);
int xStrHeight = fontMetrics.getHeight();
String yString = "y-axis label";
int yStrWidth = fontMetrics.stringWidth(yString);
int yStrHeight = fontMetrics.getHeight();
String titleString ="Title of Graphic";
int titleStrWidth = fontMetrics.stringWidth(titleString);
int titleStrHeight = fontMetrics.getHeight();
int leftMargin = ins.left;
//set parameters for inner rectangle
int hPad=10;
int vPad = 6;
int testLeftStartPlotWindow = ins.left+5+(3*yStrHeight);
int testInnerWidth = width-testLeftStartPlotWindow-ins.right-hPad;
getMaxMinDiffs();
getMaxPlotVal();
double increment = 5.0;
int numTicks = (int)(maxPlot/increment);//will use numTicks for: remainder, leftStartPlotWindow, innerRectangle+labels+tickmarks
int remainder = testInnerWidth%numTicks;
int leftStartPlotWindow = testLeftStartPlotWindow-remainder;
System.out.println("remainder is: "+remainder);
int bottomPad = (3*xStrHeight)-vPad;
int blueTop = ins.bottom+(vPad/2)+titleStrHeight;
int blueHeight = height-bottomPad-blueTop;
int blueWidth = blueHeight;
int blueBottom = blueHeight+blueTop;
//plot outer rectangle
g.setColor(Color.red);
int redWidth = width-leftMargin-1;
g.drawRect(leftMargin, ins.bottom, redWidth, height-ins.bottom-1);
//write top label
g.setColor(Color.black);
g.drawString(titleString, leftStartPlotWindow+((blueWidth/2)-(titleStrWidth/2)), titleStrHeight);
// fill, then plot, inner rectangle
g.setColor(Color.white);
g.fillRect(leftStartPlotWindow, blueTop, blueWidth, blueHeight);
g.setColor(Color.blue);
g.drawRect(leftStartPlotWindow, blueTop, blueWidth, blueHeight);
//scale the diffs to fit window
double Scalar = blueWidth/maxPlot;
ArrayList<Double> scaledDiffs = new ArrayList<Double>();
for(int e = 0;e<myDiffs.size();e++){scaledDiffs.add(myDiffs.get(e)*Scalar);}
//plot the scaled Diffs
AffineTransform at = g2d.getTransform();//save the graphics context's transform
g2d.translate(leftStartPlotWindow, blueTop);//translate origin to bottom-left corner of blue rectangle
g2d.scale(1, -1);//invert the y-axis
for(int w = 0;w<scaledDiffs.size();w++){
if(w>0){
double prior = scaledDiffs.get(w-1);
int priorInt = (int)prior;
double current = scaledDiffs.get(w);
int currentInt = (int)current;
g2d.drawOval(priorInt, currentInt, 4, 4);
}
}
g2d.setTransform(at);//restore the transform for conventional rendering
//write x-axis label
g.setColor(Color.red);
g.drawString(xString, leftStartPlotWindow+((blueWidth/2)-(xStrWidth/2)), height-ins.bottom-vPad);
//write y-axis label
g2d.rotate(Math.toRadians(-90), 0, 0);//rotate text 90 degrees counter-clockwise
g.drawString(yString, -(height/2)-(yStrWidth/2), yStrHeight);
g2d.rotate(Math.toRadians(+90), 0, 0);//rotate text 90 degrees clockwise
// draw tick marks on x-axis
NumberFormat formatter = new DecimalFormat("#0.0");
double k = (double)blueWidth/(double)numTicks;
double iteration = 0;
for(int h=0;h<=numTicks;h++){
int xval = (int)(h*k);
g.setColor(Color.red);
g.drawLine(leftStartPlotWindow+xval, blueBottom+2, leftStartPlotWindow+xval, blueBottom+(xStrHeight/2));//draw tick marks
g.drawString(formatter.format(iteration),leftStartPlotWindow+xval-(fontMetrics.stringWidth(Double.toString(iteration))/2),blueBottom+(xStrHeight/2)+13);
iteration+=increment;
}
// draw tick marks on y-axis
iteration = 0;
for(int h=0;h<=numTicks;h++){
int yval = (int)(h*k);
g.setColor(Color.red);
g.drawLine(leftStartPlotWindow-2, blueBottom-yval, leftStartPlotWindow-(yStrHeight/2), blueBottom-yval);//draw tick marks
g2d.rotate(Math.toRadians(-90), 0, 0);//rotate text 90 degrees counter-clockwise
g.drawString(formatter.format(iteration),leftStartPlotWindow-2,blueBottom-(fontMetrics.stringWidth(Double.toString(iteration))/2));
g2d.rotate(Math.toRadians(+90), 0, 0);//rotate text 90 degrees clockwise
iteration+=increment;
}
}
void getMaxMinDiffs(){// get max and min of Diffs
for(int u = 0;u<myDiffs.size();u++){
if(myDiffs.get(u)>maxDiff){maxDiff = myDiffs.get(u);}
if(myDiffs.get(u)<minDiff){minDiff = myDiffs.get(u);}
}
}
void getMaxPlotVal(){
maxPlot = maxDiff;
maxPlot += 1;//make sure maxPlot is bigger than the max data value
while(maxPlot%5!=0){maxPlot+=1;}//make sure maxPlot is a multiple of 5
}
}
Also, as always, links to articles or tutorials on the topic are much appreciated.
One approach is shown in SineTest. In outline,
Save the graphics context's transform.
Graphics2D g2d = (Graphics2D) g;
AffineTransform at = g2d.getTransform();
Translate the origin to the center.
g2d.translate(w / 2, h / 2);
Invert the y-axis.
g2d.scale(1, -1);
Render using cartesian coordinates.
Restore the transform for conventional rendering.
g2d.setTransform(at);
Apologies for somewhat incomplete answer, but this may get your gears turning. Java draws things the way you described them: It considers the top left corner of the screen to be 0, 0 and draws x increasing to the right and y increasing downwards. If you make the line that states
g2d.drawOval(priorInt, currentInt, 4, 4);
into
g2d.drawOval(blueWidth - priorInt, blueHeight - currentInt, 4, 4);
it should yield the correct results for your first issue. I need a bit more info on the second problem to help you with that one though. Are they just off the screen or are the getting drawn over by something else? Try flipping +s and -s around to see if you can get the correct result if that is the case.
I want to put several rectangle i a row. But because I'm new to Android and specially to Bitmap, Canvas and so on, I need some help.
It should look like this, only with rectangles:
I have created one rectangle with this code:
Paint paint = new Paint();
paint.setColor(Color.parseColor("#CD5C5C"));
Bitmap bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bg);
canvas.drawRect(50, 80, 200, 200, paint);
RelativeLayout ll = (RelativeLayout) findViewById(R.id.rect);
ImageView iV = new ImageView(this);
iV.setImageBitmap(bg);
ll.addView(iV);
But now I dont know how to create more rectangles with different colors in a row.
I'm really new and sorry for that maybe stupid question but I need help for it.
Can anybody guide me how to do this in the best way?
The key here are these lines:
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(50, 80, 200, 200, paint);
They set the colour and draw a rectangle. You can now repeat these lines to get 2 rectangles:
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(50, 80, 200, 200, paint);
paint.setColor(Color.parseColor("#DDDDDD"));
canvas.drawRect(210, 80, 360, 200, paint);
Note that I have changed the colour and co-ordinates a little bit. You could continue doing this several times to get all of your rectangles drawn.
Better still use a variable for the x and y coordinates, and use a loop:
int left = 50; // initial start position of rectangles (50 pixels from left)
int top = 50; // 50 pixels from the top
int width = 150;
int height = 150;
for (int row = 0; row < 2; row++) { // draw 2 rows
for(int col = 0; col < 4; col++) { // draw 4 columns
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(left, top, left+width, top+height, paint);
left = (left + width + 10); // set new left co-ordinate + 10 pixel gap
// Do other things here
// i.e. change colour
}
top = top + height + 10; // move to new row by changing the top co-ordinate
}
Hope that helps.
This should do it. I tried to self-document my code as mush as possible. This is very dynamic i.e. you can adjust the height, width, xPad, yPad, etc. and the window will compensate.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class RectanglesPanel extends JPanel {
public static final int[] COLORS = new int[] {
0xFFFFFF, 0xF67457, 0xFFC238, 0xEFEF38,
0xBCCACA, 0x75D1E0, 0x84E0C2, 0xC2E749
};
private static Random rand = new Random();
private int width = 80;
private int height = 50;
private int rows = 2;
private int cols = 4;
private int xPad = 20;
private int yPad = 30;
private float strokeWidth = 2.0f;
int windowWidth = calculateOffset(width, cols, xPad);
int windowHeight = calculateOffset(height, rows, yPad);
public RectanglesPanel() {
setPreferredSize(new Dimension(windowWidth, windowHeight));
}
private int calculateOffset(int whole, int partitions, int padding) {
return (whole * partitions) + (padding * (partitions + 1));
}
#Override
public void paintComponent(Graphics g) {
Stroke stroke = new BasicStroke(strokeWidth,
BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
((Graphics2D)g).setStroke(stroke);
// Fill in background.
g.setColor(new Color(0xF6F6F6));
g.fillRect(0, 0, windowWidth, windowHeight);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
int x = calculateOffset(width, col, xPad);
int y = calculateOffset(height, row, yPad);
int color = (row * cols + col) % COLORS.length;
// Fill in rectangle.
g.setColor(new Color(COLORS[color]));
g.fillRect(x, y, width, height);
// Stroke the border of the rectangle.
g.setColor(new Color(0xE7E7E7));
g.drawRect(x, y, width, height);
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new RectanglesPanel();
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
use for loop keeping the y coordinates constant
for(i=0;i<=200;i=i+40)
{
canvas.drawRect(i,0,i+30,100);
}
for next row increase y coordinate by your require amount and repeat the same or use nested for loops
you can set color by
myPaint.setColor(color.black);
myPaint.setStyle(Style.FILL);
canvas.drawRect(0,0,100,100, myPaint);