JavaFX get minimum width/height/size of a Pane before it starts clipping - javafx

FFor the sake of simplicity it is better to show you the problem and then describe it
I plan to set the minimum width of the window to the minimum size possible before the pane (groupPane in this example) starts being clipped
how can i calculate that width beforehand.
the fxml section :
the current calculation method:
public void setupMinStageSizeInStandardMode(Stage primaryStage, Scene scene)
{
// the thickness of the border of the window
ObjectBinding<Insets> insets = Bindings.createObjectBinding(() ->
new Insets(scene.getY(),
primaryStage.getWidth()-scene.getWidth() - scene.getX(),
primaryStage.getHeight()-scene.getHeight() - scene.getY(),
scene.getX()),
scene.xProperty(),
scene.yProperty(),
scene.widthProperty(),
scene.heightProperty(),
primaryStage.widthProperty(),
primaryStage.heightProperty()
);
//i am trying to get the grid to the smallest size here
controlsGrid.setMaxWidth(0);
controlsGrid.setPrefWidth(0);
// then i am trying to calculate the wanted size
double minStageWidth = controlsGrid.getWidth() +insets.get().getLeft() + insets.get().getRight();
double minStageHeight = controlsGrid.getHeight() +insets.get().getTop() + insets.get().getBottom();
System.out.println(minStageWidth);
System.out.println(minStageHeight);
//then return the grid to it's intended size
controlsGrid.setMaxWidth(Region.USE_PREF_SIZE);
controlsGrid.setPrefWidth(Region.USE_PREF_SIZE);
primaryStage.setMinHeight(minStageHeight);
primaryStage.setMinWidth(minStageWidth);
}
Please help. i am losing sleep over this...

Related

Get visible elements from AnchorPane

I'm developing a JavaFX application where the user is able to zoom and drag the elements (all contained in a AnchorPane). Some of those elements are simple lines and I need to have something like a ruler that has different parent to stick on the screen on the same position even if the user zooms or drags the mentioned AnchorPane. I got almost everything working but I have one problem, I need to know which lines from the AnchorPane are visible to the user (as if the user zooms and drags the AnchorPane, some of the lines are not visible anymore). Here's what I tried (not working...)
private List<Double> getVisibleVerticalLinesXCoordonate() {
List<Double> xCoordonatesOfVisibleVerticalLines = new ArrayList<>();
List<Node> visibleNodes = new ArrayList<>();
Bounds bounds = rulerParent.getBoundsInLocal();
Bounds paneBounds = rulerParent.localToScene(bounds);
for (Node n : gridVerticalLines) {
Bounds nodeBounds = n.getBoundsInParent();
if (paneBounds.intersects(nodeBounds)) {
visibleNodes.add(n);
}
}
for (Node node : visibleNodes) {
Bounds newBounds = getRelative(node);
xCoordonatesOfVisibleVerticalLines.add(newBounds.getMinX());
}
System.out.println(Arrays.asList(xCoordonatesOfVisibleVerticalLines));
return xCoordonatesOfVisibleVerticalLines;
}
private Bounds getRelative(Node node) {
return rulerParent.sceneToLocal(node.localToScene(node.getBoundsInLocal()));
}
So, the rulerParent is what is fixed on the screen (is not zooming or dragging at all). After I have the visible lines from the AnchorPane I get the x coordinates of the lines relative to rulerParent - so I can align the ruler lines with the lines in the AnchorPane.
The problem is that this is not returning the actual visible lines...
I don't need to be able to see the whole line to consider it visible, that's why I'm using intersect...if any part of a line is visible, I need it.
It's about how you handle the zoom and dragging actions try to use ViewPort instead of scaling as with ViewPort you can know the translation X and Y coordinates of the ViewPort which is the visible X and Y coordinates of the AnchorPane

Display JavaFX Image without blur/dithering when zooming in

I'm trying to create a image editor tool, where I have X- and Y-axis. Now I want to support the user by seeing each pixel when zooming in so that they can work more exactly. In comparison you should take a look at paint.net where you can see the pixels when zooming in.
I'll give you a code snippet and perhaps you might have a hint for me where I should dig into (API or code examples). I've found nothing like it in the JAVAFX API documentation. I want to use an ImageView instance but not a Canvas.
ScrollPane scrollPane = new ScrollPane ();
BorderPane borderPane = new BorderPane();
Group group = new Group();
DoubleProperty zoomProperty = new SimpleDoubleProperty(1);
Scale scaleTransformation = new Scale();
scaleTransformation.xProperty().bind(zoomProperty);
scaleTransformation.yProperty().bind(zoomProperty);
ImageView viewer = new ImageView(getBackgroundImage());
viewer.setFitWidth(600);
viewer.setPreserveRatio(true);
viewer.setDisable(true);
viewer.setSmooth(false);
group.getChildren().add(viewer);
this.addEventFilter(ScrollEvent.SCROLL, new EventHandler<ScrollEvent>(){
#Override
public void handle(ScrollEvent se) {
if (se.isControlDown() && se.getDeltaY() > 0) {
double value = zoomProperty.get() * 1.1;
zoomProperty.set(value);
se.consume();
} else if (se.isControlDown() && se.getDeltaY() < 0) {
double value = zoomProperty.get() / 1.1;
zoomProperty.set(value);
se.consume();
}
}
});
borderPane.setCenter(group);
scrollPane.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scrollPane.setVbarPolicy(ScrollBarPolicy.ALWAYS);
scrollPane setContent(new Group(borderPane));
Thanks for you help.
EDIT
The related question and it's answers do not solve my problem (JavaFX ImageView without any smoothing). The solution 1-4 do not work. Only the hack does. I guess I could be related the node structure I use. I've adjusted my code.
I have found one solution (referring to the possible duplicate) and using a variant of method 1.
In my image constructor I set the requested size to something large - so for an image that I know is about 1000 pixels wide I request an image 10000 pixels wide:
Image image = new Image(file.toURI().toString(), 10000.0, 10000.0, true, false);
I am not sure if this is giving a true view of the pixels, or if it is smoothing at a very low level...... but it works for my needs.

JavaFX: maximum ImageView size

This may sound like a duplicate of Set maximum size for JavaFX ImageView but it's different.
I'd like to restrict the maximum size of an ImageView. Unfortunately, the only way to set the ImageView's size seems to be fitWidth and fitHeight which however enlarges the image if it's smaller than the fit values.
I tried setting fitWidth/fitHeight to 0/0 and wrap the ImageView into a pane with maxWidth set - no success (image is displayed in original size).
To me it seems as this is not achievable by JavaFX, however I can't believe it. But I couldn't find anything online. Are there any tricks/bugs/workarounds on this?
If you dont want the image to stretch, you can use:
setPreserveRatio(true);
Then you are able to fit width and height as you want
ImageView setPreserveRatio javadoc
In javadoc in this method there are the rules of scaling too
You just needed to add in if statement to set those larger than maxsize to a fixed size. The rest would remain their original size.
ImageView im = new ImageView();
im.setImage(image);
im.maxHeight(690 - 10);
int yoursize = 690;
if(im.maxHeight(690 - 10)> yoursize ){
im.setFitHeight(690- 10);
System.out.println("Fix Size : 690 ");
}
im.setPreserveRatio(true);
im.setSmooth(true);
im.setCache(true);
You can get the actual Image resource and query its width/height to use for the fit values:
Image image = imageView.getImage();
double nativeWidth = image.getWidth();
double nativeHeight = image.getHeight();

Flex 3 - Diagonally draw text in a shape and adjust size

I'm trying to create the following component:
Just for information, the blank space will contain a text control, and I'm creating a component that represents the black corner with the (i) icon and the "promotion" text.
The part I'm having issues with is this component representing the black corner with the diagonal text. The text has to be able to hold 2 lines. And the black corner has to be able to adjust to the text's size.
What's more, the text has a rotation...
I'm having some doubts on how to do this:
Should I have different controls for each text line?
Should I draw the text in the shape (after doing the rotation) or should I just overlap both components? [When I talk about drawing the text in the shape, I mean in the same way as asked in this question]
Is there any way to get the proper size of the triangle shape without doing some extravagant calculations?
And... do you have any "easier" ways to do this ?
A big thanks for any help you can provide :) I'm a little bit lost with this little component :)
Regards.
BS_C3
Edit 1:
The triangle may have 2 sizes: 1 size that will fit 1 line, and another size to fit 2 lines of text.
The text will be sent as a single string, so it will have to be automatically divided in two lines if needed
I was thinking of using graphics to draw the triangle shape and then use a mask to create the rounded corner --> This is because the same component will be used in other places of the application without the rounded corner
Flex is pretty good at updating group components to whatever size thier contents become, updating dynamically on the fly..
for what your suggesting, I'd probably create the "Promotion" group in the corner as a rectangle, rotate it and fit it to the corner like you want, then using a copy of the rounded rect you use as the maing component background, i'd make a mask to cut the "Promotion" component so you don't see the overlap.
Well, I finally wrote the class and this is the result:
public class Corner extends Canvas
{
private var infoIcon:Image;
private var text:Text;
private var triangle:Shape;
private var bgColor:uint;
public function Corner()
{
super();
infoIcon = new Image;
text = new Text;
text.rotation = -45;
text.width = 75;
text.maxHeight = 30;
text.setStyle('color', '0xffffff');
text.setStyle('textAlign', 'center');
text.y = 53;
this.addChild(infoIcon);
this.addChild(text);
triangle = new Shape;
}
public function build(bgColor:uint = 0x61113D):void{
this.bgColor = bgColor;
// info icon data
// set text
text.addEventListener(FlexEvent.UPDATE_COMPLETE, textHandler);
text.text = 'blabla';
text.validateNow();
}
/**
*
*/
private function textHandler(e:FlexEvent):void{
switch(e.type){
case FlexEvent.UPDATE_COMPLETE:
text.removeEventListener(FlexEvent.UPDATE_COMPLETE, textHandler);
drawTriangle();
break;
}
}
/**
*
*/
private function drawTriangle():void{
var h:int = 80;
// check if the text has 1 or 2 lines
if(text.height > 20)
h = 95;
// remove the triangle shape if it exists
if(this.rawChildren.contains(triangle))
this.rawChildren.removeChild(triangle);
// draw triangle
triangle = new Shape;
triangle.graphics.moveTo(0, 0);
triangle.graphics.beginFill(bgColor);
triangle.graphics.lineTo(h, 0);
triangle.graphics.lineTo(0, h);
triangle.graphics.lineTo(0, 0);
triangle.graphics.endFill();
this.rawChildren.addChildAt(triangle,0);
dispatchEvent(new MyEvent(MyEvent.CORNER_UPDATED));
}
...
}

Zooming in/out on a mouser point ?

As seen in the pictures.
I have QWidget inside a QScrollArea.
QWidget act as a render widget for cell image and some vector based contour data.
User can performe zoom in/out and what simply happens is, it changes the QPainters scale and change the size of QWidget size accordinly.
Now I want to perform the zooming in/out on the point under the mouse. (like zooming action in GIMP).
How to calculate the new positions of the scrollbars according to the zoom level ?
Is it better to implement this using transformations without using a scrollarea?
One solution could be to derive a new class from QScrollArea and reimplementing wheelEvent for example so that zooming is performed with the mouse wheel and at the current mouse cursor position.
This method works by adjusting scroll bar positions accordingly to reflect the new zoom level. This means as long as there is no visible scroll bar, zooming does not take place under mouse cursor position. This is the behavior of most image viewer applications.
void wheelEvent(QWheelEvent* e) {
double OldScale = ... // Get old scale factor
double NewScale = ... // Set new scale, use QWheelEvent...
QPointF ScrollbarPos = QPointF(horizontalScrollBar()->value(), verticalScrollBar()->value());
QPointF DeltaToPos = e->posF() / OldScale - widget()->pos() / OldScale;
QPointF Delta = DeltaToPos * NewScale - DeltaToPos * OldScale;
widget()->resize(/* Resize according to new scale factor */);
horizontalScrollBar()->setValue(ScrollbarPos.x() + Delta.x());
verticalScrollBar()->setValue(ScrollbarPos.y() + Delta.y());
}
Will void QScrollArea::ensureVisible(int x, int y, int xmargin = 50, int ymargin = 50) do what you need?
You need to pick up the wheelEvent() on the QWidget, get the event.pos() and pass it into the QscrollArea.ensureVisible(), right after scaling your QWidget.
def wheelEvent(self, event):
self.setFixedSize(newWidth, newHeight)
self.parent().ensureVisible(event.pos())
That should more or less produce what you want.

Resources