简体   繁体   English

Java摇摆不定JProgressBar从结束时从左侧开始而不是弹跳

[英]Java swing indeterminate JProgressBar starting from the left when reaching end instead of bouncing

I created a JProgressBar in a GUI application, and setted it to "indeterminate" , but I don't like that it bounces instead of restarting every time it reaches the end. 我在GUI应用程序中创建了一个JProgressBar ,并将其设置为“ indeterminate” ,但是我不喜欢它反弹而不是每次到达终点重新启动 What can I do to fix this graphic setting? 我该怎么做才能解决此图形设置?

Change the UI of the JProgressBar. 更改JProgressBar的UI。

The UI is the class that paints the progress bar. UI是绘制进度条的类。 The BasicProgressBarUI, makes the box bounce by default. BasicProgressBarUI,默认情况下使框反弹。 You just have to write your own class extending MetalProgressBarUI (if you're using Metal) and overriding getBox(Rectangle) , which is the method that stores the position of the box in the given rectangle. 您只需要编写自己的类即可扩展MetalProgressBarUI(如果您使用的是Metal)并覆盖getBox(Rectangle) ,这是将框的位置存储在给定矩形中的方法。

Use JProgressBar.setUI to apply the UI to your progress bar. 使用JProgressBar.setUI将UI应用于进度栏。 You can also change the defaults with UIManager.put("ProgressBarUI", "fullyQualifiedClassName") to change the default UI for a progress bar. 您也可以使用UIManager.put(“ ProgressBarUI”,“ fullyQualifiedClassName”)更改默认值,以更改进度栏的默认UI。

As Snowy_1803 has already said, you would need to override the BasicProgressBarUI#getBox(...) : 正如Snowy_1803已经说过的那样,您将需要重写BasicProgressBarUI#getBox(...)

import java.awt.*;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.swing.*;
import javax.swing.plaf.basic.BasicProgressBarUI;

public final class MainPanel extends JPanel implements HierarchyListener {
  private transient SwingWorker<String, Void> worker;

  private MainPanel() {
    super(new BorderLayout());

    BoundedRangeModel model = new DefaultBoundedRangeModel();
    JProgressBar progressBar = new JProgressBar(model) {
      @Override public void updateUI() {
        super.updateUI();
        setUI(new OneDirectionProgressBarUI());
      }
    };

    List<JProgressBar> list = Arrays.asList(new JProgressBar(model), progressBar);

    JPanel p = new JPanel(new GridLayout(5, 1));
    list.forEach(bar -> p.add(makePanel(bar)));

    JButton button = new JButton("Test start");
    button.addActionListener(e -> {
      if (Objects.nonNull(worker) && !worker.isDone()) {
        worker.cancel(true);
      }
      worker = new BackgroundTask();
      list.forEach(bar -> {
        bar.setIndeterminate(true);
        worker.addPropertyChangeListener(new ProgressListener(bar));
      });
      worker.execute();
    });

    Box box = Box.createHorizontalBox();
    box.add(Box.createHorizontalGlue());
    box.add(button);
    box.add(Box.createHorizontalStrut(5));

    addHierarchyListener(this);
    add(p);
    add(box, BorderLayout.SOUTH);
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  }

  @Override public void hierarchyChanged(HierarchyEvent e) {
    boolean isDisplayableChanged = (e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0;
    if (isDisplayableChanged && !e.getComponent().isDisplayable() && Objects.nonNull(worker)) {
      worker.cancel(true);
      worker = null;
    }
  }

  private static Component makePanel(Component cmp) {
    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.insets = new Insets(5, 5, 5, 5);
    c.weightx = 1d;

    JPanel p = new JPanel(new GridBagLayout());
    p.add(cmp, c);
    return p;
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new MainPanel());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class OneDirectionProgressBarUI extends BasicProgressBarUI {
  @Override
  protected Rectangle getBox(Rectangle r) {
    Rectangle rect = super.getBox(r);

    boolean vertical = progressBar.getOrientation() == JProgressBar.VERTICAL;
    Insets ins = new Insets(0, 0, 0, 0); // progressBar.getInsets();

    int currentFrame = getAnimationIndex();
    int framecount = getFrameCount() / 2;
    currentFrame = currentFrame % framecount;

    // @see com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java
    // this code adjusts the chunk size to properly account for the
    // size and gap specified in the XP style. It also does it's own
    // box placement for the chunk animation. This is required because
    // the inherited algorithm from BasicProgressBarUI goes back and
    // forth whereas XP only goes in one direction. XP also has ghosted
    // trailing chunks to create the illusion of speed. This code
    // adjusts the pixel length of the animation to account for the
    // trails.
    if (!vertical) {
      rect.y = rect.y + ins.top;
      rect.height = progressBar.getHeight() - ins.top - ins.bottom;
      int len = progressBar.getWidth() - ins.left - ins.right;
      len += rect.width * 2; // add 2x for the trails
      double delta = (double) (len) / (double) framecount;
      rect.x = (int) (delta * currentFrame) + ins.left;
    } else {
      rect.x = rect.x + ins.left;
      rect.width = progressBar.getWidth() - ins.left - ins.right;
      int len = progressBar.getHeight() - ins.top - ins.bottom;
      len += rect.height * 2; // add 2x for the trails
      double delta = (double) (len) / (double) framecount;
      rect.y = (int) (delta * currentFrame) + ins.top;
    }
    return rect;
  }
}

class BackgroundTask extends SwingWorker<String, Void> {
  @Override public String doInBackground() {
    try { // dummy task
      Thread.sleep(5000);
    } catch (InterruptedException ex) {
      return "Interrupted";
    }
    int current = 0;
    int lengthOfTask = 100;
    while (current <= lengthOfTask && !isCancelled()) {
      try { // dummy task
        Thread.sleep(50);
      } catch (InterruptedException ex) {
        return "Interrupted";
      }
      setProgress(100 * current / lengthOfTask);
      current++;
    }
    return "Done";
  }
}

class ProgressListener implements PropertyChangeListener {
  private final JProgressBar progressBar;

  protected ProgressListener(JProgressBar progressBar) {
    this.progressBar = progressBar;
    this.progressBar.setValue(0);
  }

  @Override public void propertyChange(PropertyChangeEvent e) {
    String strPropertyName = e.getPropertyName();
    if ("progress".equals(strPropertyName)) {
      progressBar.setIndeterminate(false);
      int progress = (Integer) e.getNewValue();
      progressBar.setValue(progress);
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM