2015-01-11 15 views
11

Có cách nào để thay đổi chính sách của ScrollBar trong TableView tương tự như ScrollPane không? Tôi đã chỉ thấy rằng VirtualFlow của một TableView tính toán khả năng hiển thị, nhưng không có khả năng can nhiễu thủ công.TableView ScrollBar Policy

Tôi cần thanh cuộn dọc để luôn hiển thị và ngang không bao giờ. Thay đổi trạng thái hiển thị của các thanh không hoạt động.

Ví dụ:

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

Bạn có ý nghĩa gì với "không hoạt động"? Bạn đã thử 'setManaged (false)'? – eckig

+0

Tôi lấy thanh cuộn ở bảng bên trái và đặt chế độ hiển thị thành sai. Chúng vẫn hiển thị. Và trên bảng bên phải (xem ảnh chụp màn hình) Tôi muốn thanh cuộn luôn hiển thị, vì vậy tôi đặt chế độ hiển thị thành true. Tôi đã thử setManaged, điều đó cũng không hoạt động. Nói cách khác: Tôi không muốn tính toán khả năng hiển thị. Tôi muốn xác định xem họ có nên được nhìn thấy hay không. Tôi cần nó cho bảng tóm tắt ở đây: http://stackoverflow.com/questions/27884486/tableview-with-summary-section – Roland

+0

@James_D Bạn có thể xem câu hỏi này không. Nó có nhiều upvotes và vẫn không có câu trả lời. –

Trả lời

-1

CSS

đây là giải pháp làm việc chỉ cho tôi, chỉ hidde nó

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

hãy giải thích mã số –

2

Thêm đối tượng TableView của bạn để một đối tượng StackPane . Các thanh cuộn sẽ tự động được thêm vào bảng. Họ cũng sẽ tự động thay đổi kích thước.

Tôi nhận thấy rằng các loại vùng chứa khác không hoạt động tốt cho các đối tượng TableView. Trong số đó có các đối tượng ScrollPane và các đối tượng AnchorPane. Vì vậy, tôi tự hỏi nếu HBox có thể được thêm vào danh sách đó.

1

Giải pháp CSS là một giải pháp tồi, vì nó làm rối loạn khung nhìn khi bạn có thể nhìn thấy TableMenuButton (nút "+" làm cho khả năng hiển thị của các cột có thể).

Giải pháp của tôi (vẫn còn khá khó chịu) để nhận được một tham chiếu đến thanh cuộn:

Lớp TableView tạo ra một TableViewSkin chứa một VirtualFlow. VirtualFlow sau đó lại giữ VirtualScrollBar ngang và dọc. Tôi đang ghi đè TableView và TableViewSkin. Tùy thuộc vào vấn đề của bạn, bạn có thể cần phải ghi đè và thay đổi nhiều hơn nữa. (Kiểm tra nguồn của các tập tin ..).

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(); 
      } 
     }); 
    } 
} 

}

Sau đó bạn có thể sử dụng TableView mới của bạn trong FXML hoặc mã.

Tôi chỉ muốn tắt cuộn, vì vậy, tôi cũng đã cuộn cuộn trên toàn bộ bảng và đã tiêu thụ sự kiện. CSS của tôi để ẩn các nút:

.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

tôi trường hợp này tôi đặt đối tượng của tôi vào ScrollPane và làm việc với hbarPolicy/vbarPolicy của nó.

Trong Fxml nó trông giống như:

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

Trong điều khiển cái gì đó như:

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

cách này không hoạt động –

+0

Tôi hiện không làm việc với JavaFx , vì vậy không thể tìm thấy mã của tôi, nơi nó được sử dụng, nhưng ít nhất là bởi tôi nó hoạt động tốt như tôi nhớ. Bạn có ý nghĩa gì với "không hoạt động"? Bạn có lỗi hay gì không? Nếu bạn không nhìn thấy một cuộn trong ScrollPane của bạn nó có thể có nghĩa là bạn có nó trong nút khác, mà "blokes" nó hoặc một cái gì đó như thế. Bạn đã thử đặt các giá trị này trong bộ điều khiển chưa? –

2

Nó cũng hoạt động nếu TableView là stil không hiển thị. Nó hoạt động nếu có một chút dữ liệu, vì

private boolean computeBarVisiblity() { 
    if (cells.isEmpty()) { 
     // In case no cells are set yet, we assume no bars are needed 
     needLengthBar = false; 
     needBreadthBar = false; 
     return true; 
    } 

    // ... other method code 
} 

trong mã VirtualFlow. Nhưng bạn có thể mở rộng ví dụ này.

 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

Phương thức alwaysShowVerticalScroll cũng có thể được sửa đổi để lấy TreeTableView thay vì chỉ một TableView. – Agricola