Google Tag Manager

Showing posts with label SwingWorker. Show all posts
Showing posts with label SwingWorker. Show all posts

2024/01/31

Paint a JProgressBar with indeterminate progress status in a cell of a JTable

Code

private final JTable table = new JTable(model) {
  @Override public void updateUI() {
    super.updateUI();
    removeColumn(getColumnModel().getColumn(3));
    JProgressBar progress = new JProgressBar();
    TableCellRenderer renderer = new DefaultTableCellRenderer();
    TableColumn tc = getColumnModel().getColumn(2);
    tc.setCellRenderer((tbl, value, isSelected, hasFocus, row, column) -> {
      Component c;
      if (value instanceof JProgressBar) {
        c = (JProgressBar) value;
      } else if (value instanceof Integer) {
        progress.setValue((int) value);
        c = progress;
      } else {
        c = renderer.getTableCellRendererComponent(
            tbl, Objects.toString(value), isSelected, hasFocus, row, column);
      }
      return c;
    });
  }
};

class IndeterminateProgressBarUI extends BasicProgressBarUI {
  @Override public void incrementAnimationIndex() {
    super.incrementAnimationIndex();
  }
}

class BackgroundTask extends SwingWorker<Integer, Object> {
  private final Random rnd = new Random();

  @Override protected Integer doInBackground() throws InterruptedException {
    int lengthOfTask = calculateTaskSize();
    int current = 0;
    int total = 0;
    while (current <= lengthOfTask && !isCancelled()) {
      publish(100 * current / lengthOfTask);
      total += doSomething();
      current++;
    }
    return total;
  }

  private int calculateTaskSize() throws InterruptedException {
    int total = 0;
    JProgressBar indeterminate = new JProgressBar() {
      @Override public void updateUI() {
        super.updateUI();
        setUI(new IndeterminateProgressBarUI());
      }
    };
    indeterminate.setIndeterminate(true);
    // Indeterminate loop:
    for (int i = 0; i < 200; i++) {
      int iv = rnd.nextInt(50) + 1;
      Thread.sleep(iv);
      ProgressBarUI ui = indeterminate.getUI()
      ((IndeterminateProgressBarUI) ui).incrementAnimationIndex();
      publish(indeterminate);
      total += iv;
    }
    return 1 + total / 100;
  }

  private int doSomething() throws InterruptedException {
    int iv = rnd.nextInt(50) + 1;
    Thread.sleep(iv);
    return iv;
  }
}

References

2019/12/30

Create a speedometer by changing the shape of JProgressBar to a donut-shaped semicircle

Code

class SolidGaugeUI extends BasicProgressBarUI {
  private final int[] pallet;
  private final double extent;

  protected SolidGaugeUI(int range, double extent) {
    super();
    this.pallet = makeGradientPallet(range);
    this.extent = extent;
  }

  @Override public void paint(Graphics g, JComponent c) {
    Rectangle rect = SwingUtilities.calculateInnerArea(progressBar, null);
    if (rect.isEmpty()) {
      return;
    }
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);

    // double extent = -150d;
    double start = 90d + extent * .5;
    double degree = extent * progressBar.getPercentComplete();
    double or = Math.min(rect.width, rect.height);
    double cx = rect.getCenterX();
    double cy = rect.getMaxY();
    double sz = or * 2d;
    double ir = or * .6;
    Shape inner = new Arc2D.Double(
        cx - ir, cy - ir, ir * 2d, ir * 2d, start, -extent, Arc2D.PIE);
    Shape outer = new Arc2D.Double(
        cx - or, cy - or, sz, sz, start, -extent, Arc2D.PIE);
    Shape sector = new Arc2D.Double(
        cx - or, cy - or, sz, sz, start, -degree, Arc2D.PIE);

    Area foreground = new Area(sector);
    Area background = new Area(outer);
    Area hole = new Area(inner);

    foreground.subtract(hole);
    background.subtract(hole);

    // Draw the track
    g2.setPaint(new Color(0xDD_DD_DD));
    g2.fill(background);

    // Draw the circular sector
    g2.setPaint(getColorFromPallet(
        pallet, progressBar.getPercentComplete()));
    g2.fill(foreground);

    // Draw ...
    Font font = progressBar.getFont();
    float fsz = font.getSize2D();
    float min = (float) (cx - or - fsz);
    float max = (float) (cx + or + 4d);
    g2.setPaint(progressBar.getForeground());
    g2.drawString(
        Objects.toString(progressBar.getMinimum()), min, (float) cy);
    g2.drawString(Objects.toString(
        progressBar.getMaximum()), max, (float) cy);

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      float h = (float) cy - fsz;
      String str = String.format("%d", progressBar.getValue());
      float vx = (float) cx - g2.getFontMetrics().stringWidth(str) * .5f;
      g2.drawString(str, vx, h);
      float ksz = fsz * .66f;
      g2.setFont(font.deriveFont(ksz));
      String kmh = "㎞/h";
      float tx = (float) cx - g2.getFontMetrics().stringWidth(kmh) * .5f;
      g2.drawString(kmh, tx, h + ksz);
    }
    g2.dispose();
  }

  private static int[] makeGradientPallet(int range) {
    BufferedImage image = new BufferedImage(
        range, 1, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = image.createGraphics();
    Point2D start = new Point2D.Float();
    Point2D end = new Point2D.Float(range - 1f, 0f);
    float[] dist = {0f, .8f, .9f, 1f};
    Color[] colors = {Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED};
    g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
    g2.fillRect(0, 0, range, 1);
    g2.dispose();

    int width = image.getWidth(null);
    int[] pallet = new int[width];
    PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
    try {
      pg.grabPixels();
    } catch (InterruptedException ex) {
      ex.printStackTrace();
      Toolkit.getDefaultToolkit().beep();
      Thread.currentThread().interrupt();
    }
    return pallet;
  }

  private static Color getColorFromPallet(int[] pallet, double pos) {
    if (pos < 0d || pos > 1d) {
      throw new IllegalArgumentException("Parameter outside of expected range");
    }
    int i = (int) (pallet.length * pos);
    int max = pallet.length - 1;
    int index = Math.min(Math.max(i, 0), max);
    return new Color(pallet[index] & 0x00_FF_FF_FF);
  }
}

References

2014/06/02

How to create a circular progress component

Code

class ProgressCircleUI extends BasicProgressBarUI {
  @Override public Dimension getPreferredSize(JComponent c) {
    Dimension d = super.getPreferredSize(c);
    int v = Math.max(d.width, d.height);
    d.setSize(v, v);
    return d;
  }

  @Override public void paint(Graphics g, JComponent c) {
    Insets b = progressBar.getInsets(); // area for border
    int barRectWidth  = progressBar.getWidth()  - b.right - b.left;
    int barRectHeight = progressBar.getHeight() - b.top - b.bottom;
    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }

    // draw the cells
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    double degree = 360 * progressBar.getPercentComplete();
    double sz = Math.min(barRectWidth, barRectHeight);
    double cx = b.left + barRectWidth  * .5;
    double cy = b.top  + barRectHeight * .5;
    double or = sz * .5;
    double ir = or * .5; //or - 20;
    Shape inner  = new Ellipse2D.Double(cx - ir, cy - ir, ir * 2, ir * 2);
    Shape outer  = new Ellipse2D.Double(cx - or, cy - or, sz, sz);
    Shape sector = new Arc2D.Double(
        cx - or, cy - or, sz, sz, 90 - degree, degree, Arc2D.PIE);

    Area foreground = new Area(sector);
    Area background = new Area(outer);
    Area hole = new Area(inner);

    foreground.subtract(hole);
    background.subtract(hole);

    g2.setPaint(new Color(0xDDDDDD));
    g2.fill(background);

    g2.setPaint(progressBar.getForeground());
    g2.fill(foreground);
    g2.dispose();

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      paintString(g, b.left, b.top, barRectWidth, barRectHeight, 0, b);
    }
  }
}

// ...
JProgressBar progress = new JProgressBar();
progress.setUI(new ProgressCircleUI());
progress.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
progress.setStringPainted(true);
progress.setFont(progress.getFont().deriveFont(24f));
progress.setForeground(Color.ORANGE);

(new Timer(50, e -> {
  int iv = Math.min(100, progress.getValue() + 1);
  progress.setValue(iv);
})).start();

References

2014/05/01

JProgressBar in JTable cell render a progress string

Code

class Task extends SwingWorker<Integer, ProgressValue> {
  private final int lengthOfTask;
  private final int randomSleep = new Random().nextInt(100) + 1;
  public Task(int lengthOfTask) {
    super();
    this.lengthOfTask = lengthOfTask;
  }

  @Override protected Integer doInBackground() {
    int current = 0;
    while (current < lengthOfTask && !isCancelled()) {
      current++;
      try {
        Thread.sleep(randomSleep);
      } catch (InterruptedException ie) {
        break;
      }
      publish(new ProgressValue(lengthOfTask, current));
    }
    return randomSleep * lengthOfTask;
  }
}

class ProgressValue {
  private final Integer progress;
  private final Integer lengthOfTask;
  public ProgressValue(Integer lengthOfTask, Integer progress) {
    this.progress = progress;
    this.lengthOfTask = lengthOfTask;
  }

  public Integer getProgress() {
    return progress;
  }

  public Integer getLengthOfTask() {
    return lengthOfTask;
  }
}

class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar progress = new JProgressBar();
  private final JPanel renderer = new JPanel(new BorderLayout());
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    Component c;
    renderer.removeAll();
    progress.setValue(0);
    if (value instanceof ProgressValue) {
      ProgressValue pv = (ProgressValue) value;
      Integer current = pv.getProgress();
      Integer lengthOfTask = pv.getLengthOfTask();
      if (current < 0) {
        c = super.getTableCellRendererComponent(
            table, "Canceled", isSelected, hasFocus, row, column);
      } else if (current < lengthOfTask) {
        progress.setValue(current * 100 / lengthOfTask);
        progress.setStringPainted(true);
        progress.setString(String.format("%d/%d", current, lengthOfTask));
        renderer.add(progress);
        c = renderer;
      } else {
        c = super.getTableCellRendererComponent(
                table, "Done", isSelected, hasFocus, row, column);
      }
    } else {
      c = super.getTableCellRendererComponent(
              table, "Waiting...", isSelected, hasFocus, row, column);
    }
    return c;
  }

  @Override public void updateUI() {
    super.updateUI();
    setOpaque(true);
    if (Objects.nonNull(renderer)) {
      SwingUtilities.updateComponentTreeUI(renderer);
    }
  }
}

References

2013/06/28

Turn the JProgressBar red with JLayer and RGBImageFilter

Code

class BlockedColorLayerUI extends LayerUI<JProgressBar> {
  public boolean isPreventing;
  private transient BufferedImage bi;
  private int prevw = -1;
  private int prevh = -1;

  @Override public void paint(Graphics g, JComponent c) {
    if (isPreventing && c instanceof JLayer) {
      JLayer jlayer = (JLayer) c;
      JProgressBar progress = (JProgressBar) jlayer.getView();
      int w = progress.getSize().width;
      int h = progress.getSize().height;

      if (bi == null || w != prevw || h != prevh) {
        bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
      }
      prevw = w;
      prevh = h;

      Graphics2D g2 = bi.createGraphics();
      super.paint(g2, c);
      g2.dispose();

      Image image = c.createImage(new FilteredImageSource(
          bi.getSource(), new RedGreenChannelSwapFilter()));
      g.drawImage(image, 0, 0, null);
    } else {
      super.paint(g, c);
    }
  }
}

class RedGreenChannelSwapFilter extends RGBImageFilter {
  @Override public int filterRGB(int x, int y, int argb) {
    int r = (int) ((argb >> 16) & 0xFF);
    int g = (int) ((argb >> 8) & 0xFF);
    int b = (int) (argb & 0xFF);
    return (argb & 0xFF_00_00_00) | (g << 16) | (r << 8) | (b);
  }
}

References

2011/09/29

JProgressBar in JComboBox

Code

class ProgressCellRenderer extends DefaultListCellRenderer {
  private final JProgressBar bar = new JProgressBar() {
    @Override public Dimension getPreferredSize() {
      return ProgressCellRenderer.this.getPreferredSize();
    }
  };

  @Override public Component getListCellRendererComponent(
      JList list, Object value, int index,
      boolean isSelected, boolean cellHasFocus) {
    if (index < 0 && worker != null && !worker.isDone()) {
      bar.setFont(list.getFont());
      bar.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
      bar.setValue(count);
      return bar;
    } else {
      return super.getListCellRendererComponent(
        list, value, index, isSelected, cellHasFocus);
    }
  }

  @Override public void updateUI() {
    super.updateUI();
    if (bar != null) {
      SwingUtilities.updateComponentTreeUI(bar);
    }
  }
}

// ...
button = new JButton(new AbstractAction("load") {
  @Override public void actionPerformed(ActionEvent e) {
    button.setEnabled(false);
    combo.setEnabled(false);
    combo.removeAllItems();
    worker = new SwingWorker<String, String>() {
      private int max = 30;
      @Override public String doInBackground() throws InterruptedException {
        int current = 0;
        while (current <= max && !isCancelled()) {
          Thread.sleep(50);
          // setProgress(100 * current / max);
          count = 100 * current / max;
          publish("test: "+current);
          current++;
        }
        return "Done";
      }

      @Override protected void process(List<String> chunks) {
        DefaultComboBoxModel m = (DefaultComboBoxModel) combo.getModel();
        for (String s: chunks) {
          m.addElement(s);
        }
        combo.setSelectedIndex(-1);
        combo.repaint();
      }

      @Override public void done() {
        String text = null;
        if (!isCancelled()) {
          combo.setSelectedIndex(0);
        }
        combo.setEnabled(true);
        button.setEnabled(true);
        count = 0;
      }
    };
    worker.execute();
  }
});

References

2011/07/29

Pause and Resume SwingWorker

Code

class RunAction extends AbstractAction {
  public RunAction() {
    super("run");
  }

  @Override public void actionPerformed(ActionEvent evt) {
    JProgressBar bar1 = new JProgressBar(0, 100);
    JProgressBar bar2 = new JProgressBar(0, 100);
    runButton.setEnabled(false);
    canButton.setEnabled(true);
    pauseButton.setEnabled(true);
    statusPanel.removeAll();
    statusPanel.add(bar1, BorderLayout.NORTH);
    statusPanel.add(bar2, BorderLayout.SOUTH);
    statusPanel.revalidate();
    worker = new SwingWorker<String, Progress>() {
      private final Random r = new Random();
      @Override public String doInBackground() {
        int current = 0;
        int lengthOfTask = 12; //filelist.size();
        publish(new Progress(Component.LOG, "Length Of Task: " + lengthOfTask));
        publish(new Progress(Component.LOG, "\n---------------------------\n"));
        while (current < lengthOfTask && !isCancelled()) {
          publish(new Progress(Component.LOG, "*"));
          if (!bar1.isDisplayable()) {
            return "Disposed";
          }
          try {
            convertFileToSomething();
          } catch (InterruptedException ie) {
            return "Interrupted";
          }
          publish(new Progress(Component.TOTAL, 100 * current / lengthOfTask));
          current++;
        }
        publish(new Progress(Component.LOG, "\n"));
        return "Done";
      }

      private void convertFileToSomething() throws InterruptedException {
        boolean flag = false;
        int current = 0;
        int lengthOfTask = 10 + r.nextInt(50);
        while (current <= lengthOfTask && !isCancelled()) {
          if (isPaused) {
            try {
              Thread.sleep(500);
            } catch (InterruptedException ie) {
              return;
            }
            publish(new Progress(Component.PAUSE, flag));
            flag ^= true;
            continue;
          }
          int iv = 100 * current / lengthOfTask;
          Thread.sleep(20);
          publish(new Progress(Component.FILE, iv + 1));
          current++;
        }
      }

      @Override protected void process(java.util.List<Progress> chunks) {
        for (Progress s: chunks) {
          switch (s.component) {
            case TOTAL: bar1.setValue((Integer) s.value); break;
            case FILE:  bar2.setValue((Integer) s.value); break;
            case LOG:   area.append((String) s.value); break;
            case PAUSE: {
              if ((Boolean) s.value) {
                area.append("*");
              } else {
                try {
                  Document doc = area.getDocument();
                  doc.remove(doc.getLength() - 1, 1);
                } catch (Exception ex) {
                  ex.printStackTrace();
                }
              }
              break;
            }
          }
        }
      }

      @Override public void done() {
        // ...
      }
    };
    worker.execute();
  }
}

// ...
private boolean isPaused = false;
class PauseAction extends AbstractAction {
  public PauseAction() {
    super("pause");
  }

  @Override public void actionPerformed(ActionEvent evt) {
    isPaused = (worker != null && !worker.isCancelled() && !isPaused);
    JButton b = (JButton) evt.getSource();
    b.setText(isPaused ? "resume" : "pause");
  }
}

References

2008/03/18

JProgressBar in JTable Cell

Code

class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar b = new JProgressBar(0, 100);
  public ProgressRenderer() {
    super();
    setOpaque(true);
    b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    Integer i = (Integer) value;
    String text = "Done";
    if (i < 0) {
      text = "Canceled";
    } else if (i < 100) {
      b.setValue(i);
      return b;
    }
    super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
    return this;
  }
}
final Executor executor = Executors.newCachedThreadPool();
final int rowNumber = model.getRowCount();
SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() {
  private int sleepDummy = new Random().nextInt(100) + 1;
  private int lengthOfTask = 120;
  @Override
  protected Integer doInBackground() {
    int current = 0;
    while (current < lengthOfTask && !isCancelled()) {
      if (!table.isDisplayable()) {
        return -1;
      }
      current++;
      try {
        Thread.sleep(sleepDummy);
      } catch (InterruptedException ie) {
        publish(-1);
        break;
      }
      publish(100 * current / lengthOfTask);
    }
    return sleepDummy * lengthOfTask;
  }
  @Override
  protected void process(List<Integer> chunks) {
    for (Integer value : chunks) {
      model.setValueAt(value, rowNumber, 2);
    }
    // model.fireTableCellUpdated(rowNumber, 2);
  }
  @Override
  protected void done() {
    String text;
    int i = -1;
    if (isCancelled()) {
      text = "Canceled";
    } else {
      try {
        i = get();
        text = (i>=0)?"Done":"Disposed";
      } catch (Exception ignore) {
        ignore.printStackTrace();
        text = ignore.getMessage();
      }
    }
    System.out.println(rowNumber +":"+text+"("+i+"ms)");
  }
};
model.addTest(new Test("example", 0), worker);
executor.execute(worker); // JDK 1.6.0_18
// worker.execute();

References