Changing color of a chechboxTableViewer input JFace - jface

I am having a CheckboxTableViewer with several entries. Now I need to display a few of the entries in a different color. Kindly help me to do this as I am very new to this topic. Thanks in advance.
checkboxTableViewer = CheckboxTableViewer.newCheckList(composite,
SWT.BORDER | SWT.FULL_SELECTION);
checkboxTableViewer.setColumnProperties(new String[] {});
checkboxTableViewer.setAllChecked(false);
checkboxTableViewer.setAllGrayed(false);
table = checkboxTableViewer.getTable();
table.setFont(SWTResourceManager.getFont("Tahoma", 8, SWT.NORMAL));
table.setBounds(0, 10, 805, 277);
checkboxTableViewer.getTable().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
checkboxTableViewer.setContentProvider(new ArrayContentProvider());
checkboxTableViewer.setInput(listSelCommit);

Make your Label Provider implement IColorProvider, this adds two methods to the provider:
public MyLabelProvider extends LabelProvider implements IColorProvider
{
... other label provider methods
#Override
public Color getForeground(Object element)
{
// TODO return foreground color for 'element' or null to use the default
}
#Override
public Color getBackground(Object element)
{
// TODO return background color for 'element' or null to use the default
}
}

Related

Styling background of TornadoFX ListView

Is it possible to style a ListView component so that none of the elements have a shaded background?
I.e not like this:
But instead have them all styled like the first, third, fifth item etc.
TIA
In the default stylesheet, modena.css the background color for ListCells is governed by the following lines of code:
.list-cell,
.tree-cell {
-fx-background: -fx-control-inner-background;
-fx-background-color: -fx-background;
-fx-text-fill: -fx-text-background-color;
}
/* ... */
.list-cell:odd {
-fx-background: -fx-control-inner-background-alt;
}
So to remove the alternative color for the odd-numbered cells (note that counting is zero-indexed, so the odd-numbered cells are the 2nd, 4th, etc in the list view), you just need to include the following in your external CSS file, to revert the color for the odd-numbered cells to the same as the even-numbered cells:
.list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
If you need to apply this to one specific ListView, you can set an id on that ListView:
ListView myListView ;
// ...
myListView.setId("plain-list-view");
and then the CSS selector becomes
#plain-list-view .list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
You need to create a custom ListCell with a non-null Background. Once you do this, the automatic colour handling of the ListView for selected rows won't work properly any more. So you'll have to handle that yourself. The selection action will invert the colour of the text to white, but that's all. So you need to set the background colour of the cell based on the "Selected" property of the ListCell. In Java it would look like this:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
Background unselectedBackground =
new Background(new BackgroundFill(Color.WHITESMOKE, CornerRadii.EMPTY, Insets.EMPTY));
Background selectedBackground = new Background(new BackgroundFill(Color.BROWN, CornerRadii.EMPTY,
Insets.EMPTY));
backgroundProperty().bind(Bindings.createObjectBinding(() -> isSelected() ? selectedBackground :
unselectedBackground, selectedProperty()));
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
Once you do this, the cell background is no longer transparent, and the stripe pattern of the ListView itself won't show through.
EDIT:
As pointed out, this IS heavy-handed, except that in most cases a ListView isn't going to be a simple Label with a string in it. It's going to have some sort of layout in the ListCell that is going to require that you create a custom ListCell in any event.
However, messing with the Background directly via a binding to the "Selected" property is clumsy. You can create a new StyleClass, and then just define the modified PseudoClasses in the css. Then add this new StyleClass to the custom ListCell, and then it will handle it automatically as it applies the "EVEN" and "ODD" pseudoclasses.
One thing I found was that since the new "odd" definition gets applied after all of the other definitions in the default Modena css, that the "SELECTED" pseudoclass for ODD lines is suppressed. This means that the odd and even lines look different when they are selected, so a duplicate "SELECTED" definition needed to be added to the new css after the "ODD" definition. Then everything works properly. So the new code looks like this:
The CSS:
.custom-list-cell:odd {
-fx-background: -fx-control-inner-background;
}
.custom-list-cell:selected {
-fx-background: -fx-selection-bar;
-fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
}
The main, now loads the new stylesheet into the Scene:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
scene.getStylesheets().add(getClass().getResource("/css/samples.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
And then the only customization to the ListCell is to add the new StyleClass:
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
getStyleClass().add("custom-list-cell");
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
But if you really are just wanting to have a ListView with just simple labels in it, you can just have the cell factory add the StyleClass on to the standard TextFieldListCell:
public ListBackgroundWhite() {
super();
setCellFactory(listView -> {
ListCell<String> cell = new TextFieldListCell<>();
cell.getStyleClass().add("custom-list-cell");
return cell;
});
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}

Is it somehow possible to have two master views and one detail view?

If I have for example one master view on the left and one in the middle, each showing oder Java Beans/POJOs, can I use a shared detail view that somehow listens to the active beans of each view and then displays the currently selected one in more detail? A one to one relation is quite easy to manage by using your Context library.
#ViewDocking(areaId ="left", position=1, displayName="Profiles", menuEntry = #WindowMenuEntry(path = "", position=0), accelerator="Shortcut+1")
public class ProfileListView extends BorderPane implements LocalContextProvider {
private final SimpleContextContent content = new SimpleContextContent();
private final SimpleContext context = new SimpleContext(content);
#FXML
private ListView<Profile> listview;
public ProfileListView() {
load();
// add some profiles
listview.getItems().add(new Profile("Profile1"));
listview.getItems().add(new Profile("Profile2"));
listview.getItems().add(new Profile("Profile3"));
// setup selection listener
listview.getSelectionModel().selectedItemProperty().addListener((value, oldProfile, newProfile) -> {
// set active profile and remove old one
content.remove(oldProfile);
content.add(newProfile);
});
// setup double click listener
configureClickListener();
}
private Profile getSelectedProfile() {
return listview.getSelectionModel().getSelectedItem();
}
private void configureClickListener() {
listview.setOnMouseClicked(event -> {
// check if it was a double click
if(event.getClickCount() == 2) {
System.out.println(getSelectedProfile());
// inject into editor pane
// calls the procedure to create a tab in the center area...
}
});
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
}
This is one master view holding a list view of items.
The other one would be the same, docking to the right as another tab and holding POJOs of type 'Action'.
The detail view is here:
#ViewDocking(areaId = "right", displayName = "Properties", accelerator = "Shortcut+2", menuEntry = #WindowMenuEntry(path = "", position = 0), position = 1)
public class ProfilePropertiesView extends BorderPane implements LocalContextProvider, ActiveContextSensitive {
private Context activeContext;
private SimpleContextContent content = new SimpleContextContent();
private SimpleContext context = new SimpleContext(content);
private Profile profile;
private IWindowService service = new NullWindowService();
#FXML
private PropertySheet propertysheet;
public ProfilePropertiesView() {
load();
// retrieve framework service, TODO: use tracker
BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
service = ctx.getService(ctx.getServiceReference(IWindowService.class));
// initialize callback
service.addCallback(title -> {
System.out.println("callback called " + title);
// update the property sheet ui by re-creating the items list
// updateUI();
// we can safely return null
return null;
});
// configure editor factory so the user is able to use a combobox
propertysheet.setPropertyEditorFactory(new CustomPropertyEditorFactory(service));
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
private void contextChanged() {
// find profile information
Profile found = activeContext.find(Profile.class);
// if the found profile is null, ignore it
if (found != null) {
// reset if profile is valid
if (profile != null) {
reset();
}
// create reference and register
profile = found;
register();
}
}
private void register() {
// retrieve observablelist of bean properties if some profile is selected
if(profile != null) {
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().setAll(items);
}
}
private void updateUI() {
// clear property elements and re-create them
reset();
// re-create items
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().addAll(items);
}
private ObservableList<Item> createDetailedList(Object bean) {
ObservableList<Item> list = FXCollections.observableArrayList();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
Arrays.stream(beanInfo.getPropertyDescriptors()).map(pd -> new DetailedBeanProperty(bean, pd)).forEach(list::add);
} catch (IntrospectionException e) {
e.printStackTrace();
}
return list;
}
private void reset() {
propertysheet.getItems().clear();
}
#Override
public void setActiveContext(Context activeContext) {
this.activeContext = activeContext;
this.activeContext.addContextListener(Profile.class, event -> contextChanged());
// trigger change
contextChanged();
}
}
The current ProfilePropertiesView is just configured to display the properties of the selected profile. I want it to be able to display the current information of the last selected POJO in the UI. That means that if the user selected a Profile from the ListView, that profile should be displayed in the properties view. If he selected an Action from the Table (which is displayed in the center), the properties of the Action should be displayed.
Do I just need to register a new ContextListener for the Action.class
POJO and then call a method to populate the PropertiesView? I was
unsure if this is the right solution...
Yes, just add another ContextListener to the activeContext for every POJO type you want to observe.
Also note that in the constructor of views it's better to use a ServiceTracker instead of looking for the service via BundleContext as the service might not be available yet, depending on the order the bundles are loaded.
You can find a sample which uses a ServiceTracker here: https://stackoverflow.com/a/35974498/506855

Dataexporter pdf header position

I'm using dataexporter to create a pdf of a data table, in my data table the header of the columns is centralized, however the pdf version of the same columns is align to the left. how can I make the columns of the pdf be centralized like the data table.
I use the solution to customize the PDFExporter, it work very well, thank you for your attention. Below is how i've done:
My custom class:
public class CustomPDFExporter extends PDFExporter {
#Override
protected void addColumnFacets(DataTable table, PdfPTable pdfTable, ColumnType columnType) {
for(UIColumn col : table.getColumns()) {
if(!col.isRendered()) {
continue;
}
if(col instanceof DynamicColumn) {
((DynamicColumn) col).applyModel();
}
if(col.isExportable()) {
addHeaderValue(pdfTable, col.getFacet(columnType.facet()), FontFactory.getFont(FontFactory.TIMES, "iso-8859-1", Font.DEFAULTSIZE, Font.BOLD));
}
}
}
protected void addHeaderValue(PdfPTable pdfTable, UIComponent component, Font font) {
String value = component == null ? "" : exportValue(FacesContext.getCurrentInstance(), component);
PdfPCell cell = new PdfPCell(new Paragraph(value, font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfTable.addCell(cell);
}
}
bean:
public void exportPDF(DataTable table, String filename) throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
Exporter exporter = new CustomPDFExporter();
exporter.export(context, table, filename, false, false, "iso-8859-1", null, null);
context.responseComplete();
}
In my page I added:
<h:commandLink action="#{boxBean.exportPDF(boxTable, 'relatorio_caixas')}" >
<p:graphicImage value="/resources/img/pdf.png"/>
</h:commandLink>
Well your answer is already on stackoverflow: changing style on generating pdf with Primefaces dataExporter
Also take a look here: http://www.primefaces.org/showcase/ui/exporterProcessor.jsf how to use the exportProcessor of Primefaces.
In short you need to create your own processor to create an custom PDF

JavaFX How to change ProgressBar color dynamically?

I was trying to solve my problem with colored progress bars in this thread. The solution was present, but then I ran into another problem: I can't change color dynamically from my code. I want to do it right from my code, not with pre-defined .css. Generally I can do it, but I run into some difficulties when I try to do it with more than one progess bar.
public class JavaFXApplication36 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
ProgressBar pbRed = new ProgressBar(0.4);
ProgressBar pbGreen = new ProgressBar(0.6);
pbRed.setLayoutY(10);
pbGreen.setLayoutY(30);
pbRed.setStyle("-fx-accent: red;"); // line (1)
pbGreen.setStyle("-fx-accent: green;"); // line (2)
root.getChildren().addAll(pbRed, pbGreen);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
I always get 2 red progressbars with it! It seems that code in line (1) changes the style of ProgressBar class, not the instance.
Another strange moment is that deleting line (1) don't result in 2 green progress bars. So I can figure that line (2) is completely useless!! WHY?! That's definitely getting odd.
Is there any way to set different colors for separate progressbars?
See also the StackOverflow JavaFX ProgressBar Community Wiki.
There is a workaround you can use until a bug to fix the sample code in your question is filed and fixed.
The code in this answer does a node lookup on the ProgressBar contents, then dynamically modifies the bar colour of the progress bar to any value you like.
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ProgressBarDynamicColor extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
PickedColorBar aquaBar = new PickedColorBar(0.4, Color.AQUA);
PickedColorBar fireBar = new PickedColorBar(0.6, Color.FIREBRICK);
HBox layout = new HBox(20);
layout.getChildren().setAll(aquaBar, fireBar);
layout.setStyle("-fx-background-color: -fx-box-border, cornsilk; -fx-padding: 15;");
stage.setScene(new Scene(layout));
stage.show();
aquaBar.wasShown();
fireBar.wasShown();
}
class PickedColorBar extends VBox {
private final ProgressBar bar;
private final ColorPicker picker;
private boolean wasShownCalled = false;
final ChangeListener<Color> COLOR_LISTENER = new ChangeListener<Color>() {
#Override public void changed(ObservableValue<? extends Color> value, Color oldColor, Color newColor) {
setBarColor(bar, newColor);
}
};
public PickedColorBar(double progress, Color initColor) {
bar = new ProgressBar(progress);
picker = new ColorPicker(initColor);
setSpacing(10);
setAlignment(Pos.CENTER);
getChildren().setAll(bar, picker);
}
// invoke only after the progress bar has been shown on a stage.
public void wasShown() {
if (!wasShownCalled) {
wasShownCalled = true;
setBarColor(bar, picker.getValue());
picker.valueProperty().addListener(COLOR_LISTENER);
}
}
private void setBarColor(ProgressBar bar, Color newColor) {
bar.lookup(".bar").setStyle("-fx-background-color: -fx-box-border, " + createGradientAttributeValue(newColor));
}
private String createGradientAttributeValue(Color newColor) {
String hsbAttribute = createHsbAttributeValue(newColor);
return "linear-gradient(to bottom, derive(" + hsbAttribute+ ",30%) 5%, derive(" + hsbAttribute + ",-17%))";
}
private String createHsbAttributeValue(Color newColor) {
return
"hsb(" +
(int) newColor.getHue() + "," +
(int) (newColor.getSaturation() * 100) + "%," +
(int) (newColor.getBrightness() * 100) + "%)";
}
}
}
The code uses inlined string processing of css attributes to manipulate Region backgrounds. Future JavaFX versions (e.g. JDK8+) will include a public Java API to manipulate background attributes, making obsolete the string processing of attributes from the Java program.
Sample program output:

How to Color TableViewer Rows alternatively

I'm using Viewer Framework in my rcp application, i would like to color viewer rows alternatively,i tried to override getBackground method of ColumnLabelProvider, below is code snippet
col.setLabelProvider(new ColumnLabelProvider(){
----//other methods
#override
public Color getBackground(Object element) {
return gray;//here gray is color object defined somewhere in class
}
});
this colors the columns, but not a row, below is output
how do i achieve this correctly
You can find an example here which uses an IColorProvider. Maybe you could just reuse the getBackground() method in your code, just change the reference to your tableViewer:
public Color getBackground(Object element) {
ArrayList list = (ArrayList) tableViewer.getInput();
int index = list.indexOf(element);
if ((index % 2) == 0) {
return gray;
} else {
return null;
}
}