Tooltip background (with JavaFX CSS)
The .root
style class is added to the root node of all scenes. Since Tooltip
has its own scene, tooltip's root node has the .root
class as well, so the background image is applied to it as well, as per your CSS. The solution is to add a distinct style class to your main scene's root
scene.getRoot().getStyleClass().add("main-root");
and specify the background image for this distinct style class
.main-root {
-fx-background-image: url("media/background.jpg");
}
JavaFX quickfixes with tooltips and hyperlinks
You can add any node to a tooltip using the setGraphic()
method. Here is a simple example demonstrating using a tooltip for "quick fix" functionality:
import java.util.Random;
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TooltipWithQuickfix extends Application {
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
textField.pseudoClassStateChanged(PseudoClass.getPseudoClass("invalid"), true);
textField.setTextFormatter(new TextFormatter<Integer>(c -> {
if (c.getText().matches("\\d*")) {
return c ;
}
return null ;
}));
textField.textProperty().isEmpty().addListener((obs, wasEmpty, isNowEmpty) ->
textField.pseudoClassStateChanged(PseudoClass.getPseudoClass("invalid"), isNowEmpty));
Tooltip quickFix = new Tooltip();
Hyperlink setToDefault = new Hyperlink("Set to default");
Hyperlink setToRandom = new Hyperlink("Set to random");
setToDefault.setOnAction(e -> {
textField.setText("42");
quickFix.hide();
});
Random rng = new Random();
setToRandom.setOnAction(e -> {
textField.setText(Integer.toString(rng.nextInt(100)));
quickFix.hide();
});
VBox quickFixContent = new VBox(new Label("Field cannot be empty"), setToDefault, setToRandom);
quickFixContent.setOnMouseExited(e -> quickFix.hide());
quickFix.setGraphic(quickFixContent);
textField.setOnMouseEntered(e -> {
if (textField.getText().isEmpty()) {
quickFix.show(textField, e.getScreenX(), e.getScreenY());
}
});
VBox root = new VBox(textField);
root.getStylesheets().add("style.css");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with the stylesheet (style.css):
.root {
-fx-alignment: center ;
-fx-padding: 24 10 ;
}
.text-field:invalid {
-fx-control-inner-background: #ff7979 ;
-fx-focus-color: red ;
}
How to change or override the tooltip in JavaFX ColorPicker
Based on the code posted by the OP after my first answer, and due to the substancial changes in the problem addressed, I'm adding a new answer that covers both situations:
- The
ColorPicker
is embedded in the main scene, as a regular node - The
ColorPicker
is embedded in aContextMenu
In the second situation, the proposed solution for the first one is no longer valid, since the window found will be the one with the context menu.
A task is required to keep looking for windows until the one with the ComboBoxPopupControl
is found.
This is a full runnable example:
public class ColorPickerFinder extends Application {
ExecutorService findWindowExecutor = createExecutor("FindWindow");
@Override
public void start(Stage primaryStage) {
AnchorPane panCircles = new AnchorPane();
Scene scene = new Scene(panCircles, 400, 400);
final Random random = new Random();
IntStream.range(0,5).boxed().forEach(i->{
final Circle circle= new Circle(20+random.nextInt(80),
Color.rgb(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
circle.setTranslateX(100+random.nextInt(200));
circle.setTranslateY(100+random.nextInt(200));
panCircles.getChildren().add(circle);
});
panCircles.setPrefSize(400, 400);
ColorPicker colorPicker = new ColorPicker();
panCircles.getChildren().add(colorPicker);
primaryStage.setScene(scene);
primaryStage.show();
// We add listeners AFTER showing the stage, as we are looking for nodes
// by css selectors, these will be available only after the stage is shown
colorPicker.showingProperty().addListener((obs,b,b1)->{
if(b1){
// No need for task in this case
getPopupWindow();
}
});
panCircles.getChildren().stream()
.filter(c->c instanceof Circle)
.map(c->(Circle)c)
.forEach(circle->{
circle.setOnMouseClicked(e->{
if(e.getButton().equals(MouseButton.SECONDARY)){
// We need a task, since the first window found is the ContextMenu one
findWindowExecutor.execute(new WindowTask());
final ColorPicker picker = new ColorPicker();
picker.setStyle("-fx-border-radius: 10 10 10 10;"
+ "-fx-background-radius: 10 10 10 10;");
picker.setValue((Color)(circle.getFill()));
picker.valueProperty().addListener((obs,c0,c1)->circle.setFill(c1));
final ContextMenu contextMenu = new ContextMenu();
MenuItem editLabel = new MenuItem();
contextMenu.getItems().add(editLabel);
editLabel.setGraphic(picker);
contextMenu.show(panCircles,e.getScreenX(),e.getScreenY());
}
});
});
}
private PopupWindow getPopupWindow() {
@SuppressWarnings("deprecation")
final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
if(window.getScene()!=null && window.getScene().getRoot()!=null){
Parent root = window.getScene().getRoot();
if(root.getChildrenUnmodifiable().size()>0){
Node popup = root.getChildrenUnmodifiable().get(0);
if(popup.lookup(".combo-box-popup")!=null){
// only process ComboBoxPopupControl
Platform.runLater(()->{
popup.lookupAll(".color-rect").stream()
.forEach(rect->{
Color c = (Color)((Rectangle)rect).getFill();
Tooltip.install(rect.getParent(),
new Tooltip("Custom tip for "+c.toString()));
});
});
return (PopupWindow)window;
}
}
}
return null;
}
}
return null;
}
private class WindowTask extends Task<Void> {
@Override
protected Void call() throws Exception {
boolean found=false;
while(!found){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
found=(getPopupWindow()!=null);
}
return null;
}
}
private ExecutorService createExecutor(final String name) {
ThreadFactory factory = r -> {
Thread t = new Thread(r);
t.setName(name);
t.setDaemon(true);
return t;
};
return Executors.newSingleThreadExecutor(factory);
}
public static void main(String[] args) {
launch(args);
}
}
This will be the result after right clicking on a circle, and clicking on the color picker:
JavaFX styling TableColumn cells
You could use multiple class selectors to select the cells:
.column-1.table-cell {
-fx-background-color: white;
}
<TableColumn styleClass="column-1">
Related Topics
How to Connect a CSS Animation's End to the Beginning So It Smoothly Continues
Transform-Origin Not Working in Firefox Even Properties in Percentage Value
Using Less Variables in Media Queries
Change Colour of Selectizeinput Options in R Shiny
Dotted/Dashed Circle Shapes Using CSS - Not Rendering Right in Chrome
CSS Mystery: Width Being Set to 0Px Without Any CSS Rules
How to Use CSS Custom Properties in Values for the Content Property
Change the Number of Columns and Rows in a Grid as the Number of Items Increase
Preventing Horizontal Scrolling in Mobile Devices
How to Use @Media (Prefers-Color-Scheme) in Responsive Email in Gmail
Right Aligned Bootstrap Container Which Also Aligns with Default Container
How to Provide CSS Properties for Different Browsers Like Mozilla and Chrome
Position Element at Bottom Right Corner of Current Window
Small Space Between Box Shadow and Div When Alpha Set
Layout Using Vh Does Not Scale with Zoom