2

I was trying to use XOR mode in Graphics to draw a 1bit texture in color against a flat background, when I encountered a behaviour in Graphics I don't understand.

Here is an example of what I mean, isolated:

package teststuff;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;

public class XORTest extends JFrame {

public XORTest() {
    super("Test");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(500, 400);
    setIgnoreRepaint(true);
    setResizable(false);
    setVisible(true);
    createBufferStrategy(2);
    Graphics graphics = getBufferStrategy().getDrawGraphics();
    graphics.setColor(Color.black);
    graphics.fillRect(0, 0, getWidth(), getHeight());
    graphics.setColor(Color.green);
    graphics.fillRect(30, 40, 100, 200);
    graphics.setXORMode(Color.white);         // (*)
    graphics.fillRect(60, 80, 100, 200);
    graphics.dispose();
    getBufferStrategy().show();
}


public static void main(String[] args) {
    XORTest test = new XORTest();
}
}

If I uncomment the line marked with (*), two green rectangles are drawn as expected. If I leave it, nothing is drawn into the component, not even the black background or green rectangle that is drawn beforehand. Even more odd, it worked once. I had the color as Color.green instead of white before. After I changed it, it drew as expected. But when I closed the application and started it again, it didn't work anymore and it hasn't since.

Is this a bug in java? In my jre? Undocumented behaviour for Graphics? I'm on Windows and running the example on the jdk7.

Screenshots: Imgur album because it won't let me post 3 links

The third screenshot is the code as it is above, the first with (*) commented and the second is how it looked the one time it worked (I created that in GIMP because I didn't take a screenshot then).

Scaatis
  • 137
  • 2
  • 10
  • relevant? http://stackoverflow.com/questions/12127187/what-does-graphics-setxormodecolor-do-in-simple-terms – Marc B May 23 '13 at 17:11
  • I read that question. I know what XOR mode is supposed to do. The thing here is that it draws nothing. I will include screenshots in the original question. – Scaatis May 23 '13 at 17:17
  • When I run it I get the second picture except the blue is pink. Although sometimes it is blank. – FDinoff May 23 '13 at 17:29
  • I may have misremembered the blue, it may well have been pink. But I'm glad you can reproduce the error. It seems like a bug in java if it is unpredictable. – Scaatis May 23 '13 at 17:31
  • More along the lines of a race condition. However I do not understand graphics in java well enough to debug this. – FDinoff May 23 '13 at 17:32
  • +1 for [sscce](http://sscce.org/). – trashgod May 23 '13 at 21:18

1 Answers1

3

Without a compelling reason to the contrary, it's easier and more reliable to override paintComponent() in JPanel, which is double buffered by default. With a compelling reason, follow the guidelines in BufferStrategy and BufferCapabilities. Also note,

test image

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @see https://stackoverflow.com/a/16721780/230513
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new XORPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class XORPanel extends JPanel {

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(190, 320);
        }

        @Override
        protected void paintComponent(Graphics graphics) {
            super.paintComponent(graphics);
            graphics.setColor(Color.black);
            graphics.fillRect(0, 0, getWidth(), getHeight());
            graphics.setColor(Color.green);
            graphics.fillRect(30, 40, 100, 200);
            graphics.setXORMode(Color.white);
            graphics.fillRect(60, 80, 100, 200);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I do have a compelling reason not to use paintcomponent. I need it to be in the same thread as the rest of my logic. I will look into the rest of your advice. – Scaatis May 23 '13 at 20:25
  • @Scaatis: Fair enough, but you still have to synchronize access to shared data; you can disable `JPanel` buffering with `super(false)`; also note the circumstances in which "colors are changed in an unpredictable but reversible manner" with `setXORMode()`. – trashgod May 23 '13 at 21:18
  • The "unpredictable manner" I assumed to be the colors being xor'ed all over the place, not the entire drawing failing. I still don't understand why I only get a grey screen when drawing in XOR mode, but I'll tag your answer as accepted anyway. – Scaatis May 24 '13 at 16:05