CustomResizePolicy не срабатывает при двойном щелчке разделителя заголовка столбца

Я написал пользовательскую политику изменения размера для TableView, которая похожа на TableView.CONSTRAINED_RESIZE_POLICY тем, что общая ширина видимых столбцов всегда равна ширине самой таблицы.

Всякий раз, когда размер столбца изменяется либо в результате изменения размера таблицы, либо в результате перетаскивания столбца пользователем, вызывается политика изменения размера, и размеры столбцов изменяются соответствующим образом.

Однако при двойном щелчке одного из разделителей в заголовке таблицы (чтобы «упаковать» содержимое столбца) пользовательская политика изменения размера не запускается.

В результате общая ширина столбцов может быть больше или меньше ширины таблицы, что не есть хорошо.

Как я могу обнаружить эти двойные щелчки и заставить мой CustomResizePolicy вызывать вызов после этого?

Вот рабочий пример, показывающий, что двойные щелчки не приводят к вызову CustomResizePolicy:

import java.util.Locale;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class CustomResizeExample extends Application {

    @SuppressWarnings("unchecked")
    private Parent getContent () {
        TableView <Locale> table = new TableView <>( FXCollections.observableArrayList( Locale.getAvailableLocales() ) );
        TableColumn <Locale, String> countryCode = new TableColumn <>( "CountryCode" );
        countryCode.setCellValueFactory( new PropertyValueFactory <>( "country" ) );
        TableColumn <Locale, String> language = new TableColumn <>( "Language" );
        language.setCellValueFactory( new PropertyValueFactory <>( "language" ) );
        table.getColumns().addAll( countryCode, language );

        TableColumn <Locale, Locale> local = new TableColumn <>( "Locale" );
        local.setCellValueFactory( c -> new SimpleObjectProperty <>( c.getValue() ) );

        table.getColumns().addAll( local );
        table.setColumnResizePolicy( new CustomResizePolicy() );

        BorderPane pane = new BorderPane( table );
        return pane;
    }
    @Override
    public void start ( Stage stage ) throws Exception {
        stage.setScene( new Scene( getContent(), 800, 400 ) );
        stage.show();
    }

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

}

@SuppressWarnings ( "rawtypes" ) 
class CustomResizePolicy implements Callback <TableView.ResizeFeatures, Boolean> {
    @Override
    public Boolean call ( TableView.ResizeFeatures feature ) {

        System.out.println ( "Called" ); //This does not print when the divider is double-clicked.

        return TableView.CONSTRAINED_RESIZE_POLICY.call( feature );
    }
}

person JoshuaD    schedule 17.12.2017    source источник


Ответы (1)


Это ошибка в TableViewSkin.

В Java 8 метод resizeColumnToFitContent, который вызывается двойным щелчком по разделителю столбцов, не вызывает resizeColumn в TableView. В результате макет обновляется неправильно. Достаточно попробовать изменить размер столбца по ширине, чтобы увидеть это. На самом деле, повторная подгонка по ширине будет устанавливать ширину все ближе и ближе к ее реальной ширине. Попробуйте подогнать, а затем несколько раз подряд изменить размер одного и того же столбца (выполнение этого действия с другими столбцами приведет к сбросу поведения).

У меня не было времени найти хороший обходной путь. Есть некоторое подобие улучшения путем создания подкласса TableViewSkin и переопределения resizeColumnToFitContent:

class CustomTableSkin<T> extends TableViewSkin<T> {

    public CustomTableSkin(TableView<T> tableView) {
        super(tableView);
        i = tableView.getColumns().size() + 1;
    }

    private int i;

    @Override
    protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
        double before = tc.getWidth();
        super.resizeColumnToFitContent(tc, maxRows);
        double now = tc.getWidth();
        double diff = before - now;
        i--;
        if (i >= 0)
            resizeColumn(tc, -diff);
    }
}

Добавление вызовов resizeColumn помогает в некоторых случаях, но потребуется дополнительное исследование, чтобы найти правильное исправление.

Java 9 изменил реализацию скинов, хотя я считаю, что проблема все еще присутствует.

person user1803551    schedule 17.12.2017
comment
Я не могу найти CustomTableSkin в Java 8. Я неправильно понял ваш пост? - person JoshuaD; 19.12.2017
comment
Эр. Я имею в виду, что не могу найти TableViewSkin в своей версии java -- openjdk 1.8.0_151. Когда я пытаюсь импортировать com.sun.javafx.scene.control.TableViewSkin, я получаю сообщение Импорт не может быть разрешен. - person JoshuaD; 20.12.2017
comment
@JoshuaD Google должен помочь вам в этом. - person user1803551; 20.12.2017
comment
Я гуглил это перед публикацией, оба раза. попробую в третий раз. А пока, если у вас есть ответ, было бы полезно отредактировать его в своем посте, так как я уверен, что буду не единственным, кто столкнется с этой проблемой, и я обещаю, что не совсем очевидно, как использовать предлагаемое вами решение. - person JoshuaD; 20.12.2017
comment
@JoshuaD Это зависит от вашей IDE. - person user1803551; 21.12.2017
comment
Я смотрю javadoc javafx 8 и не вижу его: i.imgur.com/E3oevLH .png, docs.oracle.com/javase/8 /javafx/api/toc.htm - person JoshuaD; 21.12.2017
comment
@JoshuaD com.sun — это внутренний API. Документация находится в исходном коде. - person user1803551; 21.12.2017
comment
Я тоже не могу импортировать TableViewSkin. В моей Java 8 нет пакета javafx.scene.control.skin... не знаю, что это за TableViewSkin и откуда вы его взяли? - person Spenhouet; 07.01.2018
comment
@Spen Как я уже сказал в комментариях выше, он находится в домене com.sun, в частности com.sun.javafx.scene.control.skin. - person user1803551; 08.01.2018
comment
Кажется, у меня нет доступа к этому в IntelliJ Idea. - person Spenhouet; 08.01.2018
comment
@Spen У вас есть, вам просто нужно установить его в IntelliJ. Я им не пользуюсь, поэтому не знаю, как. Как я уже сказал выше, Google должен помочь вам в этом. - person user1803551; 09.01.2018