JComponent () { String[] columns = { "First column", "Second column" }; String[][] data = {{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}, {"seven", "7"}, {"eight", "8"}, {"nine", "9"}, {"ten", "10"}, {"eleven", "11"}, {"twelve", "12"}, {"thirteen", "13"}, {"fourteen", "14"}, {"fifteen", "15"}, {"sixteen", "16"}}; JBTable table = new JBTable(new DefaultTableModel() { @Override public String getColumnName(int column) { return columns[column]; } @Override public int getRowCount() { return data.length; } @Override public int getColumnCount() { return columns.length; } @Override public Object getValueAt(int row, int col) { return col == 0 ? data[row][col] : Integer.valueOf(data[row][col]); } @Override public boolean isCellEditable(int row, int column) { return true; } @Override public void setValueAt(Object value, int row, int col) { if (col == 0 || col == 1) { data[row][col] = value.toString(); fireTableCellUpdated(row, col); } } }); HyperlinkListener hyperlinkListener = e -> { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { System.out.println("Table cell tooltip link clicked. Desc = " + e.getDescription()); } }; BiFunction<String, JComponent, ValidationInfo> validationInfoGenerator = (text, component) -> new ValidationInfo("Illegal value: " + text + " <a href=\"#check.cell.rules\">check rules.</a>", component); // Install custom tooltip manager for displaying error/warning tooltips new CellTooltipManager(getDisposable()). withCellComponentProvider(CellComponentProvider.forTable(table)). withHyperlinkListener(hyperlinkListener).installOn(table); // Configure left column ExtendableTextField cellEditor = new ExtendableTextField(); ExtendableTextComponent.Extension browseExtension = ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, "Open file", () -> System.out.println("Table browse clicked")); cellEditor.addExtension(browseExtension); cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); new ComponentValidator(getDisposable()).withValidator(() -> { boolean isAllowed = ALLOWED_VALUES.contains(cellEditor.getText()); ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, !isAllowed); return isAllowed ? null : validationInfoGenerator.apply(cellEditor.getText(), cellEditor); }).withHyperlinkListener(hyperlinkListener). andRegisterOnDocumentListener(cellEditor). installOn(cellEditor); TableColumn col = table.getColumnModel().getColumn(0); col.setCellEditor(new DefaultCellEditor(cellEditor)); col.setCellRenderer(new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). bindToEditorSize(cellEditor::getPreferredSize). withCellValidator((value, row, column) -> value == null ? new ValidationInfo("Null value") : ALLOWED_VALUES.contains(value.toString()) ? null : validationInfoGenerator.apply(value.toString(), null))); // Configure right column JComboBox<Integer> rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); col = table.getColumnModel().getColumn(1); col.setCellEditor(new StatefulValidatingCellEditor(rightEditor, getDisposable())); col.setCellRenderer(new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { { setIpad(JBInsets.emptyInsets()); } // Reset standard pads @Override protected void customizeCellRenderer(@NotNull JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { if (value == null) { append("No data", SimpleTextAttributes.ERROR_ATTRIBUTES); } else { try { int iv = Integer.parseInt(value.toString()); append("value ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); append(value.toString(), iv <= 8 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : WARNING_CELL_ATTRIBUTES); } catch (NumberFormatException nfe) { append(value.toString(), SimpleTextAttributes.ERROR_ATTRIBUTES); } } } }).bindToEditorSize(rightEditor::getPreferredSize). withCellValidator((value, row, column) -> { if (value == null) return NULL_VALUE_ERROR; else { try { int iv = Integer.parseInt(value.toString()); return iv <= 8 ? null : new ValidationInfo("Value " + value + " is not preferred").asWarning(); } catch (NumberFormatException nfe) { return NAN_VALUE_ERROR; } } })); return table; }