JPanel侦听器和线程问题 [英] JPanel listeners and threads issues

查看:94
本文介绍了JPanel侦听器和线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是用于以给定的延迟率在帧内的面板上的面板上显示半径变化的圆的代码,但是该代码显示的是最终输出而不是中间阶段,即,圆不是一一出现而是全部出现.圆立即作为最终输出.可能存在一些与按钮操作侦听器和面板线程有关的错误.该代码使用初始圆的半径和迭代的总数(要显示的圆的总数),每个下一个圆的半径增加10.

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

public class ControlCircle extends JFrame {
  private JButton jbtEnlarge = new JButton("Start");
  private JButton jbtShrink = new JButton("Stop");
  private CirclePanel canvas = new CirclePanel();

  private int radius = 0;
  private int iter;

  public ControlCircle() {
    JPanel panel = new JPanel();
    JPanel jp = new JPanel();
    jp.setPreferredSize(new Dimension(300, 0));
    panel.add(jbtEnlarge);
    panel.add(jbtShrink);

    this.add(jp, BorderLayout.WEST);
    this.add(canvas, BorderLayout.CENTER);
    this.add(panel, BorderLayout.SOUTH);

    final JTextField f1 = new JTextField(8),f2 = new JTextField(8);

    jp.setLayout(new FlowLayout(FlowLayout.RIGHT, 50, 30));
    jp.add(new JLabel("Radius"));
    jp.add(f1);
    jp.add(new JLabel("Iteration"));
    jp.add(f2);

    f1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        radius = Integer.parseInt(new String(f1.getText()));
      }
    });

    f2.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        iter = Integer.parseInt(new String(f2.getText()));
      }
    });

    jbtEnlarge.addActionListener(new EnlargeListener());
    jbtShrink.addActionListener(new ShrinkListener());
  }

  public static void main(String[] args) {
    JFrame frame = new ControlCircle();

    frame.setTitle("ControlCircle");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class EnlargeListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      canvas.enlarge();
    }
  }

  class ShrinkListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      //canvas.shrink();
    }
  }

  class CirclePanel extends JPanel {
    private int r = radius;

    public void enlarge() {
      //radius += 2;

      repaint();
    }

    public void shrink() {
      radius -= 2;

      repaint();
    }

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

      for (int i = 0; i < iter; i++) {
        g.drawOval(getWidth() / 2 - r, getHeight() / 2 - r, 2 * r, 2 * r);

        try {
          Thread.sleep(100);
        } catch (Exception exp) {
        }

        r = r + 10;
      }

      r = 0;
    }
  }
}

解决方案

想法是使用按钮StartStop我添加了ContinueReset附加控件来更好地解释这个想法.这些按钮控制动画线程的执行,从而在绘图表面上绘制圆.我作为内部类分离的绘图表面仅具有绘制所执行内容的功能.采取此方法的另一种想法是逐步绘制圆,直到完成绘制为止,因此使用了增量绘制.

我已经使用了上面的代码,并对其进行了一些更改以支持我的想法.如果您需要更多(通常是更好)的示例,请参见此文章.. >

下面的代码是完整的,我没有完善代码以使其具有明智的生产外观,但仅出于演示目的.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class ControlCircle extends JFrame implements Runnable {
  private JButton jbtStart = new JButton("Start");
  private JButton jbtStop = new JButton("Stop");
  private JButton jbtContinue = new JButton("Continue");
  private JButton jbtReset = new JButton("Reset");
  private CirclePanel canvas = new CirclePanel();

  private JTextField f1;
  private int radius = 0;

  private JTextField f2;
  private int iter;

  protected boolean  incrementalPainting;

  /**
   * Flag indicates that a thread is suspended
   */
  private boolean suspended = false;


  /**An instance of the class Thread.*/
  private Thread thread = null;

  public ControlCircle() {
    JPanel panel = new JPanel();
    JPanel jp = new JPanel();
    jp.setPreferredSize(new Dimension(300, 0));
    panel.add(jbtStart);
    panel.add(jbtStop);
    panel.add(jbtContinue);
    panel.add(jbtReset);

    this.add(jp, BorderLayout.WEST);
    this.add(canvas, BorderLayout.CENTER);
    this.add(panel, BorderLayout.SOUTH);

    f1 = new JTextField(8);
    f2 = new JTextField(8);

    jp.setLayout(new FlowLayout(FlowLayout.RIGHT, 50, 30));
    jp.add(new JLabel("Radius"));
    jp.add(f1);
    jp.add(new JLabel("Iteration"));
    jp.add(f2);


    jbtStart.addActionListener(new StartListener());
    jbtStop.addActionListener(new StopListener());
    jbtContinue.addActionListener(new ContinueListener());
    jbtReset.addActionListener(new ResetListener());
  }

  public static void main(String[] args) {
    JFrame frame = new ControlCircle();

    frame.setTitle("ControlCircle");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class StartListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread == null) {
        repaint();
        startThread();
      }
    }
  }

  class StopListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread != null){
        mySuspend();
      }
    }
  }

  class ContinueListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      myResume();
    }
  }

  class ResetListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread != null) {
        stopThread();
      }
      repaint();
    }

  }

  /**
   * my Suspend
   */
  private void mySuspend() {
    System.out.println("mySyspend()");
    suspended = true;
  }

  /**
   * my Resume
   */
  private synchronized void myResume(){
    System.out.println("myResume()");
    suspended = false;
    notifyAll();
  }

  public void run(){
    System.out.println("run() - started");

    Thread me = Thread.currentThread();
    while (thread == me) {
      radius = Integer.parseInt(f1.getText());
      iter = Integer.parseInt(f2.getText());
      for (int i = 0; i < iter; i++) {
        if (thread == null) return;
        incrementalPainting = true;
        myRepaint();
        try {
          Thread.sleep(1000);
        }
        catch(InterruptedException e){}
        radius += 10;
      }
      if(thread != null) thread = null; // exiting while
    }
    System.out.println("run() - exiting");
  }

  /**
   * start Thread
   */
  private void startThread(){
    System.out.println("startThread()");
    if(thread == null){
      thread = new Thread(this);
      thread.start();
    }
  }

  /**
   *  stop Thread
   */
  private synchronized void stopThread() {
    System.out.println("stopThread()");
    thread = null; // exiting from while
    if (suspended) {
      suspended = false;
      notify();
    }
  }

  /**
   * This is called from the run method to invoke painting.
   */
  private void myRepaint() {
    System.out.println("myRepaint()");
    incrementalPainting = true;
    repaint();
    synchronized (this) {
      while (incrementalPainting) {
        System.out.println("wait while incremental painting");
        try {
          wait();
        } catch (InterruptedException e) {
          System.out.println("interrupted");
        }
      }
    }

    suspend();
  }
  /**
   * This method should place somewhere when run() has started. Perfectly
   * when repaint() performed.
   */
  private void suspend(){
    System.out.println("suspend()");
    synchronized (this) {
      while (suspended) {
        System.out.println("wait while suspended");
        try {
          wait();
        } catch (InterruptedException e) {
          System.out.println("interrupted");
        }
      }
    }

  }

  public synchronized void myPaint(Graphics g) {
    if (g == null){
      if (incrementalPainting){
        incrementalPainting = false;
        notifyAll();
      }
      return;
    }
    if (incrementalPainting){
      myDraw(g);
      incrementalPainting = false;
      notifyAll();

    }
    else {
      myDraw(g);
    }
  }

  public void myDraw(Graphics g){
    g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, 2 * radius, 2 * radius);
  }

  protected final class CirclePanel extends JPanel {
    //Offscreen buffer of this canvas
    private BufferedImage backBuffer = null;

    public void paintComponent (Graphics g) {
      System.out.println("incrementalPainting="+incrementalPainting);
      // First paint background
      super.paintComponent(g);
      Dimension d = this.getSize();
      if (! incrementalPainting)
        backBuffer = (BufferedImage) this.createImage(d.width, d.height);
      Graphics2D g2 = backBuffer.createGraphics();
      if (! incrementalPainting){
        g2.setColor(Color.WHITE);
        g2.fillRect(0,0, d.width, d.height);
      }
      myPaint(g2);
      g.drawImage(backBuffer, 0, 0, this);

    }

  }

}

Here is the code for displaying circles with varying radius on a panel inside a frame with a given delay rate, but the code is showing the final output not the intermediate stages i.e., the circles are not appearing one by one but all the circles are coming at once as a final output. There may be some errors related to button action listeners and panel threads. The code is taking initial circle radius and the total number of iterations (the total number of circles to be displayed), radius of each next circle gets incremented by 10.

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

public class ControlCircle extends JFrame {
  private JButton jbtEnlarge = new JButton("Start");
  private JButton jbtShrink = new JButton("Stop");
  private CirclePanel canvas = new CirclePanel();

  private int radius = 0;
  private int iter;

  public ControlCircle() {
    JPanel panel = new JPanel();
    JPanel jp = new JPanel();
    jp.setPreferredSize(new Dimension(300, 0));
    panel.add(jbtEnlarge);
    panel.add(jbtShrink);

    this.add(jp, BorderLayout.WEST);
    this.add(canvas, BorderLayout.CENTER);
    this.add(panel, BorderLayout.SOUTH);

    final JTextField f1 = new JTextField(8),f2 = new JTextField(8);

    jp.setLayout(new FlowLayout(FlowLayout.RIGHT, 50, 30));
    jp.add(new JLabel("Radius"));
    jp.add(f1);
    jp.add(new JLabel("Iteration"));
    jp.add(f2);

    f1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        radius = Integer.parseInt(new String(f1.getText()));
      }
    });

    f2.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        iter = Integer.parseInt(new String(f2.getText()));
      }
    });

    jbtEnlarge.addActionListener(new EnlargeListener());
    jbtShrink.addActionListener(new ShrinkListener());
  }

  public static void main(String[] args) {
    JFrame frame = new ControlCircle();

    frame.setTitle("ControlCircle");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class EnlargeListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      canvas.enlarge();
    }
  }

  class ShrinkListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      //canvas.shrink();
    }
  }

  class CirclePanel extends JPanel {
    private int r = radius;

    public void enlarge() {
      //radius += 2;

      repaint();
    }

    public void shrink() {
      radius -= 2;

      repaint();
    }

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

      for (int i = 0; i < iter; i++) {
        g.drawOval(getWidth() / 2 - r, getHeight() / 2 - r, 2 * r, 2 * r);

        try {
          Thread.sleep(100);
        } catch (Exception exp) {
        }

        r = r + 10;
      }

      r = 0;
    }
  }
}

解决方案

The idea is to control the drawing animation on the panel used as a canvas with the buttons Start, Stop and I added Continue and Reset additional controls to better explain the idea. These buttons control the animation thread execution thus drawing circles on the drawing surface. the drawing surface I separated as inner class that has only function to draw whatever performed. Another idea that the approach is taken to draw the circles one by one incrementally until it finishes drawing thus used incremental painting.

I have used the code from the above and changed it a little to support my ideas. If you need more and usually better examples look at this article.

The code is below, I didn't polish it enough to have a production wise look and feel but for demonstration purpose only.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class ControlCircle extends JFrame implements Runnable {
  private JButton jbtStart = new JButton("Start");
  private JButton jbtStop = new JButton("Stop");
  private JButton jbtContinue = new JButton("Continue");
  private JButton jbtReset = new JButton("Reset");
  private CirclePanel canvas = new CirclePanel();

  private JTextField f1;
  private int radius = 0;

  private JTextField f2;
  private int iter;

  protected boolean  incrementalPainting;

  /**
   * Flag indicates that a thread is suspended
   */
  private boolean suspended = false;


  /**An instance of the class Thread.*/
  private Thread thread = null;

  public ControlCircle() {
    JPanel panel = new JPanel();
    JPanel jp = new JPanel();
    jp.setPreferredSize(new Dimension(300, 0));
    panel.add(jbtStart);
    panel.add(jbtStop);
    panel.add(jbtContinue);
    panel.add(jbtReset);

    this.add(jp, BorderLayout.WEST);
    this.add(canvas, BorderLayout.CENTER);
    this.add(panel, BorderLayout.SOUTH);

    f1 = new JTextField(8);
    f2 = new JTextField(8);

    jp.setLayout(new FlowLayout(FlowLayout.RIGHT, 50, 30));
    jp.add(new JLabel("Radius"));
    jp.add(f1);
    jp.add(new JLabel("Iteration"));
    jp.add(f2);


    jbtStart.addActionListener(new StartListener());
    jbtStop.addActionListener(new StopListener());
    jbtContinue.addActionListener(new ContinueListener());
    jbtReset.addActionListener(new ResetListener());
  }

  public static void main(String[] args) {
    JFrame frame = new ControlCircle();

    frame.setTitle("ControlCircle");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class StartListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread == null) {
        repaint();
        startThread();
      }
    }
  }

  class StopListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread != null){
        mySuspend();
      }
    }
  }

  class ContinueListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      myResume();
    }
  }

  class ResetListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (thread != null) {
        stopThread();
      }
      repaint();
    }

  }

  /**
   * my Suspend
   */
  private void mySuspend() {
    System.out.println("mySyspend()");
    suspended = true;
  }

  /**
   * my Resume
   */
  private synchronized void myResume(){
    System.out.println("myResume()");
    suspended = false;
    notifyAll();
  }

  public void run(){
    System.out.println("run() - started");

    Thread me = Thread.currentThread();
    while (thread == me) {
      radius = Integer.parseInt(f1.getText());
      iter = Integer.parseInt(f2.getText());
      for (int i = 0; i < iter; i++) {
        if (thread == null) return;
        incrementalPainting = true;
        myRepaint();
        try {
          Thread.sleep(1000);
        }
        catch(InterruptedException e){}
        radius += 10;
      }
      if(thread != null) thread = null; // exiting while
    }
    System.out.println("run() - exiting");
  }

  /**
   * start Thread
   */
  private void startThread(){
    System.out.println("startThread()");
    if(thread == null){
      thread = new Thread(this);
      thread.start();
    }
  }

  /**
   *  stop Thread
   */
  private synchronized void stopThread() {
    System.out.println("stopThread()");
    thread = null; // exiting from while
    if (suspended) {
      suspended = false;
      notify();
    }
  }

  /**
   * This is called from the run method to invoke painting.
   */
  private void myRepaint() {
    System.out.println("myRepaint()");
    incrementalPainting = true;
    repaint();
    synchronized (this) {
      while (incrementalPainting) {
        System.out.println("wait while incremental painting");
        try {
          wait();
        } catch (InterruptedException e) {
          System.out.println("interrupted");
        }
      }
    }

    suspend();
  }
  /**
   * This method should place somewhere when run() has started. Perfectly
   * when repaint() performed.
   */
  private void suspend(){
    System.out.println("suspend()");
    synchronized (this) {
      while (suspended) {
        System.out.println("wait while suspended");
        try {
          wait();
        } catch (InterruptedException e) {
          System.out.println("interrupted");
        }
      }
    }

  }

  public synchronized void myPaint(Graphics g) {
    if (g == null){
      if (incrementalPainting){
        incrementalPainting = false;
        notifyAll();
      }
      return;
    }
    if (incrementalPainting){
      myDraw(g);
      incrementalPainting = false;
      notifyAll();

    }
    else {
      myDraw(g);
    }
  }

  public void myDraw(Graphics g){
    g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, 2 * radius, 2 * radius);
  }

  protected final class CirclePanel extends JPanel {
    //Offscreen buffer of this canvas
    private BufferedImage backBuffer = null;

    public void paintComponent (Graphics g) {
      System.out.println("incrementalPainting="+incrementalPainting);
      // First paint background
      super.paintComponent(g);
      Dimension d = this.getSize();
      if (! incrementalPainting)
        backBuffer = (BufferedImage) this.createImage(d.width, d.height);
      Graphics2D g2 = backBuffer.createGraphics();
      if (! incrementalPainting){
        g2.setColor(Color.WHITE);
        g2.fillRect(0,0, d.width, d.height);
      }
      myPaint(g2);
      g.drawImage(backBuffer, 0, 0, this);

    }

  }

}

这篇关于JPanel侦听器和线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆