基本上我尝试实现这种行为,当从treeView拖动一个项目并且在treeView的底部或顶部时,treeView将自动向下或向上滚动。
到目前为止,我只需要扩展TreeView并向其添加onMouseDragged事件处理程序。像这样
public ExtendedTreeView()
{
super();
setOnMouseDragged((MouseEvent event) -> onMouseMoved(event));
}
事件处理程序看起来像这样(系统输出基本上仅用于调试目的)
private void onMouseMoved(MouseEvent event)
{
System.out.println("onMouseMoved-----------------------------------------------------------------");
System.out.println(event.getEventType().toString());
// -----only apply when there is a drag event in progress
if(event.getEventType().equals(MouseEvent.MOUSE_DRAGGED))
{
// -----first check if we are the scrollEdges
System.out.println(String.format("Size: %f : %f", getWidth(), getHeight()));
System.out.println(String.format("Bounds: %f : %f : %f : %f", _scrollBounds.getTop(), _scrollBounds.getRight(), _scrollBounds.getBottom(), _scrollBounds.getLeft()));
System.out.println(String.format("Node: %f : %f", event.getX(), event.getY()));
//-----up and down directions are preferred
ScrollDirection direction = ScrollDirection.None;
if(event.getY() <= _scrollBounds.getTop())
direction = ScrollDirection.Top;
else if(event.getY() >= _scrollBounds.getBottom())
direction = ScrollDirection.Bottom;
else if(event.getX() >= _scrollBounds.getRight())
direction = ScrollDirection.Right;
else if(event.getX() <= _scrollBounds.getLeft())
direction = ScrollDirection.Left;
System.out.println(String.format("Direction: %s", direction.toString()));
}
}
当我在TreeView中拖动并移动鼠标时,它会得到所需的结果。
问题是如何 只要我拖动一个实际项目,拖动事件只会发生一次,然后再也不会再发生。
该项目还有一个拖放处理,基本上是这样的。 请注意,这实际上是一个控制器,其中包含有关他所属的TreeCell的信息。
@FXML
public void onDragDetected(MouseEvent event)
{
Base item = getTreeCell().getItem();
Dragboard dragboard = getTreeCell().startDragAndDrop(TransferMode.MOVE);
//-----get info from the item and put it in the clipboard
dragboard.setContent(content);
//event.consume();
}
@FXML
public void onDragEntered(DragEvent event)
{
boolean acceptDrag = false;
Dragboard dragboard = event.getDragboard();
Base current = getTreeCell().getItem();
//-----get the info from the clipboard and do something with it
//-----essentially the acceptDrag will be set to true here
if((_isDragAccepted = acceptDrag))
{
event.acceptTransferModes(TransferMode.MOVE);
//event.consume();
}
}
@FXML
public void onDragOver(DragEvent event)
{
if(_isDragAccepted)
{
event.acceptTransferModes(TransferMode.MOVE);
//event.consume();
}
}
@FXML
public void onDragExited(DragEvent event)
{
_isDragAccepted = false;
//event.consume();
}
@SuppressWarnings("unchecked")
@FXML
public void onDragDropped(DragEvent event)
{
Dragboard dragboard = event.getDragboard();
TreeItem<Base> currentItem = getTreeCell().getTreeItem();
Base current = getTreeCell().getItem();
//-----get info from clipboard again and do the necessary stuff
//-----essentially an item will be transfered here from one node to another
event.setDropCompleted(true);
//event.consume();
}
我还从this链接
获得了有关javafx中事件处理的一些信息根据这个,如果事件没有消耗,它应该一直冒泡到源,因此如果不是它也应该传递TreeView?所以我真的想知道我在这里做错了什么。
答案 0 :(得分:4)
好的所以我弄清楚问题是什么,
我正在听错事件,我需要注册的事件是onDragOver事件而不是onMouseDragged事件。
因此,如果有人需要autoscrollTreeView,autoscroll treeView的最终解决方案现在看起来像这样:
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.DragEvent;
import com.sun.javafx.scene.control.skin.VirtualFlow;
@SuppressWarnings("restriction")
public class AutoscrollTreeView<T> extends TreeView<T>
{
// region Enumerations
private enum ScrollDirection
{
None, Top, Bottom
}
// endregion
// region Static
private static final double _milliSecondToSecondFactor = 1.0d / 1000.0d;
// endregion
// region Fields
/**
* the time interval in milliseconds in which the scroll is performed
*/
private final LongProperty _checkInterval = new SimpleLongProperty(50);
/**
* the actual scroll speed when being in the scroll areas
*/
private final DoubleProperty _scrollSpeed = new SimpleDoubleProperty(1.0);
/**
* the scroll speed increment per second the user remain in the scroll area
*/
private final DoubleProperty _scrollSpeedIncrementPerSecond = new SimpleDoubleProperty(0.0);
/**
* distance from the top, which defines the area which will start a scroll in the -y axis
*/
private final DoubleProperty _dragIdentifierTop = new SimpleDoubleProperty();
/**
* distance from the bottom, which defines the area which will start a scroll in the +y axis
*/
private final DoubleProperty _dragIdentifierBottom = new SimpleDoubleProperty();
/**
* time at which the user entered the any scroll area
*/
private long _initialDragTime = -1;
/**
* last time the interval was checked
*/
private long _lastCheck = -1;
// endregion
// region Constructor
public AutoscrollTreeView()
{
super();
addEventHandlers();
}
public AutoscrollTreeView(TreeItem<T> root)
{
super(root);
addEventHandlers();
}
// endregion
// region Getter/Setter
public final void setCheckInterval(long value)
{
_checkInterval.set(value);
}
public final long getCheckInterval()
{
return _checkInterval.get();
}
public final LongProperty checkIntervalProperty()
{
return _checkInterval;
}
public final void setScrollSpeed(double value)
{
_scrollSpeed.set(value);
}
public final double getScrollSpeed()
{
return _scrollSpeed.get();
}
public final DoubleProperty scrollSpeedProperty()
{
return _scrollSpeed;
}
public final void setScrollSpeedIncrementPerSecond(double value)
{
_scrollSpeedIncrementPerSecond.set(value);
}
public final double getScrollSpeedIncrementPerSecond()
{
return _scrollSpeedIncrementPerSecond.get();
}
public final DoubleProperty scrollSpeedIncrementPerSecondProperty()
{
return _scrollSpeedIncrementPerSecond;
}
public final void setDragIdentiferTop(double value)
{
_dragIdentifierTop.set(value);
}
public final double getDragIdentifierTop()
{
return _dragIdentifierTop.get();
}
public final DoubleProperty dragIdentifierTopProperty()
{
return _dragIdentifierTop;
}
public final void setDragIdentiferBottom(double value)
{
_dragIdentifierBottom.set(value);
}
public final double getDragIdentifierBottom()
{
return _dragIdentifierBottom.get();
}
public final DoubleProperty dragIdentifierBottomProperty()
{
return _dragIdentifierBottom;
}
// endregion
// region Events
private void onDragEvent(DragEvent event)
{
// -----only apply when there is a drag event in progress
if(event.getEventType().equals(DragEvent.DRAG_OVER))
{
if(_lastCheck == -1 || System.currentTimeMillis() - _lastCheck > _checkInterval.get())
{
ScrollDirection direction = ScrollDirection.None;
if(event.getY() <= _dragIdentifierTop.get())
direction = ScrollDirection.Top;
else if(event.getY() >= getHeight() - _dragIdentifierBottom.get())
direction = ScrollDirection.Bottom;
if(direction != ScrollDirection.None)
{
double additionalScrollSpeed = 0;
if(_initialDragTime > 0)
additionalScrollSpeed = _scrollSpeedIncrementPerSecond.get() * (System.currentTimeMillis() - _initialDragTime) * _milliSecondToSecondFactor;
else
_initialDragTime = System.currentTimeMillis();
if(direction == ScrollDirection.Bottom)
scrollY(_scrollSpeed.get() + additionalScrollSpeed);
else
scrollY(-(_scrollSpeed.get() + additionalScrollSpeed));
}
else
{
_initialDragTime = -1;
}
_lastCheck = System.currentTimeMillis();
}
}
else
{
_initialDragTime = -1;
_lastCheck = -1;
}
}
// endregion
// region Private
/**
* adds the necessary event filters
*/
private void addEventHandlers()
{
addEventHandler(DragEvent.DRAG_OVER, event -> onDragEvent(event));
addEventHandler(DragEvent.DRAG_EXITED, event -> onDragEvent(event));
addEventHandler(DragEvent.DRAG_DROPPED, event -> onDragEvent(event));
addEventHandler(DragEvent.DRAG_DONE, event -> onDragEvent(event));
}
private void scrollY(double offset)
{
VirtualFlow<?> flow = ((VirtualFlow<?>) lookup("VirtualFlow"));
flow.adjustPixels(offset);
}
// endregion
}