2015-01-11 2 views
11

Gibt es eine Möglichkeit, die Richtlinie einer ScrollBar in einem TableView ähnlich einem ScrollPane zu ändern? Ich habe nur gesehen, dass der VirtualFlow eines TableViews die Sichtbarkeit berechnet, aber keine Möglichkeit für manuelle Eingriffe.TableView-ScrollBar-Richtlinie

Ich brauche die vertikale Bildlaufleiste immer sichtbar und die horizontale nie. Das Ändern des sichtbaren Status der Balken funktioniert nicht.

Beispiel:

import java.time.LocalDate; 
import java.time.Month; 
import java.util.Set; 

import javafx.application.Application; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.geometry.Orientation; 
import javafx.scene.Group; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

import com.sun.javafx.scene.control.skin.VirtualFlow; 

public class ScrollBarInTableViewDemo extends Application { 

    private TableView<Data> table1 = new TableView<>(); // table with scrollbars 
    private TableView<Data> table2 = new TableView<>(); // table without scrollbars 

    private final ObservableList<Data> data = 
      FXCollections.observableArrayList( 
        new Data(LocalDate.of(2015, Month.JANUARY, 10), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 11), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 12), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 13), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 14), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 15), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 16), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 17), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 18), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 19), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 20), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 21), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 22), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 23), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 24), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 25), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 26), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 27), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 28), 10.0, 20.0, 30.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 29), 40.0, 50.0, 60.0), 
        new Data(LocalDate.of(2015, Month.JANUARY, 30), 10.0, 20.0, 30.0) 

      ); 

    final HBox hb = new HBox(); 

    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(800); 
     stage.setHeight(800); 

     // setup table columns 
     setupTableColumns(table1); 
     setupTableColumns(table2); 

     // fill tables with data 
     table1.setItems(data); 
     table1.setTableMenuButtonVisible(true); 

     // create container 
     HBox hBox = new HBox(); 
     hBox.getChildren().addAll(table1, table2); 

     ((Group) scene.getRoot()).getChildren().addAll(hBox); 

     stage.setScene(scene); 
     stage.show(); 

     ScrollBar table1HorizontalScrollBar = findScrollBar(table1, Orientation.HORIZONTAL); 
     ScrollBar table1VerticalScrollBar = findScrollBar(table1, Orientation.VERTICAL); 

     // this doesn't work: 
     table1HorizontalScrollBar.setVisible(false); 
     table1VerticalScrollBar.setVisible(false); 

     ScrollBar table2HorizontalScrollBar = findScrollBar(table2, Orientation.HORIZONTAL); 
     ScrollBar table2VerticalScrollBar = findScrollBar(table2, Orientation.VERTICAL); 

     // this doesn't work: 
     table2HorizontalScrollBar.setVisible(true); 
     table2VerticalScrollBar.setVisible(true); 

     // enforce layout to see if anything has an effect 
     VirtualFlow flow1 = (VirtualFlow) table1.lookup(".virtual-flow"); 
     flow1.requestLayout(); 

     VirtualFlow flow2 = (VirtualFlow) table2.lookup(".virtual-flow"); 
     flow2.requestLayout(); 

    } 

    /** 
    * Primary table column mapping. 
    */ 
    private void setupTableColumns(TableView table) { 


     TableColumn<Data, LocalDate> dateCol = new TableColumn<>("Date"); 
     dateCol.setPrefWidth(120); 
     dateCol.setCellValueFactory(new PropertyValueFactory<>("date")); 

     TableColumn<Data, Double> value1Col = new TableColumn<>("Value 1"); 
     value1Col.setPrefWidth(90); 
     value1Col.setCellValueFactory(new PropertyValueFactory<>("value1")); 

     TableColumn<Data, Double> value2Col = new TableColumn<>("Value 2"); 
     value2Col.setPrefWidth(90); 
     value2Col.setCellValueFactory(new PropertyValueFactory<>("value2")); 

     TableColumn<Data, Double> value3Col = new TableColumn<>("Value 3"); 
     value3Col.setPrefWidth(90); 
     value3Col.setCellValueFactory(new PropertyValueFactory<>("value3")); 

     table.getColumns().addAll(dateCol, value1Col, value2Col, value3Col); 


    } 

    /** 
    * Find the horizontal scrollbar of the given table. 
    * @param table 
    * @return 
    */ 
    private ScrollBar findScrollBar(TableView<?> table, Orientation orientation) { 

     // this would be the preferred solution, but it doesn't work. it always gives back the vertical scrollbar 
     //  return (ScrollBar) table.lookup(".scroll-bar:horizontal"); 
     //  
     // => we have to search all scrollbars and return the one with the proper orientation 

     Set<Node> set = table.lookupAll(".scroll-bar"); 
     for(Node node: set) { 
      ScrollBar bar = (ScrollBar) node; 
      if(bar.getOrientation() == orientation) { 
       return bar; 
      } 
     } 

     return null; 

    } 

    /** 
    * Data for primary table rows. 
    */ 
    public static class Data { 

     private final ObjectProperty<LocalDate> date; 
     private final SimpleDoubleProperty value1; 
     private final SimpleDoubleProperty value2; 
     private final SimpleDoubleProperty value3; 

     public Data(LocalDate date, double value1, double value2, double value3) { 

      this.date = new SimpleObjectProperty<LocalDate>(date); 

      this.value1 = new SimpleDoubleProperty(value1); 
      this.value2 = new SimpleDoubleProperty(value2); 
      this.value3 = new SimpleDoubleProperty(value3); 
     } 

     public final ObjectProperty<LocalDate> dateProperty() { 
      return this.date; 
     } 
     public final LocalDate getDate() { 
      return this.dateProperty().get(); 
     } 
     public final void setDate(final LocalDate date) { 
      this.dateProperty().set(date); 
     } 
     public final SimpleDoubleProperty value1Property() { 
      return this.value1; 
     } 
     public final double getValue1() { 
      return this.value1Property().get(); 
     } 
     public final void setValue1(final double value1) { 
      this.value1Property().set(value1); 
     } 
     public final SimpleDoubleProperty value2Property() { 
      return this.value2; 
     } 
     public final double getValue2() { 
      return this.value2Property().get(); 
     } 
     public final void setValue2(final double value2) { 
      this.value2Property().set(value2); 
     } 
     public final SimpleDoubleProperty value3Property() { 
      return this.value3; 
     } 
     public final double getValue3() { 
      return this.value3Property().get(); 
     } 
     public final void setValue3(final double value3) { 
      this.value3Property().set(value3); 
     } 


    } 
} 

enter image description here

+0

Was meinst du mit "funktioniert nicht"? Hast du 'setManaged (false)' versucht? – eckig

+0

Ich nehme die Bildlaufleisten in der linken Tabelle und setze die Sichtbarkeit auf falsch. Sie sind immer noch sichtbar. Und am rechten Tisch (siehe Screenshot) möchte ich, dass die Bildlaufleisten immer sichtbar sind, also setze ich die Sichtbarkeit auf wahr. Ich habe versucht, setManaged, das hat auch nicht funktioniert. Mit anderen Worten: Ich möchte nicht, dass die Sichtbarkeit berechnet wird. Ich möchte angeben, ob sie sichtbar sein sollen oder nicht. Ich brauche es für die Übersichtstabelle hier: http://stackoverflow.com/questions/27884486/tableview-with-summary-section – Roland

+0

@James_D Könnten Sie einen Blick auf diese Frage werfen. Es hat viele Upvotes und immer noch keine Antwort. –

Antwort

-1

CSS

dies ist die einzige funktionierende Lösung für mich, nur HIDDE es

.scroll-bar:vertical { 
    -fx-opacity: 0; 
    -fx-padding:-7; 
} 
+0

den Code –

2

Fügen Sie Ihr Tableview Objekt zu einem StackPane Objekt . Bildlaufleisten werden automatisch zur Tabelle hinzugefügt. Sie werden auch automatisch die Größe ändern.

Ich habe festgestellt, dass andere Containertypen nicht gut für TableView-Objekte funktionieren. Zu diesen zählen ScrollPane-Objekte und AnchorPane-Objekte. Also frage ich mich, ob HBox zu dieser Liste hinzugefügt werden kann.

1

Die CSS-Lösung ist ein schlechter, weil sie die Ansicht vermasselt, wenn Sie die TableMenuButton sichtbar (die Taste „+“, die die Sichtbarkeit der Spalten ermöglicht, Makel) haben.

Meine Lösung (noch recht böse) einen Verweis auf die Bildlaufleisten zu bekommen:

Die Tableview Klasse erstellt eine TableViewSkin, die eine VirtualFlow hält. Der VirtualFlow enthält dann wieder die horizontale und vertikale VirtualScrollBar. Ich überschreibe TableView und TableViewSkin. Abhängig von Ihrem Problem müssen Sie möglicherweise etwas überschreiben und ändern. (Überprüfen Sie die Quelle der Dateien ..).

public class OneRowTableView<S> extends TableView<S>{ 

@Override 
protected Skin<?> createDefaultSkin() { 
    return new OneRowTableViewSkin<S>(this); 
} 
public class OneRowTableViewSkin<T> extends TableViewSkin<T> { 
    public OneRowTableViewSkin(final TableView<T> tableView) { 
     super(tableView); 
     VirtualScrollBar vBar = null; 
     for(Node child : flow.getChildrenUnmodifiable()){ 
      if(child instanceof VirtualScrollBar){ 
       if(((VirtualScrollBar)child).getOrientation() == Orientation.VERTICAL){ 
        Log.d("Found the vertical scroll bar!"); 
        vBar = (VirtualScrollBar) child; 
       } 
      } 
     } 
     if(vBar == null) return; 
     vBar.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { 

      @Override 
      public void handle(Event event) { 
       Log.d("Suppressing mouse pressing on the Vertical Virtual Scroll Bar"); 
       event.consume(); 
      } 
     }); 
    } 
} 

}

Anschließend können Sie Ihr neues Tableview in FXML oder Code verwenden.

Ich wollte nur das Scrollen deaktivieren, also habe ich auch das Scrollen auf der ganzen Tabelle gefiltert und das Ereignis verbraucht. Meine CSS verstecken die Tasten:

.table-view *.scroll-bar:vertical *.increment-button, 
.table-view *.scroll-bar:vertical *.decrement-button, 
.table-view *.scroll-bar:vertical *.increment-arrow, 
.table-view *.scroll-bar:vertical *.decrement-arrow { 
    -fx-background-color: null; 
} 
-1

ich solche Fälle, die ich meine Aufgabe in ScrollPane setzen und die Arbeit mit hbarPolicy/vbarPolicy davon.

In Fxml sieht es so aus:

<ScrollPane fx:id="yourScrollPane" hbarPolicy="NEVER"> 
<ScrollPane fx:id="yourScrollPane" vbarPolicy="ALWAYS"> 

In Controller so etwas wie:

yourScrollPane.setHbarPolicy(ScrollBarPolicy.NEVER); 
yourScrollPane.setVbarPolicy(ScrollBarPolicy.ALWAYS); 
+0

bitte erklären dies nicht funktioniert –

+0

Ich bin nicht gerade mit JavaFx Arbeits , so kann ich meinen Code nicht finden, wo er benutzt wurde, aber zumindest bei mir funktioniert es gut, wie ich mich erinnere. Was meinst du mit "nicht arbeiten"? Hast du einen Fehler oder was? Wenn Sie in Ihrem ScrollPane keinen Scroll sehen, könnte dies bedeuten, dass Sie ihn in einem anderen Knoten haben, der ihn "blokkiert" oder so ähnlich. Haben Sie versucht, diese Werte im Controller zu setzen? –

2

Es funktioniert auch, wenn Tableview zeigt stil nicht ist. Es funktioniert nur, wenn es ein wenig Daten gibt, wegen

in VirtualFlow-Code. Aber Sie können dieses Beispiel erweitern.

 public static void alwaysShowVerticalScroll(final TableView view) { 
    new Thread(() -> { 
     while (true) { 
      Set<Node> nodes = view.lookupAll(".scroll-bar"); 
      if (nodes.isEmpty()) { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException ignore) { 
       } 
       continue; 
      } 
      Node node = view.lookup(".virtual-flow"); 
      if (node == null) { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException ignore) { 
       } 
       continue; 
      } 
      final VirtualFlow flow = (VirtualFlow) node; 
      for (Node n : nodes) { 
       if (n instanceof ScrollBar) { 
        final ScrollBar bar = (ScrollBar) n; 
        if (bar.getOrientation().equals(Orientation.VERTICAL)) { 
         bar.visibleProperty().addListener(l -> { 
          if (bar.isVisible()) { 
           return; 
          } 
          Field f = getVirtualFlowField("needLengthBar"); 
          Method m = getVirtualFlowMethod("updateViewportDimensions"); 
          try { 
           f.setBoolean(flow, true); 
           m.invoke(flow); 
          } catch (Exception e) { 
           e.printStackTrace(); 
          } 
          bar.setVisible(true); 
         }); 
         Platform.runLater(() -> { 
          bar.setVisible(true); 
         }); 
         break; 
        } 
       } 
      } 
      break; 
     } 
    }).start(); 
} 

private static Field getVirtualFlowField(String name) { 
    Field field = null; 
    try { 
     field = VirtualFlow.class.getDeclaredField(name); 
     field.setAccessible(true); 
    } catch (NoSuchFieldException e) { 
     e.printStackTrace(); 
    } 
    return field; 
} 

private static Method getVirtualFlowMethod(String name) { 
    Method m = null; 
    try { 
     m = VirtualFlow.class.getDeclaredMethod(name); 
     m.setAccessible(true); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return m; 
} 
+0

Die alwaysShowVerticalScroll-Methode kann auch so geändert werden, dass sie eine TreeTableView anstelle von TableView verwendet. – Agricola