How can I pass values to paintComponent - java

I have an array of 100 random ints. I want to create a bar graphic from them. I know how to create a single rectangle in a frame but without passing values.
This is the draw class:
import javax.swing.*;
import java.awt.*;
public class draw extends JPanel
{
public void drawing() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(100, 150, 12, 3);
}
}
I want to replace the values in g.fillRect(100,150,12,3) with my random int values. But since i call repaint() from main to call paintComponent, i cant pass values to paintComponent. How do i do it? if its impossible, what alternatives do i have?

You can do it by introducing fields and intitialize then using a constructors, setters, or both :
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Draw extends JPanel {
int x, y, width, height;
public Draw(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
void setX(int x) {this.x = x;}
void setY(int y) {this.y = y;}
void setWidth(int width) {this.width = width;}
void setHeight(int height) {this.height = height;}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(x, y, width, height);
}
}

How can I pass values to paintComponent
You can't pass values to paintComponent().
But since i call repaint() from main to call paintComponent, i cant pass values to paintComponent. How do i do it?
For whatever object you want to customize and draw by yourself, you can create a class for that and have a method like draw() to do the painting, for example:
//Just a normal class with a draw() method
class BarGraph{
private int x;
private int y;
private int width;
private int height;
private Color color;
public BarGraph(int x, int y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void setColor(Color color){
this.color = color;
}
public void draw(Graphics g){
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
Then in your main panel for displaying your customized image:
class DrawingSpace extends JPanel{
private BarGraph barGraph;
public DrawingSpace(){
barGraph = new BarGraph(50, 50, 400, 100);
barGraph.setColor = (Color.RED);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g){
barGraph.draw(g); //draw your own customized object
}
}
}
So instead of trying to pass values to dictate how paintComponent draws, you can pass/set your values in your own class (in this case, BarGraph class). From the Graphics content, implement how you want it to be painted.
In your paintComponent, simply call the draw method which already has "a set of instructions" for how it should be drawn.

We cannot pass values to paintComponent method as parameters because, we are just overriding an existing method which is called by Swing. But we can have an instance variable (values in my example) in the class which is accessible inside paintComponent method (as suggested in other answers/comments).
I'm putting an example program below since, sometimes examples convey ideas better.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
public class BarGraph extends JPanel
{
private static final int GRAPH_HEIGHT = 300;
private static final int BAR_WIDTH = 50;
private static final int GAP_BETWEEN_BARS = 20;
private static final int GRAPH_X_OFFSET = 50;
private int[] values;
public BarGraph(int[] values)
{
this.values = values;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
for (int i = 0; i < values.length; i++)
{
g.fillRect(
GRAPH_X_OFFSET + (i * (GAP_BETWEEN_BARS + BAR_WIDTH)),
GRAPH_HEIGHT - values[i],
BAR_WIDTH,
values[i]
);
}
}
public static void main(String[] args)
{
int[] graphValues = {100, 150, 50, 250, 200, 75};
JFrame frame = new JFrame("Graph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new BarGraph(graphValues), BorderLayout.CENTER);
frame.setBounds(300, 200, 600, 400);
frame.setVisible(true);
}
}

Related

Blank Frame in Java Frame

I have been trying to create a 10x10 grid in Java, and I tried to use the drawLines function in order to do so. However, when I run the program, all I see is a blank window with that will not close. These are my two classes to draw the grid. Could someone explain why this code does not work?
import java.awt.*;
public class RandomWalk extends Canvas{
int width, height;
public RandomWalk(int w, int h) {
setSize(width = w, height = h);
}
public void paintGrid(Graphics g) {
width = getWidth();
height = getHeight();
for(int i = 0; i < 11; i++) {
g.drawLine(i*width/10, 0, i*width/10, height);
g.drawLine(0, i*height/10, width, i*height/10);
}
}
}
import java.awt.*;
public class GridViewer extends Frame{
GridViewer(String title, int w, int h) {
setTitle(title);
RandomWalk grid = new RandomWalk(w, h);
add(grid);
}
public static void main(String[] args) {
new GridViewer("Random Walk", 300, 300).setVisible(true);
}
}
Add a printout to paintGrid like : System.out.println("paintGrid invoked");
Does it ever get invoked ?
This might help: Performing Custom Painting
You u need to override paint() method in Canvas class to achieve your goal
and for the window closing, you need to add WindowListener to dispose the window (or u could simply use javax.swing.JFrame class instead of java.awt.Frame)
refer the below code
import java.awt.*;
import java.awt.event.*;
public class RandomWalk extends Canvas {
int width, height;
public RandomWalk(int w, int h) {
setSize(width = w, height = h);
}
#Override
public void paint(Graphics g) {
width = getWidth();
height = getHeight();
for (int i = 0; i < 11; i++) {
g.drawLine(i * width / 10, 0, i * width / 10, height);
g.drawLine(0, i * height / 10, width, i * height / 10);
}
}
}
public class GridViewer extends Frame {
GridViewer(String title, int w, int h) {
setTitle(title);
setSize(w, h);
RandomWalk grid = new RandomWalk(w, h);
add(grid);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
dispose();
}
});
}
public static void main(String[] args) {
new GridViewer("Random Walk", 300, 300).setVisible(true);
}
}

how to use the wait(long timeout) on jpanel

I am taking an introductory java class and I have an inheritance related problem. I have to implement a system that has classes for various figures. the superclass is Figures and subclasses are Circle, Box and Rectangle and I am supposed to output the figures in the JPanel. I have designed all the classes and my code is below but I need to define the center() method on the figure class which when called on an object should draw and also erase the object. so within the main method of the JPanel class, I want to use the center() method to draw the three shapes and use the wait(long timeout) method to make the shapes change to random positions after 15 seconds.
import java.awt.Graphics;
import javax.swing.JPanel;
public abstract class Figure extends JPanel {
protected int xCoord;
protected int yCoord;
public Figure() {
}
public void erase() {
}
public void draw() {
}
public void center() {
}
}
the rectangle sub class is:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Rectangle extends Figure {
int width;
int height;
public Rectangle() {
this.width = 0;
this.height = 0;
}
public Rectangle(int xCoord, int yCoord, int width, int height)
{
this.xCoord = xCoord;
this.yCoord = yCoord;
this.width = width;
this.height = height;
}
public void draw(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(xCoord, yCoord, width, height);
}
public void erase(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 0, 0);
}
}
the circle subclass:
public class Circle extends Figure {
private int radius;
public Circle ()
{
this.radius = 0;
}
public Circle (int xCoord, int yCoord, int radius)
{
this.xCoord = xCoord;
this.yCoord = yCoord;
this.radius = radius;
}
public void draw(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(xCoord, yCoord, radius, radius);
}
public void erase(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(0,0,0,0);
}
}
the box subclass:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Box extends Figure {
private int edgeLength;
public Box() {
this.edgeLength = 0;
}
public Box(int xCoord, int yCoord, int edgeLength)// Creating Rectangle
// Class given width and
// height
{
this.xCoord = xCoord;
this.yCoord = yCoord;
this.edgeLength = edgeLength;
}
public void draw(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(xCoord, yCoord, edgeLength, edgeLength);
}
public void erase(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 0, 0);
}
}
the JPanel class
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SamplePanel extends JPanel {
private static final int PANEL_HEIGHT = 400;
private static final int PANEL_WIDTH = 400;
Rectangle rect = new Rectangle(75, 85, 50,30);
Circle circle = new Circle(275, 75, 50);
Box box = new Box (75, 275, 50);
public SamplePanel() {
setPreferredSize(new Dimension(PANEL_HEIGHT, PANEL_WIDTH));
setBackground(Color.WHITE);
//Rectangle rect = new Rectangle(100, 100, 15,10);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
rect.draw(g);
circle.draw(g);
box.draw(g);
g.drawLine(200, 0, 200, 400);
g.drawLine(0, 200, 400, 200);
}
/**
* #param layout
*/
public SamplePanel(LayoutManager layout) {
super(layout);
}
/**
* #param isDoubleBuffered
*/
public SamplePanel(boolean isDoubleBuffered) {
super(isDoubleBuffered);
}
/**
* #param layout
* #param isDoubleBuffered
*/
public SamplePanel(LayoutManager layout, boolean isDoubleBuffered) {
super(layout, isDoubleBuffered);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Window Title Here");
SamplePanel panel = new SamplePanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
Figure box = new Box(75, 275, 50);
}
}
Answer...
How to use Swing Timers
It is safe to use within the context of Swing as it won't block the Event Dispatching Thread while waiting and will generate notifications within the context of the Event Dispatching Thread, making it safe to update the UI from.
Observations...
Your basic design, while correct in concept, is implemented in correctly. I'd would strongly discourage you from using JPanel in this way. Components have a particular life cycle which you're not managing correctly, which could cause no end of issues.
Instead, go right back to basics. What is it the shape should be able to?
public interface Figure {
public void draw(Graphics2D g2d);
public Rectangle getBounds();
public void setBounds(Rectangle bounds);
}
Here, it's capable of been painted and has a concept of size and position (yes, you can use an abstract class, but this removes all requirements on the base implementation, making it far more flexible)
Because I imagine most of the implementations are going to be basically the same, I can use an abstract class to implement the core functionality...
public abstract class AbstractFigure implements Figure {
private Rectangle bounds;
#Override
public Rectangle getBounds() {
return bounds;
}
#Override
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}
Based on your needs, you might be able to create a few abstract classes which implement the functionality different, but the basic idea is to see what functionality is common to all the implementations and reduce the amount of duplicate code you generate.
Then you can start implementing your concrete classes...
public class RectangleFigure extends AbstractFigure {
public RectangleFigure(Rectangle bounds) {
setBounds(bounds);
}
#Override
public void draw(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
g2d.fill(getBounds());
}
}
But where's the "erase" method you ask? Well, erase is just the absence of painting, so, when you want to "erase" a shape, remove it from the painting process and repaint the container, shape is erased
This is suggests to me that you need to have a look at Painting in AWT and Swing and Performing Custom Painting to better understand how painting works in Swing.
"Where's the center method?" I hear you ask. Okay, you "could" have a center method in the Figure, the problem is, Figure has no concept of the parent container, is you'd have to pass the size of the container to it. Not difficult, I'd argue, however, this really isn't a function of the Figure, but a function of the container, so I'd have the center method implemented there, since you want to change the position of the Figures anyway, it makes sense (to me) to all that wrapped up in the container

How do I draw an array of graphics objects?

So I have been pulling my hair out over this assignment for quite some time now, and I could really use some help. I have to create a rectangle graphics object in a super class, then extend that class into a subclass, that then draws 7 of said rectangles to draw a number like you would see on a calculator. I am creating an array of rectangles in the subclass and trying to add them to a panel, however I keep getting errors for all the ways I try to add to the panel. Any help would be appreciated immensely.
This is my super class
import javax.swing.*;
import java.awt.*;
public class Bar extends JPanel {
public Color myColor;
Graphics g;
int x;
int y;
int w;
int h;
public Bar(int newX, int newY, int newW, int newH) {
x = newX;
y = newY;
w = newW;
h = newH;
super.paintComponent(g);
g.setColor(getColor());
g.fillRect(x, y, w, h);
}
public Color getColor() {
return myColor;
}
}
and then my subclass
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LED extends Bar {
public static Bar[] myLED;
public static int number;
public boolean isOn;
public LED(Bar[] myLED) {
super(10, 10, 15, 45);
switch(number) {
case 0: myLED[0] = new Bar(10, 10, 15, 45);
isOn = true;
}
}
public void setOn(boolean isOn) {
if(isOn = true) {
myColor = Color.GREEN;
}
else
myColor = Color.BLACK;
}
public static Bar[] getLED() {
return myLED;
}
public static void main(String[] a) {
JFrame window = new JFrame("Calculator");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 500, 500);
JPanel panel = new JPanel();
panel.add(myLED); //I'm getting an error on this line, as well as the one below this.
window.getContentPane().add(myLED);//getContentPane().
window.setVisible(true);
}
}
Thanks.

How to change locations of drawn objects with user input

I'm attempting to draw multiple fish (very simple ones), as many as the user specifies. But the circles aren't drawn in the proper places when the user specifies they want more than one fish to be drawn. All ovals are drawn, they just aren't in the right spots, so they no longer look like fish.
public class FishList extends JPanel {
static int fn = Integer.parseInt(JOptionPane.showInputDialog(null, "How many fish would you like to draw? "));
static int w = 200;
static int h = 100;
static int x;
static int y;
static int a = x + 20;
static int b = y + 30;
static int d = 50;
static int c = x + 195;
public FishList() {
setPreferredSize(
new Dimension(400,400));
}
public void paint(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, w, h);
g.fillOval(c, y, d, h);
g.setColor(Color.BLACK);
g.fillOval(a, b, 25, 25);
}
public static void main(String[] args) {
MyFrame frame1 = new MyFrame("Drawing Fish");
JPanel outer = new JPanel();
for(int i=0; i<fn; i++){
x = 0 + (i*(w+d+1));
y = 0;
FishList sPanel1 = new FishList();
outer.add(sPanel1);
}
frame1.add(outer);
frame1.pack();
frame1.setVisible(true);
}
}
JPanel, by default, uses a FlowLayout. FlowLayout also uses the component's preferred size to determine how to layout each component within the Container.
Failing to call super.paint is going to cause you serious issues. In fact, you should use paintComponent instead of paint and make sure you are calling super.paintComponent.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
Components already have a sense of location and size, which you are ignoring. The use of static variables in this context isn't going to help, because basically, each instance of your fish will be painted in the exact same location, as they will share the same value of the each of the static variables...
A better solution would be to generate a class that is capable of begin painted, which then paints the "fish".
These would be included inside a component capable of painting them, which you could then just add to a Container which is using a BorderLayout.
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Fishies {
public static void main(String[] args) {
new Fishies();
}
public Fishies() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FishBowel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class FishBowel extends JPanel {
private List<Fish> fishes = new ArrayList<>(25);
public FishBowel() {
for (int index = 0; index < 10; index++) {
int width = random(20);
int height = width;
int x = random(200 - 20);
int y = random(200 - 20);
fishes.add(new Fish(new Rectangle(x, y, width, height)));
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Fish fish : fishes) {
fish.paint(g2d);
}
g2d.dispose();
}
}
public static int random(int max) {
return (int)(Math.round(Math.random() * max));
}
public class Fish {
private Color color;
private Ellipse2D fish;
public Fish(Rectangle bounds) {
this(new Color(random(255), random(255), random(255)), bounds);
}
public Fish(Color color, Rectangle bounds) {
this.color = color;
fish = new Ellipse2D.Float(bounds.x, bounds.y, bounds.width, bounds.height);
}
public Ellipse2D getFish() {
return fish;
}
public Color getColor() {
return color;
}
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
g2d.fill(fish);
}
}
}

Java - draw graphics using a method and a constructor

I am working on a java 2d game library. I want a method named paintImage() to do graphics.drawImage() every time paintImage() is called.
public void paintImage(image1, x, y){
//i want it to run graphics.drawImage every time it is called.
}
public void anotherMethod(){
paintImage(...);
paintImage(...);
//paint as many times as i want.
}
public void paintComponent(Graphics graphics){
graphics.drawImage();
super.paintComponents();
}
Thanks for your time and please leave a suggestion, sorry but its kind of hard to explain this.
For Single Image Display
public class DrawingDemo {
private JPanel panel;
private MyImage imageData;
public DrawingDemo() {
...
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (imageData != null) {
g.drawImage(imageData.getImage(), imageData.getX(), imageData.getY(), this);
}
}
};
...
}
public void paintImage(Image image1, int x, int y) {
imageData = new MyImage(image1, x, y);
panel.repaint();
}
public void anotherMethod() {
paintImage(...);
paintImage(...);
}
}
public class MyImage { // bean class for storing image information
private Image image;
private int x;
private int y;
public MyImage(Image image, int x, int y) {
this.image = image;
this.x = x;
this.y = y;
}
public Image getImage(){
return image;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
... you can add setter methods
}
UPDATE : For multiple image display
private JPanel panel;
private ArrayList<MyImage> imageData; // or any other data structure you like
public DrawingDemo() {
imageData = new ArrayList<>();
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (MyImage myImage : imageData) {
g.drawImage(myImage.getImage(), myImage.getX(), myImage.getY(), this);
}
}
};
frame.add(panel);
frame.setVisible(true);
}
public void paintImage(Image image1, int x, int y) {
imageData.add(new MyImage(image1, x, y));
panel.repaint();
}
public void anotherMethod() {
paintImage(new ImageIcon("/home/blackadmin/Desktop/image.jpg").getImage(), 0, 0);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image2.jpg").getImage(), 50, 50);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image3.jpg").getImage(), 100, 100);
}
OUTPUT :
Have a look at this answer
Comment if you don't understand anything, hope this will help
What I think you're looking to do is to make changes to some states in your class and then redrawing your images with changes based on those state changes -- in other words perhaps you're looking to do animation. If so, then your image drawing should all be done either within the paintComponent method using its Graphics object, or in another method called by paintComponent one that uses the Graphics object passed into paintCocalzmponent. This can be done by passing a Graphics parameter into the other method. Your anotherMethod would then request that the JVM repaint the GUI by calling repaint(). For example:
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
A complete example of this is as follows:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
import javax.swing.*;
public class PaintEg extends JPanel {
private static final int IMG_W = 30;
private static final int IMG_H = IMG_W;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage image1;
private int x;
private int y;
public PaintEg() {
image1 = createImg();
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
anotherMethod();
}
}).start();
}
private BufferedImage createImg() {
BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.red);
g2.clearRect(0, 0, IMG_W, IMG_H);
g2.setColor(Color.blue);
g2.fillRect(IMG_W / 4, IMG_H / 4, IMG_W / 2, IMG_H / 2);
g2.dispose();
return img;
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
private static void createAndShowGUI() {
PaintEg paintEg = new PaintEg();
JFrame frame = new JFrame("PaintEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Categories