LINUX.ORG.RU

JavaFX: масштабирование Node

 ,


1

1

Допустим, я создаю SVGPath и Label, а затем добавляю их на StackPane (хочу чтобы надпись отображалась поверх SVGPath), а затем всё это добавляю в окно. Как-то так:

package sample;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.FillRule;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;

public class Main extends Application {

    private static final String BUBBLE_SVG_PATH = "m 32.339338,-904.55632 c -355.323298,0 -643.374998,210.31657 " +
            "-643.374998,469.78125 0,259.46468 288.0517,469.812505 643.374998,469.812505 123.404292,0 " +
            "238.667342,-25.3559002 336.593752,-69.3438 69.80799,78.7043 181.84985,84.1354 378.90625,5.3126 " +
            "-149.2328,-8.9191 -166.3627,-41.22 -200.6562,-124.031305 80.6876,-78.49713 128.5,-176.04496 " +
            "128.5,-281.75 0,-259.46468 -288.0205,-469.78125 -643.343802,-469.78125 z";

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Hello World");
        SVGPath svgPath = new SVGPath();
        svgPath.setContent(BUBBLE_SVG_PATH);
        svgPath.setFill(Color.WHITE);
        svgPath.setStroke(Color.BLACK);
        svgPath.setScaleX(0.5);
        svgPath.setScaleY(0.5);
        Label label = new Label("Hello world");
        System.out.println(svgPath.getBoundsInLocal());
        System.out.println(svgPath.getBoundsInParent());
        System.out.println(svgPath.getLayoutBounds());
        StackPane stackPane = new StackPane();
        stackPane.getChildren().add(svgPath);
        stackPane.getChildren().add(label);
        Group root = new Group();
        root.getChildren().add(stackPane);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

Проблема в том, что layoutBounds у Node не учитывает трансформацию. В результате stackPane растягивается до исходного размера SVGPath, а в след за собой растягивает и окно.

То есть получается, что окно и stackPane имеют размер в 2 раза больше, чем надо. И это совсем не прикольно. Ах да, задание scale для самого stackPane ничего не меняет + я хочу масштабировать только SVGPath, но не остальных детей stackPane.

Я понимаю, что это поведение согласно документации. Но как правильно масштабировать Node, чтобы родитель это корректно воспринимал и растягивался под новый, а не старый размер?

★★★★★

Сколько не работал с SVG - всё время какое-то мозго...во. Не очень удачно реализованы концепции векторной графики.

menangen ★★★★★
()

Решение: обернуть SVGPath в Group.

StackPane stackPane = new StackPane();
// stackPane.getChildren().add(svgPath);
stackPane.getChildren().add(new Group(svgPath));
stackPane.getChildren().add(label);
KivApple ★★★★★
() автор топика
Ответ на: комментарий от menangen

Они просто пытались сделать больше, чем нужно. Там большинство проблем из-за того, что спека не очень строгая. Хочешь пиши так, хочешь - сяк. В итоге куча мороки.

В прочем чего ещё ожидать от w3c. html, css и прочие страдают от тех же проблем.

RazrFalcon ★★★★★
()
Ответ на: комментарий от vertexua

Он в смысле, что тулкит ему нравится и то как выглядит у кклиента :) у нас в рф мало же кто пишет софт с fx.

menangen ★★★★★
()
Ответ на: комментарий от menangen

Рисковано нынче в такое вкладываться, учитывая что плагины отключают в браузерах. Конечно можно через WebStart гонять или просто декстоп

vertexua ★★★★★
()
Ответ на: комментарий от GblGbl

https://github.com/deskchanproject/DeskChanJava

http://deskchan.info/

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

KivApple ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Я разрабатываю десктопное приложение, так что на плагины в браузерах мне в принципе пофиг.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от ii8_

Соглашусь. Хотя пары вещей мне всё же не хватило (но они есть в AWT/Swing) - нефокусируемые окна и недекорированные окна без кнопки на панели задач. При том, что сам тулкит (внутренние классы, которые взаимодействуют с ОС) таки всё это умеет, но почему-то никто не догадался вынести эти методы в публичный API.

В итоге для нефокусируемых окон мне пришлось дёргать приватный метод через Reflection, а для создания недекорированного окна без кнопки на панели задач - вообще запилить прокси-обёртку над одним из внутренних классов тулкита (и подменять экземляр сигнлтона в рантайме). Причём генерируемую в рантайме с помощью javassist.

Это дикий костыль и он с вероятностью 99% сломается в Java 9 (но я сделал достаточно проверок, чтобы просто данный функционал отвалился, но всё остальное продолжило работать). Вот почему нельзя было сделать по-нормальному?!

Есть, конечно, вариант запихнуть компонент JavaFX внутрь окна Swing, но это приведёт к потерям производительности + для меня в JavaFX была другая киллер-фича - то что там окна произвольной формы создаются без проблем под Linux (в Swing даже если пиксель окна прозрачный он всё равно ловит события мыши под иксами, нужно устанавливать форму с помощью setShape, а он принимает только векторный контур, которого у меня нет, а генерировать его из растра в рантайме слишком нерационально).

KivApple ★★★★★
() автор топика
Ответ на: комментарий от GblGbl

Насколько реально, что в JavaFX добавят эти две фичи - JavaFX: масштабирование Node (комментарий) ?

Я даже готов написать патчи, если бы был уверен, что их не проигнорят или не скажут «программисту не нужно создавать нефокусируемые окна, мы лучше знаем». Просто фич-реквесты у них уже пару лет висят в баг-трекере.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

что хоть за проект? детально описано как собрать, но не единого слова, что это вообще такое и чего делает.

даже интересно стало.

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Тоже не понял. На сайте чуть больше информации, но тоже не ясно.

orm-i-auga ★★★★★
()
Ответ на: комментарий от GblGbl

Технология в принципе была перспективной, пока браузеры все не испортили/исправили допилив HTML5/SVG/Canvas/CSS3/WebGL

vertexua ★★★★★
()
Ответ на: комментарий от KivApple

Про нефокусированные окна - не знаю, как сделать. Если есть патч, работающий для win/mac/linux (Ubuntu 16+), то можно предложить его в рассылку openjfx-dev, оформив по этим гайдлайнам.

Окно без обрамления можно сделать так:

stage.initStyle(StageStyle.UTILITY);

GblGbl ★★★★★
()
Ответ на: комментарий от ii8_

полноценная замена AWT/Swing

AWT в чистом виде уже никто не применяет.

А что касается Swing, то я полагаю, что в JetBrains Вас просто не поймут.

И до проекта Kenai (SwingX) FX'у как до Луны пешком.

Не говоря уже про IBM OTI, успешно использующую SWT.

Bioreactor ★★★★★
()
Ответ на: комментарий от GblGbl

У меня StageStyle.UTILITY создаёт окно без кнопки на панели задач, но при этом оно имеет декорации. К тому же так нельзя создать прозрачное окно (StageStyle.TRANSPARENT).

Про нефокусируемые окна:

1) Надо добавить метод setFocusable интерфейсу com.sun.javafx.TKStage.

2) Надо реализовать этот метод в com.sun.javafx.WindowStage как вызов this.platformWindow.setFocusable.

3) Для com.sun.javafx.EmbeddedStage надо реализовать этот метод либо как пустую заглушку, либо бросать какое-нибудь исключение типа Unimplemented (не знаю как лучше).

4) Надо добавить метод setFocusable для класса javafx.stage.Window. Он должен вызывать this.impl_peer.setFocusable (который мы добавили на шаге 1).

То есть по сути просто сделать доступным вызов уже имеющегося метода setFocusable com.sun.glass.ui.Window из пользовательского кода.

Сделать такой патч - дело 15 минут максимум. Но примут ли его?

UPD: Немного соврал. В методе setFocusable класса javafx.stage.Window надо проверять, если impl_peer == null, то сохранять значение параметра до лучших времён, а внутри impl_visibleChanging вызывать setFocusable повторно после создания impl_peer.

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 3)
Ответ на: комментарий от GblGbl

Запилил патч, добавляющий setFocusable - http://pastebin.com/hdiJhW7J.

Однако не могу проверить, собирается ли оно.

$ gradle clean sdk apps test

FAILURE: Build failed with an exception.

* Where:
Build file '/home/kiv/Projects/rt/buildSrc/build.gradle' line: 81

* What went wrong:
A problem occurred evaluating project ':buildSrc'.
> java.lang.String cannot be cast to org.gradle.api.artifacts.Configuration

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 0.749 secs
KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

Нашёл одну ошибку с помощью IDEA. Вот версия патча, которая теоретически должна собраться - http://pastebin.com/7aS9TraG.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от Bioreactor

Всё верно. Но я бы не стал в 2017 стартавать проект на AWT/Swing и компании. Эта замена и имелась в виду.

ii8_ ★★★★
()
Ответ на: комментарий от KivApple

Важна ещё версия gradle. С самыми новыми не соберётся, нужно что-то в районе 1.8, или чуть новее.

А коммит завернут, скорее всего - потому что нет focusableProperty. Если посмотреть на исходники fx-ных компонентов, то почти для всех полей есть соответствующие property (иногда, readonly).

GblGbl ★★★★★
()
Последнее исправление: GblGbl (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.