Custom text cell color in tableview - javafx-8

I have this tableview data:
I want change the text color of last column cells following this rules:
if row is selected -> default selection color
if text is PENDING or WORKING and row not selected -> default text color
if text is CANCELLED and row not selected -> red color
if text is DONE and not row not selected -> green color
How can I get that? For selection I use:
tableview.getSelectionModel().setCellSelectionEnabled(false);
tableview.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
I have tried:
lastCol.setCellFactory(col -> new TableCell<Work, StateEnum> () {
#Override
protected void updateItem (StateEnum item, boolean empty) {
super.updateItem(item, empty);
Paint textColor = null;
if (this.isSelected()) // doesn't work, always is false
textColor = getDefaultSelectionTextColor(); // how can I get this?
else {
if ((item.equals(StateEnum.PENDING) ||
(item.equals(StateEnum.WORKING))
textColor = getDefaultTextColor(); // how can I get this?
else if (item.equals(StateEnum.CANCELLED))
textColor = Color.RED;
else
textColor = Color.GREEN;
}
setTextFill(textColor);
}
}
but, I don't know how get the default text colors and how know if cell row is selected. Maybe updateItem is not the most suitable method for do this? Can I do this with styles in css? I have read about pseudoclasses but I have no idea how can I use it for this problem.

You could and should use CSS to style the text. PseudoClass would be the simplest way of changing, if certain selectors match the cell:
*final PseudoClass cancelled = PseudoClass.getPseudoClass("cancelled");
final PseudoClass done = PseudoClass.getPseudoClass("done");
lastCol.setCellFactory(col -> new TableCell<Work, StateEnum> () {
#Override
protected void updateItem (StateEnum item, boolean empty) {
super.updateItem(item, empty);
pseudoClassStateChanged(done, false);
pseudoClassStateChanged(cancelled, false);
if (empty || item == null) {
setText("");
} else {
setText(item.toString());
switch (item) {
case CANCELLED:
pseudoClassStateChanged(cancelled, true);
break;
case DONE:
pseudoClassStateChanged(done, true);
break;
}
}
}
}
CSS stylesheet
/* keep old style when selected */
.table-row-cell:selected .table-cell:cancelled,
.table-cell:selected:cancelled,
.table-row-cell:selected .table-cell:done,
.table-cell:selected:done {
-fx-text-fill: -fx-text-background-color;
}
/* adjustment of color for unselected cases */
.table-cell:cancelled {
-fx-text-fill: red;
}
.table-cell:done {
-fx-text-fill: green;
}

Related

How to change SWT Table Item selection background color

I have a similar use case as mentioned here. I want to change the SWT Table Item selection background color from default grey or blue to some other color. I tried using the StyledCellLabelProvider#update method but it was of no use. It simply updates the background color for all table items to the given color. But I need it to be only for the selected item. Below is the code Snippet of my label provider update method
#Override
public void update(ViewerCell cell) {
cell.setText(provider.getDisplay((T) cell.getElement(), cell.getColumnIndex()));
TableItem currentTableItem = ((TableItem) cell.getViewerRow().getItem());
if (currentTableItem.getParent().getSelectionCount() > 0) {
TableItem selectedTableItem = currentTableItem.getParent().getSelection()[0];
if(currentTableItem == selectedTableItem) {
cell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION));
}
}
cell.setForeground(provider.getDisplayColor((T) cell.getElement(), cell.getColumnIndex()));
super.update(cell);
}
Thanks in advance for the help!
The selection colour is normally chosen by the OS, so to change the colour you have to turn off the selected flag in the StyledCellLabelProvider erase, measure and paint methods. You also have to draw the selection colour yourself in the erase method.
Something like the following:
#Override
protected void erase(final Event event, final Object element)
{
if ((event.detail & SWT.SELECTED) != 0) {
event.detail &= ~SWT.SELECTED;
Rectangle bounds = event.getBounds();
event.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION));
event.gc.fillRectangle(bounds);
}
super.erase(event, element);
}
#Override
protected void measure(final Event event, final Object element)
{
event.detail &= ~SWT.SELECTED;
super.measure(event, element);
}
#Override
protected void paint(final Event event, final Object element)
{
event.detail &= ~SWT.SELECTED;
super.paint(event, element);
}

JavaFX custom ListCell

I'm trying to animate ListCell when they appear.
Specially I try to animate a new cell when it was just added to the list.
For now it's working pretty OK except when I scroll the ListView, then indexes get messed up and the wrong cell is animated.
I use a boolean flag (entering) in my item model to detect when a cell is used for a brand new item.
public class TimeListCell extends ListCell<MarkItem> {
private static final String BUTTON_GOTO_MARK_CLASS = "but-markgoto";
private static final String LABEL_TIME_MARK_CLASS = "track-time";
private static final String BUTTON_DELETE_MARK_CLASS = "but-markdel";
private static final String MARK_HIGHLIGHT_CURRENT_CLASS = "highlighted";
private Instant time;
private MarkItem markItem;
protected ListCellAnimation anim;
private HBox root = new HBox();
private Button go = new Button();
private Label track = new Label();;
private Button del = new Button();
private ChangeListener<? super Boolean> highlightChange = (e, o, n) -> { setHighlighted(n); };
public TimeListCell (Consumer<MarkItem> onGoto, Consumer<MarkItem> onDelete) {
root.setAlignment(Pos.CENTER);
go.getStyleClass().add(BUTTON_GOTO_MARK_CLASS);
go.setOnAction( e -> {
if (onGoto != null) {
// Trigger GOTO consumer function
onGoto.accept(markItem);
}
});
track.getStyleClass().add(LABEL_TIME_MARK_CLASS);
del.getStyleClass().add(BUTTON_DELETE_MARK_CLASS);
del.setOnAction( e -> {
// First trigger exit animation then delete item
this.animateExit(onDelete);
});
root.getChildren().add(go);
root.getChildren().add(track);
root.getChildren().add(del);
}
#Override
protected void updateItem (final MarkItem item, boolean empty) {
super.updateItem(item, empty);
if (markItem != null) {
markItem.highlightedProperty().removeListener(highlightChange);
}
if (!empty && item != null) {
markItem = item;
time = item.getTime();
track.setText(DateUtil.format(time, DateUtil.Pattern.TIME));
setGraphic(root);
item.highlightedProperty().addListener(highlightChange);
setHighlighted(item.isHighlighted());
if (anim == null) {
//Adding Animation to the ListCell
anim = new ListCellAnimation(this);
//KeyFrame[] f = getKeyFrames(types);
KeyFrame[] frames = null;
if (anim.getKeyFrames().size() == 0) {
KeyFrame[] f = anim.getPopIn(frames);
if (f != null) {
anim.getKeyFrames().addAll(f);
}
}
}
if (item.isEntering()) {
//Checking when to play Animation
animateEnter();
item.setEntering(false);
}
} else {
setGraphic(null);
}
}
/**
* Set/unset cell highlighted style for display.
*
* #param highlighted
* Whether or not to highlight the cell
*/
public void setHighlighted (boolean highlighted) {
track.getStyleClass().remove(MARK_HIGHLIGHT_CURRENT_CLASS);
if (highlighted)
track.getStyleClass().add(MARK_HIGHLIGHT_CURRENT_CLASS);
}
/**
* Animate entering cell.
*/
private void animateEnter() {
if (anim != null && anim.getKeyFrames().size() >= 0
&& (anim.getTimeline().getStatus() == Timeline.Status.STOPPED
|| anim.getTimeline().getStatus() == Timeline.Status.PAUSED)) {
anim.getTimeline().playFromStart();
}
}
/**
* Animate exiting cell.
* Trigger DELETE consumer function when animation is complete.
*/
private void animateExit (Consumer<MarkItem> onDelete) {
anim.getReversedTimeline().setOnFinished( t -> {
// Remove item from list
if (onDelete != null) {
onDelete.accept(markItem);
}
// Prepare cell for next item to use it
scaleXProperty().set(1);
scaleYProperty().set(1);
});
anim.getReversedTimeline().playFromStart();
}
public Instant getTime () {
return time;
}
}
Has anyone any idea of what could mess up the cell indexing ?
Thanks.
If a cell which is animating is reused to display an item that is not "entering", then you need to stop the current animation:
if (item.isEntering()) {
//Checking when to play Animation
animateEnter();
item.setEntering(false);
} else {
anim.getTimeline().stop();
}
In general, you seem to be assuming that any given cell is only ever used for a single item, which is certainly not the case. There may be other bugs in your code that are consequences of this assumption, but this is the main one I can see.

javafx tableview row text color is not changed using pseudo class

I need to show only a few rows with red text in a tableview, but no result!
My code:
PseudoClass pClass = PseudoClass.getPseudoClass("warn");
myTable.setRowFactory(new Callback<TableView<MyData>, TableRow<MyData>>() {
#Override
public TableRow<MyData> call(TableView<MyData> param) {
return new TableRow<MyData>() {
#Override
protected void updateItem(MyData item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
return;
}
setItem(item);
pseudoClassStateChanged(pClass, item.getWarning());
}
};
}
});
The css
.table-view .table-row-cell .text{
-fx-fill: black;
}
.table-view .table-row-cell .text:warn{
-fx-fill: red;
}
Can anyone review it or suggest some easier way?
You're setting the pseudo class on the TableRow, not on the .text nodes. Therefore the pseudoclass selector needs to be combined with the selector selecting the TableRow, not with the selector selecting the text element:
.table-view .table-row-cell:warn .text {

TreeViewer color row alternatively

I am new to eclipse SWT. I am trying to override the getBackground method of ITableColorProvider to color rows alternatively of a treeViewer. I was trying coloring with row index (index%2 == 0). It colors all the rows instead.
TreeViewer colors one cell at a time, instead of rows. Any pointers on how to achieve it (alternate row color for treeviewer) or code snippet will be very helpful.
List<TreeItem> treeItems = Arrays.asList( m_viewer.getTree().getItems() );
int index = treeItems.indexOf( element );
if( index % 2 == 0 )
{
backgroundColor = Display.getDefault().getSystemColor(
SWT.COLOR_YELLOW );
}
else
{
backgroundColor = Display.getDefault().getSystemColor(
SWT.COLOR_GRAY );
}
ITableColorProvider is used for TableViewer , for TreeViewer your class that extends LabelProvider should implement IColorProvider
public class MyLabelProvider extends LabelProvider implements IColorProvider{
#Override
public String getText(Object element) {
//how the label is obtained for an element
}
#Override
public Color getBackground(Object element) {
if(((TreeItem) element).getId() % 2 == 0) {
return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
}else{
return Display.getCurrent().getSystemColor(SWT.COLOR_RED);
}
}
#Override
public Color getForeground(Object element) {
return null;
}
}
The Color Class is the one from org.eclipse.swt.graphics.Color. I supposed that every TreeItem has an id property that is generated cosecutively

eclipse rcp :how to select a single cell in tableviewer?

hwo can I change the default selection behaviour of tables, I want to make a cell selected when user click it and make it editable when user double click it.
with #nonty 's help, I get what I want.
here is my cell highlighter implemention:
package com.amarsoft.rcputil;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
public class DefaultCellFocusHighlighter extends FocusCellOwnerDrawHighlighter {
public DefaultCellFocusHighlighter(ColumnViewer viewer) {
super(viewer);
}
protected boolean onlyTextHighlighting(ViewerCell cell) {
return false;
}
protected Color getSelectedCellBackgroundColor(ViewerCell cell) {
return cell.getControl().getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE);
}
protected Color getSelectedCellForegroundColor(ViewerCell cell) {
return cell.getControl().getDisplay().getSystemColor(SWT.COLOR_WHITE);
}
protected Color getSelectedCellForegroundColorNoFocus(ViewerCell cell) {
return cell.getControl().getDisplay().getSystemColor(SWT.COLOR_WHITE);
}
protected Color getSelectedCellBackgroundColorNoFocus(ViewerCell cell) {
return cell.getControl().getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE);
}
protected void focusCellChanged(ViewerCell newCell, ViewerCell oldCell) {
super.focusCellChanged(newCell, oldCell);
}
}
the code to use it :
TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tv,new DefaultCellFocusHighlighter(tv));
ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tv) {
protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
|| event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
|| (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
|| event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
}
};
TableViewerEditor.create(tv, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL
| ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
| ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION);
but I got new problem :
when I double click on cell to edit it's value, there is a little area at the left side of the cell is still highlighted with dark blue color
I know why :
When a text control is created with a border, the operating system includes a platform specific inset around the contents of the control.
still seeking for fixing...
Have a look at these two JFace Snippets:
Snippet036FocusBorderCellHighlighter - Demonstrates keyboard navigation by highlighting the currently selected cell with a focus border showing once more the flexibility of the new cell navigation support
Snippet034CellEditorPerRowNewAPI - Demonstrates different CellEditor-Types in one COLUMN with 3.3-API of JFace-Viewers
After digging through the code, I found the following method in the ColumnViewer class:
/**
* Hook up the editing support. Subclasses may override.
*
* #param control
* the control you want to hook on
*/
protected void hookEditingSupport(Control control) {
// Needed for backwards comp with AbstractTreeViewer and TableTreeViewer
// who are not hooked this way others may already overwrite and provide
// their
// own impl
if (viewerEditor != null) {
control.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
// Workaround for bug 185817
if (e.count != 2) {
handleMouseDown(e);
}
}
public void mouseDoubleClick(MouseEvent e) {
handleMouseDown(e);
}
});
}
}
So, I overrode that function within my TableViewer subclass:
#Override protected void hookEditingSupport(Control control) {
// We know there should be an editor avaiable
// if (viewerEditor != null) {
control.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
// Workaround for bug 185817
if (e.count != 2) {
// We don't want to edit on single clicks
// handleMouseDown(e);
}
}
public void mouseDoubleClick(MouseEvent e) {
// This method is private, so copy the implementation
// handleMouseDown(e);
ViewerCell cell = getCell(new Point(e.x, e.y));
e.count--; // A hack to make things work - pretend like it's a single click
if (cell != null) {
triggerEditorActivationEvent(new ColumnViewerEditorActivationEvent(
cell, e));
}
}
});
// }
}
This works for me. Tell me if it works for you.