Tileing image on JPanel, java - java

I have a method to set the 'texture' of a JPanel, however it is throwing a NullPointerException, and i cannot figure out why.
Method:
void setTexutre(Image tileImage) {
Graphics g = panel.getGraphics();
int width = (int) getBounds().getWidth();
int height = (int) getBounds().getHeight();
int imageW = tileImage.getWidth(panel);
int imageH = tileImage.getHeight(panel);
for (int x5 = 0; x5 < width; x5 += imageW) {
for (int y5 = 0; y5 < height; y5 += imageH) {
g.drawImage(tileImage, x5, y5, panel);
}
}
panel.paint(g);
}
The NullPointerException is thrown when i call "g.drawImage(tileImage, x5, y5, panel);"
And yes, the image is a real image, i have checked. In the method above panel is defined as a new JPanel, and intializes normally when I do not call the method.
Thanks for any help!

DON'T use Graphics g = panel.getGraphics();
NEVER call panel.paint(g);
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing/AWT.
getGraphics may return null (it's even documented as saying so) and you SHOULD never rely on it, it's not how custom painting works. Instead, you should override the components paintComponent method and perform your custom painting within it.
You don't control the paint process and should never call paint directly, Swing uses a passive rendering algorithm, this means that components are update ad-hoc, when ever the RepaintManager decides that they need to be repainted. This means, even if you could get your current code to work, the moment the RepaintManager decides to repaint panel, all you rendering would be lost...

The following is the class I used for anyone else looking at this question.
package i.am.not.posting.the.real.pack.name;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class TiledPanel extends JPanel {
private BufferedImage tileImage;
public TiledPanel(BufferedImage tileImage) {
this.tileImage = tileImage;
}
protected void paintComponent(Graphics g) {
int width = getWidth();
int height = getHeight();
int imageW = tileImage.getWidth();
int imageH = tileImage.getHeight();
// Tile the image to fill our area.
for (int x = 0; x < width; x += imageW) {
for (int y = 0; y < height; y += imageH) {
g.drawImage(tileImage, x, y, this);
}
}
}
}
simply creating a TilePanel object will correctly tile the image.

Related

How to fill histogram with array data?

I am having trouble getting my histogram to fill correctly.
I was given a large data file full of doubles that represented GPAs, about 5500 of them. I created a method to calculate the count, mean, and standard deviation of the data, however my last problem is to graph the data.
I am to make a histogram for each of the possible grades (12 of them) and graph them about the total of each grade.
I think I have coded the total for each grade correctly, but when it comes to actually drawing the histogram I cannot figure out the 4 arguments needed for fillRect.
I've been playing around with different variables, but nothing seems to get me close.
Any help is appreciated.
private static int[] gradeCounts(double[] stats) throws Exception{
double stdv = 0;
double sum = 0;
double sum2 = 0;
double variance = 0;
Scanner fsc = new Scanner(new File("introProgGrades.txt"));
while (!fsc.hasNextDouble())
fsc.nextLine();
int[] binCounts = new int[NUM_OF_GRADE_CATEGORIES];
double x = 0;
while (fsc.hasNextDouble()){
stats[2]++;
x = fsc.nextDouble();
sum += x;
sum2 += x * x;
if (x == 0.0)
binCounts[0]++;
else if (x == 0.6666667)
binCounts[1]++;
else if (x == 1.0)
binCounts[2]++;
else if (x == 1.3333333)
binCounts[3]++;
else if (x == 1.6666667)
binCounts[4]++;
else if (x == 2.0)
binCounts[5]++;
else if (x == 2.3333333)
binCounts[6]++;
else if (x == 2.6666667)
binCounts[7]++;
else if (x == 3.0)
binCounts[8]++;
else if (x == 3.3333333)
binCounts[9]++;
else if (x == 3.6666667)
binCounts[10]++;
else
binCounts[11]++;
}
stats[0] = sum/stats[2];
variance = (stats[2] * sum2 - sum * sum) / (stats[2]*(stats[2]-1));
stdv = Math.sqrt(variance);
stats[1] = stdv;
return binCounts;
}
What I am having trouble with:
private static void plotHistogram(int[] binCounts){
int max = Arrays.stream(binCounts).max().getAsInt();
DrawingPanel panel = new DrawingPanel (800,800);
Graphics2D g = panel.getGraphics();
g.fillRect(0, 0, 800/binCounts.length,max);
}
I think I have to iterate through the data with a for loop, but it's the parameters of fillRect that I am clueless on.
but when it comes to actually drawing the histogram I cannot figure out the 4 arguments needed for fillRect.
The JavaDocs are quite explicit in the properties and their meanings, it's just a box, with a position (x/y) and size (width/height)
public abstract void fillRect​(int x,
int y,
int width,
int height)
Fills the specified rectangle. The left and right edges of the rectangle are at x and x +
width - 1. The top and bottom edges are at y and y + height - 1. The
resulting rectangle covers an area width pixels wide by height pixels
tall. The rectangle is filled using the graphics context's current
color. Parameters: x - the x coordinate of the rectangle to be filled.
y - the y coordinate of the rectangle to be filled. width - the width
of the rectangle to be filled. height - the height of the rectangle to
be filled.
I've been playing around with different variables, but nothing seems to get me close.
So, two things come to mind, the first comes from the JavaDocs above...
The rectangle is filled using the graphics context's current
color
This is something that's easy to forget
The second is it seems that you misunderstand how painting works in Swing.
Painting in Swing has a very specific and well documented workflow. The first thing you should do is go read Performing Custom Painting and Painting in AWT and Swing to get a better understanding of how painting works and how you should work with it.
There is never a good reason to call JComponent#getGraphics, apart from been able to return null, this is just a snapshot of the last paint cycle and will be wiped clean on the next paint pass (which may occur at any time for any number of reasons).
Instead, you will need a custom component and override it's paintComponent method instead.
You should then have a read through the 2D Graphics trail to get a better understanding of how the API works and what features/functionality it can provide.
For example....
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.util.Arrays;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Random rnd = new Random();
int[] binCounts = new int[10];
for (int index = 0; index < binCounts.length; index++) {
binCounts[index] = rnd.nextInt(100);
}
JFrame frame = new JFrame();
frame.add(new DrawingPanel(binCounts));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawingPanel extends JPanel {
private int[] binCounts;
private int max;
public DrawingPanel(int[] binCounts) {
this.binCounts = binCounts;
max = Arrays.stream(binCounts).max().getAsInt();
System.out.println(max);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int barWidth = 800 / binCounts.length;
for (int i = 0; i < binCounts.length; i++) {
int barHeight = (int)((binCounts[i] / (double)max) * getHeight());
// I personally would cache this until the state of the component
// changes, but for brevity
Rectangle rect = new Rectangle(i * barWidth, getHeight() - barHeight, barWidth, barHeight);
g2d.setColor(Color.BLUE);
g2d.fill(rect);
g2d.setColor(Color.BLACK);
g2d.draw(rect);
}
g2d.dispose();
}
}
}

Drawing shapes in loops

So Im basically just trying to Draw a whole bunch of random triangles to the screen in a loop while changing the colors which seemed not very difficult but i cannot find where my problem lies... it wont loop it just displays one image here's what i have
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
public class ManyTriangles extends Canvas {
public void paint(Graphics g) {
Random r = new Random();
int x1 = r.nextInt(350);
int x2 = r.nextInt(400);
int x3 = r.nextInt(300);
int y1 = r.nextInt(800);
int y2 = r.nextInt(200);
int y3 = r.nextInt(600);
int[] xpts = { x1, x2, x3 };
int[] ypts = { y1, y2, y3 };
int randomColor = r.nextInt(3);
for (int x = 0; x <= 500; x++) {
if (randomColor == 3) {
g.setColor(Color.green);
} else if (randomColor == 2) {
g.setColor(Color.red);
} else if (randomColor == 1) {
g.setColor(Color.blue);
}
g.fillPolygon(xpts, ypts, 3);
}
}
public static void main(String[] args) {
ManyTriangles canvas = new ManyTriangles();
JFrame frame = new JFrame("Lots of Triangle's");
frame.setSize(1024, 768);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(canvas);
frame.setVisible(true);
}
}
Your xpts and yppts never change within the loop, so you are painting the same thing over and over again in different colors
You've broken the paint chain by not calling super.paint
You're mixing heavy and light weight components (Canvas on a JFrame), this is not really a good idea...
Instead...
Move the creation of the xpts and yppts into the loop
Call super.paint before doing any custom painting or event better
Use a JPanel instead of a Canvas and override it's paintComponent method instead, making sure you call super.paintComponent before doing any custom painting...
See Painting in AWT and Swing, Performing Custom Painting for more details
Other issues...
Because you're re-generating the output each time paint is called, your output could change at random times (as the repaint manager schedules new repaint requests). If you don't want this, generate the shapes in the constructor or other method, adding them to some kind of List or array and iterate over this within your paintComponent method...

Paint Method within an ActionListener

I am trying to use the Java paint method within an ActionListener. However, when paint is placed within the ActionListener, my compiler throws errors, and eclipse does not recognize paint as a method at all, despite importing java.awt.geom.*;
private class NumHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//Draw Ovals
public void paint (Graphics g)
{
int number;
int x = 10;
int y = 30;
int width = 20;
int height = 10;
number = Integer.parseInt(numberTF.getText());
for (int i = 0; i < number; i++)
{
g.drawOval(x, y, width, height);
x += 5;
y += 5;
width += 5;
height += 5;
}
}
}
}
Your paint method cannot be inside your actionPerformed method. It needs to exist as a class member method of your component rather than NumHandler. You could place a single repaint() call in your ActionListener method to request that a repaint be carried out.
Don't place any logic that is likely to lead to an exception in your paint method, namely:
number = Integer.parseInt(numberTF.getText());
This is better done in the actionPerformed method.
Also if using Swing, paintComponent is preferred for optimized paint performance. Remember to call super.paintComponent(g); to repaint any child components.
See: Painting in AWT and Swing

setBackgrounds throws exception in Windows (but not in MacOSX)

I was trying to have a image background, so I created the following code in a JFrame:
#Override
public void paint(Graphics g) {
super.paint(g);
try {
final Image image = ImageIO.read(getClass().getResource("/images/login/gentlenoise100.png"));
int iw = 256;
int ih = 256;
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
} catch (IOException ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
for(Component componente:getComponents()){
componente.repaint();
}
}
I saw that the background color had some kind of preference and I decided so set it to invisible:
setBackground(new java.awt.Color(0,0,0,0));
It was working fine in Mac OS X (java 1.6), and I had to probe it in Windows and if I remove the setBackground call it doesn't show my background, if I keep the background color invisible it throws an exception and says the Frame is decorated!
I tried to use setUndecorate(true) but in macosx it looses the title bar (of course) and in Windows it gives me a transparent window.
How can I solve that?
there are three ways, to use
JComponent#setOpaque() in the case that you don't want to panting background
How to Create Translucent and Shaped Windows on Win, OSX a few ***unix
for Transparency have to change value of AlphaComposite
don't paint() whatever to JFrame, put there JPanel and override paintComponent()
If you can avoid it, don't override the paint methods of top level containers (like JFrame), they do to many important things.
In the case, you'd be better of using a JPanel and setting the frames content pane to it...
Something like...
public class BackgroundPane extends JPanel {
private Image background;
public BackgroundPane() {
try {
background = ImageIO.read(getClass().getResource("/images/login/gentlenoise100.png"));
} catch (IOException ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int iw = 256;
int ih = 256;
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(background, x, y, iw, ih, this);
}
}
}
}
//...
JFrame frame = new JFrame();
frame.setContentPane(new BackgroundPane());
//...
Don't do anything in your paint method's that are either time consuming or that may cause the repaint manager to schedule your component for repainting again
Things like...
final Image image = ImageIO.read(getClass().getResource("/images/login/gentlenoise100.png"));
and
for(Component componente:getComponents()){
componente.repaint();
}
Inside you're paint method is an really bad idea.
The second one could cause the repaint manager to decide that the parent container (your frame) needs to repainted, over and over and over and over again...eventually consuming your CPU...
Beware, as of Java 7, calling setBackground with a color that that contains a alpha value of less then 255 on Window will cause the window to become transparent.
Window.setBackground(Color) Passing new Color(0,0,0,alpha) to this
method, where alpha is less than 255, installs per-pixel translucency
This will also throw an exception if the window is decorated...

Painting pixels images in Java

Which method is the best way to create a pixel image with java.
Say, I want to create a pixel image with the dimensions 200x200 which are 40.000 pixels in total. How can I create a pixel from a random color and render it at a given position on a JFrame.
I tried to create a own component which just creates pixel but it seems that this is not very performant if I create such a pixel a 250.000 times with a for-loop and add each instance to a JPanels layout.
class Pixel extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getRandomColor());
g.fillRect(0, 0, 1, 1);
}
}
You do not need to create a class for this. Java already has the excellent BufferedImage class that does exactly what you need. Here is some pseudo-code:
int w = 10;
int h = 10;
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage image = new BufferedImage(w, h, type);
int color = 255; // RGBA value, each component in a byte
for(int x = 0; x < w; x++) {
for(int y = 0; y < h; y++) {
image.setRGB(x, y, color);
}
}
// Do something with image
The key here is the Canvas class. It is the standard Component that allows arbitrary draw operations. In order to use it, you must subclass the Canvas class and override the paint(Graphics g) method, then loop through each pixel and draw your random color. The following code should work:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
public class PixelCanvas extends Canvas {
private static final int WIDTH = 400;
private static final int HEIGHT = 400;
private static final Random random = new Random();
#Override
public void paint(Graphics g) {
super.paint(g);
for(int x = 0; x < WIDTH; x++) {
for(int y = 0; y < HEIGHT; y++) {
g.setColor(randomColor());
g.drawLine(x, y, x, y);
}
}
}
private Color randomColor() {
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(WIDTH, HEIGHT);
frame.add(new PixelCanvas());
frame.setVisible(true);
}
}
The generated image looks like this:
You'll probably want to create a BufferedImage of the size you want, and use img.setRGB(x, y, getRandomColor()) to create a bunch of random pixels. Then you could render the whole image wherever you want it.

Categories