2016-05-19 18 views
9

Ho Scene che è impostato su Scene della mia primaryStage che - tra gli altri nodi - contiene uno VBox con un e alcuni pulsanti. Quando scatta un'istantanea su una riga nella tabella utilizzando TableRow.snapshot(null, null), la dimensione di Scene viene modificata. La larghezza viene modificata di circa 10 pixel mentre l'altezza viene modificata di circa 40 - a volte più di 600 (!) - pixel.Node.snapshot (null, null) modifica la dimensione della scena

Ciò accade perché Node.snapshot(null, null) richiama Scene.doCSSLayoutSyncForSnapshot(Node node) che sembra ottenere la dimensione preferita di tutti i nodi nella dimensione e ricalcolare la dimensione utilizzando quello. Questo in qualche modo restituisce valori errati poiché i miei nodi hanno solo le dimensioni preferite specificate e sembrano grandi prima che questo metodo venga invocato. C'è un modo per prevenire questo?

La modifica della dimensione è un problema, ma è anche un problema che la fase principale non modifica la dimensione con lo Scene che contiene.

Ho provato a creare un MCVE che riproduce il problema, ma dopo alcuni giorni di tentativi, non riesco ancora a riprodurre il problema. Il programma originale contiene circa 2000 righe di codice che non voglio pubblicare qui.

Perché il Scene.doCSSLayoutSyncForSnapshot(Node node) comprometterebbe il mio layout quando è correttamente disposto in primo luogo? Posso in qualche modo verificare che il layout sia sincronizzato correttamente prima di richiamare questo metodo per assicurarmi che non cambi nulla?

+0

così si può provare a impostare vincoli sui nodi prima del evocando quella funzione e annullarle, voglio dire, ' setMinSize (Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE); 'e' setMaxSize (Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE); 'potrebbe aiutare dal modo in cui hai descritto il tuo problema, :) – Elltz

+0

Grazie per non aver pubblicato tutte le 2000 righe di codice. Ma se riesci a scrivere un breve esempio compilabile per riprodurre il problema che sarebbe utile. Altrimenti un link a tutto il tuo codice se non riesci a riprodurre un piccolo campione? – Amber

+0

Suggerisco di utilizzare [Vista panoramica] (http://fxexperience.com/scenic-view/) che consente di visualizzare tutte le proprietà su una vista durante il runtime della GUI dell'utente. Questo ti permetterà almeno di verificare se il problema che descrivi è davvero il problema. Puoi anche pubblicare alcune schermate usando Vista panoramica. Questo strumento consente inoltre di visualizzare tutti gli eventi che si verificano nella GUI dell'utente. Lo uso molto :-) – Westranger

risposta

1

Risolto il problema. Ho dovuto copiare tutto il mio progetto e quindi rimuovere parti del codice fino a quando il problema non è scomparso.

In ogni caso. Fondamentalmente avevo tre componenti nella mia applicazione. Un componente di navigazione, un componente di tabella e una barra di stato compontent. Si presentava così:

app sketch

Il problema che avevo era che la larghezza della barra di stato e la larghezza e l'altezza del componente tabella è stata aumentata ogni volta che ho preso una fotografia istantanea di una riga della tabella.

Apparentemente, ciò era dovuto al riempimento del componente di stato della barra. Aveva una spaziatura destra e sinistra di 5 pixel e, una volta rimossa la padding, il problema scomparve.

I 10 pixel aggiunti in larghezza hanno reso lo BorderPane che conteneva tutto questo espandibile con la stessa quantità di pixel, e poiché la larghezza della tabella era legata alla larghezza BorderPane, aumentava dello stesso importo. Ciò che ancora non capisco, è il motivo per cui lo BorderPaneBorderPane non si adatta alla nuova larghezza.

Il componente è stato riempito correttamente prima dell'invocazione di Scene.doCSSLayoutSyncForSnapshot(Node node), quindi non capisco perché viene aggiunta la larghezza extra di dieci pixel.

In ogni caso: la rimozione del padding dal componente della barra di stato e il riempimento dei componenti all'interno della barra di stato ha risolto il problema. Se qualcuno ha una buona spiegazione per questo, sono tutto orecchie.

Ecco un MCVE in cui è possibile riprodurre il problema trascinando una riga nella tabella:

import java.io.File; 
import java.sql.SQLException; 
import java.util.ArrayList; 

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.geometry.Insets; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.scene.input.ClipboardContent; 
import javafx.scene.input.Dragboard; 
import javafx.scene.input.TransferMode; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.Region; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

public class MCVE extends Application { 

    private Stage primaryStage; 
    private BorderPane rootLayout; 
    private VBox detailsView; 
    private StatusBar statusBar; 

    public void start(Stage primaryStage) throws SQLException { 

     this.primaryStage = primaryStage; 
     this.primaryStage.setTitle("MCVE"); 

     initRootLayout(); 
     showStatusBar(); 
     showDetailsView(); 

     detailsView.prefWidthProperty().bind(rootLayout.widthProperty()); 
     detailsView.prefHeightProperty().bind(rootLayout.heightProperty()); 
    } 

    @Override 
    public void init() throws Exception { 
     super.init(); 

    } 

    public void initRootLayout() { 
     rootLayout = new BorderPane(); 

     primaryStage.setWidth(1000); 
     primaryStage.setHeight(600); 

     Scene scene = new Scene(rootLayout); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public void showStatusBar() { 
     statusBar = new StatusBar(); 
     rootLayout.setBottom(statusBar); 
    } 

    public void showDetailsView() { 
     detailsView = new VBox(); 
     rootLayout.setCenter(detailsView); 

     setDetailsView(new Table(this)); 

     detailsView.prefHeightProperty().bind(primaryStage.heightProperty()); 
     detailsView.setMaxHeight(Region.USE_PREF_SIZE); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

    public VBox getDetailsView() { 
     return detailsView; 
    } 

    public void setDetailsView(Node content) { 
     detailsView.getChildren().add(0, content); 
    } 

    public StatusBar getStatusBar() { 
     return statusBar; 
    } 

    class StatusBar extends HBox { 
     public StatusBar() { 
      setPadding(new Insets(0, 5, 0, 5)); 

      HBox leftBox = new HBox(10); 

      getChildren().addAll(leftBox); 

      /** 
      * CONTROL SIZES 
      */ 
      setPrefHeight(28); 
      setMinHeight(28); 
      setMaxHeight(28); 

      // Leftbox takes all the space not occupied by the helpbox. 
      leftBox.prefWidthProperty().bind(widthProperty()); 

      setStyle("-fx-border-color: black;"); 
     } 
    } 

    class Table extends TableView<ObservableList<String>> { 

     private ObservableList<ObservableList<String>> data; 

     public Table(MCVE app) { 

      prefWidthProperty().bind(app.getDetailsView().widthProperty()); 
      prefHeightProperty() 
        .bind(app.getDetailsView().heightProperty()); 

      widthProperty().addListener((obs, oldValue, newValue) -> { 
       System.out.println("Table width: " + newValue); 
      }); 

      setRowFactory(r -> { 
       TableRow<ObservableList<String>> row = new TableRow<ObservableList<String>>(); 

       row.setOnDragDetected(e -> { 
        Dragboard db = row.startDragAndDrop(TransferMode.ANY); 
        db.setDragView(row.snapshot(null, null)); 

        ArrayList<File> files = new ArrayList<File>(); 

        // We create a clipboard and put all of the files that 
        // was selected into the clipboard. 
        ClipboardContent filesToCopyClipboard = new ClipboardContent(); 
        filesToCopyClipboard.putFiles(files); 

        db.setContent(filesToCopyClipboard); 
       }); 

       row.setOnDragDone(e -> { 
        e.consume(); 
       }); 

       return row; 
      }); 

      ObservableList<String> columnNames = FXCollections.observableArrayList("Col1", "col2", "Col3", "Col4"); 

      data = FXCollections.observableArrayList(); 

      for (int i = 0; i < columnNames.size(); i++) { 
       final int colIndex = i; 

       TableColumn<ObservableList<String>, String> column = new TableColumn<ObservableList<String>, String>(
         columnNames.get(i)); 

       column.setCellValueFactory((param) -> new SimpleStringProperty(param.getValue().get(colIndex).toString())); 

        getColumns().add(column); 
      } 

      // Adds all of the data from the rows the data list. 
      for (int i = 0; i < 100; i++) { 
       // Each column from the row is a String in the list. 
       ObservableList<String> row = FXCollections.observableArrayList(); 

       row.add("Column 1"); 
       row.add("Column 2"); 
       row.add("Column 3"); 
       row.add("Column 4"); 

       // Adds the row to data. 
       data.add(row); 
      } 

      // Adds all of the rows in data to the table. 
      setItems(data); 
     } 
    } 
} 
Problemi correlati