How to know if a scroll bar is visible on a JavaFx TableView - javafx

Is there a way to know if a scroll bar is present on a table view? (Other than what I did in my code below)
My goal is to position 2 arrow images (to close/open a side panel) on the right side of a table (over the table.). But I don't want to put them over the scroll bar.
The table content is a result of a search, so sometime the scroll bar is visible and other time it is not. If there is not enough items.
I want the position of my arrows to change every time the tableview items change.
I already try the following solution, but the result is that the arrows are moved the second time I do the search. Looks like a concurrency problem. Like if my listener code is executed before the table is rendered.
Is there a way to solve that?
tableView.getItems().addListener( (ListChangeListener<LogData>) c -> {
// Check if scroll bar is visible on the table
// And if yes, move the arrow images to not be over the scroll bar
Double lScrollBarWidth = null;
Set<Node> nodes = tableView.lookupAll( ".scroll-bar" );
for ( final Node node : nodes )
{
if ( node instanceof ScrollBar )
{
ScrollBar sb = (ScrollBar) node;
if ( sb.getOrientation() == Orientation.VERTICAL )
{
LOGGER.debug( "Scroll bar visible : {}", sb.isVisible() );
if ( sb.isVisible() )
{
lScrollBarWidth = sb.getWidth();
}
}
}
}
if ( lLogDataList.size() > 0 && lScrollBarWidth != null )
{
LOGGER.debug( "Must move the arrows images" );
tableViewController.setArrowsDistanceFromRightTo( lScrollBarWidth );
}
else
{
tableViewController.setArrowsDistanceFromRightTo( 0d );
}} );

I assume you know that it is not a good idea to rely on the internal implementation of TableView. Having said that, you're code looks mostly good (I did a similar thing for an infinite scrolling example).
However you should also consider the case that the scrollbar may appear due to the main window changing its size.
I would therefore suggest you listen to changes in the visibilty-property of the scrollbar.
private ScrollBar getVerticalScrollbar() {
ScrollBar result = null;
for (Node n : table.lookupAll(".scroll-bar")) {
if (n instanceof ScrollBar) {
ScrollBar bar = (ScrollBar) n;
if (bar.getOrientation().equals(Orientation.VERTICAL)) {
result = bar;
}
}
}
return result;
}
...
bar.visibleProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
// tableViewController.setArrowsDistanceFromRightTo(...)
}
);

Related

TreeView scrolling jumps when using large graphic nodes (TornadoFX/JavaFX)

In the following TornadoFX/Kotlin code
import javafx.scene.control.TreeItem
import javafx.scene.control.TreeView
import tornadofx.*
class MyObj {
var type : Int = 0
constructor(type : Int) {
this.type = type
}
}
class MainView: View("Minimal TV demo") {
var treeRoot : TreeItem<MyObj> = TreeItem()
var objectsTreeView : TreeView<MyObj>? = null
override val root = vbox {
objectsTreeView = treeview(treeRoot) {
showRootProperty().value = false
cellFormat {
if(it.type == 0) {
text = "Test"
graphic = null
}
else {
text = null
graphic = vbox {
label("Label 1")
button("123")
textarea {
prefWidth = 100.0
prefHeight = 125.0
}
}
}
}
}
}
init {
with (root) {
for(i in 1..10) {
val x = TreeItem(MyObj(0))
treeRoot.children.add(x)
x.children.add(TreeItem(MyObj(1)))
}
}
}
}
when opening a few of the tree items and scrolling the tree view, the tree view contents and slider seems to act rather "jumpy", i.e. when I move the slider down, the mouse moves but the slider and content stay where it is, until the mouse gets so far down, then the content jumps. It just doesn't feel or look good.
I believe I could get around this by adding separate TreeItem's for each UI element row, but is there a way to achieve a smooth scroll without doing this? I tried suing a fixed cell height, which seems to work, but of course this doesn't look right at all given that some rows a shorter than others.
Don't use cellFormat for complex tree UIs, since the elements will be recreated very rapidly and most probably cause flicker. Your best bet is to create a subclass of TreeCellFragment and configured it using the cellFragment call.
Now you can create the UI only once per Tree cell, and reuse it when the data it represents changes. This is much more performant.

Scrolling sets to top once new data is appended to wijmo-grid in virtual scrolling

While implementing virtual scrolling with wijmo grid, as per the below code, when the new data is appended to data array (once we scroll and reach to the last record of the grid), the scroll gets reset to the initial position.
Check this JSFiddle
scrollPositionChanged: function(s, e) {
// if we're close to the bottom, add 10 items
if (s.viewRange.bottomRow >= s.rows.length - 1) {
addData(data, 20);
s.collectionView.refresh();
}
}
Any idea how can we stop this behaviour? Other grids like slickgrid, ag-grid provides smooth behaviour - once the data is appended, the previous last record stays in the view. Can we achieve similar kind of behaviour for wijmo-grid?
You can save scroll postion before refreshing the grid and restore the same after scroll.
var pos;
var grid = new wijmo.grid.FlexGrid('#flex', {
itemsSource: data,
scrollPositionChanged: function (s, e) {
// if we're close to the bottom, add 10 items
if (s.viewRange.bottomRow >= s.rows.length - 1) {
addData(data, 20);
//save current scroll postion
pos = grid.scrollPosition;
s.collectionView.refresh();
}
//restore scroll position
if (pos) {
s.scrollPosition = Object.assign({}, pos);
pos = null;
}
}
});
Check the updated fiddle:- http://jsfiddle.net/797tjc5u/
You need to store scroll position before making http request and set back once items have been added to FlexGrid.
Please refer to the following updated fiddle with http service delay simulation:
[http://jsfiddle.net/hwr2ra1q/41/][1]

Why mousewheel event is not working some times with my code?

I'm trying to make a fullpage component in Angular :
I want each sections take a 100% height of my screen, and when I scroll in a section (up or down) it goes to the next / previous section. I declared this function to do that, and it works :
#HostListener('wheel', ['$event'])
onScroll(event: WheelEvent) {
if (event.deltaY < 0) {
this.slidePrev();
} else {
this.slideNext();
}
}
Now, I want to update a little to slide to the previous slide only if the scrollbar is on the top, or slide to the next only if the scrollbar is to the bottom. I Used JQuery to do that, this way :
#HostListener('mousewheel', ['$event'])
onScroll(event: WheelEvent) {
if (this.isSliding) {
event.preventDefault();
return;
}
let $section = $(event.target).closest(".section");
//$section.css("opacity", "0.99");
//setTimeout(() => {
// $section.css("opacity", "1");
//}, 100);
if (event.deltaY < 0) {
if ($section.scrollTop() == 0) this.slidePrev();
} else {
if ($section.scrollTop() == $section.prop("scrollHeight") - $section.height()) this.slideNext();
}
}
It works the first time, but if I slide down to the next slide, when I want to sroll to move my scrollbar, it doesn't move.
I noticed that after the website trigger an update (example : css :hover event that update style) the scrollbar move again. So, if I uncomment my 4 commented lines, it works again because the style is updated.
Can someone tell me why ? And is there a better way to fix that issue ?
EDIT :
in slideNext() and slidePrev() I'm using $().animate("scrollTop", ...) function, and it's the function that breaks my scroll

Is it possible to arrows on a pageable container (visual composer)?

I'm working on my WordPress website with Visual Composer.
I need to include a pageable container but it would be great if it can be like a slideshow.
This is my pageable container
Thanks in advance,
Regards :)
Based upon the current version of WP Bakery Page Builder the below works for me:
To build it I created a row with 3 columns, with the pageable container in the middle column and the left and right arrow images in the columns on either side.
Both arrow images and the pageable container were given IDs. In my example the IDs of the arrows were #arrow_prev and #arrow_next respectively. You can give your pageable container any unique ID.
(function ($) {
$(document).ready(function(){
$( '#arrow_prev' ).click( function( e ) {
var pageable_container = $(this).closest(".vc_row").find(".vc_tta-panels-container");
move_pageable_container(pageable_container,'prev');
});
$( '#arrow_next' ).click( function( e ) {
var pageable_container = $(this).closest(".vc_row").find(".vc_tta-panels-container");
move_pageable_container(pageable_container,'next');
});
function move_pageable_container(pageable_container,direction){
// Make a list of the panel IDs
var panel_ids = $(pageable_container.find(".vc_tta-panel"))
.map(function() { return this.id; }) // convert to set of IDs
.get();
// Find position of the active panel in list
var current_active_pos = panel_ids.indexOf($(pageable_container).find(".vc_tta-panel.vc_active").attr('id'));
var new_pos = 0;
switch(direction) {
case 'prev':
if (current_active_pos > 0){
new_pos = current_active_pos-1;
}else{
new_pos = panel_ids.length-1;
}
break;
case 'next':
if (current_active_pos < panel_ids.length-1){
new_pos = current_active_pos+1;
}else{
new_pos = 0;
}
break;
}
// Clear active panels
$(pageable_container.find(".vc_tta-panel")).each(function(i,a) {
$(this).removeClass("vc_active");
});
var new_active_panel = $(pageable_container).find('#'+ panel_ids[new_pos]);
$(new_active_panel).addClass("vc_animating");
$(new_active_panel).addClass("vc_active");
setTimeout(
function(){
$(new_active_panel).removeClass("vc_animating");
}, 350);
}
}
);
})(jQuery);
If you want a pseudo fading-in effect then you can use this additional CSS in your style sheet:
#id_of_pageable_container .vc_tta-panel.vc_animating {
opacity: 0!important;
}
Where #id_of_pageable_container is the ID that you gave your pageable container
A simpler solution with vanilla js only:
The idea is to find the target page button and press it programmatically, so that there is no need to mimic the plugin's animations as in Chaz's solution.
Add js (via Raw JS widget / other means):
function prevSlide () {
const slides = document.getElementsByClassName('vc_pagination-item');
for (let i = 0; i < slides.length; i++) {
if (slides[i].className.includes('vc_active')) {
if (i - 1 < 0) return;
slides[i - 1].firstChild.click();
return;
}
}
}
function nextSlide () {
const slides = document.getElementsByClassName('vc_pagination-item');
for (let i = 0; i < slides.length; i++) {
if (slides[i].className.includes('vc_active')) {
if (i + 1 >= slides.length) return;
slides[i + 1].firstChild.click();
return;
}
}
}
Add button widgets and set href to call js:
For left arrow button,
javascript:prevSlide();
For right arrow button,
javascript:nextSlide();
Hope this helps.
I prefer to use the Post Grid widget for that. Keep in mind that the pageable container is not totally responsive, it doesn't react to swipe touching, but the Post Grid does.
Post Grid is really powerful, although it also has its caveouts. You can create your content with posts and pages, or a custom post type and then filter what you want to show in your slider from the widget options.
In "advanced mode" you can use the Grid Builder to create your own template and control the output.
The only problems that I've found with this method is to set a variable height in sliders and that sometimes it is slow loading content and is not possible to do a lazyload.

Algorithm to determine if a component is fully visible in Flex?

Is there a built in way to determine if a component is fully visible in a Flex application (i.e. not offscreen one way or the other). If not how would I go about figurin it out?
I want to show or hide additional 'next' and 'previous' buttons if my primary 'next' and 'previous' buttons are off screen.
What event would be best to listen to to 'recalculate' ? stage.resize?
thanks!
here is a method for calculating if the component is within the bounds of the stage, it will not however tell you if the component is being hidden by another component, or if the component is being hidden because it is outside the bounds of another container.
public function isComponentWithinStage(c:UIComponent):Boolean {
var tl:Point = c.localToGlobal(new Point(0, 0));
var br:Point = c.localToGlobal(new Point(c.width, c.height));
//are we off the left or top of stage?
if ( tl.x < 0 || tl.y < 0 ) {
return false;
}
var stage:Stage = Application.application.stage;
//off the right or bottom of stage?
if ( br.x > stage.width || br.y > stage.height ) {
return false;
}
return true;
}
Could you give the specifics of the visible item and the container(s) it's in? Is it a matter of having to scroll some container to get to the buttons? Or is it a matter of someone has dragged a child window of a flexlib:MDICanvas partially off screen?
I think it's going to come down to if the x,y position of the component is beyond the width and height of its container, (and so on up through the parent containers until you reach your top level Application.)

Resources