java - 在框架上渲染 Canvas 和面板以进行动画时出现问题

标签 java swing concurrency thread-safety

我在使用canvas Jpanel时遇到问题,需要优化的解决方案 我从这个论坛的一篇帖子中得到了这个设计。

我有三门课:

一个是用于动画的 Canvas (BallPanel),一个是框架(Main),一个是用于 Swing 控件的面板(ControlPanel)

Main 正在渲染 Controlpanel 和 BallPanel,但最终,我看不到 BallPanel 的 drawworld() 渲染,但我只能看到 ControlPanel

我看不到动画和黑色背景,似乎控制面板全部在框架上,而 Canvas (黑色背景)位于其后面/下方或某处但不可见

球面板:

 public BallPanel()
    {
        try {
            this.aBall = (BallServer) Naming
                    .lookup("rmi://localhost/BouncingBalls");

        } catch (Exception e) {
            System.out.println("Exception: " + e);
        }
        box = new Box(0, 0, BOX_WIDTH, BOX_HEIGHT);
        setPreferredSize(new Dimension(800, 600));
        setIgnoreRepaint(true);

        // Wire up Events
//      MouseHandler mouseHandler = new MouseHandler();
//      addMouseMotionListener(mouseHandler);
//      addMouseListener(mouseHandler);
    }



public void drawworld() throws RemoteException {

        if (strategy == null || strategy.contentsLost())
        {
            // Create BufferStrategy for rendering/drawing
            this.createBufferStrategy(2);
            strategy = getBufferStrategy();
            Graphics g = strategy.getDrawGraphics();
            this.g2 = (Graphics2D) g;
        }

        // Turn on anti-aliasing
        this.g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    //  box.draw(this.g2); // this can be another but it's also not working

        // Render Background
        this.g2.setColor(Color.BLACK);
        this.g2.fillRect(0, 0, getWidth(), getHeight());

        serball = aBall.getState();// other version UNcomment this line

        for (int i = 0; i < currentNumBalls; i++) {
            this.g2.setColor(serball[i].getBallColor(velocity.getLength()));
            this.g2
                    .fillOval((int) (serball[i].position.getX() - serball[i]
                            .getRadius()),
                            (int) (serball[i].position.getY() - serball[i]
                                    .getRadius()), (int) (2 * serball[i]
                                    .getRadius()), (int) (2 * serball[i]
                                    .getRadius()));

        }


public void mainLoop() {

        long previousTime = System.currentTimeMillis();
        long currentTime = previousTime;
        long elapsedTime;
        long totalElapsedTime = 0;
        int frameCount = 0;

        while (true) {
            currentTime = System.currentTimeMillis();
            elapsedTime = (currentTime - previousTime); // elapsed time in
            // seconds
            totalElapsedTime += elapsedTime;
            if (totalElapsedTime > 1000) {
                currentFrameRate = frameCount;
                frameCount = 0;
                totalElapsedTime = 0;
            }


                try {
                    drawworld();
                } catch (RemoteException e1) {
                    e1.printStackTrace();
                }


            try {
                Thread.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            }

            previousTime = currentTime;
            frameCount++;

        }
    }


public void start()
    {
        mainLoop();
    }

start() 上面的 Main 类从这里调用:

public static void main(String[] args)
    {


                JFrame frame = new JFrame("BallBounce");

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));


                BallPanel ballCanvas = new BallPanel();

                ControlPanel controlPanel = new ControlPanel(ballCanvas);

                frame.getContentPane().add(ballCanvas);
                frame.getContentPane().add(controlPanel);
                frame.pack();
                frame.setVisible(true);

                ballCanvas.start();
        }

这是用作 Controller 的控制面板:

public class ControlPanel extends JPanel {

    private BallPanel mainPanel;
    private JButton resetButton;

    public ControlPanel(BallPanel mainPanel)
    {
        this.setPreferredSize(new Dimension(200, 60));
        this.setMaximumSize(new Dimension(5000, 100));
        this.mainPanel = mainPanel;

....
..
..
private class ButtonHandler implements ActionListener
    {

        public void actionPerformed(ActionEvent e) 
        {
            JButton source = (JButton)e.getSource();

            if (source == resetButton)
            {
                mainPanel.clearBalls();
            }

非常感谢您的帮助以及我们如何使用 RMI 动画和 Swing 控件来处理此类 GUI 来进行交互/控制 有人可以告诉优化的方法吗? 吉比拉拉

P.S:我认为在调用远程方法并渲染绘图世界时存在一些线程问题,任一线程正在挂起或被阻止

交叉发帖:http://www.coderanch.com/forums/jforum?module=posts&action=edit&post_id=2406332&start=0

我用计时器做了这个,但问题仍然存在,请帮忙:

public CopyOfCleanBallPanel2() throws IOException, InterruptedException {

        frame = new JFrame("simple gaming loop in java");
        frame.setSize(BOX_WIDTH, BOX_WIDTH);
        frame.setResizable(false);

        displayCanvas = new CustomCanvas();
        displayCanvas.setLocation(0, 0);
        displayCanvas.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
        displayCanvas.setBackground(Color.BLACK);
        displayCanvas.setFont(new Font("Arial", Font.BOLD, 14));
        displayCanvas.setPreferredSize(new Dimension(CANVAS_WIDTH,CANVAS_HEIGHT));

        frame.add(displayCanvas);
        displayCanvas.requestFocus();

        frame.setLocationRelativeTo(null);

        try {
            this.aBall = (BallServer) Naming
                    .lookup("rmi://localhost/BouncingBalls");

        } catch (Exception e) {
            System.out.println("Exception: " + e);
        }


        frame.pack();
        frame.setVisible(true);

        aBall.start();
        startFrameTimer();

    }

    /*
     * Initializes the frame (also game update) timer.
     */
    private void startFrameTimer() {
        frameTimer.schedule(new FrameTimerTask(), 1, GAME_TIMER_COOLDOWN);
    }

    public void updateSimulation() throws RemoteException {
        repaintCanvas();
    }
    /*
     * This method gets called by the timer. It updates the game simulation and
     * redraws it.
     */
    private void onFrameTimer() throws RemoteException {
        updateSimulation();
    }

    /*
     * Causes the whole canvas to get repainted.
     */
    private final void repaintCanvas() throws RemoteException  {
        Graphics g =  displayCanvas.getGraphics();
        drawworld(g);
    }

    private class FrameTimerTask extends TimerTask {
        public void run() {
            try {
                onFrameTimer();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    /*
     * This custom canvas overrides the paint method thus allowing for a custom
     * painting on the component.
     */
    private class CustomCanvas extends Canvas {
        @Override
        public void paint(Graphics g) {
            // Currently the game message gets drawn over the inner border
            // of the canvas so we have to repaint the whole thing.
            try {
                repaintCanvas();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }


    public void drawworld(Graphics g) throws RemoteException {
            g.setColor(Color.BLACK);
             g.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);

            System.out.println("i m in drawworld ");

            serBall = aBall.getState1();// other version UNcomment this line

            System.out.println("i m in drawworld "+serBall.length);

            for (int i = 0; i < currentNumBalls; i++) {
                g.setColor(serBall[i].getBallColor(velocity.getLength()));
                g
                        .fillOval((int) (serBall[i].position.getX() - serBall[i]
                                .getRadius()),
                                (int) (serBall[i].position.getY() - serBall[i]
                                        .getRadius()), (int) (2 * serBall[i]
                                        .getRadius()), (int) (2 * serBall[i]
                                        .getRadius()));

                // Draw our framerate and ball count
                g.setColor(Color.WHITE);
                g.drawString("FPS: " + currentFrameRate + " Balls: "
                        + currentNumBalls, 15, 15);
            }   
        }

请帮忙。

最佳答案

这看起来像是一个线程问题,因为在我看来,您正在 EDT(主 Swing 线程)上调用 while (true) 和 Thread.sleep(...) 。您读过Concurrency in Swing吗? ?如果没有,请查看内部链接的文章。还强烈考虑使用 Swing Timer 来驱动动画,而不是 while (true) 和 Thread.sleep(...)。

关于java - 在框架上渲染 Canvas 和面板以进行动画时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5301069/

相关文章:

concurrency - ConcurrentHashMap,JDK8 中改进的并发特性

java - 是否有任何插件或功能可以确定应用程序或项目(在给定的项目生命周期中)中未使用哪些 JAR

java - 图像/文本未在 JFrame 中显示

java - 一种在 java 代码中定义/实现故障转移 ldap 服务器的方法

java - Java 中的二叉搜索树可视化

java - 如何在 JList 上工作

ruby-on-rails - 如何同时获取多个提要

c++ - 跨线程的unique_lock?

java - 我应该更喜欢使用 JPA - 纯 SQL 还是 JPQL 以及如何使用 JPQL 和实体创建/删除表

java - 为什么我在一种情况下会出现空指针异常,而在类似情况下却不会?