graphics2D is returning "NULL" always in below code. Due to that putPixel() method is not being called. I am calling PictureBox from form design.
public class PictureBox extends JPanel {
Graphics2D graphics2D;
static BufferedImage image;
int imageSize = 300;
public PictureBox(){
setDoubleBuffered(false);
this.setBorder(UIManager.getBorder("ComboBox.border"));
this.repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(image == null){
image = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_RGB);
graphics2D = (Graphics2D)image.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(image, 0, 0, this);
repaint();
}
public final void putPixel(int x, int y, Color color) {
if(graphics2D != null){
graphics2D.setColor(color);
graphics2D.drawLine(x, y, x, y);
repaint();
}
}
public void clear() {
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, imageSize,imageSize);
repaint();
}
}
putPixel method is being called from main where i have (x,y) coordinate stored in Point2D array.
Since you have called putPixel from outside the class and you have not initialised the graphics2D and image in the constructor it may be that when you all calling putPixel method the class may not have been displayed. So you are getting graphics2D to be null as it initialises only when the paintComponent is called and it is called when this class gets displayed.
The solution could be that you shift the initialisation code for the image and graphics2D to the constructor so that you do not encounter null while calling putPixel.
NOTE
You have indiscriminately called the method repaint(). You should keep in mind that repaint() calls paint() method which in turn calls paintComponent() method. So if you call repaint() inside paintComponent() method, you run into the risk of creating an infinite loop. Here you have called it twice once in paintComponent and again in clear method which is called by paintComponent.
Related
I've run into a bit of a wall here. I read elsewhere while trying to fix this issue that you are never supposed to getGraphics(). The problem is, I can't use the provided Graphics context from the paint() / paintComponent() methods. I require it to only call my generate(Graphics g) function once, and I can not provide Graphics outside of the override functions.
Any tips? Trimmed for your convenience.
public class Main extends JPanel {
...
static JFrame displayFrame, inputFrame;
...
...
// Generator node list
ArrayList<Node> nodes = new ArrayList<Node>();
public static void main(String[] args) {
// Set up the frame
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
displayFrame = new JFrame("City generator");
displayFrame.setSize(screenSize.width / 3, screenSize.width / 3);
displayFrame.setLocation(screenSize.width / 2 - displayFrame.getWidth()
/ 2, screenSize.height / 2 - displayFrame.getHeight() / 2);
displayFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
displayFrame.add(new Main());
// displayFrame.setUndecorated(true);
displayFrame.setBackground(Color.lightGray);
displayFrame.setVisible(true);
displayFrame.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
// Mouse movement events here
}
});
}
// Override function
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Calls multiple times
generate(g);
}
private void generate(Graphics g) {
............................
Instead of painting directly to the Graphics context, you could generate a BufferedImage image of what you want painted and paint to that instead...
private BufferedImage buffer;
public BufferedImage generate() {
if (buffer == null) {
buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_IMAGE_ARGB);
Graphics2D g2d = buffer.createGraphics();
// Paint away...
g2d.dispose();
}
return buffer;
}
Then you would paint the result within the paintComponent method...
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Calls multiple times
BufferedImage img = generate();
g.drawImage(img, 0, 0, this);
}
As an example...
Why not just keep a boolean value to track if generate() has been called.
public boolean calledGenerate = false;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!calledGenerate) generate(g);
}
void generate(Graphics g) {
calledGenerate = true;
....
}
also you are calling AWT/Swing code outside of the EDT which is a bad idea.
In your main function you normally should call:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
//build your awt/swing objects here
}
});
What does generate() do though? There is probably a better way to do it.
This is a current problem I am facing for a game. It is a game of Tic-Tac-Toe the user and a friend can play together. I'm not finished yet, but this is what I've got. Any time the window is minimized or covered up by another window the portion of the graphics drawn (X and O) get deleted. I don't really know what to do about this, it would be nice to have a way where the drawing does not get deleted. My paintComponent() method for my main class just sets up the design of the board.
Any help appreciated, thank you!
private class DrawXO implements MouseListener {
public void mousePressed(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
Graphics gContext = getGraphics();
Graphics2D graphics = (Graphics2D) gContext;
graphics.setStroke(new BasicStroke(8));
if (playerOneTurn) {
Player1.drawCircle(gContext, x, y );
checkForWinner();
if(playerOneWins) {
System.out.println("Player one wins");
}
playerTwoTurn = false;
} else {
// Still need to implement drawing for this ~
checkForWinner();
}
}
public void mouseExited(MouseEvent evt) {}
public void mouseEntered(MouseEvent evt) {}
public void mouseClicked(MouseEvent evt) {}
public void mouseReleased(MouseEvent evt) {}
}
Don't use getGraphics();
You need to learn how custom painting is done in Swing. Run through Performing Custom Painting. You will notice that paint required the use of a paintComponent method (in your JPanel or JComponent class) which takes in a Graphics (created for you) context that you use to perform your custom painting. All painting should be done within that context.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
// do painting here
}
Note: Never call this method explicitly, it is automatically called
To update the graphics, you will make some update to some paint variables, then call repaint(). Maybe something like:
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.fillRect(x, y, width, height);
}
If you want to add/draw multiple object, say with the click of a mouse, then keep a List of objects and iterate through the list int the paintComponent method. When the mouse is clicked, add another object to the list and repaint. Something like
List<Rectangle2D> rectangles;
...
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
rectangles.add(new Rectangle2d.Double(x, y, width, height);
repaint();
}
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (Rectangle2D rect: rectangles) {
g2.fill(rect);
}
}
What's the easiest way in Java SE 7 to obtain an instance just to plot a few points for debugging? Desktop environment.
You could use a BufferedImage:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = image.createGraphics();
The easiest and safest way is to use to cast the Graphics reference in paintComponent and cast it as needed. That way the Object is correctly initialized. This reference can be passed to other custom painting methods as required.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
...
}
You should probably just create a JPanel and paint on it.
public class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
.... // my painting
}
}
My code:
public class YesOrNo{
Graphics g;
public void createAndShowGui() {
JPanel x=new JPanel(){
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
}
}
public void drawARectangle(){
g.drawRect(10, 10, 50, 50);
}
}
I know I can call a method inside paintComponent and pass g to it as parameter, but can you do it without calling that method inside paintComponent?
I am trying to allow the user to select what shape they want to draw on my GUI. I have a selection of buttons: circle, square and rectangle. My actionListener works as it prints a string to my console, but it won't show the shape on my GUI. How can I use the actionCommand to draw that shape on my panel.
public void paintComponent(Graphics g) {
g2D = (Graphics2D) g;
//Rectangle2D rect = new Rectangle2D.Double(x, y, x2-x, y2-y);
//g2D.draw(rect);
repaint();
}
public void actionPerformed(ActionEvent arg0) {
if(arg0.getActionCommand().equals("Rect")){
System.out.println("hello");
Rectangle2D rect = new Rectangle2D.Double(x, y, x2-x, y2-y);
g2D.draw(rect); //can only be accessed within paintComponent method
repaint();
}
If you firstly paint your rectangle and then ask for a repaint the rectangle will disappear.
You should store your new shape in a temp variable and render it inside paintComponent.
private Rectangle2D temp;
// inside the actionPerformed
temp = new Rectangle2D.Double(x, y, x2-x, y2-y);
repaint();
// inside the paintComponent
if(temp != null) {
g2D.draw(temp);
}
Make the rect to be field nto local variable. In the actionPerformed create proper rect and call repaint(). Then paintComponent() will be called. It should be like this
public void paintComponent(Graphics g) {
g2D = (Graphics2D) g;
g2D.draw(rect);
}