Painting Yellow on White using Java Graphics - java

My application performs data visualization using gray-scale "heat map". Above it I need to paint time axis in yellow color. It looks good on black background, but becomes invisible on white background (see attached image). How to make it visible regardless of background?
Here is how I paint the timestamps:
g.setColor(Color.yellow);
g.drawString("12:43:15", x, y);
where g is java.awt.Graphics object

What about XOR'ing your Color. For e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
#SuppressWarnings("serial")
public class XorEg extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W / 4;
private static final float SIZE = 24f;
private String text = "Hello world, how's it going? ";
public XorEg() {
setFont(getFont().deriveFont(SIZE));
for (int i = 0; i < 2; i++) {
text += text;
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
int x = 0;
int y = 0;
int width = getWidth() / 2;
int height = getHeight();
g.fillRect(x, y, width, height);
g.setColor(Color.white);
x = width;
g.fillRect(x, y, width, height);
g.setXORMode(Color.blue);
g.drawString(text, 10, PREF_H / 2);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
XorEg mainPanel = new XorEg();
JFrame frame = new JFrame("XorEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
which shows:

You could "outline" the text (in black for example)
For example...
As demonstrated in Assigning a image to a String

Put a rectangle behind the text, and paint it a dark translucent color.
E.G. as seen in this answer (OK that is 'dark on light' as opposed to 'light on dark' but ..Batteries Not Included).
Here is another example that uses the same 'outline' approach as mentioned by #MadProgrammer.

Use another color that works good with black and white or detect lower color and change text color based on that, which is a better approach

Related

how do you draw a line that resize when window size change? [duplicate]

I've written an app that custom draws everything inside paint() based on fixed pixel positions. Then I disabled resize of the frame so its always visible.
However, now I would like to be able to resize it but I dont want to change my drawling code. I was hoping I could grab the 300x300 square of the Graphics g object and resize it to the JFrame current size after all of my drawling code, but I have no idea what I'm doing.
Here sample code. In this I want the 100x100 square to remain in the middle, proportionate to the resized JFrame:
package DrawAndScale;
import java.awt.Color;
import java.awt.Graphics;
public class DASFrame extends javax.swing.JFrame {
public DASFrame() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.setSize(300, 300);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DASFrame().setVisible(true);
}
});
}
#Override
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fill3DRect(100, 100, 100, 100, true);
}
}
Thanks.
Assuming you rename your method that paints for 300x300 as paint300, define a buffered image:
#Override public void paint(Graphics g) {
Image bufferImage = createImage(300, 300); // empty image
paint300(bufferImage.getGraphics()); // fill the image
g.drawImage(bufferImage, 0, 0, null); // send the image to graphics device
}
Above is when you want to draw at full size (300x300).
If your window is resized:
#Override public void paint(Graphics g) {
Image bufferImage = createImage(300, 300);
paint300(bufferImage.getGraphics());
int width = getWidth();
int height = getHeight();
CropImageFilter crop =
new CropImageFilter((300 - width)/2, (300 - height)/2 , width, height);
FilteredImageSource fis = new FilteredImageSource(bufferImage, crop);
Image croppedImage = createImage(fis);
g.drawImage(croppedImage, 0, 0, null);
}
The new classes are from from java.awt.image.*.
I didn't test this code. It's just to send you in the right direction.
if you want to painting Custom paint then look for JLabel or JPanel and including Icon/ImageIcon inside, simple example about that
import java.awt.*;
import javax.swing.*;
public class MainComponentPaint extends JFrame {
private static final long serialVersionUID = 1L;
public MainComponentPaint() {
setTitle("Customize Preffered Size Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponent());
pack();
setMinimumSize(getSize());
setPreferredSize(getSize());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
setVisible(true);
}
});
}
public static void main(String[] args) {
MainComponentPaint main = new MainComponentPaint();
main.display();
}
}
class CustomComponent extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
for (int i = 0; i < Math.max(w, h); i += 20) {
g.drawLine(i, 0, i, h);
g.drawLine(0, i, w, i);
}
}
}
Not an expert, but you could just scale the Graphics2D object (the passed Graphics is in fact a Graphics2D instance), where the x and y ratios are the ratios of the fixed size you chose to draw and the actual size of the frame.
See http://download.oracle.com/javase/6/docs/api/java/awt/Graphics2D.html#scale%28double,%20double%29
You could do this with some math.
public void paint(Graphics g){
int height = 100;
int width = 100;
int x = (this.getWidth() / 2) - (width / 2);
int y = (this.getHeight() / 2) - (height / 2);
g.setColor(Color.BLACK);
g.fill3DRect(x, y, width, height, true);
}
Or if you wanted to keep the width and height of the box with the same proportion, use int width = this.getWidth() / 3; and int height = this.getHeight() / 3.
The other option is to use Graphics2D.scale(), as JB pointed out, the passed Graphics object is actually a Graphics2D object.

How to multithread with paintComponent()?

I created an app that contains a square that bounces every time it touches an edge of the frame.I don't have issues lunching the app,the problem is that i don't know how to create various threads in order to have multiples squares inside the frame.
I tried multiple things but i can't figure out where i should create the threads.
I also noticed that the square is visible only when i add it directly inside the frame and not when i put it inside a JPanel.
Square.java
public class Square extends JComponent implements ActionListener {
int width = 20;
int height = 20;
double y = Math.random() * 360;
double x = Math.random() * 360;
boolean xMax = false;
boolean yMax = false;
boolean xMin = true;
boolean yMin = true;
Rectangle2D.Double square = new Rectangle2D.Double(x, y, width, height);
public Square() {
Timer t = new Timer(2, this);
t.start();
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(Color.BLUE);
g2.fill(square);
x_y_rules();
}
public void x_y_rules() {
if (xMax == true) {
x = x - 0.5;
if (x <= 0) {
xMax = false;
}
} else {
x = x + 0.5;
if (x >= this.getWidth()) {
xMax = true;
}
}
if (yMax == true) {
y = y - 0.5;
if (y <= 0) {
yMax = false;
}
} else {
y = y + 0.5;
if (y >= this.getHeight()) {
yMax = true;
}
}
square.setFrame(x, y, width, height);
}
#Override
public void actionPerformed(ActionEvent arg0) {
repaint();
}
}
App.java
public class App extends JFrame {
public static void main(String[] args) {
JFrame jf = new JFrame();
Square sqr = new Square();
jf.setSize(400, 400);
jf.setVisible(true);
jf.add(sqr);
jf.setDefaultCloseOperation(EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
}
}
Is it normal that despite i put a time of 2 inside the Timer,the square moves very slowly?
Issues:
you've got program logic, the x_y_rules() method call, inside of the paintComponent method. Get it out as it does not belong there, and instead put it into the Timer's ActionListener code where it belongs.
you can give each Square its own Swing Timer if you want. This isn't really a threading issue since each Timer's ActionListener will run on the EDT.
Two milliseconds is an unrealistic time slice to expect to use in a Swing Timer and no timer will run that fast. 11 to 13 is about the fastest to expect or hope for.
if you want your sprite to move faster, give it a greater value for delta-x and delta-y in your movement code.
Your JComponent has no preferred size defined which is likely why it's not showing up in the JPanel, since the default FlowLayout will size it then to [0, 0]. Override its getPreferredSize() and have it return a reasonable Dimension value.
you're calling setVisible(true) on your JFrame before adding all components, a no-no.
Ok,i put a getPrefferedSize() inside the square class but i've encountered a problem: the squares are not "together",it's like they're bouncing on separate panels
Then your program structure is broken. You really don't want create separate Swing components, and in fact your Square class shouldn't extend JComponent or JPanel. Rather
Square should be a logical class, one that extends from nothing (other than default Object).
Give it a drawing method, say public void draw(Graphics g) {....}
Create one class that extends JPanel, say called DrawingPanel, and override its paintComponent method.
Give the DrawingPanel class an ArrayList<Square> so that it can hold multiple Square objects.
Give the DrawingPanel class a Swing Timer
In the DrawingPanel class's Timer, have it update the position of all the Squares in the ArrayList, and then call repaint()
In the paintComponent method, iterate through all the Squares in the list, using a for loop, and call each one's draw method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private static final Color[] SQUARE_COLOR = { Color.BLUE, Color.CYAN, Color.DARK_GRAY,
Color.BLACK, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.RED, Color.YELLOW };
List<Square> squareList = new ArrayList<>();
public DrawingPanel() {
// create a bunch of squares
for (int i = 0; i < SQUARE_COLOR.length; i++) {
squareList.add(new Square(SQUARE_COLOR[i], PREF_W, PREF_H));
}
setBackground(Color.WHITE);
// create and start the timer
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// simply draw all the squares in the list
for (Square square : squareList) {
square.draw(g);
}
}
// set size of JPanel
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// simply iterate through list and move all squares
for (Square square : squareList) {
square.move();
}
repaint(); // then repaint the GUI
}
}
private static void createAndShowGui() {
DrawingPanel mainPanel = new DrawingPanel();
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
// this class does *not* extend JPanel or JComponent
class Square {
public static final int WIDTH = 20;
// location of Square
private double sqrX;
private double sqrY;
// X and Y speed
private double deltaX;
private double deltaY;
// width and height of DrawingPanel JPanel
private int dpWidth;
private int dpHeight;
// image to draw
private Image image;
public Square(Color color, int dpWidth, int dpHeight) {
this.dpWidth = dpWidth;
this.dpHeight = dpHeight;
// create square at random location with random speed
sqrX = Math.random() * (dpWidth - WIDTH);
sqrY = Math.random() * (dpHeight - WIDTH);
deltaX = Math.random() * 10 - 5;
deltaY = Math.random() * 10 - 5;
// one way to draw it is to create an image and draw it
image = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, WIDTH, WIDTH);
g.dispose();
}
public void move() {
// check that we're not hitting boundaries
if (sqrX + deltaX < 0) {
deltaX = Math.abs(deltaX);
}
if (sqrX + deltaX + WIDTH >= dpWidth) {
deltaX = -Math.abs(deltaX);
}
sqrX += deltaX;
// check that we're not hitting boundaries
if (sqrY + deltaY < 0) {
deltaY = Math.abs(deltaY);
}
if (sqrY + deltaY + WIDTH >= dpHeight) {
deltaY = -Math.abs(deltaY);
}
sqrY += deltaY;
}
public void draw(Graphics g) {
int x = (int) sqrX;
int y = (int) sqrY;
g.drawImage(image, x, y, null);
}
}

Generate square wave in JFrame

I have inefficient code of a square wave. I have 2 buttons, 1 table and something like a coordinate system where the square appears in. I want the wave to scroll/move in real time until it hits the end of the coordinate system instead of just appearing by selecting both of the buttons. Additionally, if anyone has a better way of drawing a square wave please tell me.
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(20, 300, 20, 450);
g2d.drawLine(20, 350, 400, 350);
g2d.drawLine(20, 400, 400, 400);
g2d.drawLine(20, 450, 400, 450);
if (this.jButtonSTART.isSelected() & this.jButtonAND.isSelected()) {
this.draw(g2d);
}
}
public void draw(Graphics2D g2d) {
boolean up = true;
while (x <= 380) {
g2d.setColor(Color.blue);
if (x > 0 && x % 95 == 0) {
up = !up;
g2d.drawLine(20 + x, up ? 315 : 350 + y, 20 + x, up ? 350 : 315 + y);
} else {
if (up) {
g2d.drawLine(20 + x, 315 + y, 21 + x, y + 315);
} else {
g2d.drawLine(20 + x, 350 + y, 21 + x, y + 350);
}
}
x++;
}
x = 0;
}
Simple way to draw your square wave and move it:
Create a BufferedImage that is longer than your GUI. It should have length that matches a the period of your square wave and be at least twice as long as the GUI component that it's displayed in.
Draw within the paintComponent method override of a JPanel, not the paint method.
Call the super's paintComponent method first within your override.
You'll draw the image using g.drawImage(myImage, imageX, imageY, this) where imageX and imageY are private instance fields of the JPanel-extending drawing class.
In a Swing Timer, advance imageX with each tick of the Timer, that is each time its ActionListener's actionPerformed method is called).
Then call repaint() on the drawing JPanel within the same actionPerformed method.
Done.
for example, note that this code does not do exactly what you're trying to do, but does show an example of Swing animation using a Swing Timer and paintComponent.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveWave extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 200;
private static final int TIMER_DELAY = 40;
public static final int DELTA_X = 2;
public static final int STARTING_MY_IMAGE_X = -PREF_W;
private static final Color COLOR_1 = Color.RED;
private static final Color COLOR_2 = Color.BLUE;
private static final Color BG = Color.BLACK;
private static final int CIRCLE_COUNT = 10;
private BufferedImage myImage = null;
private int myImageX = STARTING_MY_IMAGE_X;
private int myImageY = 0;
public MoveWave() {
setBackground(BG);
myImage = new BufferedImage(2 * PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = myImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, COLOR_1, 20, 20, COLOR_2, true));
for (int i = 0; i < CIRCLE_COUNT; i++) {
int x = (i * 2 * PREF_W) / CIRCLE_COUNT;
int y = PREF_H / 4;
int width = (2 * PREF_W) / CIRCLE_COUNT;
int height = PREF_H / 2;
g2.fillOval(x, y, width, height);
}
g2.dispose();
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
g.drawImage(myImage, myImageX, myImageY, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
myImageX += DELTA_X;
if (myImageX >= 0) {
myImageX = STARTING_MY_IMAGE_X;
}
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveWave");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveWave());
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

BufferedImage doesn't draw from 0,0

I hope my first post isn't too basic for y'all.
I'm trying to do some per-pixel drawing on a JCanvas using a BufferedImage (using setRGB()). I thought I would test all was working with a single diagonal line from the origin to the width/height of the JCanvas. The trouble is that I get a strange offset in the x axis that I can't seem to fix!
Here's a link to the problem:
http://i811.photobucket.com/albums/zz31/bohngy/problemMandel_zpsae20713a.jpeg
Here's the code:
public class Mandelbrot extends JFrame {
private BufferedImage I;
public Mandelbrot() {
super("Mandelbrot Set");
setSize(600, 600);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < getHeight(); x++) {
for (int y = 0; y < getWidth(); y++) {
I.setRGB(x, x, Color.GREEN.getRGB());
}
}
}
#Override
public void paint(Graphics g) {
g.drawImage(I, 0, 0, this);
}
public static void main(String[] args) {
new Mandelbrot().setVisible(true);
}
}
General issues
Don't extend JFrame (particularly, don't override the paint method of JFrame). Instead, do the painting in the paintComponent method a class that extends JPanel
Create the GUI from the Event Dispatch Thread
The main reason for the unexpected result is that you are creating an image that has the size of the frame - but the frame also has a title bar and a border, and these are "covering" parts of the image. The size of the area that is actually available for painting is smaller than the total frame size. Additionally, the getWidth() and getHeight() methods may return garbage as long as the frame is not yet visible on the screen.
One approach considering all this could look like in this snippet:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Mandelbrot
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1, 1));
BufferedImage image = createImage(500, 500);
ImagePanel imagePanel = new ImagePanel(image);
frame.getContentPane().add(imagePanel);
frame.pack();
frame.setVisible(true);
}
private static BufferedImage createImage(int w, int h)
{
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < w; x++)
{
image.setRGB(x, x, Color.GREEN.getRGB());
}
return image;
}
static class ImagePanel extends JPanel
{
private final BufferedImage image;
ImagePanel(BufferedImage image)
{
this.image = image;
}
#Override
public Dimension getPreferredSize()
{
if (super.isPreferredSizeSet())
{
return super.getPreferredSize();
}
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
}
}
All BufferedImage objects have an upper left corner coordinate of (0, 0). Any Raster used to construct a BufferedImage must therefore have minX=0 and minY=0.
Therein lies your problem.
JavaDoc for BufferedImage
Edit:
Also remove this from your loop:
for (int y = 0; y < getWidth(); y++) {
I.setRGB(x, x, Color.GREEN.getRGB());
}

Drawing more than one rectangle with Java (awt)

Here's my code:
class Ramka extends JFrame
{
public static final int SZEROKOSC = 800;
public static final int WYSOKOSC = 600;
Container powZawartosci = getContentPane();
public Ramka()
{
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
}
public void addRectangle(int startX, int startY, int sizeX)
{
drawRectangle rect = new drawRectangle(startX, startY, sizeX);
powZawartosci.add(rect);
}
class drawRectangle extends JPanel
{
private int a, startX, startY;
public drawRectangle(int startX, int startY, int a) // square
{
this.a = a;
this.startX = startX;
this.startY = startY;
}
public void paintComponent(Graphics g)
{
Rectangle2D rect = new Rectangle2D.Double(startX, startY, a, a);
Graphics2D g1 = (Graphics2D) g;
g1.draw(rect);
}
}
public class Main
{
public static void main(String[] args)
{
Ramka ramka = new Ramka();
ramka.addRectangle(200, 200, 50);
ramka.addRectangle(100, 100, 100);
ramka.addRectangle(300, 300, 150);
ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ramka.setVisible(true);
}
}
What I want it to do is draw three rectangles (set aside the functionality and sense of doing so, I'm still just learning).
But it draws only the last one, starting at 300 and 300. I don't really understand the paintComponent thing...
Thanks in advance for any help,
Paul
I beleive that you are adding three JPanels on top of each other. This seems like an odd way to draw rectangles, but with this design, you need to use a LayoutManager.
Check out this link, and try to learn. The code below should do the trick though.
...
Container powZawartosci = getContentPane();
public Ramka()
{
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));//Only this line is inserted.
}
public void addRectangle(int startX, int startY, int sizeX)
{
drawRectangle rect = new drawRectangle(startX, startY, sizeX);
powZawartosci.add(rect);
}
...
In your JPanel derivative, you can keep track of the Rectangles that you need to draw. I am writing the code below spontanously, so check for errors first.
class RectangleDrawer extends JPanel{
ArrayList<Rectangle> rList = new ArrayList()<Rectangle>;
public void addRectangle(Rectangle rect){
rList.add(rect);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i=0; i<rList.size(); r++){
g.drawRectangle(rList.get(i));
}
}
}
The problem basically is that you're using two different levels of abstraction here.
In the first, you are adding a component to your JFrame, which is fine at some point.
You're adding your "DrawRectangle" instance, just the same way you would add a new button, a label or another panel. The problem comes when you add components in the same position. JFrame's main panel ( the content pane ) uses a "Border" layout manager that places the component in the middle if you don't add any constraint.
As a convenience, BorderLayout interprets the absence of a string specification the same as the constant CENTER
So, this line:
powZawartosci.add(rect);
Always adds your component in the "center", overriding the previous one. That's why you only saw one rectangle.
The second level of abstraction used here is painting the component yourself. This is low level and you have to tell the component who to draw each line and where.
That's fine, but if you want to draw several rectangles in the same component, you have to hold the references for each one ( using a collection like a list ) and then iterate that collection and draw them all.
Like this:
many http://img40.imageshack.us/img40/8125/capturadepantalla201001nd.png
I took your code, and changed it, to reflect what I'm saying. The final result, uses the same component, but this component in turn draws all the rectangles.
Notice also the naming/brace style, while is not mandatory it is common while programming in Java
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
class Ramka extends JFrame {
public static final int SZEROKOSC = 800;
public static final int WYSOKOSC = 600;
Container powZawartosci = getContentPane();
DrawRectangle rectangle = new DrawRectangle();
public Ramka() {
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
powZawartosci.add( new JLabel("Several rectangles are being displayed"), BorderLayout.NORTH );
powZawartosci.add(rectangle);
}
public void addRectangle(int startX, int startY, int sizeX) {
this.rectangle.addRectangle( startY, startY, sizeX );
}
}
class DrawRectangle extends JPanel {
private java.util.List<Rectangle2D> squares;
//private int a, startX, startY;
public DrawRectangle(){
squares = new ArrayList<Rectangle2D>();
}
public void addRectangle(int startX, int startY, int a) { // square
squares.add( new Rectangle2D.Double(startX, startY, a, a) ) ;
//this.a = a;
//this.startX = startX;
//this.startY = startY;
}
public void paintComponent(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
for( Rectangle2D rect : squares ) {
g1.draw(rect);
}
}
}
public class Main {
public static void main(String[] args) {
Ramka ramka = new Ramka();
//ramka.addRectangle(200, 200, 50);
//ramka.addRectangle(100, 100, 100);
//ramka.addRectangle(300, 300, 150);
for( int i = 0 ; i < 20 ; i++ ){
ramka.addRectangle( i * 10 , i * 10 , i * 20 );
}
ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ramka.setVisible(true);
}
}

Categories