-
Bug
-
Resolution: Unresolved
-
P4
-
8, 9
-
generic
-
generic
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
OS X El Capitan 10.11.6
A DESCRIPTION OF THE PROBLEM :
I have a timer serving data onto a queue which is then read in the JavaFX thread and updates the TableView.
I seem to be able to stop the TableView scroll bar (the one that is automatically provided by the StackPane ) from responding to mouse clicks when I increase the timer frequency beyond a certain rate.
I have also added manually a scroll bar to the test program and this does not suffer from the same issue.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test program and try to scroll with the scroll bar for the TableView. It doesn't scroll.
The programmatically supplied scroll bar (which is in the middle of the TableView) doesn't exhibit this problem.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
TableView scroll bar should be able to be clicked by the mouse and scrolled up and down.
ACTUAL -
TableView scroll bar cannot be clicked and scrolled.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package mygroupid.myartifactid;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ListChangeListener;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TableViewSample extends Application
{
private static final int GUI_SERVE_TIMER_MS = 200;
private static final int DATA_ADD_TIMER_MS = 2;
private static final int NUM_TABS = 10;
private static final int NUM_COLUMNS = 15;
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage stage)
{
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(1200);
stage.setHeight(500);
createTabs(scene);
stage.setScene(scene);
stage.show();
}
private void createTabs(
final Scene scene)
{
final TabPane tabPane = new TabPane();
((Group) scene.getRoot()).getChildren().addAll(tabPane);
for (int i = 0 ; i < NUM_TABS ; ++i)
{
final StackPane basePane = new StackPane();
final Tab tab = new Tab(Integer.toString(i));
tab.setContent(basePane);
tabPane.getTabs().add(tab);
final MyTable myTable = new MyTable();
// add custom scrollbar
final ScrollBar scrollBar = new ScrollBar();
scrollBar.setMin(0);
scrollBar.setOrientation(Orientation.VERTICAL);
scrollBar.valueProperty().addListener((obs, o, n) ->
{
myTable.getTable().scrollTo(n.intValue());
});
myTable.getTable().itemsProperty().get().addListener(new ListChangeListener<String>()
{
@Override
public void onChanged(
javafx.collections.ListChangeListener.Change<? extends String> c)
{
scrollBar.setMax(c.getList().size());
}
});
basePane.getChildren().add(myTable.getTable());
basePane.getChildren().add(scrollBar);
}
}
private class MyTable
{
private TableView<String> mTable = new TableView<>();
private BlockingQueue<String> mDataQueue = new ArrayBlockingQueue<>(1000);
private int mCount;
public MyTable()
{
mTable.setFixedCellSize(24);
mTable.setEditable(true);
createColumns();
startPopulateListTimer();
startGuiServeTimer();
}
public TableView<String> getTable()
{
return mTable;
}
private void createColumns()
{
for (int i=0; i < NUM_COLUMNS; ++i)
{
TableColumn<String, String> col = new TableColumn<>(Integer.toString(i));
col.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue()));
mTable.getColumns().add(col);
}
}
private void startPopulateListTimer()
{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
mDataQueue.add(Integer.toString(mCount++));
}
}, DATA_ADD_TIMER_MS, DATA_ADD_TIMER_MS);
}
private void startGuiServeTimer()
{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
Platform.runLater(() ->
{
for (int i = 0; i < mDataQueue.size(); ++i)
{
mTable.getItems().add(mDataQueue.remove());
}
});
}
}, GUI_SERVE_TIMER_MS, GUI_SERVE_TIMER_MS);
}
}
}
---------- END SOURCE ----------
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
OS X El Capitan 10.11.6
A DESCRIPTION OF THE PROBLEM :
I have a timer serving data onto a queue which is then read in the JavaFX thread and updates the TableView.
I seem to be able to stop the TableView scroll bar (the one that is automatically provided by the StackPane ) from responding to mouse clicks when I increase the timer frequency beyond a certain rate.
I have also added manually a scroll bar to the test program and this does not suffer from the same issue.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test program and try to scroll with the scroll bar for the TableView. It doesn't scroll.
The programmatically supplied scroll bar (which is in the middle of the TableView) doesn't exhibit this problem.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
TableView scroll bar should be able to be clicked by the mouse and scrolled up and down.
ACTUAL -
TableView scroll bar cannot be clicked and scrolled.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package mygroupid.myartifactid;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ListChangeListener;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TableViewSample extends Application
{
private static final int GUI_SERVE_TIMER_MS = 200;
private static final int DATA_ADD_TIMER_MS = 2;
private static final int NUM_TABS = 10;
private static final int NUM_COLUMNS = 15;
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage stage)
{
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(1200);
stage.setHeight(500);
createTabs(scene);
stage.setScene(scene);
stage.show();
}
private void createTabs(
final Scene scene)
{
final TabPane tabPane = new TabPane();
((Group) scene.getRoot()).getChildren().addAll(tabPane);
for (int i = 0 ; i < NUM_TABS ; ++i)
{
final StackPane basePane = new StackPane();
final Tab tab = new Tab(Integer.toString(i));
tab.setContent(basePane);
tabPane.getTabs().add(tab);
final MyTable myTable = new MyTable();
// add custom scrollbar
final ScrollBar scrollBar = new ScrollBar();
scrollBar.setMin(0);
scrollBar.setOrientation(Orientation.VERTICAL);
scrollBar.valueProperty().addListener((obs, o, n) ->
{
myTable.getTable().scrollTo(n.intValue());
});
myTable.getTable().itemsProperty().get().addListener(new ListChangeListener<String>()
{
@Override
public void onChanged(
javafx.collections.ListChangeListener.Change<? extends String> c)
{
scrollBar.setMax(c.getList().size());
}
});
basePane.getChildren().add(myTable.getTable());
basePane.getChildren().add(scrollBar);
}
}
private class MyTable
{
private TableView<String> mTable = new TableView<>();
private BlockingQueue<String> mDataQueue = new ArrayBlockingQueue<>(1000);
private int mCount;
public MyTable()
{
mTable.setFixedCellSize(24);
mTable.setEditable(true);
createColumns();
startPopulateListTimer();
startGuiServeTimer();
}
public TableView<String> getTable()
{
return mTable;
}
private void createColumns()
{
for (int i=0; i < NUM_COLUMNS; ++i)
{
TableColumn<String, String> col = new TableColumn<>(Integer.toString(i));
col.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue()));
mTable.getColumns().add(col);
}
}
private void startPopulateListTimer()
{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
mDataQueue.add(Integer.toString(mCount++));
}
}, DATA_ADD_TIMER_MS, DATA_ADD_TIMER_MS);
}
private void startGuiServeTimer()
{
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
Platform.runLater(() ->
{
for (int i = 0; i < mDataQueue.size(); ++i)
{
mTable.getItems().add(mDataQueue.remove());
}
});
}
}, GUI_SERVE_TIMER_MS, GUI_SERVE_TIMER_MS);
}
}
}
---------- END SOURCE ----------