Google Tag Manager

2017/10/27

Set Sudoku style border lines created by MatteBorder as cell ruled lines of JTable

Code

static class SudokuCellRenderer extends DefaultTableCellRenderer {
  private final Font font;
  private final Font bold;
  private final Border b0 = BorderFactory.createMatteBorder(
      0, 0, BORDERWIDTH1, BORDERWIDTH1, Color.GRAY);
  private final Border b1 = BorderFactory.createMatteBorder(
      0, 0, BORDERWIDTH2, BORDERWIDTH2, Color.BLACK);
  private final Border b2 = BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 0, BORDERWIDTH2, 0, Color.BLACK),
      BorderFactory.createMatteBorder(0, 0, 0, BORDERWIDTH1, Color.GRAY));
  private final Border b3 = BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 0, 0, BORDERWIDTH2, Color.BLACK),
      BorderFactory.createMatteBorder(0, 0, BORDERWIDTH1, 0, Color.GRAY));
  private final Integer[][] data;
  protected SudokuCellRenderer(Integer[][] src, Font font) {
    super();
    this.font = font;
    this.bold = font.deriveFont(Font.BOLD);
    Integer[][] dest = new Integer[src.length][src[0].length];
    for (int i = 0; i < src.length; i++) {
      System.arraycopy(src[i], 0, dest[i], 0, src[0].length);
    }
    this.data = dest;
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    boolean isEditable = data[row][column] == 0;
    super.getTableCellRendererComponent(
        table, value, isEditable && isSelected, hasFocus, row, column);
    if (isEditable && Objects.equals(value, 0)) {
      this.setText(" ");
    }
    setFont(isEditable ? font : bold);
    setHorizontalAlignment(CENTER);
    boolean rf = (row + 1) % 3 == 0;
    boolean cf = (column + 1) % 3 == 0;
    if (rf && cf) {
      setBorder(b1);
    } else if (rf) {
      setBorder(b2);
    } else if (cf) {
      setBorder(b3);
    } else {
      setBorder(b0);
    }
    return this;
  }
}

References

2017/09/28

Add a JComboBox that selects the encoding at the bottom of JFileChooser

Code

class EncodingFileChooserUI extends MetalFileChooserUI {
  public final JComboBox< String> combo = new JComboBox<>(
      new String[] {"UTF-8", "UTF-16", "Shift_JIS", "EUC-JP"});
  protected EncodingFileChooserUI(JFileChooser filechooser) {
    super(filechooser);
  }
  @Override public void installComponents(JFileChooser fc) {
    super.installComponents(fc);
    JPanel bottomPanel = getBottomPanel();

    JLabel label = new JLabel("Encoding:") {
      @Override public Dimension getPreferredSize() {
        return SwingUtils.stream(bottomPanel)
          .filter(JLabel.class::isInstance).map(JLabel.class::cast)
          .findFirst()
          .map(JLabel::getPreferredSize)
          .orElse(super.getPreferredSize());
      }
    };
    label.setDisplayedMnemonic('E');
    label.setLabelFor(combo);

    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
    panel.add(label);
    panel.add(combo);

    // 0: fileNamePanel
    // 1: RigidArea
    // 2: filesOfTypePanel
    bottomPanel.add(Box.createRigidArea(new Dimension(1, 5)), 3);
    bottomPanel.add(panel, 4);

    SwingUtils.stream(bottomPanel)
      .filter(JLabel.class::isInstance).map(JLabel.class::cast)
      .forEach(l -> {
        l.setHorizontalAlignment(SwingConstants.RIGHT);
        l.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
      });
  }
}

References

2017/08/22

Apply sort order cycle with ascending, descending, and unsorted in TableRowSorter with multi-key sorting

Summary

A three-state sorter(ascending, descending, none) example. Primary sort column is highlighted and the next ones have their sort-order number in brackets as shown on the screenshot below.
  • Left click: Change sort order in ascending, descending, unsorted
  • Right click: Unsorted

Code

/**
 * @author ssr
 */
jTable1.getTableHeader().setDefaultRenderer(new TestTableCellRenderer(jTable1));
TableRowSorter sorter = new TableRowSorter(jTable1.getModel()) {
  @Override
  public void toggleSortOrder(int column) {
    int keyIndex;
    if (column >= 0 && column < getModelWrapper().getColumnCount() && isSortable(column)) {
      List keys = new ArrayList<>(getSortKeys());
      boolean found = false;
      for (keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
        RowSorter.SortKey sortKey = keys.get(keyIndex);
        if (sortKey.getColumn() == column) {
          found = true;
          break;
        }
      }
      if (isSortable(column)) {
        if (!found) {
          // Key doesn't exist
          RowSorter.SortKey sortKey = new RowSorter.SortKey(column, SortOrder.ASCENDING);
          keys.add(sortKey);
          System.out.println("ADDED: ");
          keys.stream().forEach(k -> System.out.println(k.getColumn() + ":" + k.getSortOrder()));
        } else {
          RowSorter.SortKey sortKey = keys.get(keyIndex);
          if (sortKey.getSortOrder() == SortOrder.DESCENDING) {
            keys.remove(keyIndex);
            System.out.println("REMOVED: ");
            keys.stream().forEach(k -> System.out.println(k.getColumn() + ":" + k.getSortOrder()));
          } else {
            keys.set(keyIndex, new RowSorter.SortKey(
                column, sortKey.getSortOrder() == SortOrder.ASCENDING
                  ? SortOrder.DESCENDING
                  : SortOrder.ASCENDING));
            System.out.println("MODIFIED: ");
            keys.stream().forEach(k -> System.out.println(k.getColumn() + ":" + k.getSortOrder()));
          }
        }
        if (keys.size() > getMaxSortKeys()) {
          keys = keys.subList(0, getMaxSortKeys());
        }
        setSortKeys(keys);
      }
    }
  }
};
sorter.setMaxSortKeys(4);
jTable1.setRowSorter(sorter);

References

2017/07/31

Detects that it has reached the bottom of JScrollPane

Code

JScrollPane scroll = new JScrollPane(c);
scroll.getVerticalScrollBar().getModel().addChangeListener(e -> {
  BoundedRangeModel m = (BoundedRangeModel) e.getSource();
  int extent  = m.getExtent();
  int maximum = m.getMaximum();
  int value   = m.getValue();
  if (value + extent >= maximum) {
    check.setEnabled(true);
  }
});

References

2017/06/29

Automatically adjust the height of JTable's row

Code

class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
  private final List< List< Integer > > rowAndCellHeightList = new ArrayList<>();

  @Override public void updateUI() {
    super.updateUI();
    setLineWrap(true);
    setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    setName("Table.cellRenderer");
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    setFont(table.getFont());
    setText(Objects.toString(value, ""));
    adjustRowHeight(table, row, column);
    return this;
  }

  /**
   * Calculate the new preferred height for a given row, and sets the height on the table.
   * http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx
   */
  private void adjustRowHeight(JTable table, int row, int column) {
    // The trick to get this to work properly is to set the width of the column to the
    // textarea. The reason for this is that getPreferredSize(), without a width tries
    // to place all the text in one line. By setting the size with the with of the column,
    // getPreferredSize() returnes the proper height which the row should have in
    // order to make room for the text.
    // int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
    // int cWidth = table.getCellRect(row, column, false).width; //Ignore IntercellSpacing
    // setSize(new Dimension(cWidth, 1000));

    setBounds(table.getCellRect(row, column, false));
    // doLayout();

    int preferredHeight = getPreferredSize().height;
    while (rowAndCellHeightList.size() <= row) {
      rowAndCellHeightList.add(new ArrayList<>(column));
    }
    List cellHeightList = rowAndCellHeightList.get(row);
    while (cellHeightList.size() <= column) {
      cellHeightList.add(0);
    }
    cellHeightList.set(column, preferredHeight);
    int max = cellHeightList.stream().max(Integer::compare).get();
    if (table.getRowHeight(row) != max) {
      table.setRowHeight(row, max);
    }
  }
  // ...

References