Автоматическое масштабирование текста кнопки с помощью кнопки в JavaFX

Я создал сетку кнопок в JavaFX.
Когда я изменяю размер окна с сеткой внутри, кнопки также изменяются внутри сетки.
Проблема в том, что текст на эти кнопки не изменяются вместе с ними: они все время остаются одного размера, поэтому, когда кнопки становятся большими, на кнопке остается много пустого места, а затем крошечный текст посередине, что выглядит ужасно.< br/> Я бы предпочел, чтобы размер текста автоматически изменялся вместе с этими кнопками, чтобы он соответствовал пустому пространству, чтобы, когда весь пользовательский интерфейс становится больше, текст на кнопках также становился больше.
Как я могу это сделать? это?

Я попытался установить -fx-font-size в таблице стилей CSS на процентные значения, но, похоже, это не работает так же, как для веб-сайтов: текст масштабируется не в процентах от своего контейнера, а в процентах от некоторого предопределенного размера текста. .

Изменить
Это не дубликат! Прекратите отмечать каждый вопрос как дубликат! Если бы на него ответили, я бы вообще не спрашивал!

Из того, что я вижу, первая из этих тем была о ситуации, когда кто-то хотел установить размер/стиль текста для новых кнопок с учетом текущего размера их контейнера и т. д. Это это не то, что мне нужно, потому что я хочу, чтобы кнопки, которые были уже созданы, также автоматически изменяли размер своего текста, когда эти кнопки каким-то образом изменяют размер внутри своего контейнера.

Другой поток касался масштабирования текста вместе с корневым контейнером/окном с заданным размером шрифта. Это также отличается от того, что мне нужно, потому что я хочу, чтобы текст масштабировался не с размером окна, а с размерами самих кнопок. И он должен быть определенным образом масштабирован: чтобы всегда соответствовал размеру кнопки. Вы знаете: текст остается прежним, но растягивается так, что всегда помещается внутри кнопки (с небольшим отступом, а не огромной пустой областью вокруг текста).

Это размер кнопки, который должен определять размер текста на ней, а не окна или контейнера или чего-то еще, и это должно быть сделано автоматически самой кнопкой (либо встроенным один или подкласс), а не вручную с помощью охватывающего контейнера, перебирающего все эти кнопки и обновляющего размеры их текста (что было бы глупым способом сделать это).


person SasQ    schedule 04.05.2016    source источник
comment
Это может быть дубликат stackoverflow.com/questions/34812022/ или stackoverflow.com/questions/23705654/bind-font-size-in-javafx   -  person hotzst    schedule 04.05.2016
comment
Если бы больше людей на самом деле отвечали на вопросы, а не просто искали дубликаты или потенциальные закрытия, StackOverflow снова был бы великолепен, как в те старые времена... ;P Я прочитал эти два вопроса, прежде чем задать свой. Если бы я нашел решение там, я бы вообще не задавал свой вопрос. (Если я что-то не пропустил в этих темах.)   -  person SasQ    schedule 04.05.2016
comment
В чем разница между установкой размера шрифта кнопки при ее создании, чтобы он соответствовал фиксированному размеру кнопки, и обновлением размера шрифта при изменении размера кнопки, чтобы он делал то же самое? Извините: я правда не понимаю, чем это разные вещи. (Не то, чтобы это решение было особенно хорошим, но все же... чем оно отличается, кроме совершенно тривиального?)   -  person James_D    schedule 04.05.2016
comment
Я прекрасно понимаю вопрос. Я не понимаю ваших разглагольствований о том, что кто-то указал на почти идентичный вопрос. Я ответил, потому что думал, что смогу улучшить ответ на дубликат.   -  person James_D    schedule 05.05.2016
comment
Разница в том, что мне пришлось бы делать это вручную, перебирая все кнопки и обновляя размеры их шрифтов каждый раз, когда я обнаруживаю изменение (и у меня было бы 2 вычисления правильного размера 1-го). Это решение не очень элегантно (как и Java, но мне все равно нужно его использовать, так что ...) и плохо масштабируется: PI скорее хотел бы научить мои кнопки обновлять размер текста самостоятельно. когда их внутренняя область меняет размер, потому что они лучше знают, как это сделать, чем любой внешний объект. Вот как должно работать хорошее объектно-ориентированное программирование, управляемое событиями.   -  person SasQ    schedule 05.05.2016
comment
Любой ответ обязательно просто демо-код. Однако вам не нужно перебирать кнопки, вы просто регистрируете слушателя при их создании. Вы можете достаточно легко преобразовать эту идею (или мою) в подкласс Button (или альтернативный скин), если предпочитаете другие подходы к проектированию.   -  person James_D    schedule 05.05.2016


Ответы (2)


Это, как понравились связанные вопросы, что-то вроде взлома: но рассмотрите возможность масштабирования текстового узла внутри кнопки вместо изменения размера шрифта. Кажется, это работает нормально:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;

public class ScaledButtons extends Application {

    @Override
    public void start(Stage primaryStage) {
        GridPane root = new GridPane();
        root.setHgap(5);
        root.setVgap(5);
        for (int i = 1; i <= 9 ; i++) {
            root.add(createScaledButton(Integer.toString(i)), (i-1) % 3, (i-1) / 3);
        }
        root.add(createScaledButton("#"), 0, 3);
        root.add(createScaledButton("0"), 1, 3);
        root.add(createScaledButton("*"), 2, 3);

        primaryStage.setScene(new Scene(root, 250, 400));
        primaryStage.show();
    }

    private Button createScaledButton(String text) {
        Button button = new Button(text);
        GridPane.setFillHeight(button, true);
        GridPane.setFillWidth(button, true);
        GridPane.setHgrow(button, Priority.ALWAYS);
        GridPane.setVgrow(button, Priority.ALWAYS);

        button.layoutBoundsProperty().addListener((obs, oldBounds, newBounds) -> 
            scaleButton(button));

        button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

        return button ;
    }

    private void scaleButton(Button button) {
        double w = button.getWidth();
        double h = button.getHeight();

        double bw = button.prefWidth(-1);
        double bh = button.prefHeight(-1);

        if (w == 0 || h == 0 || bw == 0 || bh == 0) return ;

        double hScale = w / bw ;
        double vScale = h / bw ;

        double scale = Math.min(hScale, vScale);

        button.lookup(".text").setScaleX(scale);
        button.lookup(".text").setScaleY(scale);
    }

    public static void main(String[] args) {
        launch(args);
    }
}
person James_D    schedule 04.05.2016
comment
Хм... интересно. Я не знал, что внутри кнопки есть текстовый узел. Это где-то задокументировано? - person SasQ; 05.05.2016
comment
Я думал, что это задокументировано в документах CSS, хотя, когда я бегло проверил, я не увидел его там. - person James_D; 05.05.2016

Альтернативный подход для получения подобного эффекта может заключаться в создании подкласса com.sun.javafx.scene.control.skin.ButtonSkin и переопределении метода layoutLabelInArea(double x, double y, double w, double h, Pos alignment) из родительского скина (LabeledSkinBase). Затем вы можете явно назначить обновленный скин своей кнопке (через CSS или вызовы Java API).

Для этого потребуется создание подклассов com.sun API, которые могут быть изменены без предварительного уведомления в последующих выпусках JavaFX. Кроме того, layoutLabelInArea достаточно сложна в своей работе, поэтому изменение логики макета может быть немного сложным. Конечно, предложение Джеймса применить операцию масштабирования текста, основанную на слушателе свойства границ макета, в данном конкретном случае проще.

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

person jewelsea    schedule 04.05.2016
comment
Обратите внимание, что в Java 9 класс темы оформления является общедоступным API. - person James_D; 05.05.2016