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());
}
}
Related
OK so i'm working on a school project (little animation) and I am currently trying to make rain. I'm not sure how I would go about drawing individual "drops" using JPanel. My Code so far:
Main Class:
public class RainPanel extends JPanel {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
new RainPanel();
}
private final int WIDTH = 800, HEIGHT = 800;
Drop drop;
public RainPanel() {
init();
}
public void init() {
JFrame frame = new JFrame("Rain");
JPanel drop = new Drop();
frame.setVisible(true);
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(drop);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drop.paint(g);
}
Drop class:
public class Drop extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
int x,y;
int yVel = 2;
Timer t = new Timer(5, this);
Random r = new Random();
ArrayList<Drop> DropArray;
public Drop() {
x = r.nextInt(800);
y = r.nextInt(800);
t.start();
}
public void paint(Graphics g) {
super.paintComponent(g);
DropArray = new ArrayList<>(100);
for (int i = 0; i < DropArray.size(); i++) {
DropArray.add(new Drop());
}
g.setColor(Color.BLUE);
g.fillRect(x, y, 3, 15);
}
public void update() {
y += yVel;
if (y > 800)
y = r.nextInt(800);
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
I understand if you might be cringing hard right now (I'm fairly new to graphics coding and mostly familiar with Java itself). All i'm getting drawn currently is a single rain drop. Any suggestions are appreciated.
Don't call super.paintComponent from within paint, you're breaking the paint chain which could cause no end of issues. Override paintComponent directly instead
You shouldn't be modifying the state of a component or anything the component relies on from within any paint method, paint can be called a number of times in quick succession and this can cause no end of issues
Component based animation is not a simple task and unless you really, really need it, you should try and avoid it. Instead, write a class which is "paintable", which you can call from your paintComponent method
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RainDropsKeepFalling {
public static void main(String[] args) {
new RainDropsKeepFalling();
}
public RainDropsKeepFalling() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new RainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RainPane extends JPanel {
private List<Drop> drops = new ArrayList<>(100);
public RainPane() {
for (int index = 0; index < 100; index++) {
drops.add(new Drop(getPreferredSize()));
}
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Drop drop : drops) {
drop.update(getSize());
repaint();
}
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drop drop : drops) {
Graphics2D g2d = (Graphics2D) g.create();
drop.paint(g2d);
g2d.dispose();
}
}
}
protected static final Random random = new Random();
public static class Drop {
private double vDelta = random.nextDouble() + 0.5;
private int height = 15;
private int width = 3;
private double x;
private double y = -height;
private Rectangle2D shape;
public Drop(Dimension size) {
x = random.nextInt(size.width - width) + width;
y = random.nextInt(size.height - height) + height;
shape = new Rectangle2D.Double(x, y, width, height);
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.BLUE);
g2d.fill(shape);
}
public void update(Dimension size) {
y += vDelta;
if (y > size.height) {
y = -height;
x = random.nextInt(size.width - width) + width;
}
shape.setRect(x, y, width, height);
}
}
}
I checked this code for hours, but the rectangle is not showing, can anyone tell me why it is not showing?:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
int resx = 700,resy = 500;
frame.setSize(resx,resy);
frame.setLocationRelativeTo(null);
frame.setTitle("Game");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
try {
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:\\Users\\ivans\\Pictures\\Cookies.png")))));
} catch (IOException e) {
}
frame.repaint();
frame.setLayout(new FlowLayout());
frame.add(new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(50,50,450,650);
}
}, BorderLayout.CENTER);
frame.repaint();
frame.setVisible(true);
}
}
Every time I try to activate the background, the rectangle is not shown, and every time I activate the rectangle, the background is not shown. Please help!
You're setting the JFrame's contentPane to a JLabel, a container that uses no layout, and so adding a component to it will not allow that component to be displayed unless you fully specify that component's size and position, i.e., its bounds. This is one reason I avoid using JLabels for contentPanes (also that it will not set its preferred size based on the components it holds) and instead in general prefer to do my drawing in a background JPanel's paintComponent method.
Side recommendations:
You've too much going on in the main method -- unless this program is not for anything other than demonstration purposes
You set the JFrame's original contentPane (a JPanel) to FlowLayout, but understand that this is meaningless once you change the contentPane.
Despite your assuming that the contentPane uses FlowLayout, you're trying to add the drawing JPanel into a BorderLayout position, something that doesn't make sense.
You have an empty catch block, something that almost never should be done.
Get your images as resources, not files.
Avoid using absolute file paths and prefer use of relative paths to resources.
Don't set sizes of things if you can avoid it.
Avoid so-called "magic numbers", e.g., g.fillRect(50,50,450,650); as this makes your code hard to debug and enhance.
For example, something like:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShowRectangle extends JPanel {
private static final int RECT_X = 50;
private static final int RECT_Y = RECT_X;
private static final int RECT_W = 200;
private static final int RECT_H = 200;
private static final String URL_SPEC = "https://duke.kenai.com/guitar/DukeAsKeith-daylightSmall.png";
private BufferedImage img;
public ShowRectangle(BufferedImage img) {
this.img = img;
}
// have same JPanel draw image and graphic element
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// avoid magic numbers
// g.fillRect(50,50,450,650);
g.fillRect(RECT_X, RECT_Y, RECT_W, RECT_H);
}
// Size the JPanel to the image size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
private static void createAndShowGui(BufferedImage image) {
ShowRectangle mainPanel = new ShowRectangle(image);
JFrame frame = new JFrame("ShowRectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
URL imageUrl = new URL(URL_SPEC);
BufferedImage img = ImageIO.read(imageUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
If you avoid using "magic" numbers for instance, it's easy to make the black rectangle draggable, since it is now be drawn by variable values, values that you can change inside of a MouseAdapter (MouseListener and MouseMotionListener combined). For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShowRectangle extends JPanel {
private static final int RECT_X = 50;
private static final int RECT_Y = RECT_X;
private static final int RECT_W = 200;
private static final int RECT_H = 200;
private static final String URL_SPEC = "https://duke.kenai.com/guitar/DukeAsKeith-daylightSmall.png";
private int rectX = RECT_X;
private int rectY = RECT_Y;
private BufferedImage img;
public ShowRectangle(BufferedImage img) {
this.img = img;
MouseAdapter myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
// have same JPanel draw image and graphic element
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// avoid magic numbers
// g.fillRect(50,50,450,650);
g.fillRect(rectX, rectY, RECT_W, RECT_H);
}
// Size the JPanel to the image size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
private class MyMouse extends MouseAdapter {
private Point p1;
private Point rectP = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
if (new Rectangle(rectX, rectY, RECT_W, RECT_H).contains(p1)) {
rectP = new Point(rectX, rectY);
}
}
#Override
public void mouseDragged(MouseEvent e) {
moveRect(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
moveRect(e.getPoint());
rectP = null;
}
private void moveRect(Point p2) {
if (rectP == null) {
return;
}
rectX = rectP.x + p2.x - p1.x;
rectY = rectP.y + p2.y - p1.y;
repaint();
}
}
private static void createAndShowGui(BufferedImage image) {
ShowRectangle mainPanel = new ShowRectangle(image);
JFrame frame = new JFrame("ShowRectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
URL imageUrl = new URL(URL_SPEC);
BufferedImage img = ImageIO.read(imageUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
Its there just it was going out of boundary and hence not visible.
replace these two lines and check
g.setColor(Color.BLACK);
g.fillRect(0,0,250,250);
Try this,
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle clipBounds = g.getClipBounds();
System.out.println(clipBounds.getX() +" "+ clipBounds.getY() + " "+ clipBounds.getHeight() + " " + clipBounds.getWidth());
g.setColor(Color.BLACK);
g.fillRect(0,0,450,450);
}
You will get 0.0 0.0 10.0 10.0
as output meaning the fill reactangle container is starting from 0,0 till 10,10 and hence it was not shown
Change the layout to GridLayout() will solve your problem,
frame.setLayout(new GridLayout());
frame.add(new JPanel(new GridLayout()){
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle clipBounds = g.getClipBounds();
System.out.println(clipBounds.getX() +" "+ clipBounds.getY() + " "+ clipBounds.getHeight() + " " + clipBounds.getWidth());
g.setColor(Color.BLACK);
g.fillRect(frame.getWidth()/2,0,frame.getWidth(),frame.getWidth());
}
}, BorderLayout.CENTER);
As per doc,
void java.awt.Graphics.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.
So that's the issue
I have a problem with JApplet. The code was working just fine, but when I converted it from JFrame to JApplet, the render part stopped working properly. Basicly what I'm trying to do is simplistic draw app. When launching applet, half of time repaint() is not working (There is no gray background; you have to put mouse over button for it to update its color etc), furtheremore the pixel rendering part is not shown up at all. Here's the code:
The Frame class (JApplet)
package painter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Frame extends JApplet {
public JPanel panel;
private JButton plus, minus, buttonColor;
private int scaleSize;
private JLabel labelScale;
private final Timer updateTimer;
private static boolean painting = false;
public static Color currentColor;
public static int mode = 0;
// 0 = draw; 1 = setcolor; 2 = erase
private ArrayList<Pixel> pixelArray;
public Frame() {
pixelArray = new ArrayList<>();
for (int i = 1; i <= 8; i++) {
for (int j = 1; j <= 8; j++) {
pixelArray.add(new Pixel(i, j));
}
}
setLayout(new BorderLayout());
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//g.fillRect(10, 10, 100, 100); <- test if fillRect works at all. Yus it does.
for (int i = 0; i < pixelArray.size(); i++) {
pixelArray.get(i).render(g);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
};
//panel.setBounds(0, 0, 800, 800);
//add(panel);
getContentPane().add(panel);
//panel.setLayout(null);
//panel.setOpaque(true);
//panel.setDoubleBuffered(true);
currentColor = Color.yellow;
buttonColor = new JButton("Choose color");
buttonColor.setBounds(10, 10, 128, 64);
buttonColor.setBackground(currentColor);
buttonColor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
currentColor = JColorChooser.showDialog(null, "JColorChooser Sample", Color.gray);
}
});
updateTimer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buttonColor.setBackground(currentColor);
repaint();
}
});
updateTimer.start();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
painting = true;
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
painting = false;
}
});
panel.add(buttonColor);
repaint();
}
public static boolean getPaint() {
return painting;
}
public static void main(String[] args) {
new Frame();
}
}
And here is the Pixel class:
package painter;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
public class Pixel {
private Color color;
private int size;
private int x, y, relativex, relativey;
public Pixel(int relx, int rely) {
color = new Color(0x999999, false);
size = 32;
x = relx * size + 64;
y = rely * size + 64;
}
public boolean mouseOver() {
Point pos, mousepos;
pos = new Point(x, y);
mousepos = MouseInfo.getPointerInfo().getLocation();
if ((mousepos.x > pos.x)
&& (mousepos.x < pos.x + size)
&& (mousepos.y > pos.y)
&& (mousepos.y < pos.y + size)) {
return true;
} else {
return false;
}
}
public void render(Graphics g) {
g.setColor(color);
if (mouseOver() && Frame.getPaint()) {
if (Frame.mode == 0) {
color = Frame.currentColor;
}
if (Frame.mode == 1) {
Frame.currentColor = color;
}
if (Frame.mode == 2) {
color = new Color(0xffffffff, true);
}
}
g.fillRect(x, y, size, size);
if (mouseOver()) {
g.setColor(Color.black);
g.drawRect(x, y, size - 1, size - 1);
g.setColor(Color.yellow);
g.drawRect(x + 1, y + 1, size - 3, size - 3);
}
//g.fillRect(10, 10, 250, 250);
}
}
As a stab in the dark, don't call Graphics#dipose on a Graphics context you did not create yourself explicitly
Apart from the fact the the Graphics context is a shared resource, used by all the components that might need to be painted within a given paint cycle, it can also prevent what ever was painted to it to be displayed on some platforms
In 15 years of professional development, I've never had reason to call Toolkit.getDefaultToolkit().sync();. I doubt it'll make that big a difference, I'm just saying
Java applets provide us with these methods
[here] http://docs.oracle.com/javase/tutorial/deployment/applet/appletMethods.html
the method
public void paint(Graphics g){}
is used as alternative of
public void paintComponent(Graphics g){}
of swing.
Check out http://docs.oracle.com/javase/tutorial/uiswing/painting/index.html for the recommended way to perform custom painting of swing components
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());
}
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);
}
}
}