我有一個帶有多個選項卡的Tabpane。 我想通過在特定位置拖動標籤來重新定位標籤(就像我們能夠在瀏覽器中安排標籤的方式一樣)。 我有什麼辦法可以實現它嗎?JavaFX標籤定位鼠標拖放
回答
我們以略微不同的方式實現了它。取代拖放功能,我們在選項卡上下文菜單中提供了左移/右移功能,然後輪流移動選項卡。 我們希望優先考慮這個功能,以便現在使用此解決方案來實現它。對於MoveRight的
代碼片段:
public void moveRight() {
protected TabPane workBook;
int cTabIndex = bem.workBook.getTabs().indexOf(bem.activeSheet);
int tabCount = workBook.getTabs().size();
if (tabCount > 1 && cTabIndex > 0) {
workBook.getTabs().remove(bem.activeSheet);
workBook.getTabs().add(cTabIndex - 1, bem.activeSheet);
}
}
一個非常描述這個問題,可以發現在這裏你可以爲同一個創建自定義選項卡:
http://0divides0.wordpress.com/2010/10/21/movable-tabbed-panes-in-javafx/
一個JavaFX煮熟的解決方案是很難找到,因爲開發的博客同樣指出,這些功能對於選項卡不存在,並且他們計劃在稍後進行合併。
http://grokbase.com/p/openjdk/openjfx-dev/123fq9k310/draggable-tabs
更新2016年2月
有一個開放的功能要求,你可以用它來追蹤落實:
功能請求當前計劃在Java 9中實現。用於獲取拖放功能的修補程序附加到功能請求。
拖放進行標籤標題是不是在基本的JavaFX 2.2平臺上實現。
在標準JDK中實現之前,您需要使用JavaFX的Drag and Drop functionality自己實現該功能。一個類似的功能是實現拖動表格列標題,所以也許你可以看看TableColumnHeader.java代碼靈感實現你的功能。
如果你實施它(如果你願意的話),你可以通過TabSkin.java源代碼補丁將修改內容返回OpenJFX。
,我實現了同時處理拖動和可拆卸的標籤一類 - 更多詳情here。這個實現並不是最簡單的,也不是最有彈性的,但對於我迄今爲止嘗試過的簡單案例來說,這種實現非常有效。我故意將所有內容都放在一個類中,以便其他人能夠在他們認爲合適的情況下複製/使用/修改。
我使用的基本概念(可以說是誤用)是,您可以在選項卡上設置的圖形可以是任何節點,而不僅僅是一個ImageView
(或類似的)。)因此,我不直接使用Tab
上的setText()
,而是根本不添加任何文本,只是將圖形設置爲包含所需文本的Label
。現在標籤出現在標籤頁頭中(幾乎是空間上的標籤頁頭),這使得它更容易(和皮膚無關)獲取窗格中每個標籤頁頭的全局座標。從那時起,只需要一些相對簡單的定位邏輯來確定何時將標籤分離到新窗口,何時重新添加標籤以及何時對其重新排序。
當然,這不是一個理想的解決方案,但不幸的是我還沒有看到這方面的其他內容!
import java.util.HashSet;
import java.util.Set;
import javafx.collections.ListChangeListener;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
/**
* A draggable tab that can optionally be detached from its tab pane and shown
* in a separate window. This can be added to any normal TabPane, however a
* TabPane with draggable tabs must *only* have DraggableTabs, normal tabs and
* DrragableTabs mixed will cause issues!
* <p>
* @author Michael Berry
*/
public class DraggableTab extends Tab {
private static final Set<TabPane> tabPanes = new HashSet<>();
private Label nameLabel;
private Text dragText;
private static final Stage markerStage;
private Stage dragStage;
private boolean detachable;
static {
markerStage = new Stage();
markerStage.initStyle(StageStyle.UNDECORATED);
Rectangle dummy = new Rectangle(3, 10, Color.web("#555555"));
StackPane markerStack = new StackPane();
markerStack.getChildren().add(dummy);
markerStage.setScene(new Scene(markerStack));
}
/**
* Create a new draggable tab. This can be added to any normal TabPane,
* however a TabPane with draggable tabs must *only* have DraggableTabs,
* normal tabs and DrragableTabs mixed will cause issues!
* <p>
* @param text the text to appear on the tag label.
*/
public DraggableTab(String text) {
nameLabel = new Label(text);
setGraphic(nameLabel);
detachable = true;
dragStage = new Stage();
dragStage.initStyle(StageStyle.UNDECORATED);
StackPane dragStagePane = new StackPane();
dragStagePane.setStyle("-fx-background-color:#DDDDDD;");
dragText = new Text(text);
StackPane.setAlignment(dragText, Pos.CENTER);
dragStagePane.getChildren().add(dragText);
dragStage.setScene(new Scene(dragStagePane));
nameLabel.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
dragStage.setWidth(nameLabel.getWidth() + 10);
dragStage.setHeight(nameLabel.getHeight() + 10);
dragStage.setX(t.getScreenX());
dragStage.setY(t.getScreenY());
dragStage.show();
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
tabPanes.add(getTabPane());
InsertData data = getInsertData(screenPoint);
if(data == null || data.getInsertPane().getTabs().isEmpty()) {
markerStage.hide();
}
else {
int index = data.getIndex();
boolean end = false;
if(index == data.getInsertPane().getTabs().size()) {
end = true;
index--;
}
Rectangle2D rect = getAbsoluteRect(data.getInsertPane().getTabs().get(index));
if(end) {
markerStage.setX(rect.getMaxX() + 13);
}
else {
markerStage.setX(rect.getMinX());
}
markerStage.setY(rect.getMaxY() + 10);
markerStage.show();
}
}
});
nameLabel.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
markerStage.hide();
dragStage.hide();
if(!t.isStillSincePress()) {
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
TabPane oldTabPane = getTabPane();
int oldIndex = oldTabPane.getTabs().indexOf(DraggableTab.this);
tabPanes.add(oldTabPane);
InsertData insertData = getInsertData(screenPoint);
if(insertData != null) {
int addIndex = insertData.getIndex();
if(oldTabPane == insertData.getInsertPane() && oldTabPane.getTabs().size() == 1) {
return;
}
oldTabPane.getTabs().remove(DraggableTab.this);
if(oldIndex < addIndex && oldTabPane == insertData.getInsertPane()) {
addIndex--;
}
if(addIndex > insertData.getInsertPane().getTabs().size()) {
addIndex = insertData.getInsertPane().getTabs().size();
}
insertData.getInsertPane().getTabs().add(addIndex, DraggableTab.this);
insertData.getInsertPane().selectionModelProperty().get().select(addIndex);
return;
}
if(!detachable) {
return;
}
final Stage newStage = new Stage();
final TabPane pane = new TabPane();
tabPanes.add(pane);
newStage.setOnHiding(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent t) {
tabPanes.remove(pane);
}
});
getTabPane().getTabs().remove(DraggableTab.this);
pane.getTabs().add(DraggableTab.this);
pane.getTabs().addListener(new ListChangeListener<Tab>() {
@Override
public void onChanged(ListChangeListener.Change<? extends Tab> change) {
if(pane.getTabs().isEmpty()) {
newStage.hide();
}
}
});
newStage.setScene(new Scene(pane));
newStage.initStyle(StageStyle.UTILITY);
newStage.setX(t.getScreenX());
newStage.setY(t.getScreenY());
newStage.show();
pane.requestLayout();
pane.requestFocus();
}
}
});
}
/**
* Set whether it's possible to detach the tab from its pane and move it to
* another pane or another window. Defaults to true.
* <p>
* @param detachable true if the tab should be detachable, false otherwise.
*/
public void setDetachable(boolean detachable) {
this.detachable = detachable;
}
/**
* Set the label text on this draggable tab. This must be used instead of
* setText() to set the label, otherwise weird side effects will result!
* <p>
* @param text the label text for this tab.
*/
public void setLabelText(String text) {
nameLabel.setText(text);
dragText.setText(text);
}
private InsertData getInsertData(Point2D screenPoint) {
for(TabPane tabPane : tabPanes) {
Rectangle2D tabAbsolute = getAbsoluteRect(tabPane);
if(tabAbsolute.contains(screenPoint)) {
int tabInsertIndex = 0;
if(!tabPane.getTabs().isEmpty()) {
Rectangle2D firstTabRect = getAbsoluteRect(tabPane.getTabs().get(0));
if(firstTabRect.getMaxY()+60 < screenPoint.getY() || firstTabRect.getMinY() > screenPoint.getY()) {
return null;
}
Rectangle2D lastTabRect = getAbsoluteRect(tabPane.getTabs().get(tabPane.getTabs().size() - 1));
if(screenPoint.getX() < (firstTabRect.getMinX() + firstTabRect.getWidth()/2)) {
tabInsertIndex = 0;
}
else if(screenPoint.getX() > (lastTabRect.getMaxX() - lastTabRect.getWidth()/2)) {
tabInsertIndex = tabPane.getTabs().size();
}
else {
for(int i = 0; i < tabPane.getTabs().size() - 1; i++) {
Tab leftTab = tabPane.getTabs().get(i);
Tab rightTab = tabPane.getTabs().get(i + 1);
if(leftTab instanceof DraggableTab && rightTab instanceof DraggableTab) {
Rectangle2D leftTabRect = getAbsoluteRect(leftTab);
Rectangle2D rightTabRect = getAbsoluteRect(rightTab);
if(betweenX(leftTabRect, rightTabRect, screenPoint.getX())) {
tabInsertIndex = i + 1;
break;
}
}
}
}
}
return new InsertData(tabInsertIndex, tabPane);
}
}
return null;
}
private Rectangle2D getAbsoluteRect(Control node) {
return new Rectangle2D(node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getX() + node.getScene().getWindow().getX(),
node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getY() + node.getScene().getWindow().getY(),
node.getWidth(),
node.getHeight());
}
private Rectangle2D getAbsoluteRect(Tab tab) {
Control node = ((DraggableTab) tab).getLabel();
return getAbsoluteRect(node);
}
private Label getLabel() {
return nameLabel;
}
private boolean betweenX(Rectangle2D r1, Rectangle2D r2, double xPoint) {
double lowerBound = r1.getMinX() + r1.getWidth()/2;
double upperBound = r2.getMaxX() - r2.getWidth()/2;
return xPoint >= lowerBound && xPoint <= upperBound;
}
private static class InsertData {
private final int index;
private final TabPane insertPane;
public InsertData(int index, TabPane insertPane) {
this.index = index;
this.insertPane = insertPane;
}
public int getIndex() {
return index;
}
public TabPane getInsertPane() {
return insertPane;
}
}
}
以下代碼顯示瞭如何以非常簡單的方式解決問題而無需技巧。
.....
.....
Tab tab1 = new Tab("Tab1");
Tab tab2 = new Tab("Tab21");
TabPane tabPane = new TabPane(tab1, tab21);
root.getChildren().add(tabPane);
....
....
System.out.println("Tabs size()= " + tabPane.lookupAll(".tab").size());
tabPane.lookupAll(".tab").forEach(t -> {
System.err.println("tab.bounds = " + t.getLayoutBounds());
});
您可以使用樣式類,如標籤內容區域,標籤頭區域,標籤頭背景,標題區域,控制按鈕標籤得到TabPane的其他地區的訪問。只需使用lookup或lookup TabPane的所有方法
- 1. 鼠標拖放
- 2. jQuery UI拖放鼠標位置問題
- 3. jQuery ui在鼠標位置拖放
- 4. javafx拖放默認圖標
- 5. C#拖放標籤
- 6. 拖放鼠標捕獲
- 7. 拖放和鼠標事件
- 8. WinForms拖放:標籤在跟隨鼠標前「跳開」
- 9. JavaFx 8 - 相對於鼠標位置縮放/縮放ScrollPane
- 10. 圖形32:用鼠標拖動,用鼠標滾輪縮放到鼠標光標
- 11. 當我拖動鼠標時,鼠標返回到原位
- 12. 拖放阻止預覽鼠標上移
- 13. 拖放和鼠標設計模式?
- 14. Listview拖放 - 鼠標與觸摸
- 15. 鼠標拖動未返回鼠標
- 16. 鼠標釋放時的抓取元素位置jQuery可拖動
- 17. 在拖放過程中獲取鼠標位置
- 18. SWTBot拖動鼠標
- 19. 如何在鼠標懸停放置目標時更改拖放光標
- 20. JavaFX - 拖放TableCell
- 21. Javafx拖放TabPane
- 22. 鎖定鼠標位置
- 23. JavaFX 2塊鼠標屬性
- 24. HTML標籤定位
- 25. div標籤內的div標籤定位
- 26. 如何在拖放過程中更改鼠標光標?
- 27. 在QGraphicScene上拖放 - 在控件中心的鼠標光標
- 28. Winforms拖放標籤的形式
- 29. 放置在鼠標上方的jvectormap標記標籤IE
- 30. 拖動,拖放,插入鼠標指針 - > HTML5
@Anshul,請創建一個描述你如何解決這個問題的答案。 – jewelsea 2013-05-10 06:22:41
我想現在你不知道在這方面做更好的做法嗎?我沒有發現任何東西,因此創建了我自己的基本解決方案(請參閱我的答案),但我知道它肯定有它的缺陷,所以想知道是否會遇到任何其他外部庫這樣做! – berry120 2014-02-01 01:55:17
對不起貝瑞,還沒有見過什麼。這將是一個很好的功能進入核心平臺。 – jewelsea 2014-02-01 03:23:13