Java качели не определяют JProgressBar, начиная слева, когда достигают конца, вместо того, чтобы подпрыгивать - PullRequest
0 голосов
/ 28 декабря 2018

Я создал JProgressBar в GUI приложении и установил «неопределенный» , но мне не нравитсячто он подпрыгивает вместо , перезапускаясь каждый раз, когда достигает конца. Что я могу сделать, чтобы исправить эту графическую настройку?

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Как уже сказал 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);
    }
  }
}
0 голосов
/ 28 декабря 2018

Изменение пользовательского интерфейса JProgressBar.

Пользовательский интерфейс - это класс, который рисует индикатор выполнения.BasicProgressBarUI, заставляет коробку отскочить по умолчанию.Вам просто нужно написать свой собственный класс, расширяющий MetalProgressBarUI (если вы используете Metal) и переопределяющий getBox (Rectangle) , который является методом, который сохраняет положение поля в данном прямоугольнике.

Используйте JProgressBar.setUI , чтобы применить пользовательский интерфейс к индикатору выполнения.Вы также можете изменить значения по умолчанию с помощью UIManager.put ("ProgressBarUI", "полностьюQualifiedClassName"), чтобы изменить пользовательский интерфейс по умолчанию для индикатора выполнения.

...