Original Question
Progress to answer below
I want to have some thumbnails inside a ScrollPane. The thumbnails highlight when you mouse-over them.
The problem is, unless I apply scrollPane.setPadding(new Insets(15,0,0,0));, the listeners I have applied, (as well as the listeners for other controls such as Buttons) DO NOT FIRE. They only fire if the mouse is ~15 pixels below the top edge of the ScrollPane.
A. Shows no padding applied. (Red area shows approximate listener firing zone)
B. Shows 15px padding applied.
I was constantly clicking in both images. The Buttons only respond below ~15px too.
So unless I have padding, you cannot interact with any controls along the top, buttons, labels etc.
How can I get around this, please?
The scrollPane is constructed by:
parentStage = stage;
parentScene = scene;
mainStyle = mS;
backgroundStyle = bS;
highlightBackgroundStyle = hBS;
selectionPanelRoot.setCenter(selectionScroller);
selectionPanelRoot.setBottom(bottomButtons);
bottomButtons.setLeft(generalButtons);
bottomButtons.setRight(moreButtons);
selectionScroller.setContent(selectionContent);
selectionContent.setPrefWrapLength(Double.MAX_VALUE);
selectionContent.setHgap(10);
selectionContent.setVgap(10);
//selectionContent.setPadding(new Insets(15,0,0,0)); //<-- Uncomment to achieve what is shown in Image B.
selectionScroller.setMinHeight(280);
selectionScroller.setPrefSize(Double.MAX_VALUE , Double.MAX_VALUE);
The thumbnails consist of:
mediaPanel = mSP;
parentStage = stage;
parentScene = scene;
mainStyle = mS;
backgroundStyle = bS;
highlightBackgroundStyle = hBS;
root.setPrefSize(100, 140);
//root.setOpaqueInsets(new Insets(10, 10, 10, 10));
root.setTop(topInfoRow);
root.setCenter(view);
root.setBottom(keySelector);
topInfoRow.setLeft(timeLabel);
topInfoRow.setCenter(testButton);
topInfoRow.setRight(closeButton);
closeButton.setAlignment(Pos.CENTER_RIGHT);
closeButton.setGraphic(closeButtonView);
view.setVisible(true);
view.setFitWidth(130);
view.setFitHeight(100);
keySelector.setEditable(false);
keySelector.setFocusTraversable(false);
keySelector.setText("No Key");
Progress
I have made a bit of progress with answering this question.
The scrollPane is actually added to a BorderPane layout, right in the "Centre". By default, there are margins between components in the BorderPane (I don't know how to change this!). But if I simply add in something to the "Top" of the BorderPane, the problem is resolved.
The BorderPane Layout:
Seemingly, adding something in the top pushes down the scrollPaneby the ~15 pixels which are causing the problem. So it's as if originally the scrollPane was occupying the area at the "Top" which it shouldn't have been doing so.
After Adding some Text to the "Top"
(This is a longshot but I'm assuming you're looking for clues, rather than a fixed code - since you went for screenshots rather than MCVE, as others say.)
I would look outside your scrollPane code, at how the scene is set up and how java code and CSS interact (ifterfere?). Padding is set by both Java code and CSS. Even if you don't set CSS there appears to be some predefined styling applied by the browser.
See this, for example:
JavaFX: Cannot set font size programmatically after font being set by CSS
(Sergey Grinev's answer)
The JavaFX CSS implementation applies the following order of precedence; a style from a user agent style sheet has lower priority than a value set from code, which has lower priority than a Scene or Parent style sheet. Inline styles have highest precedence.
Related
I have a scrollrect object on a UI canvas that has a viewport object child, and the viewport object has a content object child that stores all of the items to be scrolled.
I have selected the viewport for reference. I want to resize the viewport rect relative to LevelScroller (see hierarchy) in order for there to be a margin around the scrollview, so that the scrolling items do not touch the edge of the gray LevelScroller rect. But the viewport rect is not resizeable. Right now the result is this:
See how the button at the top (1S-Levitation) is cut off by the grey panel. I want there to be a margin between the point where it is cut off and the gray box.
I have tried adding a horizontal layout group to LevelScroller to forcibly add a margin, but this did not work. Why is the viewport not resizeable?
Any help is appreciated
I believe that the viewport is not resizable because it is supposed to manage how your scroll will behave during the user interaction. As an example, you have only one cell in your content container and the user drag it down, once it is released it is supposed to move back to the top of your viewport, and if you put a margin in there it will not be capable of move entirely back to the top.
But hopefully you can do the following trick to have your margin:
Create an empty game object called Scroller and set it as the father of your LevelScroller. Then, set your LevelScroller RectTransform to stretch in both directions, and set the desired margin on the RectTransform Top, Bottom, Right and Left fields. You should have something like this:
LevelScroller as a child with 10 pixels of top and bottom margin
Then create another empty object child of your parent Scroller, and put it behind the LevelScroller. Lets call it BgImage. Now, set the RectTransform of BgImage to stretch in both directions and add an image to it. Ta daaa, you should have now your background with your margins on your viewport.
BgImage working as the background of the LevelScroller
I have several icons on my toolbar. One of which (highlighted in red) seem to 'drift' into position when view is rendered as if the flexible space kicks in after the image is rendered. Also, the image kind of moves from the adjacent button's top left corner (the filter icon) into position.
This only happens if the app is launched when an update became available while the app was either terminated or was in the background. While I do not understand why, it seems that rendering the default icon in viewDidLoad, followed by server status check and a change of image is the sequence that causes the issue.
Any thought what might cause this behaviour will be appreciated!
Code is very simple:
if newDataAvailbleOnServer() {
myBarButton.image = cloudWithArrowImage
} else {
myBarButton.image = simpleCloudImage
}
both images are of the same size and density.
The new Unity 4.6 comes with a new GUI, when I change de resolution on Unity the UI Button scales perfectly but when I test on the Nexus 7 device the Button looks too small. Any idea how to solve this?
Unity's new GUI system uses "anchors" to control how gui elements (like buttons) scale in relation to their parent container.
Unity has a tutorial video on how to use the new "Rect Transform" component (where the anchors are configured) here: http://unity3d.com/learn/tutorials/modules/beginner/ui/rect-transform.
The last half of the tutorial is all about anchors. That page has links to the entire tutorial series. It's not too long. You should watch the whole thing.
Specific to your question:
The anchors are visible in your first screen shot. They are those 4 little arrows at the top left of your button.
Right now, your button is only anchored by it's top left corner.
The two right anchors need to be dragged to the right so that the right edge of your button is anchored to a space inside its parent container.
Depending on your situation, the two bottom arrows may need to be dragged down so that the bottom edge of your button is anchored as well.
The video I linked above covers all this in detail.
Lastly, for the font size to scale nicely on different resolutions, you will need to add and configure a reference resolution component to the base canvas of your UI, as Ash-Bash32 wrote earlier.
Update: The best way to add a Reference Resolution component is through the inspector window for the base canvas in your UI.
1) click the "Add Component Button" at the bottom of the inspector.
2) type the word "Reference" in the search filter field.
3) select the "Reference Resolution" component in the search results.
The Reference Resolution is now renamed as Canvas Scaler.. Along with the renaming they have added many more features for the dynamicity of the Canvas. You can go through the Unity Doc of Canvas Scaler and also take a look at this article for a practical example of how and why to use Canvas Scaler. Also make sure you use the Anchor Points to good effect to make this more robust...
To Scale UI added the ReferenceResolution Component to the Canvas you want to scale.
P.S. Theres no Documention for ReferenceResolution
If you want the button to be the same size for all screens and resolutions, you have to add the canvas scaler component to the canvas and the set the screen match mode to: match width or height, here is the link to the docs, this helps a lot if you want to aim to different sizes or resolutions:
http://docs.unity3d.com/Manual/HOWTO-UIMultiResolution.html
This becomes giant and convoluted once you start laying things out in code AND using a canvas scaler, so I wish to provide a thorough answer to save someone the hours I went through.
First, don't use anchoredPosition to position anything, unless you fully realize it is a 0.0 to 1.0 number. Use the RectTransform localPosition to do the actual laying out, and remember it's in relation to the parent anchor. (I had to lay out a grid from the center)
Second, put a canvas scaler on the parent layout object AND the inner ui pieces. One makes the layout in the right position, the other will resize your elements so they actually show up right. You can't rely on the the parent unless the children also have scalers (and Graphic Raycasters to touch them).
Third, if you have a scaler, DON'T use Screen.width and height, instead assume the screen is the same value you put for the scalers (hopefully you used the same, or know what you're doing). The screen width always returns the actual device pixels, retina devices too, but the canvas scalers DO NOT account for this. This probably gives unity the one remaining way to find actual screen dpi if your game wants it. Edit: This paragraph applies to any parent canvas connected to the code doing your laying out. Not stray canvases, you can probably mix it up. Just remember unity's guidelines on performance with canvases.
Fourth, the canvas is still a bit buggy. Even with the above working, some things don't render until you delete and recreate a canvas, if you re-open the scene or it crashes. Otherwise, the above is the general "rules" I've found.
To center a "grid of things" you can't just use half of the canvas scaler's width or height, you have to calculate the height of your grid and set the offset by half of it, otherwise it will always be slightly off. I just added this as an extra tip. This calculation works for all orientations.
I have a borderPane with a menu top,a grid left and an image in the center.I want the image to have the same size as the center of the border because now the image goes over my grid.
I tried this:
imageView.fitWidthProperty().bind(box.widthProperty());
where imageView is the name for my image and box is the BorderPane object.Thank you.
See JavaFX Feature Request RT-21337 Add ImageViewPane and MediaViewPane controls which contains a code attachment for a sample ImageViewPane implementation which which will resize the ImageView it contains to the area available to the region. To get the behaviour required you might also need to implement computeMinWidth and computeMinHeight on the ImageViewPane so that they return zero rather than the minimum size of the Image.
now the image goes over my grid
This is because the minimum size of your image is currently larger than the available space of the center of your BorderPane:
BorderPane does not clip its content by default, so it is possible that childrens' bounds may extend outside its own bounds if a child's min size prevents it from being fit within it space.
Some potential alternatives to prevent the center content overflowing the border:
Manually set a clip on the center node to prevent it overflowing the borders.
Dynamically resize the ImageView as in the ImageViewPane sample linked above.
Place the ImageView in a ScrollPane.
Use the css -fx-background-image attributes to display and dynamcially resize your image rather than using an ImageView.
Set the center of the borderpane first before setting the border content, that way it will be rendered underneath the border content.
Use a different construct from a borderpane (e.g. a HBoxes, VBoxes, etc.) which don't overlap their nodes when the nodes are larger than the available display area.
I tried this: imageView.fitWidthProperty().bind(box.widthProperty());
My guess from the code provided is that this didn't work because the enclosing box of the image is a dynamically resizable pane of some sort, so the minimum width of the box is being determined by the width of the image and not vice versa.
I was looking for a custom image grid and found a similar question that had a really sweet component in an answer.
I downloaded the code and after some fiddling, I managed to get it to compile in DXE2. It looks really cool, but I can't get either scrollbar to show up. I also can't figure out how to dynamically control the images displayed. Or how to update the grid based on keyboard events.
Also, to get it to compile I had to remove the GR32 references; the library I downloaded had too many incompatibilities with DXE2 for me to resolve.
Any help would be greatly appreciated. This really looks like a killer component.
Update from Bill:
Here is a screenshot of incorrect thumbnail painting. I can not get the thumbnails to look like the screenshot from the component in question.
If the thumbnails were painted at the same XY as the rects painted in the first pass they would look much better. Any idea on what is going on?
... but I can't get either scrollbar to show up.
Well, there is no horizontal scrollbar. There is the property ColWidth that controls how much images are drawn in one row, depending on the control's width. You might update ColWidth in an OnResize event handler due to anchor settings, for example.
The vertical scroll bar appears automatically when not all images (incl. spacing) fit in the clientrect. The images are drawn on a TPaintBox and that paint box' size is updated as soon as the image count changes:
procedure TImageGrid.RearrangeImages;
begin
...
FPainter.Height := Max(ClientHeight,
FRowCount * (FRowHeight + FImageSpacing) - FImageSpacing);
The component inherites from TScrollingWinControl, so the scroll bar should modify accordingly. If not, then Bill has a workaround found as commented:
VertScrollBar.Range := FRowCount * (FRowHeight + FImageSpacing) - FImageSpacing;
I understand this obviously also works, but I really wonder why the scroll bar's range should be modified manually. Here in D7 I have no problem with a hidden vertical scroll bar.
... I also can't figure out how to dynamically control the images displayed. ...
The most easy way to fill the component is by assigning the Folder property to a path with images. Only the images with the file formats in the FileFormats property will be loaded. To specify the images manually (e.g. to combine multiple folders), use the FileNames property. When the Folder property is set, then the FileNames property is updated accordingly, but those file names are not stored in the DFM. When you change the file names (e.g. you delete one from the folder), then the Folder property is cleared and the component uses the FileNames property instead.
... Or how to update the grid based on keyboard events. ...
The only keystrokes currently implemented are Up, Down, PageUp, PageDown, Home and End which all scroll the control. What more key actions do you wish? It's a viewer.
Here is a screenshot of incorrect thumbnail painting. I can not get the thumbnails to look like the screenshot from the component in question. ... If the thumbnails were painted at the same XY as the rects painted in the first pass they would look much better.
While loading the images, a temporary rect is drawn with size ColWidth * RowHeight. All images are stretchdrawn within that size, so adjust your ratio of these properties to make the spacing equal everywhere. Note that you can also influence appearance with the ImageHorzAlign and ImageVertAlign properties.
Update:
The component you refer to is recently completely rewritten, and some of the answers above are outdated.
It now has a Propertional property that defaults to True, but when set False, it will stretch up the thumbs to whatever cell size you have set, independent from the original image sizes. Small images could remain narow though, unless you set the new Stretch property to True.
It now distinguishes between RowHeight and CellHeight, and ColWidth and CellWidth. The difference between both is CellSpacing.
The component does not descend from TScrollingWinControl anymore, but from TCustomControl and only the vertical scroll bar is added.