BufferedImage doesn't draw from 0,0 - java

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());
}

Related

java gui paintComponent refresh

I am learning java gui interface and wrote a program that has a button. Each time the button is clicked, a random sized rectangle will be added to the screen. But instead of adding it to the screen, the program keeps erasing the old one, which I want to keep on the screen. Here is my code. I tried to do paint() and it did not work. Thanks in advance.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class SimpleGui implements ActionListener {
JFrame frame = new JFrame();
public static void main(String[] args){
SimpleGui gui = new SimpleGui();
gui.go();
}
public void go(){
JButton button = new JButton("Add a rectangle");
MyDrawPanel panel = new MyDrawPanel();
button.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event){
frame.repaint();
}
class MyDrawPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(Color.blue);
int height = (int) (Math.random()*120 + 10);
int width = (int) (Math.random()*120 + 10);
int x = (int) (Math.random()*40 + 10);
int y = (int) (Math.random()*40 + 10);
g.fillRect(x, y, height, width);
}
}
}
Your paintComponent method is written to draw only one rectangle, so its behavior should come as no shock to you. If you want it to draw multiple, you have one of two options:
Create an ArrayList<Rectangle>, and in the actionPerformed method, add a new random Rectangle to this List and then call repaint(). In the paintComponent method, iterate through this List with a for-loop, painting each Rectangle.
Or you could draw the new random rectangle onto a BufferedImage that is displayed by the paintComponent method.
The first method is the easier of the two, the 2nd is better if you're worried about program responsiveness, say in an animation program.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class TwoDrawRectMethods extends JPanel {
// Array to hold our two drawing JPanels
private AddRandomRect[] addRandomRects = {
new DrawList("Using List"),
new DrawBufferedImage("Using BufferedImage")};
// constructor
public TwoDrawRectMethods() {
// add drawing rectangles onto GUI
for (AddRandomRect addRandomRect : addRandomRects) {
add(addRandomRect);
}
// button to tell rectangles to add a new Rectangle
add(new JButton(new DrawAction("Add New Rectangle")));
}
// The button's Action -- an ActionListener on "steroids"
private class DrawAction extends AbstractAction {
public DrawAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// tell both drawing JPanels to add a new rectangle
for (AddRandomRect addRandomRect : addRandomRects) {
addRandomRect.addRectangle();
}
}
}
private static void createAndShowGui() {
TwoDrawRectMethods mainPanel = new TwoDrawRectMethods();
JFrame frame = new JFrame("TwoDrawRectMethods");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class DrawList extends AddRandomRect {
private static final Color RECT_COLOR = Color.RED;
private List<Rectangle> rectList = new ArrayList<>();
public DrawList(String title) {
super(title);
}
#Override
public void addRectangle() {
rectList.add(createRandomRect());
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(RECT_COLOR);
for (Rectangle rectangle : rectList) {
g2.draw(rectangle);
}
}
}
#SuppressWarnings("serial")
class DrawBufferedImage extends AddRandomRect {
private static final Color RECT_COLOR = Color.BLUE;
private BufferedImage img = null;
public DrawBufferedImage(String title) {
super(title);
}
#Override
public void addRectangle() {
if (img == null) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Rectangle rect = createRandomRect();
Graphics2D g2 = img.createGraphics();
g2.setColor(RECT_COLOR);
g2.draw(rect);
g2.dispose();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
}
}
#SuppressWarnings("serial")
abstract class AddRandomRect extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private Random random = new Random();
public AddRandomRect(String title) {
setBorder(BorderFactory.createTitledBorder(title));
}
abstract void addRectangle();
protected Rectangle createRandomRect() {
int x1 = random.nextInt(PREF_W);
int x2 = random.nextInt(PREF_W);
int y1 = random.nextInt(PREF_H);
int y2 = random.nextInt(PREF_H);
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Rectangle(x, y, width, height);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}

How to draw circle in rectangle using Java awt image

I have the image of a circle of size 256 x 256. The circle can be created by using a function B(i,j). By using a Java producer and consumer model, how can I create a java program to draw the circle?
The code in this image is using the octave code.
Here's the Java Swing GUI I created.
I created (or produced) the image in the CreateImage class. I used the code in your problem image, except I didn't take the square root. Comparing the squares of the numbers was faster.
I drew (or consumed) the image on a JPanel. I'm not going to explain the Swing code in great detail. I wrote what I needed to write to display the image.
Here's the code:
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawImage implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawImage());
}
#Override
public void run() {
Image image = new CreateImage(256, 256, 80).createImage();
JFrame frame = new JFrame("Image of a circle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel(256, 256, image));
frame.pack();
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1584647402715684757L;
private Image image;
public DrawingPanel(int width, int height, Image image) {
this.image = image;
this.setPreferredSize(new Dimension(width, height));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
public class CreateImage {
private int width;
private int height;
private int radius;
public CreateImage(int width, int height, int radius) {
this.width = width;
this.height = height;
this.radius = radius;
}
public Image createImage() {
int circleRadiusSquared = radius * radius;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
for (int i = 0; i < width; i++) {
int idist = i - width / 2;
for (int j = 0; j < height; j++) {
int jdist = j - height / 2;
int distSquared = idist * idist + jdist * jdist;
if (distSquared < circleRadiusSquared) {
g.setColor(Color.WHITE);
} else {
g.setColor(Color.BLACK);
}
g.drawLine(i, j, i, j);
}
}
g.dispose();
return image;
}
}
}

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);
}
}
}

Scaling image through thread - JAVA

Let say I have an image. I put the image in a JPanel and add the JPanel inside a JFrame. The image moves from the bottom part of the frame to top of the frame while its size is also decreased using AffineTransform. The variable changes using thread.
So here's the following code:
public class SplashScreen extends JFrame{
Image img1;
int w=1,h=1;
int x=0,y=0;
Thread th = new Thread(new Runnable() {
#Override
public void run() {
while(true){
w-=0.05;
h-=0.05;
y-=2;
x+=1;
if(y==-100){
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
JPanel p = new JPanel();
public SplashScreen(){
setLayout(new BorderLayout());
p.setPreferredSize(new Dimension(900,600));
p.setBackground(Color.black);
p.setLayout(new GridLayout());
add(p);
setTitle("BlueJay");
setSize(900,600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
th.start();
requestFocus();
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage();
AffineTransform at = new AffineTransform();
at.scale(w,h);
g2d.setTransform(at);
g2d.drawImage(img1, x, y, p);
}
public static void main(String[] args) {
new SplashScreen();
}
However what I get from code above is only black screen. What's the matter? Anyway, If I don't use the AffineTransform function (just move it from bottom to top), the image is shown and moves BUT the frame is flickered (blinking) rapidly.
Any idea to solve this problem so I could move the image while decrease its size and also solve the flickered/rapid blinking frame?
You should not override the paint method of the JFrame. If you want to paint anything, you should paint this in a class that extends JPanel, where you override the paintComponent method.
You should NOT load the image in the painting method. This is horribly inefficient. You should load the image only ONCE, probably in a constructor.
You should not call Graphics2D#setTransform(). Have a look at the JavaDoc at http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29 , which explicitly states
WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform
You should think about your w and h values. Should they be the size of the image that is painted, or used as scaling factors for the image? Setting them as the scaling factors of an AffineTransform will NOT have the effect of scaling an image to the desired size. At the moment, they are declared as int values, so something like w-=0.05 does not really make sense anyhow.
You should have a clear idea of how you are going to describe the animation that the image should perform.
One could possibly summarize this:
You should not write code and assume it is "correct" only because there are no compilation errors ;-)
However, the following snippet may be a first step towards your goal:
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SplashScreen extends JFrame
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new SplashScreen();
}
});
}
private PaintPanel paintPanel;
public SplashScreen()
{
setTitle("BlueJay");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setBackground(Color.BLACK);
getContentPane().setLayout(new BorderLayout());
paintPanel = new PaintPanel();
getContentPane().add(paintPanel, BorderLayout.CENTER);
setSize(900,600);
setLocationRelativeTo(null);
setFocusable(true);
requestFocus();
setVisible(true);
startAnimation();
}
void startAnimation()
{
Thread thread = new Thread(new Runnable()
{
int x = 100;
int y = 100;
int w = 0;
int h = 0;
#Override
public void run()
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
while (true)
{
if (y == 200)
{
// new MainMenu_BlueJay().setVisible(true);
dispose();
}
x += 2;
y += 1;
w += 1;
h += 1;
paintPanel.setImageCoordinates(x, y, w, h);
repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
}
}
});
thread.start();
}
}
class PaintPanel extends JPanel
{
private final Image image;
private int imageX, imageY;
private int imageW, imageH;
PaintPanel()
{
image = new ImageIcon("Clipboard02.jpg").getImage();
imageX = 0;
imageY = 0;
imageW = 0;
imageH = 0;
}
void setImageCoordinates(int imageX, int imageY, int imageW, int imageH)
{
this.imageX = imageX;
this.imageY = imageY;
this.imageW = imageW;
this.imageH = imageH;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
float scalingX = (float) imageW / image.getWidth(null);
float scalingY = (float) imageH / image.getHeight(null);
g.scale(scalingX, scalingY);
int ix = (int)(imageX / scalingX);
int iy = (int)(imageY / scalingY);
g.drawImage(image, ix, iy, null);
}
}
Don't paint on top-level containers like JFrame. Instead use a JPanel and override its paintComponent method and call super.paintComponent
No need to call Thread.sleep(). Instead Use a javax.swing.Timer.
Run your program from the EDT
Don't create a new ImageIcon in the paint method. It will create new ImageIcon object every time repaint() is called. Instead, instantiate it in the constructor.
Here's a refactor of the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SplashScreen extends JFrame {
Image img1;
int w = 900, h = 600;
int x = 0, y = 0;
public SplashScreen() {
setLayout(new BorderLayout());
add(new MyPanel());
setTitle("BlueJay");
setSize(900, 600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
setFocusable(true);
}
private class MyPanel extends JPanel {
public MyPanel() {
img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage();
setBackground(Color.black);
setLayout(new GridLayout());
Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
w -= 5;
h -= 5;
y -= 2;
x += 1;
if (y == -250) {
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//AffineTransform at = new AffineTransform();
// at.scale(w, h);
// g2d.setTransform(at);
g2d.drawImage(img1, x, y, w, h, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(900, 600);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SplashScreen();
}
});
}
}
I'm not too familiar with Graphics2D so I commented out the AffirmTransformation stuff, but fixed your other problems.

Repeating an image based on random integers

I created a background using a relatively bland texture (it repeats well, so that's a bonus). However, on top of that, I am trying to add two images in random positions, each five times. So I tried that out with this -
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RepeatDiagonals {
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static JFrame framePanel;
public static DiagonalImages diagTest;
public static void createAndInitGUI() {
diagTest = new DiagonalImages();
framePanel = new JFrame("Diagonal Testing");
framePanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
framePanel.setPreferredSize(new Dimension(1020, 720));
framePanel.add(diagTest);
framePanel.pack();
framePanel.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndInitGUI();
} // public void run() Closing
}); // SwingUtilities Closing
}
}
// TODO Add in constructor for better image import
class DiagonalImages extends JPanel {
public static final String IMAGE_PATH_WHITESTREAK = "imageFolder/whiteBackgroundStreakOverlay.png";
public static final String IMAGE_PATH_BLACKSTREAK = "imageFolder/blackBackgroundStreakOverlay.png";
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static Image overlayStreak;
DiagonalImages() {
loadImages();
setVisible(true);
setOpaque(false);
};
public void loadImages() {
try {
whiteOverlayStreak = ImageIO.read(new File(IMAGE_PATH_WHITESTREAK));
blackOverlayStreak = ImageIO.read(new File(IMAGE_PATH_BLACKSTREAK));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Dimension size = this.getSize();
Insets insets = this.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random randomInteger = new Random();
randomInteger.nextInt(900);
for (int i = 0; i < 3; i++) {
int x = randomInteger.nextInt() % w;
int y = randomInteger.nextInt() % h;
g2d.drawImage(blackOverlayStreak, x, y, null);
}
for (int i2 = 0; i2 < 5; i2++){
int x2 = randomInteger.nextInt() % w;
int y2 = randomInteger.nextInt() % h;
g2d.drawImage(whiteOverlayStreak, x2, y2, null);
}
}
}
The relevant part of the main code:
// Makes the Initial BorderLayout
allContent = new ImagePanel(image);
allContent.setLayout(new BorderLayout());
allContent.add(new DiagonalImages());
allContent.add(tabbedPane, BorderLayout.CENTER);
allContent.add(logoImage, BorderLayout.NORTH);
allContent.setVisible(true);
allContent.setOpaque(false);
// Add ScrollPane
scrollPane = new JScrollPane(allContent);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
scrollPane.setWheelScrollingEnabled(true);
// JFrame programFrame Constructors
programFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
programFrame.setLayout(new BorderLayout());
programFrame.add(scrollPane);
programFrame.pack();
programFrame.setVisible(true);
programFrame.setResizable(true);
programFrame.setSize(1280, 720);
programFrame.setLocationRelativeTo(null);
And here's the ImagePanel I have:
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImagePanel extends JPanel {
private Image image;
private boolean tile;
ImagePanel(Image image) {
this.image = image;
this.tile = false;
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw > 0 && ih > 0) {
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
}
}
}
Thanks for the (future) help!
EDIT: Made a small change based on the answer given, and it's still not working.
Okay, so the problem is that the image that's supposed to be repeated isn't actually even showing up.
EDIT2: Rewrote my entire code for this, and it's still not working. Even setting the background color isn't working, which leads me to believe it's a problem with my paintComponent.
EDIT3: paintComponent is working thanks to help. My final problem is getting it to work correctly in my main method.
First JFrame.setVisible(true); should be done last, after pack() which does layouting.
framePanel.pack();
framePanel.setVisible(true);
The images maybe better reside in the application (jar) itself, then you can use getClass().getResource("...").
They should be loaded outside paint, say in the constructor. I guess, it was test code.
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
DiagonalImages() {
loadImages();
}
private void loadImages() {
whiteOverlayStreak = new ImageIcon(
getClass().getResource("/white.jpg")).getImage();
blackOverlayStreak = new ImageIcon(
getClass().getResource("/black.jpg")).getImage();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int x = r.nextInt(w);
int y = r.nextInt(h);
Your failure was not using #Override because then you would have seen, that you miswrote Graphics2D g instead of Graphics g. The function paintComponent never got called! LoL
Additional question: adding a second panel
framePanel.setLayout(new BorderLayout());
framePanel.add(diagTest, BorderLayout.CENTER);
framePanel.add(otherPanel, BorderLayout.SOUTH);
It wasn't really an SSCCE.
I haven't tested this fully, mainly because I didn't want to have to set up an entire Eclipse project just to point out the obvious mistake.
Separate the image process from the JPanel.
Only extend Swing components when you're modifying a component method.
Here's my version of your code. I had to modify your code to read an image to get it to work. You're going to have to figure out that part of the code yourself.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
class GUIImages {
private Image whiteDiagonal;
// private Image blackDiagonal;
public GUIImages() {
loadImages();
}
private void loadImages() {
try {
whiteDiagonal = ImageIO.read(new File(
"C:/Documents and Settings/BOP00082/" +
"My Documents/My Pictures/Places-icon.png"));
} catch (IOException e) {
e.printStackTrace();
}
// whiteDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/whiteBackgroundStreakOverlay.png")).getImage();
// blackDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/blackBackgroundStreakOverlay.png")).getImage();
}
public void doDrawing(JPanel panel, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(createDiagonalImage(panel), 0, 0, null);
}
private Image createDiagonalImage(JPanel panel) {
BufferedImage buffImg = new BufferedImage(677, 856,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
Dimension size = panel.getSize();
Insets insets = panel.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random r = new Random();
for (int i = 0; i < 5; i++) {
int x = Math.abs(r.nextInt()) % w;
int y = Math.abs(r.nextInt()) % h;
gbi.drawImage(whiteDiagonal, x, y, null);
}
gbi.dispose();
return buffImg;
}
}
class Surface extends JPanel {
GUIImages images;
public Surface(GUIImages images) {
this.images = images;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
images.doDrawing(this, g);
}
}
public class RepeatDiagonals implements Runnable {
JFrame frame;
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Repeat Diagonals");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Surface(new GUIImages()));
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new RepeatDiagonals());
}
}

Categories