I have an ImageView wrapped in a StackPane that is added to the top section of a SplitPane. When I move the SplitPane's divider, I want the ImageView to resize to fit the allotted space, while also preserving the ImageView's size ratio. I have attempted to achieve this with the following code snippet:
Platform.runLater(() -> {
image.fitHeightProperty().bind(stackpane.heightProperty());
image.fitWidthProperty().bind(stackpane.widthProperty());
image.setPreserveRatio(true);
});
The problem with this however is that the ImageView will only grow, but not shrink. How can I fix this?
Mystery solved! Playing with the SplitPane's divider bindings seemed to be the solution. It isn't perfect, as sometimes the image is not flush with either top/bottom nor left/right edges depending on the width/height of the Stage, but it gets the job done.
Platform.runLater(() -> {
image.fitWidthProperty().bind(splitPane.getDividers().get(0).positionProperty().multiply(splitPane.widthProperty()));
image.fitHeightProperty().bind(splitPane.getDividers().get(0).positionProperty().multiply(splitPane.heightProperty()));
imgWebCamCapturedImage.setPreserveRatio(true);
});
Related
I am attempting to have an ImageView that scales with its parent. I have searched through every StackOverflow post I can find on this, and here is what I've tried:
taggedImage.setPreserveRatio(true);
//taggedImage.fitWidthProperty().bind(
// Bindings.min(imagePane.widthProperty(), imagePane.widthProperty()));
//taggedImage.fitHeightProperty().bind(
// Bindings.min(imagePane.heightProperty(), imagePane.heightProperty()));
taggedImage.fitWidthProperty().bind(imagePane.widthProperty());
taggedImage.fitHeightProperty().bind(imagePane.heightProperty());
The commented lines I tried as well and the issue with these approaches is that when the imageview binds to the parent, the parent can only scale up and not down. Therefore, if you increase the size of the window, the picture will get bigger. If you decrease the size of the picture again, it doesn't decrease the picture size. In this example, imagePane is a StackPane. I have also tried a borderFrame. As well, I've tried using a Pane as the parent. This way, the image successfully scales up and down. However, the image isnt centered and is always in the top left corner of the pane if it doesnt match the size of the pane exactly.
Scene Tree:
https://gyazo.com/45e0daebbfd98dfd3446185d21eb91ee
Values:
Top gridpane:
https://gyazo.com/f48ebb39f48d876a02d44792a73eaad4
lower level gridpane:
https://gyazo.com/3399d9f3ab00e8babd36ee3b0e3b27ba
BorderPane:
https://gyazo.com/51c24f8de50ae3865a299fdddf3a1490
ImageView:
https://gyazo.com/7dfc1071d2b516a83baed301596be2b9
Note, here I'm trying it with a borderpane instead of what I was using before. However, the result is the same no matter which object is the parent of the imageview.
Solved. I've been messing around and found a fix. This isn't exactly intuitive but it worked for me: I left the image inside the borderframe and, in the java code, I created a pane in the same part of the gridpane as the image. I then bound the imageview's width and height to the pane. Then, the centering of the image was correct as well as the scaling.
Here is what i did:
imageView.setPreserveRatio(true);
Pane pane = new Pane();
testGridPane.add(pane, 1, 1);
imageView.fitWidthProperty().bind(pane.widthProperty());
imageView.fitHeightProperty().bind(pane.heightProperty());
I was wondering if there is a way to disable/prevent scrolling in a ScrollPane?
Basically I have a Canvas wrapped in a Group object to enable zooming (which is done by 'Ctrl + scroll'). Though for some reason the ScrollPane consumes the event (if it can be scrolled) before it fires any other scrollEvent (e.g. the ScrollEvent from the Canvas, Group, ScrollPane and even the ScrollPane's Parent!).
So I was wondering what the options are (if there are any) to catch a scrollEvent before it is consumed by the ScrollPane.
Thanks for your time
Thanks to joshpy I got the answer.
I forgat that EventFilters are a thing in javafx. Luckly you can consume the Event in the eventFilter as well, so here is the solution.
scrollPane.addEventFilter(ScrollEvent.SCROLL, event -> {
if(event.isControlDown())
{
zoomCanvas(event) // zoom the canvas instead of scrolling the actual pane.
event.consume();
}
});
Many thanks for the tip!
Although Im still not sure why an usual event wouldn't work.
I have a series of column labels that scrolls independently from the data that is displayed in a matrix below. I can make the whole scrollbar transparent except on hover. The labels are right up against the data, which I like, however, upon hover, unless I shift the vertical scroll (which I'd rather not do), the scrollbar obscures the beginning of all the labels.
I would like to set the background of the scrollbar as transparent so that only the "grabber" (or whatever it's called) is the only thing that is drawn. (It will obscure the beginning of the labels it is over, but would be a lot less so.)
Is there any way to do that? Here is what I tried:
Color bg = new Color(255,255,255,0);
colLabelScroll.setBackground(bg);
This does not seem to make the background of the scrollbar transparent.
What I'm shooting for is like how the iPhone's scrollbar grabber hovers over info in some apps. Is that even possible with JScrollBars?
Transparent JScrollBar can do it, but consider this: if column labels are related to the data and you can scroll them independently, beginner users may not understand what is going on and associate column labels with whatever is visually aligned beneath it. Either you will need some sort of visual indicator that makes it clear that the labels are disconnected from the data, or you should change the way labels are scrolled that never leaves them statically in 1 place.
Here's how I ended up making the relationship between the labels and the data clearer:
Instead of allowing the user to independently and intentionally scroll the labels, I decided to control the label scroll position via mouse hover. This eliminates the need for the obtrusive scrollbar.
I created a scroll-bar-like indicator that shows the portion of the data the labels represent.
I highlighted the currently hovered label that corresponds to the data below it, i.e. the only label that is ever correctly aligned with the data is the one that is under (or directly above) the cursor.
When the mouse is not hovered over (or dragging from) the column labels, do not display any labels. This helps prevent invalid label/data associations by the user.
A few nuanced notes: Implementing your own scrollbar-like indicator is somewhat involved, especially if your labels are painted and then rotated, because the paint position of 0 is at the bottom of the pane, yet the vertical scroll position of the pane is at the top. You will have to track the vertical scroll position to be able to recover it again when the cursor returns since you are blanking the labels on mouse out.
When developing a plugin for IntelliJ, I accomplished it with:
scrollPane.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent());
It takes advantage of the the:
ButtonlessScrollBarUI.createTransparent()
method, which is an IntelliJ specific method. However, if you can find a ScrollBarUI which has a transparent background, you can use the same trick.
Since I got a bit lost myself at first after reading #hepcat72's answer I'm posting a little explanation about the BasicScrollBarUI class:
JScrollBar scrollbar = scrollPaneConversation.getVerticalScrollBar();
scrollbar.setUI(new BasicScrollBarUI(){
// This function returns a JButton to be used as the increase button
// You could create your own customized button or return an empty(invisible) button
#Override
protected JButton createIncreaseButton(int orientation){
}
// Same as above for decrease button
#Override
protected JButton createDecreaseButton(int orientation){
}
// This function paints the "track" a.k.a the background of the scrollbar
// If you want no background just return from this function without doing anything
// If you want a custom background you can paint the 'Graphics g' object as you like
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
{
}
// This function paints the "thumb" a.k.a the thingy that you drag up and down
// You can override this function to paint it as you like
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
{
}
});
Refer to the Transparent JScrollBar link posted by #hepcat72 for hints about what to do exactly in these functions.
I have very simple programm and very bad bug-_-
In my programm I have ScrollPane, that contains Accordion. ScrollPane prefHeightProperty binded to Accordion heightProperty.
themeScroll.prefHeightProperty().bind(themeAccordion.heightProperty());
And when I collapse titledPane, the height of the Accordion decreases. And the height of the ScrollPane, too, must be decreased to a height of Accordion, but it does not decrease until the end.
(ScrollPane has green background)
Then I minimize the window and re-open it and see:
How can I avoid this problem?
UPD 1:
I know that I need call this code for resize scrollPane:
Platform.runLater(() -> {
themeScroll.requestLayout();
});
But where?
I tried to call it in themeAccordion.expandedPaneProperty.addListener(...), but it isn't help
And if I will call it in themeAccordion.heightProperty().addListener(...), then the problem is solved, but this code themeScroll.requestLayout(); is called many times it's bad.
I have a layout where I have a vertical split pane that divides two components. The component inside the right side of the splitpane I want to grow (it's an image), but the components on the left side of the split pane I want to remain in the exact same place with the divider in the exact same position when the window is enlarged.
I have attempted to wrap the left side AnchorPane in a Vbox and it seemed to work except when the window is resized all of the components in the left side get moved down. This also occurs when I wrap it in an HBox.
I can't think of the best way to fix this. I'm using scene builder and I'm still fairly new to Javafx. Can anyone help?
Thank you!
Calling setMinWidth and setMaxWidth on the component that must not grow with the same fixed value will prevent the user to change the divider position.
So for example let's say that you want a max size of 100 for your left component, the code could be:
SplitPane pane = new SplitPane();
double leftComponentSize = 100.0;
VBox leftComponent = new VBox();
// Set the min and max width to a fixed size
leftComponent.setMinWidth(leftComponentSize);
leftComponent.setMaxWidth(leftComponentSize);
...
pane.getItems().addAll(leftComponent, rightComponent);
// Initialize the divider positions to allocate the expected size
// to the left component according to the size of the window
pane.setDividerPositions(leftComponentSize / stage.getScene().getWidth());