gpt4 book ai didi

javafx - 如何设置 TableColumn 的排序箭头对齐方式?

转载 作者:行者123 更新时间:2023-12-04 16:05:07 25 4
gpt4 key购买 nike

要点

在 JavaFX TableColumn 中,右侧有一个排序箭头。

Example of the mentioned arrow

如何设置此箭头的对齐方式?

我的用例

我问是因为我正在尝试申请 Material Design到 JavaFX 并且箭头需要在左边——否则箭头看起来属于相邻的列。

Arrow appearing to belong to the adjacent column.

知道的事

我知道您可以像这样访问 TableColumnHeader:

for (final Node headerNode : tableView.lookupAll(".column-header")) {
TableColumnHeader tableColumnHeader = (TableColumnHeader) headerNode;

我知道 TableColumnHeader 有一个 Label 标签 和一个 GridPane sortArrowGrid 作为它的 child 。

如何将 sortArrowGrid 移动到 child 的前面? .toFront() 只是用于 z 顺序吗?

    Node arrow = tableColumnHeader.lookup(".arrow");
if (arrow != null) {
GridPane sortArrowGrid = (GridPane) arrow.getParent();
// TODO: Move the sortArrowGrid to the front of the tableColumnHeader's children
}

我觉得我可能做错了——我很乐意用 CSS 来做。

最佳答案

对我的评论进行一些扩展(使用一些代码):如前所述,排序指示器的对齐方式(或 fx-speak:内容显示)是不可配置的,既不是样式也不是列/标题的任何属性 -相反,它被硬编码在 header 的布局代码中。

意味着我们需要实现一个支持可配置显示的自定义columnHeader。肉在一个自定义的 TableColumnHeader 中,它有:

  • 属性 sortIconDisplayProperty() 用于配置排序指示器的相对位置
  • 一个重写的 layoutChildren() 按照配置放置标签和排序指示符
  • 为了好玩:使该属性具有样式(需要一些围绕 StyleableProperty 的样板及其在 CSS 处理程序中的注册)

要使用,我们需要自定义 TableViewSkin、TableHeaderRow、NestedTableColumnHeader 的整个堆栈:所有这些都只是样板,用于在其相关工厂方法中创建和返回自定义 xx 实例。

下面是一个粗略的示例(阅读:布局不完美,应该有一些填充并保证不与文本重叠......但是,核心不是那么擅长,也不是)支持设置文本左侧的图标。为了获得完整的支持,您可能需要将其设置在顶部/底部……我现在太懒了;)

/**
* https://stackoverflow.com/q/49121560/203657
* position sort indicator at leading edge of column header
*
* @author Jeanette Winzenburg, Berlin
*/
public class TableHeaderLeadingSortArrow extends Application {

/**
* Custom TableColumnHeader that lays out the sort icon at its leading edge.
*/
public static class MyTableColumnHeader extends TableColumnHeader {

public MyTableColumnHeader(TableColumnBase column) {
super(column);
}

@Override
protected void layoutChildren() {
// call super to ensure that all children are created and installed
super.layoutChildren();
Node sortArrow = getSortArrow();
// no sort indicator, nothing to do
if (sortArrow == null || !sortArrow.isVisible()) return;
if (getSortIconDisplay() == ContentDisplay.RIGHT) return;
// re-arrange label and sort indicator
double sortWidth = sortArrow.prefWidth(-1);
double headerWidth = snapSizeX(getWidth()) - (snappedLeftInset() + snappedRightInset());
double headerHeight = getHeight() - (snappedTopInset() + snappedBottomInset());

// position sort indicator at leading edge
sortArrow.resize(sortWidth, sortArrow.prefHeight(-1));
positionInArea(sortArrow, snappedLeftInset(), snappedTopInset(),
sortWidth, headerHeight, 0, HPos.CENTER, VPos.CENTER);
// resize label to fill remaining space
getLabel().resizeRelocate(sortWidth, 0, headerWidth - sortWidth, getHeight());
}

// --------------- make sort icon location styleable
// use StyleablePropertyFactory to simplify styling-related code
private static final StyleablePropertyFactory<MyTableColumnHeader> FACTORY =
new StyleablePropertyFactory<>(TableColumnHeader.getClassCssMetaData());

// default value (strictly speaking: an implementation detail)
// PENDING: what about RtoL orientation? Is it handled correctly in
// core?
private static final ContentDisplay DEFAULT_SORT_ICON_DISPLAY = ContentDisplay.RIGHT;

private static CssMetaData<MyTableColumnHeader, ContentDisplay> CSS_SORT_ICON_DISPLAY =
FACTORY.createEnumCssMetaData(ContentDisplay.class,
"-fx-sort-icon-display",
header -> header.sortIconDisplayProperty(),
DEFAULT_SORT_ICON_DISPLAY);

// property with lazy instantiation
private StyleableObjectProperty<ContentDisplay> sortIconDisplay;

protected StyleableObjectProperty<ContentDisplay> sortIconDisplayProperty() {
if (sortIconDisplay == null) {
sortIconDisplay = new SimpleStyleableObjectProperty<>(
CSS_SORT_ICON_DISPLAY, this, "sortIconDisplay",
DEFAULT_SORT_ICON_DISPLAY);

}
return sortIconDisplay;
}

protected ContentDisplay getSortIconDisplay() {
return sortIconDisplay != null ? sortIconDisplay.get()
: DEFAULT_SORT_ICON_DISPLAY;
}

protected void setSortIconDisplay(ContentDisplay display) {
sortIconDisplayProperty().set(display);
}

/**
* Returnst the CssMetaData associated with this class, which may
* include the CssMetaData of its superclasses.
*
* @return the CssMetaData associated with this class, which may include
* the CssMetaData of its superclasses
*/
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
return FACTORY.getCssMetaData();
}

/** {@inheritDoc} */
@Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return getClassCssMetaData();
}

//-------- reflection acrobatics .. might use lookup and/or keeping aliases around
private Node getSortArrow() {
return (Node) FXUtils.invokeGetFieldValue(TableColumnHeader.class, this, "sortArrow");
}

private Label getLabel() {
return (Label) FXUtils.invokeGetFieldValue(TableColumnHeader.class, this, "label");
}

}

private Parent createContent() {
// instantiate the tableView with the custom default skin
TableView<Locale> table = new TableView<>(FXCollections.observableArrayList(
Locale.getAvailableLocales())) {

@Override
protected Skin<?> createDefaultSkin() {
return new MyTableViewSkin<>(this);
}

};
TableColumn<Locale, String> countryCode = new TableColumn<>("CountryCode");
countryCode.setCellValueFactory(new PropertyValueFactory<>("country"));
TableColumn<Locale, String> language = new TableColumn<>("Language");
language.setCellValueFactory(new PropertyValueFactory<>("language"));
TableColumn<Locale, String> variant = new TableColumn<>("Variant");
variant.setCellValueFactory(new PropertyValueFactory<>("variant"));
table.getColumns().addAll(countryCode, language, variant);

BorderPane pane = new BorderPane(table);

return pane;
}

/**
* Custom nested columnHeader, headerRow und skin only needed to
* inject the custom columnHeader in their factory methods.
*/
public static class MyNestedTableColumnHeader extends NestedTableColumnHeader {

public MyNestedTableColumnHeader(TableColumnBase column) {
super(column);
}

@Override
protected TableColumnHeader createTableColumnHeader(
TableColumnBase col) {
return col == null || col.getColumns().isEmpty() || col == getTableColumn() ?
new MyTableColumnHeader(col) :
new MyNestedTableColumnHeader(col);
}
}

public static class MyTableHeaderRow extends TableHeaderRow {

public MyTableHeaderRow(TableViewSkinBase tableSkin) {
super(tableSkin);
}

@Override
protected NestedTableColumnHeader createRootHeader() {
return new MyNestedTableColumnHeader(null);
}
}

public static class MyTableViewSkin<T> extends TableViewSkin<T> {

public MyTableViewSkin(TableView<T> table) {
super(table);
}

@Override
protected TableHeaderRow createTableHeaderRow() {
return new MyTableHeaderRow(this);
}

}

@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
URL uri = getClass().getResource("columnheader.css");
stage.getScene().getStylesheets().add(uri.toExternalForm());
stage.setTitle(FXUtils.version());
stage.show();
}

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

@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableHeaderLeadingSortArrow.class.getName());

}

要配置的 columnheader.css:

.column-header {
-fx-sort-icon-display: LEFT;
}

版本说明:

该示例是针对 fx9 编码的——这将 Skins 与一系列其他更改一起移至公共(public)范围。让它与 fx8 一起工作

  • 将导入语句调整到 com.sun 中的旧位置。**(无论如何都不会显示,您的 IDE 是您的 friend ;)
  • 对于所有 SomethingHeader,更改构造函数以包含 tableSkin 作为参数并在所有工厂方法中传递皮肤(可能在 fx8 中,因为 getTableViewSkin() - 或类似的 - 具有 protected 范围,因此是子类可访问)

关于javafx - 如何设置 TableColumn 的排序箭头对齐方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49121560/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com