Popup & PopupFactory
Certain Components, such as JPopupMenu
and JToolTip, present themselves
above all other Components in a particular
containment hierarchy. Rather than each of these
Components containing the same code to obtain the
same behavior, they delegate
to a Popup which can be obtained from a
PopupFactory. A Popup is able to
display a Component at a particular location on the
screen. Based on the size and location of the requested
Component, PopupFactory will return an
appropriate Popup.
Currently Popup and
PopupFactory are package private. Apple has
requested that for JDK 1.4 we expose these classes to enable
custom look and feel implementations the ability to create their
own Popup. This will allow Apple to position menus
in an appropriate manner for their look and feel. In
reviewing the current API we decided to make a handful of
changes, resulting in:
PopupFactory will be defined by:
/** *PopupFactory, as the name implies, is used to obtain * instances ofPopups.Popups are used to * display aComponentabove all otherComponents * in a particular containment hierarchy. The general contract is that * once you have obtained aPopupfrom a *PopupFactory, you must invokehideon the *Popup. The typical usage is: ** PopupFactory factory = PopupFactory.getSharedInstance(); * Popup popup = factory.getPopup(owner, contents, x, y); * popup.show(); * ... * popup.hide(); ** * @see Popup * * @version %I% %G% * @since 1.4 */ public class PopupFactory { /** * Sets theAppContextspecificPopupFactory. * This will throw anIllegalArgumentExceptionif *factoryisnull. * * @param factory SharedPopupFactory* @exceptionIllegalArgumentExceptionif *factoryisnull*/ public static void setSharedInstance(PopupFactory factory); /** * Returns the sharedPopupFactorywhich can be used * to obtainPopups. * * @return sharedPopupFactory*/ public static PopupFactory getSharedInstance(); /** * Creates aPopupfor theComponent*ownercontaining the Componentcontents. *owneris used to determine whichWindow* the newPopupwill parent theComponentthe *Popupcreates to. Anullowner* implies there is no valid parent.xand *yspecify the preferred initial location to place * thePopupat. Based on screen size, or other paramaters, * thePopupmay not display atxand *y. * * @param owner component mouse coordinates are relative to, * may benull* @param contents contents of thePopup* @param x initial x screen coordinate * @param y initial y screen coordinate * @exception IllegalArgumentException if contents isnull* @returnPopupcontaining contents */ public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException;
And Popup will be defined by:
/** * Popups are used to display aComponentto the user, typically * on top of all the otherComponents in a particular containment * hierarchy.Popups have a very small life cycle. Once you * have obtained aPopup, and hidden it (invoked the *hidemethod), you should no longer * invoke any methods on it. This allows thePopupFactoryto cache *Popups for later use. ** The general contract is that if you need to change the size of the *
Component, or location of thePopup, you should * obtain a newPopup. **
Popupdoes not descend fromComponent, rather * implementations ofPopupare responsible for creating * and maintaining their ownComponents to render the * requestedComponentto the user. ** You typically do not explicitly create an instance of
Popup, * instead obtain one from aPopupFactory. * * @see PopupFactory * * @version %I% %G% * @since 1.4 */ public class Popup { /** * Creates aPopupfor the Componentowner* containing the Componentcontents.owner* is used to determine whichWindowthe new *Popupwill parent theComponentthe *Popupcreates to. * Anullownerimplies there is no * valid parent.xand *yspecify the preferred initial location to place * thePopupat. Based on screen size, or other paramaters, * thePopupmay not display atxand *y. * * @param owner component mouse coordinates are relative to, may be null * @param contents contents of the Popup * @param x initial x screen coordinate * @param y initial y screen coordinate * @exception IllegalArgumentException ifcontentsis *null* @returnPopupcontaining contents */ protected Popup(Component owner, Component contents, int x, int y); /** * Creates aPopup. This is provided for subclasses. */ protected Popup(); /** * Makes thePopupvisible. If thePopupis * currently visible, this has no effect. */ public void show(); /** * Hides and disposes of thePopup. Once aPopup* has been disposed you should no longer invoke methods on it. A *disposedPopupmay be reclaimed and later used * based on thePopupFactory. As such, if you invoke methods * on adisposedPopup, indeterminate * behavior will result. */ public void hide();
To enable the Popup used by JPopupMenu
to be replaced by the UI, we will add the following to
PopupMenuUI:
/**
* Returns the Popup that will be responsible for
* displaying the JPopupMenu.
*
* @param popup JPopupMenu requesting Popup
* @param x screen x location where Popup is to be shown
* @param y screen y location where Popup is to be shown
* @return Popup that will show the JPopupMenu
* @since 1.4
*/
public Popup getPopup(JPopupMenu popup, int x, int y);
PopupMenuUI.getPopups implementation will obtain
the Popup from the shared
PopupFactory, but custom look and feel
implementations can override this and return whatever
Popup they desire.
JPopupMenu currently defines the method
setLocation. In pre-merlin this method would invoke
setLocation on the Popup, but as we
are removing this method from Popup,
JPopupMenu will now recreate the
Popup. We don't believe this is a problem, as
generally developers don't change the location of visible
popups. And the only time this would really cause a problem is
if the developer was some how relying on the
JPopupMenus parent only changing when the
Popopup was hidden, again, quite unlikely. A quick
grep through the source code reveals that internally we only
call this from show, which typically isn't
invoked when the Popup is visible.
JPopupMenu also defines the method
setPopupSize, which would invoke
setSize on the Popup if it was
visible. Internally we will change this method to set the
preferred size of the JPopupMenu, which will give
the same results. If the JPopupMenu is
visible when this is invoked, the Popup will be
recreated. Again, we don't feel this is much of an issue as
typically the size doesn't change once the popup is visible, and
it would really only effect developers if they were listening
for containment changing and doing something rather dubious. The
javadoc will change to reflect the new behavior:
/**
* Sets the size of the Popup window using a Dimension object.
* This is equivalent to setPreferredSize(d).
*
* @param d the Dimension specifying the new size
* of this component.
* @beaninfo
* description: The size of the popup menu
*/
public void setPopupSize(Dimension d);
/**
* Sets the size of the Popup window to the specified width and
* height. This is equivalent to
* setPreferredSize(new Dimension(width, height)).
*
* @param width the new width of the Popup in pixels
* @param height the new height of the Popup in pixels
* @beaninfo
* description: The size of the popup menu
*/
public void setPopupSize(int width, int height);