【问题标题】:Change Color of bouncing Ball in a running Thread在正在运行的线程中更改弹跳球的颜色
【发布时间】:2014-04-23 14:17:09
【问题描述】:

我是 Java 新手。我通过创建一个弹跳球 GUI 开始学习。

除了一件事,我已经成功地完成了我想做的所有事情。每当它从框架边框反弹时,我都无法让球改变它的颜色。

我知道我不能使用 getGraphics 进行绘图,但在这种情况下,我也不能使用 paint 方法,因为我已经在程序开始时将它用于初始设置。如果我从循环中调用paint方法,它确实会改变颜色,但布局北侧的所有JButtons都会神秘地消失。

对我来说,让整个事情变得更加复杂的一件事是,我在 Runnable 接口的 void run 方法中循环球反弹。

我不知道如何解决它。

你们可以在 IDE 中复制我的代码。不起作用的一件事是球保持黑色并且不会改变它的颜色。其他一切都运行良好。

所以请帮我弄清楚如何在球弹起时改变球的颜色。

谢谢

代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Ball extends JFrame implements Runnable, ActionListener {

    private JButton start;
    private JButton stop;
    private JButton fast;
    private JButton slow;
    private JButton reset;
    private int ball_x;
    private int ball_y;
    private int dx = 10;
    private int dy = 20;
    private int size = 50;
    private boolean active;
    private int i = 20;
    private int R = 255;
    private int G = 0;
    private int B = 255;
    private Color rgb;


    private MyPanel screen;

    private class MyPanel extends JPanel {
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            ball_x = screen.getWidth() / 2 - 25;
            ball_y = screen.getHeight() / 2 - 25;
            i = 20;
            g.setColor(rgb);
            g.fillOval(ball_x, ball_y, size, size);
        }

        public void clr() {

            if (R <= 10) {
                R = 255;
            }
            R = R - 10;


            if (G >= 255) {
                G = 0;
            }

            G = G + 15;


            if (B <= 20) {
                B = 255;
            }

            B = B - 20;

        }
    }


    public void start() {
        active = true;
        start.setText("Start");
        start.setEnabled(false);
        start.setText("Jumping...");
        Thread th = new Thread(this); // Thread anlegen
        th.start(); // Thread starten
    }

    public void stop() {
        if (active) {
            start.setText("Continue");
        }
        active = false;
        start.setEnabled(true);
    }

    public void reset() {
        active = false;
        size = 50;
        screen.repaint();
        start.setText("Start");
        start.setEnabled(true);
    }

    public void slow() {
        i = i + 2;
        if (i >= 60) {
            i = 60;
        }
    }

    public void fast() {
        i = i - 2;
        if (i <= 5) {
            i = 5;
        }
    }

    public void actionPerformed(ActionEvent ereignis) {

        if (ereignis.getSource() == start) {
            start();
        }

        if (ereignis.getActionCommand() == "G+") {
            fast();
        }

        if (ereignis.getActionCommand() == "G-") {
            slow();
        }

        if (ereignis.getActionCommand() == "Reset") {
            reset();
        }

        if (ereignis.getActionCommand() == "Pause") {
            stop();
        }

    }

    public Ball() {

        this.setTitle("Jumping Ball \u00a9 The One");
        Container panel = new Container();
        panel.setLayout(new BorderLayout());
        JPanel subpanel = new JPanel();
        //subpanel.setLayout(new GridLayout());
        screen = new MyPanel();
        this.setVisible(true);
        this.setSize(1366, 768);
        this.setContentPane(panel);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        start = new JButton("Start");
        fast = new JButton("G+");
        slow = new JButton("G-");
        reset = new JButton("Reset");
        stop = new JButton("Pause");
        subpanel.add(start);
        subpanel.add(fast);
        subpanel.add(slow);
        subpanel.add(reset);
        subpanel.add(stop);
        panel.add(subpanel, "North");
        panel.add(screen, "Center");
        start.addActionListener(this);
        stop.addActionListener(this);
        reset.addActionListener(this);
        slow.addActionListener(this);
        fast.addActionListener(this);

    }

    public void run() {

        while (active) {
            screen.getGraphics().clearRect(ball_x, ball_y, size, size);

            if (ball_x > (screen.getWidth() - 30) || ball_x < 25) {
                dx = -dx;
                size = size + 3;
                screen.clr();

            }

            if (ball_y > (screen.getHeight() - 30) || ball_y < 25) {
                dy = -dy;
                size = size + 3;
                screen.clr();

            }

            ball_x = ball_x + dx;
            ball_y = ball_y + dy;

            rgb = new Color(R, G, B);

            screen.getGraphics().setColor(rgb);
            screen.getGraphics().fillOval(ball_x, ball_y, size, size);
            try {
                Thread.sleep(i);
            } catch (InterruptedException x) {
                x.printStackTrace();
            }
        }

    }


    public static void main(String[] args) {
        Ball bouncer = new Ball();

    } // End of Method Main


}

谢谢

【问题讨论】:

  • 为什么要花 200 多个 LOC 来显示您是如何尝试更改颜色的?为了尽快获得更好的帮助,请发布MCVE(最小完整且可验证的示例)。
  • 我会做一个改变颜色的方法。然后可以循环调用该方法,会改变颜色
  • 这是整个程序。这不仅仅是我试图改变颜色的部分。准确地说:screen.getGraphics().setColor(rgb); 不起作用,我不能使用paint 方法,因为它一开始就已经在做其他事情了。
  • @MarshallTigerus 为此,我需要paintComponent 方法,但我不能使用它,因为它已经被使用了。我像 10 天前一样刚开始使用 Java。不知道如何解决这个问题。
  • 你应该做一些调试。看看你的代码是否达到了这一点。我也看不到你在哪里调用 run()

标签: java swing colors


【解决方案1】:

虽然完成了,但您的示例有几个关键问题:

  • 它是错误的synchronized

  • 它过早地调用setVisible()

  • 它依赖于框架的几何形状,而不是封闭的面板。

相反,从引用 here 的示例开始,使用 Swing Timer。请注意,颜色会随着每个repaint() 而变化,并且每次弹跳都会播放声音。添加成员变量bounced

private boolean bounced;

当球弹起时,在TimeractionPerformed()方法中设置bounced = true

if (ballX - RADIUS < 0) {
    …
    bounced = true;
} else if (ballX + RADIUS > BOX_WIDTH) {
    …
    bounced = true;
}

paintComponent()中,相应地更改颜色。

g.setColor(clut.peek());
if (bounced) {
    clut.add(clut.remove());
    bounced = false;
}

使用较小的clut 可能更容易看到更改。

private static final float N = 16;

【讨论】:

  • 非常感谢!我会看看你所说的一切。我需要一些时间。例如,clut 是我以前从未听说过的。我刚刚用谷歌搜索了它。
  • 花点时间;检查了一个相关示例herecolor look-up table 是一种拥有灵活调色板的便捷方式。
  • 感谢这个例子。这真的很有趣。但我不明白的一件事是:为什么我不能在构造函数中调用this.setVisible(true)?为什么我必须在 main 方法中这样做?
  • 你没有; 添加你的组件并调用pack()之后调用它。
【解决方案2】:

好吧,我让它工作了,但我认为这不是最好的方法!我不得不放弃 Threads 并使用 Timer。

我一直在读到不应将 AWT 和 Swing 混合使用,但我认为除了 panel.setLayout(new BorderLayout());public void paintComponent(Graphics g) 之外没有其他可能性

这显然是在混合 AWT 和 Swing 组件,但我没有找到任何纯粹的 Swing 方式来做到这一点。

无论如何,这是我的整个代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Ball extends JFrame implements ActionListener {

    private JButton start;
    private JButton stop;
    private JButton fast;
    private JButton slow;
    private JButton reset;
    private int ball_x;
    private int ball_y;
    private int dx = 10;
    private int dy = 20;
    private boolean active;
    private int i = 30;
    private int R = 255;
    private int G = 255;
    private int B = 0;
    private Color rgb;
    private Timer trigger = new Timer(i, this);

    private MyPanel screen;

    private class MyPanel extends JPanel {

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (start.getText() == "Start") {
                ball_x = screen.getWidth() / 2 - 50;
                ball_y = screen.getHeight() / 2 - 50;
            }

            if (start.getText() == "Jumping...") {
                g.clearRect(ball_x, ball_y, 100, 100);
            }

            ball_x = ball_x + dx;
            ball_y = ball_y + dy;

            rgb = new Color(R, G, B);
            g.setColor(rgb);

            g.fillOval(ball_x, ball_y, 100, 100);

            if (ball_x > (screen.getWidth() - 100) || ball_x < 10) {
                dx = -dx;
                screen.clr();
            }

            if (ball_y > (screen.getHeight() - 100) || ball_y < 10) {
                dy = -dy;
                screen.clr();
            }

        }

        public void clr() {

            if (R <= 10) {
                R = 255;
            }
            R = R - 10;

            if (G <= 20) {
                G = 255;
            }

            G = G - 20;

            if (B >= 255) {
                B = 0;

            }

            B = B + 15;

        }
    }

    public void start() {

        active = true;
        start.setText("Start");
        start.setEnabled(false);
        start.setText("Jumping...");
        trigger.start();
        screen.repaint();

    }

    public void stop() {
        if (active) {
            start.setText("Continue");
        }
        active = false;
        start.setEnabled(true);
        trigger.stop();

    }

    public void reset() {
        active = false;
        start.setText("Start");
        start.setEnabled(true);
        i = 100;
        trigger.stop();
        screen.repaint();
    }

    public void slow() {
        i = i + 10;
        if (i >= 100) {
            i = 100;
        }

        trigger.setDelay(i);
    }

    public void fast() {
        i = i - 10;
        if (i <= 10) {
            i = 10;
        }
        trigger.setDelay(i);
    }

    public void actionPerformed(ActionEvent ereignis) {

        if ((ereignis.getSource() == start) || (trigger.isRunning() == true)) {
            start();
        }

        if (ereignis.getActionCommand() == "G+") {
            fast();
        }

        if (ereignis.getActionCommand() == "G-") {
            slow();
        }

        if (ereignis.getActionCommand() == "Reset") {
            reset();
        }

        if (ereignis.getActionCommand() == "Pause") {
            stop();
        }

    }

    public Ball() {

        this.setTitle("Jumping Ball \u00a9 The One");
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        this.setContentPane(panel);
        JPanel subpanel = new JPanel();
        panel.add(subpanel, "North");
        screen = new MyPanel();
        screen.setBackground(Color.WHITE);
        panel.add(screen, "Center");
        start = new JButton("Start");
        fast = new JButton("G+");
        slow = new JButton("G-");
        reset = new JButton("Reset");
        stop = new JButton("Pause");
        subpanel.add(start);
        subpanel.add(fast);
        subpanel.add(slow);
        subpanel.add(reset);
        subpanel.add(stop);
        start.addActionListener(this);
        stop.addActionListener(this);
        reset.addActionListener(this);
        slow.addActionListener(this);
        fast.addActionListener(this);
        this.setSize(1280, 720);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        Ball fenster = new Ball();

    } // Ende der Methode Main
}

我知道这不是专业的方法,但这是我能做的最好的事情,它可以做到我想要它做的事情。

如果有人能在我的代码中指出一些绝对不可行的地方,我会非常高兴。

感谢

【讨论】:

  • +1 大大改进了代码;另见Initial Threads;格言是避免混合 AWT 和 Swing 组件;使用 AWT 事件和图形很好..
  • 非常感谢垃圾神 =) 线程似乎比我预期的要困难。现在我正在做一个“让球反弹否则你输”的游戏。基本上它只是一个随着鼠标x位置移动(没有y移动)的drawRect,并且必须用它反弹球。没什么大不了的,但似乎是一种很好的做法。
  • 我同意;这样的原型是非常宝贵的设计工具;你可能想研究这个相关的example。今后,您可以通过点击左侧的empty check mark 来接受答案。
猜你喜欢
  • 1970-01-01
  • 2021-06-20
  • 2019-08-25
  • 1970-01-01
  • 2021-03-06
  • 2013-05-14
  • 2022-12-25
  • 2011-08-25
  • 1970-01-01
相关资源
最近更新 更多