2017-12-15 16 views
1

私はスクロールペインの内側にタイル区画を持っています。タイルペインには、削除や編集のようなアクションを持つボタンがあります。ボタンを削除または編集した後、スクロールペインは自動的に先頭に戻りますが、これは嫌です。私はそれを現在の位置(ユーザーがスクロールした位置)のままにしておきたい。scrollPaneを目的のvValueに設定するにはどうすればよいですか?

スクロールペインのvValueを取得して設定しようとしました。 getvValueは値を取得し、setterはそれを設定しますが、スクロールペインはそれに応答せず、アクション(削除/編集)の後に最初に戻ります。私はこの質問からの解決策を試した:JavaFX ScrollPane setVvalue() not working as intendedしかし、レイアウト()メソッドは何もしません。私はここで間違って何をしていますか?スクロールペインをどこに残すには?

編集:私は問題を発見しましたが、それを修正する方法はまだ分かりません。どうやら、fxmlのhBoxesの可視性を設定して変更すると、スクロールペインが上に戻ります。 setVisibleメソッドを削除して実行すると、アイテムを削除でき、スクロールペインはそのままの位置にとどまります。これを修正するには?

ご要望に応じて、自分のコードの最小、完全、および検証可能な例を作成しました。それを実行し、少し下にスクロールし、名前と価格のボタンを右クリックしてから、「削除」をクリックします。それは上にスクロールバックします。

これは私のコードです:

public class Controller { 
private static LinkedHashMap<String, BigDecimal> mProductMap = new LinkedHashMap<>(); 

@FXML private TilePane fieldContainer = new TilePane(); 
@FXML private ScrollPane scroll; 
@FXML private Button deletebtn; 
@FXML private Button editbtn; 
@FXML private HBox homeBar; 
@FXML private HBox actionBar; 

@FXML 
private void initialize() { 
    addProduct("Coffee", new BigDecimal("2.00")); 
    addProduct("Tea", new BigDecimal("2.00")); 
    addProduct("Cappuccino", new BigDecimal("2.00")); 
    addProduct("Espresso", new BigDecimal("2.00")); 
    addProduct("Cooky", new BigDecimal("2.00")); 
    addProduct("Candy", new BigDecimal("2.00")); 
    addProduct("Chocobar", new BigDecimal("2.00")); 
    addProduct("Cola", new BigDecimal("2.00")); 
    addProduct("Fanta", new BigDecimal("2.00")); 
    addProduct("Beer", new BigDecimal("2.00")); 
    addProduct("Salad", new BigDecimal("2.00")); 
    addProduct("Sandwich", new BigDecimal("2.00")); 
    addProduct("Water", new BigDecimal("2.00")); 
    addProduct("Cassis", new BigDecimal("2.00")); 
} 

// makes the delete and edit buttons appear after selecting a button from the tilepane 
private void select(String selectedProduct) { 

    /* 
    the setVisible method for the hBoxes in fxml cause the scrollbar to go back to the top 
    without them, the scrollpane stays where it is. 
    I tried changing visibility with both setVisible and CSS, but they both cause the problem 
    I need the actionbar to appear when you select a button (right click on it) 
    */ 
    homeBar.setVisible(false); 
    actionBar.setVisible(true); 

    EventHandler<ActionEvent> delete = event -> { 
     deleteProduct(selectedProduct); // deletes an item from a LinkedHashMap 
     homeBar.setVisible(true); 
     actionBar.setVisible(false); 
    }; 
    deletebtn.setOnAction(delete); 

    // I want the same to happen when the edit handler is used, scrollpane needs to remain its position 
    EventHandler<ActionEvent> edit = event -> { 
     editProduct(selectedProduct); // edits an item from a LinkedHashMap 
     homeBar.setVisible(true); 
     actionBar.setVisible(false); 
    }; 
    editbtn.setOnAction(edit); 
} 

/* 
Code below does not cause the problem, but I added it as a reference 
*/ 

private void deleteProduct(String product) { 
    if (mProductMap.containsKey(product)) { 
     mProductMap.remove(product); 
     System.out.printf("%s has been deleted!%n", product); 
    } else { 
     System.out.printf("%s does not exist. Please try again.%n", product); 
    } 
    addButtons(); 
} 

private void editProduct(String product) { 
    List<String> indexKeys = new ArrayList<>(mProductMap.keySet()); 
    List<BigDecimal> indexValues = new ArrayList<>(mProductMap.values()); 
    BigDecimal price = mProductMap.get(product); // gets the product's value (the price) 
    int indexKey = indexKeys.indexOf(product); 
    int indexValue = indexValues.indexOf(price); 

    if (mProductMap.containsKey(product)) { 
     int sizeBefore = mProductMap.size(); 
     addingProduct(); 
     int sizeAfter = mProductMap.size(); 

     if (sizeAfter > sizeBefore) { 
      indexKeys.remove(product); 
      indexValues.remove(price); 
      mProductMap.remove(product); 

      // Make a new list to get the new entry at the end 
      List<Map.Entry<String,BigDecimal>> entryList = new ArrayList<>(mProductMap.entrySet()); 
      Map.Entry<String, BigDecimal> lastEntry = entryList.get(entryList.size()-1); 

      String key = lastEntry.getKey(); 
      BigDecimal value = lastEntry.getValue(); 
      indexKeys.add(indexKey, key); 
      indexValues.add(indexValue, value); 
      mProductMap.clear(); 

      // Put the keys and values from the two lists back to the map 
      for (int i=0; i<indexKeys.size(); i++) { 
       addProduct(indexKeys.get(i), indexValues.get(i)); 
      } 
     } 
    } else { 
     System.out.printf("%s does not exist. Please try again.%n", product); 
    } 
} 

void addProduct(String product, BigDecimal price) { 
    mProductMap.put(product, price); 
    addButtons(); 
} 

// Adding buttons to the TilePane fieldContainer in center of BorderPane 
// One button per key-value pair of mProductMap 
private void addButtons() { 
    // clears the TilePane to prevent duplicate buttons 
    fieldContainer.getChildren().clear(); 

    for (Map.Entry<String, BigDecimal> entry : mProductMap.entrySet()) { 
     StackPane newField = new StackPane(); 
     Button main = new Button(); 
     main.setOnMousePressed(me -> { 
      if (me.getButton() == MouseButton.SECONDARY) { // = right click 
       select(entry.getKey()); 
      } 
     }); 
     main.setText(entry.getKey() + "\n" + entry.getValue()); 
     newField.getChildren().add(main); 
     fieldContainer.setAlignment(Pos.TOP_LEFT); 
     fieldContainer.getChildren().add(newField); 
    } 
} 

// Popup for adding products to the Map with the + button 
@FXML 
private void addingProduct(){ 
    Stage newStage = new Stage(); 
    VBox popup = new VBox(); 
    final BooleanProperty firstTime = new SimpleBooleanProperty(true); // Variable to store the focus on stage load 
    TextField product = new TextField(""); 
    product.setId("product"); 
    product.setPromptText("Enter the item name..."); 
    // code to remove the focus from first textfield on stage load 
    product.focusedProperty().addListener((observable, oldValue, newValue) -> { 
     if(newValue && firstTime.get()){ 
      popup.requestFocus(); // Delegate the focus to container 
      firstTime.setValue(false); // Variable value changed for future references 
     } 
    }); 

    TextField price = new TextField(""); 
    price.setId("price"); 
    price.setPromptText("Enter the item price..."); 
    Button submit = new Button("Submit"); 
    Label label = new Label(); 
    label.setId("label"); 
    submit.setOnAction(e -> { 
     if ((product.getText() != null && !product.getText().isEmpty() && 
       price.getText() != null && !price.getText().isEmpty())) { 
      addProduct(product.getText(), new BigDecimal(price.getText())); 
      newStage.close(); 
     } else { 
      label.setText("Fill in both fields"); 
     } 
    }); 

    popup.getChildren().add(product); 
    popup.getChildren().add(price); 
    popup.getChildren().add(submit); 
    popup.getChildren().add(label); 
    Scene stageScene = new Scene(popup, 300, 200); 
    newStage.setScene(stageScene); 
    newStage.showAndWait(); 
    } 
} 

FXML:

<BorderPane xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller"> 
<top> 
    <StackPane> 
     <HBox fx:id="homeBar" styleClass="main-bar" visible="true"> 
      <Button StackPane.alignment="BOTTOM_LEFT">Home</Button> 
      <Button onAction="#addingProduct" StackPane.alignment="BOTTOM_RIGHT">Add a new product</Button> 
     </HBox> 
     <HBox fx:id="actionBar" styleClass="main-bar" visible="false"> 
      <Button fx:id="deletebtn" StackPane.alignment="BOTTOM_CENTER">Delete</Button> 
      <Button fx:id="editbtn" StackPane.alignment="BOTTOM_CENTER">Edit</Button> 
      <Button onAction="#addingProduct" StackPane.alignment="BOTTOM_RIGHT">Add a new product</Button> 
     </HBox> 
    </StackPane> 
</top> 

<center> 
    <ScrollPane fx:id="scroll" hbarPolicy="NEVER"> 
     <TilePane fx:id="fieldContainer" prefColumns="2" prefTileHeight="100.0" prefTileWidth="144.0"> 
     </TilePane> 
    </ScrollPane> 
</center> 

<bottom> 
</bottom> 
</BorderPane> 

メイン:

public class Main extends Application { 

@Override 
public void start(Stage primaryStage) throws Exception{ 
    Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); 
    primaryStage.setScene(new Scene(root, 300, 275)); 
    primaryStage.show(); 
} 
public static void main(String[] args) { 
    launch(args); 
    } 
} 
+1

を使用すると、1つのアイテムを削除すると、いくつかの理由で、全体 'TilePane'を再構築している場合を除きこれは、起こるべきではありません。 [MCVE]を作成します。 –

+0

アイテムが削除されるたびに 'TilePane'をクリアします。 – DVarga

+0

私は知っている、それは重複ボタンを防ぐためです。しかし、私がfieldContainer.getChildren()をコメントアウトすると、clear(); addButtonsメソッドから問題が解決されません。それでも、上にスクロールします。 – Linda

答えて

0

私はこのポストからの回答からの助けを借りて、それを自分自身を固定:ScrollPane jumps to top when deleting nodes

TilePaneからボタンを削除すると、ScrollPaneはフォーカスを当てる次のノードを見つけます。デフォルトでは、このノードはペインの最初のノードです。 TilePane(fieldContainer)にフォーカスを要求することにより、ScrollPaneはそのままの位置にとどまります。

私は両方の削除や編集方法にこのコードを追加:

fieldContainer.requestFocus(); 
関連する問題