Java-апплет - Как добавить двойную буферизацию в JButton - PullRequest
0 голосов
/ 17 мая 2018

В настоящее время я использую класс Applet для создания простой игры. Поскольку имеется эффект мерцания, я добавил двойную буферизацию для компонентов Graphics, создав закадровый буфер, например, так:

public class AppletTest extends Applet implements Runnable {

    Thread thread;
    Image img;
    Graphics gfx;

    public final int WIDTH = 700, HEIGHT = 500;

    public void init() {
        this.resize(WIDTH, HEIGHT);

        thread = new Thread(this);
        thread.start();

        img = createImage(WIDTH, HEIGHT); // off-screen buffering
        gfx = img.getGraphics();
    }
    public void draw(Graphics g) {
        gfx.setColor(Color.BLACK);
        gfx.fillRect(0, 0, WIDTH, HEIGHT);
        gfx.setColor(Color.WHITE);

        gfx.fillRect(50, 50, 100, 100);
        gfx.setFont(new Font("Century", Font.BOLD, 30));
        gfx.drawString("I feel good sometimes I don't", 200, 200);            

        g.drawImage(img, 0, 0, this); // draws the off-screen image
    }
    public void update(Graphics g) {
        draw(g);
    }

    public void run() {
        while(true) {
            repaint();
            try {
                Thread.sleep(5);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

Если вы запустите приложение, все компоненты / методы Graphics (.fillRect, .drawString и т. Д.) Будут отображены в закадровом буфере. Однако моя цель состоит в том, чтобы добавить JButton к апплету - и, как и ожидалось, нет никакой закадровой загрузки для компонента JButton (что означает мерцание).

Graphics gfx;
JButton button1;

public void draw(Graphics g) {
    setLayout(null);

    button1.setBounds(225, 400, 250, 50);
    button1.setFont(new Font("Courier", Font.PLAIN, 17));
    button1.setForeground(Color.WHITE);
    button1.setBackground(Color.DARK_GRAY);

    add(button1); // is it possible to draw the JButton on the off-screen buffer?
}

Как бы вы добавили закадровую загрузку в компонент JButton?

1 Ответ

0 голосов
/ 17 мая 2018

AppletJApplet) официально устарели, они больше не поддерживаются Java, Oracle, браузерами (или сообществом в целом)

Компоненты Swing по умолчанию имеют двойную буферизацию. Если вы работаете с системой окраски правильно, вы не должны испытывать мерцания, если вы это делаете, это явный признак того, что вы делаете что-то не так.

Я бы порекомендовал взглянуть на Выполнение пользовательского рисования и Рисование в AWT и Swing для получения более подробной информации о том, как работает система рисования Swing.

Качели однопоточные И не безопасны для нитей. Это означает, что вы не должны выполнять никаких длительных операций в контексте потока диспетчеризации событий и не должны обновлять пользовательский интерфейс вне контекста EDT.

Посмотрите Параллельность в Swing для получения более подробной информации.

Простым решением этих проблем является использование Swing Timer, который можно использовать для планирования регулярных обновлений, которые выполняются в контексте EDT.

См. Как использовать Swing Timers для получения более подробной информации ...

В качестве основного работоспособного примера ...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        public static final int WIDTH = 700, HEIGHT = 500;

        public TestPane() {
            setLayout(new GridBagLayout());
            add(new JButton("Big fat button"));
            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(WIDTH, HEIGHT);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLACK);
            g2d.fillRect(0, 0, WIDTH, HEIGHT);
            g2d.setColor(Color.WHITE);

            g2d.fillRect(50, 50, 100, 100);
            g2d.setFont(new Font("Century", Font.BOLD, 30));
            g2d.drawString("I feel good sometimes I don't", 200, 200);

            g2d.dispose();
        }

    }

}

Ладно, «Но я абсолютно, должен, без вопросов, использовать Applet ... ?, тогда мне вас жаль, но это не меняет того факта, что Swing уже имеет двойную буферизацию. Приведенный выше пример можно легко применить к J/Applet, просто создав экземпляр JPanel и добавив в Applet контейнер

Swing использует алгоритм «пассивного рендеринга», если вам абсолютно необходим полный контроль, вы можете взглянуть на BufferStrategy, который передает вам полный контроль над системой рисования, но вы не сможете использовать компоненты Swing, так как они обновляются подсистемой Swing

...