Выведите все этапы на передний план

В моем приложении есть несколько независимых (немодальных) этапов.

Хотелось бы следующего поведения:

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

Первые два требования просты (если я что-то не пропустил), например:

mainStage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue != null && newValue != oldValue) {
        for (Stage s : otherStages) { s.setIconified(newValue); }
    }
});

Однако я застрял на третьем. Я пробовал использовать focusedProperty, но он не работает (например, если я нажимаю на меню на одном из этапов, потому что он сначала выводит другие этапы на передний план, он теряет фокус и меню не открывается). .

//do this for each stage
stage.focusedProperty().addListener((observable, oldValue, newValue) -> {
    if (Boolean.TRUE.equals(newValue) && newValue != oldValue) {
        for (Stage s : otherStages) {
            s.setIconified(false);
            s.toFront();
        }
        //request the focus back, but that creates issues
        stage.requestFocus();
    }
});

Есть идеи, как реализовать третье требование?


person assylias    schedule 06.01.2014    source источник


Ответы (1)


Решение

Используйте stage.initOwner ( parentStage).

Образец приложения

Вот приложение для быстрого тестирования, которое инициализирует владельцев всех созданных этапов на этапе первичного приложения.

Кажется, что тестовое приложение соответствует всем вашим требованиям (протестировано в Windows 7, JavaFX 8b122).

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class LotsaStages extends Application {
    private static final Color[] STAGE_COLORS = { 
        Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW 
    };
    private static final double  STAGE_OFFSET = 50;

    @Override
    public void start(Stage primaryStage) throws Exception {
        addContent(primaryStage, Color.LIGHTBLUE);
        primaryStage.show();

        double offset = STAGE_OFFSET;
        for (Color color: STAGE_COLORS) {
            Stage child = new Stage();
            child.initOwner(primaryStage);
            child.initStyle(StageStyle.UTILITY);

            child.setX(primaryStage.getX() + offset);
            child.setY(primaryStage.getY() + offset);

            addContent(child, color);

            child.show();

            offset += STAGE_OFFSET;
        }
    }

    private void addContent(Stage child, Color color) {
        child.setScene(
            new Scene(
                new Group(
                    new Rectangle(150, 70, color)
                )
            )
        );
    }

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

Тестовое приложение довольно простое, и я не пытался воспроизвести ваши проблемы, связанные с меню, поэтому я не уверен, правильно ли оно пройдет для обработки на основе меню или других требований, которые могут у вас возникнуть.

Дополнительные вопросы

Так что, по сути, initOwner «связывает» детей с основной сценой?

Да, MSDN объясняет, как управление окнами работает в Windows. Поведение может немного отличаться на других платформах (поэтому JavaFX Javadoc по этому вопросу намеренно расплывчатый), но я думаю, что большинство принципов одинаковы, и он должен работать в OS X и Linux аналогичным образом.

Из MSDN:

Чтобы позволить вам создавать отношения между дочерним окном и родительским окном, Window поддерживает понятие владения. Право собственности устанавливается, когда свойство Владелец окна (принадлежащее окно) устанавливается со ссылкой на другое окно (окно-владелец).

Как только эти отношения установлены, проявляются следующие модели поведения:

  • Если окно-владелец свернуто, все принадлежащие ему окна также будут свернуты.
  • Если собственное окно свернуто, его владелец не сворачивается.
  • Если окно-владелец развернуто, восстанавливаются как окно-владелец, так и принадлежащие ему окна.
  • Окно владельца никогда не может закрывать собственное окно.
  • Окна, принадлежащие владельцам, которые не были открыты с помощью ShowDialog, не являются модальными. Пользователь по-прежнему может взаимодействовать с окном владельца.
  • Если вы закрываете окно-владелец, его собственные окна также закрываются.
  • Если собственное окно было открыто его владельцем окна с помощью Show, а собственное окно закрыто, событие Closing принадлежащего окна не возникает.

Когда вы открываете дочернее окно, вызывая ShowDialog, вы также должны установить свойство Owner дочернего окна. Если вы этого не сделаете, ваши пользователи не смогут восстановить дочернее и родительское окна, нажав кнопку на панели задач. Вместо этого нажатие кнопки панели задач приведет к появлению списка окон, включая дочернее и родительское окна, которые они могут выбрать; восстанавливается только выбранное окно.


Может ли это работать с такими детьми, как child = new Stage(UNDECORATED); child.initModality(Modality.NONE);?

Да.

person jewelsea    schedule 06.01.2014
comment
Из документов Oracle docs.oracle.com/javase/8/javafx/api/javafx/stage/ У стадии может факультативно быть окно-владелец. Когда окно является владельцем стадии, оно считается родителем этой стадии. Когда родительское окно закрывается, все его дочерние окна закрываются. Такое же цепное поведение применяется к родительскому окну, которое отображается в виде значков. Сцена всегда будет поверх своего родительского окна. Владелец должен быть инициализирован до того, как этап станет видимым. - person Linuslabo; 22.05.2015