Search code examples
javaswingbuttongraphicsbufferstrategy

Using java bufferstrategy and swing elements at the same time


I program a simple RTS game now, and it is my first experience in game design. My problem is that when I use createBufferStrategy(2) all swing elements (buttons etc...) not displayed after bufferStrategy.show(); method is invoked. My game is full of buttons, tables and other crap, and I really don't want to code all this by my own. Also I really like Java's layouts, and want to make all GUI on this. So, here is little code example, not from my game, but it is a good demonstration of my problem. Thanks. Btw, I understand the source of my problem. I know that swing draw mechanic is event-based, while using bufferstrategy is not event-based. But I don't know how to solve this. Thank you. And final - I don't want to use default swing event-based approach becouse it is slow for games, and as far as I know the bufferstratgey is only approach for games. Thx.

public static void main(String[] args){
    final JFrame frame = new JFrame();
    JPanel menuPanel = new JPanel();
    final Button button = new Button("Exit");
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    });
    menuPanel.add(button);
    frame.add(menuPanel);
    frame.setPreferredSize(new DimensionUIResource(800, 600));

    //frame.setResizable(false);
    //frame.setUndecorated(true);
    //frame.setIgnoreRepaint(true);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            final long delay = 1000/60;
            frame.pack();
            frame.setVisible(true);
            final GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
            if (device.isFullScreenSupported()){
                device.setFullScreenWindow(frame);
                // this place. If I turn into fullscreen mode button disappear. And if I stay in windowed mode button exist and work;
            }
            frame.createBufferStrategy(2);
            final BufferStrategy bufferStrategy = frame.getBufferStrategy();

            Thread renderingThread = new Thread(){
                public void run(){
                    while (true){
                        long startRenderingTime = System.currentTimeMillis();
                        Graphics g = bufferStrategy.getDrawGraphics();
                        g.setColor(Color.white);
                        g.fillRect(0,0,1680,1050);
                        //button.paint(g);
                        //button.paintAll(g);
                        // I don't know how to draw button!
                        g.dispose();
                        if (!bufferStrategy.contentsLost()){
                            bufferStrategy.show();
                        }
                        long endRenderingTime = System.currentTimeMillis();
                        long actionTime = endRenderingTime-startRenderingTime;
                        try {
                            if (actionTime>delay){
                                sleep(5);
                            } else {
                                sleep(delay-actionTime);
                            }
                        } catch (InterruptedException e){
                            return;
                        }
                    }
                }
            };
            renderingThread.start();
        }
    });
}

Solution

  • You're running an infinite loop on Swings EDT, effectively blocking Swing from doing anything.

    I don't see for what you even need BufferStrategy when you want to display Swing elements. To combine custom rendering with Swing components you normally just create a component that renders your stuff and add it to the normal layout.

    Your component just overwrites paintComponent() and draws whatever it needs to. You can easily trigger an update of your component by calling repaint() on it. This performs usually well enough. Note that Swing components are double buffered by default, so there is no need to work with BufferStrategy there.

    If you want to stick to active rendering, you could call Swings rendering chain selectively, for example you could get the Frame's ContentPane and just call paint() in your rendering loop. But hacking it this way may cause unwanted side effects.