Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.stage; 027 028import java.util.ArrayList; 029import java.util.List; 030 031import javafx.beans.property.BooleanProperty; 032import javafx.beans.property.BooleanPropertyBase; 033import javafx.beans.property.SimpleBooleanProperty; 034import javafx.beans.property.StringProperty; 035import javafx.beans.property.StringPropertyBase; 036import javafx.collections.FXCollections; 037import javafx.collections.ListChangeListener.Change; 038import javafx.collections.ObservableList; 039import javafx.geometry.NodeOrientation; 040import javafx.scene.Scene; 041import javafx.scene.image.Image; 042 043import com.sun.javafx.beans.annotations.Default; 044import com.sun.javafx.collections.TrackableObservableList; 045import com.sun.javafx.robot.impl.FXRobotHelper; 046import com.sun.javafx.scene.SceneHelper; 047import com.sun.javafx.stage.StageHelper; 048import com.sun.javafx.stage.StagePeerListener; 049import com.sun.javafx.tk.TKPulseListener; 050import com.sun.javafx.tk.TKStage; 051import com.sun.javafx.tk.Toolkit; 052import javafx.beans.property.DoubleProperty; 053import javafx.beans.property.DoublePropertyBase; 054import javafx.beans.property.Property; 055import javafx.beans.property.ReadOnlyBooleanProperty; 056import javafx.beans.property.ReadOnlyBooleanWrapper; 057import javafx.beans.value.ObservableValue; 058 059/** 060 * The JavaFX {@code Stage} class is the top level JavaFX container. 061 * The primary Stage is constructed by the platform. Additional Stage 062 * objects may be constructed by the application. 063 * 064 * <p> 065 * Stage objects must be constructed and modified on the 066 * JavaFX Application Thread. 067 * </p> 068 * <p> 069 * Many of the {@code Stage} properties are read only because they can 070 * be changed externally by the underlying platform and therefore must 071 * not be bindable. 072 * </p> 073 * 074 * <p><b>Style</b></p> 075 * <p> 076 * A stage has one of the following styles: 077 * <ul> 078 * <li>{@link StageStyle#DECORATED} - a stage with a solid white background and 079 * platform decorations.</li> 080 * <li>{@link StageStyle#UNDECORATED} - a stage with a solid white background 081 * and no decorations.</li> 082 * <li>{@link StageStyle#TRANSPARENT} - a stage with a transparent background 083 * and no decorations.</li> 084 * <li>{@link StageStyle#UTILITY} - a stage with a solid white background and 085 * minimal platform decorations.</li> 086 * </ul> 087 * <p>The style must be initialized before the stage is made visible.</p> 088 * <p>On some platforms decorations might not be available. For example, on 089 * some mobile or embedded devices. In these cases a request for a DECORATED or 090 * UTILITY window will be accepted, but no decorations will be shown. </p> 091 * 092 * <p><b>Owner</b></p> 093 * <p> 094 * A stage can optionally have an owner Window. 095 * When a window is a stage's owner, it is said to be the parent of that stage. 096 * When a parent window is closed, all its descendant windows are closed. 097 * The same chained behavior applied for a parent window that is iconified. 098 * A stage will always be on top of its parent window. 099 * The owner must be initialized before the stage is made visible. 100 * 101 * <p><b>Modality</b></p> 102 * <p> 103 * A stage has one of the following modalities: 104 * <ul> 105 * <li>{@link Modality#NONE} - a stage that does not block any other window.</li> 106 * <li>{@link Modality#WINDOW_MODAL} - a stage that blocks input events from 107 * being delivered to all windows from its owner (parent) to its root. 108 * Its root is the closest ancestor window without an owner.</li> 109 * <li>{@link Modality#APPLICATION_MODAL} - a stage that blocks input events from 110 * being delivered to all windows from the same application, except for those 111 * from its child hierarchy.</li> 112 * </ul> 113 * 114 * <p>When a window is blocked by a modal stage its Z-order relative to its ancestors 115 * is preserved, and it receives no input events and no window activation events, 116 * but continues to animate and render normally. 117 * Note that showing a modal stage does not necessarily block the caller. The 118 * {@link #show} method returns immediately regardless of the modality of the stage. 119 * Use the {@link #showAndWait} method if you need to block the caller until 120 * the modal stage is hidden (closed). 121 * The modality must be initialized before the stage is made visible.</p> 122 * 123 * <p><b>Example:</b></p> 124 * 125 * 126<pre><code> 127import javafx.application.Application; 128import javafx.scene.Group; 129import javafx.scene.Scene; 130import javafx.scene.text.Font; 131import javafx.scene.text.Text; 132import javafx.stage.Stage; 133 134public class HelloWorld extends Application { 135 136 @Override public void start(Stage stage) { 137 Text text = new Text(10, 40, "Hello World!"); 138 text.setFont(new Font(40)); 139 Scene scene = new Scene(new Group(text)); 140 141 stage.setTitle("Welcome to JavaFX!"); 142 stage.setScene(scene); 143 stage.sizeToScene(); 144 stage.show(); 145 } 146 147 public static void main(String[] args) { 148 Application.launch(args); 149 } 150} 151 152 * </code></pre> 153 * <p>produces the following on Windows:</p> 154 * <p><img src="doc-files/Stage-win.png"/></p> 155 * 156 * <p>produces the following on Mac OSX:</p> 157 * <p><img src="doc-files/Stage-mac.png"/></p> 158 * 159 * <p>produces the following on Linux:</p> 160 * <p><img src="doc-files/Stage-linux.png"/></p> 161 */ 162public class Stage extends Window { 163 164 private boolean inNestedEventLoop = false; 165 166 private static ObservableList<Stage> stages = FXCollections.<Stage>observableArrayList(); 167 168 static { 169 FXRobotHelper.setStageAccessor(new FXRobotHelper.FXRobotStageAccessor() { 170 @Override public ObservableList<Stage> getStages() { 171 return stages; 172 } 173 }); 174 StageHelper.setStageAccessor(new StageHelper.StageAccessor() { 175 @Override public ObservableList<Stage> getStages() { 176 return stages; 177 } 178 }); 179 } 180 181 private static final StagePeerListener.StageAccessor STAGE_ACCESSOR = new StagePeerListener.StageAccessor() { 182 183 @Override 184 public void setIconified(Stage stage, boolean iconified) { 185 stage.iconifiedPropertyImpl().set(iconified); 186 } 187 188 @Override 189 public void setMaximized(Stage stage, boolean maximized) { 190 stage.maximizedPropertyImpl().set(maximized); 191 } 192 193 @Override 194 public void setResizable(Stage stage, boolean resizable) { 195 ((ResizableProperty)stage.resizableProperty()).setNoInvalidate(resizable); 196 } 197 198 @Override 199 public void setFullScreen(Stage stage, boolean fs) { 200 stage.fullScreenPropertyImpl().set(fs); 201 } 202 }; 203 204 /** 205 * Creates a new instance of decorated {@code Stage}. 206 * 207 * @throws IllegalStateException if this constructor is called on a thread 208 * other than the JavaFX Application Thread. 209 */ 210 public Stage() { 211 this(StageStyle.DECORATED); 212 } 213 214 /** 215 * Creates a new instance of {@code Stage}. 216 * 217 * @param style The style of the {@code Stage} 218 * 219 * @throws IllegalStateException if this constructor is called on a thread 220 * other than the JavaFX Application Thread. 221 */ 222 public Stage(@Default("javafx.stage.StageStyle.DECORATED") StageStyle style) { 223 super(); 224 225 Toolkit.getToolkit().checkFxUserThread(); 226 227 // Set the style 228 initStyle(style); 229 } 230 231 /** 232 * Specify the scene to be used on this stage. 233 */ 234 @Override final public void setScene(Scene value) { 235 super.setScene(value); 236 } 237 238 /** 239 * @inheritDoc 240 */ 241 @Override public final void show() { 242 super.show(); 243 } 244 245 private boolean primary = false; 246 247 /** 248 * sets this stage to be the primary stage. 249 * When run as an applet, this stage will appear in the broswer 250 * @treatAsPrivate implementation detail 251 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 252 */ 253 @Deprecated 254 public void impl_setPrimary(boolean primary) { 255 this.primary = primary; 256 } 257 258 /** 259 * Returns whether this stage is the primary stage. 260 * When run as an applet, the primary stage will appear in the broswer 261 * 262 * @return true if this stage is the primary stage for the application. 263 */ 264 boolean isPrimary() { 265 return primary; 266 } 267 268 /** 269 * @treatAsPrivate implementation detail 270 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 271 */ 272 @Deprecated 273 @Override 274 public String impl_getMXWindowType() { 275 return (primary) ? "PrimaryStage" : getClass().getSimpleName(); 276 } 277 278 private boolean important = true; 279 280 /** 281 * Sets a flag indicating whether this stage is an "important" window for 282 * the purpose of determining whether the application is idle and should 283 * exit. The application is considered finished when the last important 284 * window is closed. 285 * @treatAsPrivate implementation detail 286 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 287 */ 288 @Deprecated 289 public void impl_setImportant(boolean important) { 290 this.important = important; 291 } 292 293 private boolean isImportant() { 294 return important; 295 } 296 297 /** 298 * Shows this stage and waits for it to be hidden (closed) before returning 299 * to the caller. This method temporarily blocks processing of the current 300 * event, and starts a nested event loop to handle other events. 301 * This method must be called on the FX Application thread. 302 * <p> 303 * A Stage is hidden (closed) by one of the following means: 304 * <ul> 305 * <li>the application calls the {@link #hide} or {@link #close} method on 306 * this stage</li> 307 * <li>this stage has a non-null owner window, and its owner is closed</li> 308 * <li>the user closes the window via the window system (for example, 309 * by pressing the close button in the window decoration)</li> 310 * </ul> 311 * </p> 312 * 313 * <p> 314 * After the Stage is hidden, and the application has returned from the 315 * event handler to the event loop, the nested event loop terminates 316 * and this method returns to the caller. 317 * </p> 318 * <p> 319 * For example, consider the following sequence of operations for different 320 * event handlers, assumed to execute in the order shown below: 321 * <pre>void evtHander1(...) { 322 * stage1.showAndWait(); 323 * doSomethingAfterStage1Closed(...) 324 * } 325 * 326 * void evtHander2(...) { 327 * stage1.hide(); 328 * doSomethingElseHere(...) 329 * }</pre> 330 * evtHandler1 will block at the call to showAndWait. It will resume execution 331 * after stage1 is hidden and the current event handler, in this case evtHandler2, 332 * returns to the event loop. This means that doSomethingElseHere will 333 * execute before doSomethingAfterStage1Closed. 334 * </p> 335 * 336 * <p> 337 * More than one stage may be shown with showAndWait. Each call 338 * will start a new nested event loop. The stages may be hidden in any order, 339 * but a particular nested event loop (and thus the showAndWait method 340 * for the associated stage) will only terminate after all inner event loops 341 * have also terminated. 342 * </p> 343 * <p> 344 * For example, consider the following sequence of operations for different 345 * event handlers, assumed to execute in the order shown below: 346 * <ul> 347 * <pre>void evtHander1() { 348 * stage1.showAndWait(); 349 * doSomethingAfterStage1Closed(...) 350 * } 351 * 352 * void evtHander2() { 353 * stage2.showAndWait(); 354 * doSomethingAfterStage2Closed(...) 355 * } 356 * 357 * void evtHander3() { 358 * stage1.hide(); 359 * doSomethingElseHere(...) 360 * } 361 * 362 * void evtHander4() { 363 * stage2.hide(); 364 * doSomethingElseHereToo(...) 365 * }</pre> 366 * </ul> 367 * evtHandler1 will block at the call to stage1.showAndWait, starting up 368 * a nested event loop just like in the previous example. evtHandler2 will 369 * then block at the call to stage2.showAndWait, starting up another (inner) 370 * nested event loop. The first call to stage1.showAndWait will resume execution 371 * after stage1 is hidden, but only after the inner nested event loop started 372 * by stage2.showAndWait has terminated. This means that the call to 373 * stage1.showAndWait won't return until after evtHandler2 has returned. 374 * The order of execution is: stage1.showAndWait, stage2.showAndWait, 375 * stage1.hide, doSomethingElseHere, stage2.hide, doSomethingElseHereToo, 376 * doSomethingAfterStage2Closed, doSomethingAfterStage1Closed. 377 * </p> 378 * 379 * <p> 380 * This method must not be called on the primary stage or on a stage that 381 * is already visible. 382 * </p> 383 * 384 * @throws IllegalStateException if this method is called on a thread 385 * other than the JavaFX Application Thread. 386 * @throws IllegalStateException if this method is called on the 387 * primary stage. 388 * @throws IllegalStateException if this stage is already showing. 389 * @since 2.2 390 */ 391 public void showAndWait() { 392 393 Toolkit.getToolkit().checkFxUserThread(); 394 395 if (isPrimary()) { 396 throw new IllegalStateException("Cannot call this method on primary stage"); 397 } 398 399 if (isShowing()) { 400 throw new IllegalStateException("Stage already visible"); 401 } 402 403 // TODO: file a new bug; the following assertion can fail if this 404 // method is called from an event handler that is listening to a 405 // WindowEvent.WINDOW_HIDING event. 406 assert !inNestedEventLoop; 407 408 show(); 409 inNestedEventLoop = true; 410 Toolkit.getToolkit().enterNestedEventLoop(this); 411 } 412 413 private StageStyle style; // default is set in constructor 414 415 /** 416 * Specifies the style for this stage. This must be done prior to making 417 * the stage visible. The style is one of: StageStyle.DECORATED, 418 * StageStyle.UNDECORATED, StageStyle.TRANSPARENT, or StageStyle.UTILITY. 419 * 420 * @param style the style for this stage. 421 * 422 * @throws IllegalStateException if this property is set after the stage 423 * has ever been made visible. 424 * 425 * @defaultValue StageStyle.DECORATED 426 */ 427 public final void initStyle(StageStyle style) { 428 if (hasBeenVisible) { 429 throw new IllegalStateException("Cannot set style once stage has been set visible"); 430 } 431 this.style = style; 432 } 433 434 /** 435 * Retrieves the style attribute for this stage. 436 * 437 * @return the stage style. 438 */ 439 public final StageStyle getStyle() { 440 return style; 441 } 442 443 private Modality modality = Modality.NONE; 444 445 /** 446 * Specifies the modality for this stage. This must be done prior to making 447 * the stage visible. The modality is one of: Modality.NONE, 448 * Modality.WINDOW_MODAL, or Modality.APPLICATION_MODAL. 449 * 450 * @param modality the modality for this stage. 451 * 452 * @throws IllegalStateException if this property is set after the stage 453 * has ever been made visible. 454 * 455 * @throws IllegalStateException if this stage is the primary stage. 456 * 457 * @defaultValue Modality.NONE 458 */ 459 public final void initModality(Modality modality) { 460 if (hasBeenVisible) { 461 throw new IllegalStateException("Cannot set modality once stage has been set visible"); 462 } 463 464 if (isPrimary()) { 465 throw new IllegalStateException("Cannot set modality for the primary stage"); 466 } 467 468 this.modality = modality; 469 } 470 471 /** 472 * Retrieves the modality attribute for this stage. 473 * 474 * @return the modality. 475 */ 476 public final Modality getModality() { 477 return modality; 478 } 479 480 private Window owner = null; 481 482 /** 483 * Specifies the owner Window for this stage, or null for a top-level, 484 * unowned stage. This must be done prior to making the stage visible. 485 * 486 * @param owner the owner for this stage. 487 * 488 * @throws IllegalStateException if this property is set after the stage 489 * has ever been made visible. 490 * 491 * @throws IllegalStateException if this stage is the primary stage. 492 * 493 * @defaultValue null 494 */ 495 public final void initOwner(Window owner) { 496 if (hasBeenVisible) { 497 throw new IllegalStateException("Cannot set owner once stage has been set visible"); 498 } 499 500 if (isPrimary()) { 501 throw new IllegalStateException("Cannot set owner for the primary stage"); 502 } 503 504 this.owner = owner; 505 506 final Scene sceneValue = getScene(); 507 if (sceneValue != null) { 508 SceneHelper.parentEffectiveOrientationInvalidated(sceneValue); 509 } 510 } 511 512 /** 513 * Retrieves the owner Window for this stage, or null for an unowned stage. 514 * 515 * @return the owner Window. 516 */ 517 public final Window getOwner() { 518 return owner; 519 } 520 521 /** 522 * Specifies whether this {@code Stage} should be a full-screen, 523 * undecorated window. 524 * <p> 525 * The implementation of full-screen mode is platform and profile-dependent. 526 * </p> 527 * <p> 528 * When set to {@code true}, the {@code Stage} will attempt to enter 529 * full-screen mode when visible. Set to {@code false} to return {@code Stage} 530 * to windowed mode. 531 * An {@link IllegalStateException} is thrown if this property is set 532 * on a thread other than the JavaFX Application Thread. 533 * </p> 534 * <p> 535 * The full-screen mode will be exited (and the {@code fullScreen} attribute 536 * will be set to {@code false}) if the full-screen 537 * {@code Stage} loses focus or if another {@code Stage} enters 538 * full-screen mode on the same {@link Screen}. Note that a {@code Stage} 539 * in full-screen mode can become invisible without losing its 540 * full-screen status and will again enter full-screen mode when the 541 * {@code Stage} becomes visible. 542 * </p> 543 * If the platform supports multiple screens an application can control 544 * which {@code Screen} the Stage will enter full-screen mode on by 545 * setting its position to be within the bounds of that {@code Screen} 546 * prior to entering full-screen mode. 547 * <p> 548 * However once in full-screen mode, {@code Stage}'s {@code x}, {@code y}, 549 * {@code width}, and {@code height} variables will continue to represent 550 * the non-full-screen position and size of the window; the same for 551 * {@code iconified}, {@code resizable}, {@code style}, and {@code 552 * opacity}. If changes are made to any of these attributes while in 553 * full-screen mode, upon exiting full-screen mode the {@code Stage} will 554 * assume those attributes. 555 * </p> 556 * <p> 557 * In case that more {@code Stage} modes are set simultaneously their order 558 * of importance is {@code iconified}, fullScreen, {@code maximized} (from 559 * strongest to weakest). 560 * </p> 561 * <p> 562 * The property is read only because it can be changed externally 563 * by the underlying platform and therefore must not be bindable. 564 * </p> 565 * 566 * Notes regarding desktop profile implementation. 567 * <p> 568 * For desktop profile the runtime will attempt to enter full-screen 569 * exclusive mode (FSEM) if such is supported by the platform and it is 570 * allowed for this application. If either is not the case a 571 * simulated full-screen window will be used instead; the window will be 572 * maximized, made undecorated if possible, and moved to the front. 573 * </p> 574 * For desktop profile the user can unconditionally exit full-screen mode 575 * at any time by pressing {@code ESC}. 576 * <p> 577 * There are differences in behavior between signed and unsigned 578 * applications. Signed applications are allowed to enter full-screen 579 * exclusive mode unrestricted while unsigned applications will 580 * have the following restrictions: 581 * </p> 582 * <ul> 583 * <li>Applications can only enter FSEM in response 584 * to user input. More specifically, entering is allowed from mouse 585 * ({@code Node.mousePressed/mouseReleased/mouseClicked}) or keyboard 586 * ({@code Node.keyPressed/keyReleased/keyTyped}) event handlers. It is 587 * not allowed to enter FSEM in response to {@code ESC} 588 * key. Attempting to enter FSEM from any other context will result in 589 * emulated full-screen mode. 590 * <p> 591 * If {@code Stage} was constructed as full-screen but not visible 592 * it will enter full-screen mode upon becoming visible, with the same 593 * limitations to when this is allowed to happen as when setting 594 * {@code fullScreen} to {@code true}. 595 * </p> 596 * </li> 597 * <li> If the application was allowed to enter FSEM 598 * it will have limited keyboard input. It will only receive KEY_PRESSED 599 * and KEY_RELEASED events from the following keys: 600 * {@code UP, DOWN, LEFT, RIGHT, SPACE, TAB, PAGE_UP, PAGE_DOWN, HOME, END, ENTER} 601 * </li> 602 * </ul> 603 * @defaultValue false 604 */ 605 private ReadOnlyBooleanWrapper fullScreen; 606 607 public final void setFullScreen(boolean value) { 608 Toolkit.getToolkit().checkFxUserThread(); 609 fullScreenPropertyImpl().set(value); 610 if (impl_peer != null) 611 impl_peer.setFullScreen(value); 612 } 613 614 public final boolean isFullScreen() { 615 return fullScreen == null ? false : fullScreen.get(); 616 } 617 618 public final ReadOnlyBooleanProperty fullScreenProperty() { 619 return fullScreenPropertyImpl().getReadOnlyProperty(); 620 } 621 622 private ReadOnlyBooleanWrapper fullScreenPropertyImpl () { 623 if (fullScreen == null) { 624 fullScreen = new ReadOnlyBooleanWrapper(Stage.this, "fullScreen"); 625 } 626 return fullScreen; 627 } 628 629 /** 630 * Defines the icon images to be used in the window decorations and when 631 * minimized. The images should be different sizes of the same image and 632 * the best size will be chosen, eg. 16x16, 32,32. 633 * 634 * @defaultValue empty 635 */ 636 private ObservableList<Image> icons = new TrackableObservableList<Image>() { 637 @Override protected void onChanged(Change<Image> c) { 638 List<Object> platformImages = new ArrayList<Object>(); 639 for (Image icon : icons) { 640 platformImages.add(icon.impl_getPlatformImage()); 641 } 642 if (impl_peer != null) { 643 impl_peer.setIcons(platformImages); 644 } 645 } 646 }; 647 648 /** 649 * Gets the icon images to be used in the window decorations and when 650 * minimized. The images should be different sizes of the same image and 651 * the best size will be chosen, eg. 16x16, 32,32. 652 * @return An observable list of icons of this window 653 */ 654 public final ObservableList<Image> getIcons() { 655 return icons; 656 } 657 658 /** 659 * Defines the title of the {@code Stage}. 660 * 661 * @defaultValue empty string 662 */ 663 private StringProperty title; 664 665 public final void setTitle(String value) { 666 titleProperty().set(value); 667 } 668 669 public final String getTitle() { 670 return title == null ? null : title.get(); 671 } 672 673 public final StringProperty titleProperty() { 674 if (title == null) { 675 title = new StringPropertyBase() { 676 677 @Override 678 protected void invalidated() { 679 if (impl_peer != null) { 680 impl_peer.setTitle(get()); 681 } 682 } 683 684 @Override 685 public Object getBean() { 686 return Stage.this; 687 } 688 689 @Override 690 public String getName() { 691 return "title"; 692 } 693 }; 694 } 695 return title; 696 } 697 698 /** 699 * Defines whether the {@code Stage} is iconified or not. 700 * <p> 701 * In case that more {@code Stage} modes are set simultaneously their order 702 * of importance is iconified} {@code fullScreen}, {@code maximized} (from 703 * strongest to weakest). 704 * </p> 705 * <p> 706 * On some mobile and embedded platforms setting this property to true will 707 * hide the {@code Stage} but not show an icon for it. 708 * </p> 709 * <p> 710 * The property is read only because it can be changed externally 711 * by the underlying platform and therefore must not be bindable. 712 * </p> 713 * 714 * @defaultValue false 715 */ 716 private ReadOnlyBooleanWrapper iconified; 717 718 public final void setIconified(boolean value) { 719 iconifiedPropertyImpl().set(value); 720 if (impl_peer != null) 721 impl_peer.setIconified(value); 722 } 723 724 public final boolean isIconified() { 725 return iconified == null ? false : iconified.get(); 726 } 727 728 public final ReadOnlyBooleanProperty iconifiedProperty() { 729 return iconifiedPropertyImpl().getReadOnlyProperty(); 730 } 731 732 private final ReadOnlyBooleanWrapper iconifiedPropertyImpl() { 733 if (iconified == null) { 734 iconified = new ReadOnlyBooleanWrapper(Stage.this, "iconified"); 735 } 736 return iconified; 737 } 738 739 /** 740 * Defines whether the {@code Stage} is maximized or not. 741 * <p> 742 * In case that more {@code Stage} modes are set simultaneously their order 743 * of importance is {@code iconified}, {@code fullScreen}, maximized (from 744 * strongest to weakest). 745 * </p> 746 * <p> 747 * The property is read only because it can be changed externally 748 * by the underlying platform and therefore must not be bindable. 749 * </p> 750 * 751 * @defaultValue false 752 */ 753 private ReadOnlyBooleanWrapper maximized; 754 755 public final void setMaximized(boolean value) { 756 maximizedPropertyImpl().set(value); 757 if (impl_peer != null) 758 impl_peer.setMaximized(value); 759 } 760 761 public final boolean isMaximized() { 762 return maximized == null ? false : maximized.get(); 763 } 764 765 public final ReadOnlyBooleanProperty maximizedProperty() { 766 return maximizedPropertyImpl().getReadOnlyProperty(); 767 } 768 769 private final ReadOnlyBooleanWrapper maximizedPropertyImpl() { 770 if (maximized == null) { 771 maximized = new ReadOnlyBooleanWrapper(Stage.this, "maximized"); 772 } 773 return maximized; 774 } 775 776 /** 777 * Defines whether the {@code Stage} is resizable or not by the user. 778 * Programatically you may still change the size of the Stage. This is 779 * a hint which allows the implementation to optionally make the Stage 780 * resizable by the user. 781 * <p> 782 * <b>Warning:</b> Since 8.0 the property cannot be bound and will throw 783 * {@code RuntimeException} on an attempt to do so. This is because 784 * the setting of resizable is asynchronous on some systems or generally 785 * might be set by the system / window manager. 786 * <br> 787 * Bidirectional binds are still allowed, as they don't block setting of the 788 * property by the system. 789 * 790 * @defaultValue true 791 */ 792 private BooleanProperty resizable; 793 794 public final void setResizable(boolean value) { 795 resizableProperty().set(value); 796 } 797 798 public final boolean isResizable() { 799 return resizable == null ? true : resizable.get(); 800 } 801 802 public final BooleanProperty resizableProperty() { 803 if (resizable == null) { 804 resizable = new ResizableProperty(); 805 } 806 return resizable; 807 } 808 809 //We cannot return ReadOnlyProperty in resizable, as this would be 810 // backward incompatible. All we can do is to create this custom property 811 // implementation that disallows binds 812 private class ResizableProperty extends SimpleBooleanProperty { 813 private boolean noInvalidate; 814 815 public ResizableProperty() { 816 super(Stage.this, "resizable", true); 817 } 818 819 void setNoInvalidate(boolean value) { 820 noInvalidate = true; 821 set(value); 822 noInvalidate = false; 823 } 824 825 @Override 826 protected void invalidated() { 827 if (noInvalidate) { 828 return; 829 } 830 if (impl_peer != null) { 831 applyBounds(); 832 impl_peer.setResizable(get()); 833 } 834 } 835 836 @Override 837 public void bind(ObservableValue<? extends Boolean> rawObservable) { 838 throw new RuntimeException("Resizable property cannot be bound"); 839 } 840 841 } 842 843 /** 844 * Defines the minimum width of this {@code Stage}. 845 * 846 * @defaultValue 0 847 */ 848 private DoubleProperty minWidth; 849 850 public final void setMinWidth(double value) { 851 minWidthProperty().set(value); 852 } 853 854 public final double getMinWidth() { 855 return minWidth == null ? 0 : minWidth.get(); 856 } 857 858 public final DoubleProperty minWidthProperty() { 859 if (minWidth == null) { 860 minWidth = new DoublePropertyBase(0) { 861 862 @Override 863 protected void invalidated() { 864 if (impl_peer != null) { 865 impl_peer.setMinimumSize((int) Math.ceil(get()), 866 (int) Math.ceil(getMinHeight())); 867 } 868 if (getWidth() < getMinWidth()) { 869 setWidth(getMinWidth()); 870 } 871 } 872 873 @Override 874 public Object getBean() { 875 return Stage.this; 876 } 877 878 @Override 879 public String getName() { 880 return "minWidth"; 881 } 882 }; 883 } 884 return minWidth; 885 } 886 887 /** 888 * Defines the minimum height of this {@code Stage}. 889 * 890 * @defaultValue 0 891 */ 892 private DoubleProperty minHeight; 893 894 public final void setMinHeight(double value) { 895 minHeightProperty().set(value); 896 } 897 898 public final double getMinHeight() { 899 return minHeight == null ? 0 : minHeight.get(); 900 } 901 902 public final DoubleProperty minHeightProperty() { 903 if (minHeight == null) { 904 minHeight = new DoublePropertyBase(0) { 905 906 @Override 907 protected void invalidated() { 908 if (impl_peer != null) { 909 impl_peer.setMinimumSize( 910 (int) Math.ceil(getMinWidth()), 911 (int) Math.ceil(get())); 912 } 913 if (getHeight() < getMinHeight()) { 914 setHeight(getMinHeight()); 915 } 916 } 917 918 @Override 919 public Object getBean() { 920 return Stage.this; 921 } 922 923 @Override 924 public String getName() { 925 return "minHeight"; 926 } 927 }; 928 } 929 return minHeight; 930 } 931 932 /** 933 * Defines the maximum width of this {@code Stage}. 934 * 935 * @defaultValue Double.MAX_VALUE 936 */ 937 private DoubleProperty maxWidth; 938 939 public final void setMaxWidth(double value) { 940 maxWidthProperty().set(value); 941 } 942 943 public final double getMaxWidth() { 944 return maxWidth == null ? Double.MAX_VALUE : maxWidth.get(); 945 } 946 947 public final DoubleProperty maxWidthProperty() { 948 if (maxWidth == null) { 949 maxWidth = new DoublePropertyBase(Double.MAX_VALUE) { 950 951 @Override 952 protected void invalidated() { 953 if (impl_peer != null) { 954 impl_peer.setMaximumSize((int) Math.floor(get()), 955 (int) Math.floor(getMaxHeight())); 956 } 957 if (getWidth() > getMaxWidth()) { 958 setWidth(getMaxWidth()); 959 } 960 } 961 962 @Override 963 public Object getBean() { 964 return Stage.this; 965 } 966 967 @Override 968 public String getName() { 969 return "maxWidth"; 970 } 971 }; 972 } 973 return maxWidth; 974 } 975 976 /** 977 * Defines the maximum height of this {@code Stage}. 978 * 979 * @defaultValue Double.MAX_VALUE 980 */ 981 private DoubleProperty maxHeight; 982 983 public final void setMaxHeight(double value) { 984 maxHeightProperty().set(value); 985 } 986 987 public final double getMaxHeight() { 988 return maxHeight == null ? Double.MAX_VALUE : maxHeight.get(); 989 } 990 991 public final DoubleProperty maxHeightProperty() { 992 if (maxHeight == null) { 993 maxHeight = new DoublePropertyBase(Double.MAX_VALUE) { 994 995 @Override 996 protected void invalidated() { 997 if (impl_peer != null) { 998 impl_peer.setMaximumSize( 999 (int) Math.floor(getMaxWidth()), 1000 (int) Math.floor(get())); 1001 } 1002 if (getHeight() > getMaxHeight()) { 1003 setHeight(getMaxHeight()); 1004 } 1005 } 1006 1007 @Override 1008 public Object getBean() { 1009 return Stage.this; 1010 } 1011 1012 @Override 1013 public String getName() { 1014 return "maxHeight"; 1015 } 1016 }; 1017 } 1018 return maxHeight; 1019 } 1020 1021 1022 /** 1023 * @treatAsPrivate implementation detail 1024 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 1025 */ 1026 @Deprecated 1027 @Override protected void impl_visibleChanging(boolean value) { 1028 super.impl_visibleChanging(value); 1029 Toolkit toolkit = Toolkit.getToolkit(); 1030 if (value && (impl_peer == null)) { 1031 // Setup the peer 1032 Window window = getOwner(); 1033 TKStage tkStage = (window == null ? null : window.impl_getPeer()); 1034 Scene scene = getScene(); 1035 boolean rtl = scene != null && scene.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT; 1036 1037 impl_peer = toolkit.createTKStage(getStyle(), isPrimary(), getModality(), tkStage, rtl); 1038 peerListener = new StagePeerListener(this, STAGE_ACCESSOR); 1039 1040 // Insert this into stages so we have a references to all created stages 1041 stages.add(this); 1042 } 1043 } 1044 1045 1046 /** 1047 * @treatAsPrivate implementation detail 1048 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 1049 */ 1050 @Deprecated 1051 @Override protected void impl_visibleChanged(boolean value) { 1052 super.impl_visibleChanged(value); 1053 1054 if (value) { 1055 // Finish initialization 1056 impl_peer.setImportant(isImportant()); 1057 impl_peer.setResizable(isResizable()); 1058 impl_peer.setFullScreen(isFullScreen()); 1059 impl_peer.setIconified(isIconified()); 1060 impl_peer.setMaximized(isMaximized()); 1061 impl_peer.setTitle(getTitle()); 1062 impl_peer.setMinimumSize((int) Math.ceil(getMinWidth()), 1063 (int) Math.ceil(getMinHeight())); 1064 impl_peer.setMaximumSize((int) Math.floor(getMaxWidth()), 1065 (int) Math.floor(getMaxHeight())); 1066 1067 List<Object> platformImages = new ArrayList<Object>(); 1068 for (Image icon : icons) { 1069 platformImages.add(icon.impl_getPlatformImage()); 1070 } 1071 if (impl_peer != null) { 1072 impl_peer.setIcons(platformImages); 1073 } 1074 } 1075 1076 if (!value) { 1077 // Remove form active stage list 1078 stages.remove(this); 1079 } 1080 1081 if (!value && inNestedEventLoop) { 1082 inNestedEventLoop = false; 1083 Toolkit.getToolkit().exitNestedEventLoop(this, null); 1084 } 1085 } 1086 1087 /** 1088 * Bring the {@code Window} to the foreground. If the {@code Window} is 1089 * already in the foreground there is no visible difference. 1090 */ 1091 public void toFront() { 1092 if (impl_peer != null) { 1093 impl_peer.toFront(); 1094 } 1095 } 1096 1097 /** 1098 * Send the {@code Window} to the background. If the {@code Window} is 1099 * already in the background there is no visible difference. This action 1100 * places this {@code Window} at the bottom of the stacking order on 1101 * platforms that support stacking. 1102 */ 1103 public void toBack() { 1104 if (impl_peer != null) { 1105 impl_peer.toBack(); 1106 } 1107 } 1108 1109 /** 1110 * Closes this {@code Stage}. 1111 * This call is equivalent to {@code hide()}. 1112 */ 1113 public void close() { 1114 hide(); 1115 } 1116 1117 @Override 1118 Window getWindowOwner() { 1119 return getOwner(); 1120 } 1121}