如何让GWT菜单弹出窗口保留在浏览器窗口中?

时间:2010-10-13 14:59:34

标签: gwt menu positioning

我的GWT应用程序使用DockLayoutPanel进行主要布局,页面本身不会滚动。我有一个带有MenuBar的PopupPanel,有时候当选择了MenuItem时,子菜单栏会突然从屏幕底部开始,迫使新滚动条进入浏览器并弄乱布局。

当默认定位将其从浏览器视口中移出(PopupPanel.showRelativeTo(uiTarget)定位的工作方式)时,如何让菜单弹出窗口表现良好并向上重新定位?

在查看MenuBar源代码时,看起来所有的布局都是在私有方法中完成的,所以我无法在子类中修复它,我也看不到任何我可以听到的事件会让我做重新定位自己。

3 个答案:

答案 0 :(得分:3)

看看http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/6185225fec64c091/4954d91d1461c71f?lnk=gst&q=context+menu#4954d91d1461c71f

我们已经成功地使用这个策略了一段时间。

更新:还有一些工作要做。具体做法是:

  • 创建一个reposition()方法,其中包括:

    • 确定所有菜单项的最大宽度
    • 检查菜单的左边缘+最大宽度;如果大于Window的宽度,请使用“DOM.setStyleAttribute(elem,”left“,left +”px“);”移动菜单
    • 获取菜单的高度;如果菜单顶部+菜单高度>窗口的高度,使用“DOM.setStyleAttribute(elem,”top“,top +”px“);”提升它。
  • 在onAttach()方法中,使用deferred命令调用reposition()方法。

答案 1 :(得分:1)

您可以在显示弹出窗口之前拦截弹出窗口,但是在创建弹出窗口大小之后。这样你就可以获得弹出窗口的宽度,并可以将其移动到另一个位置:

@Override
public void onContextMenu(ContextMenuEvent evt) {
    int x = evt.getNativeEvent().getClientX();
    int y = evt.getNativeEvent().getClientY();

    popupMenu.setPopupPositionAndShow(new PositionCallback() {
        @Override
        public void setPosition(int offsetWidth, int offsetHeight) {
            if (x + offsetWidth > Window.getClientWidth()) {
                x = Window.getClientWidth() - offsetWidth;
            }

            //use same technique for height if you want for y, then
            setPosition(x, y);
        }
    });
}

(我知道这是一个老问题,但如果你搜索这个问题仍然会出现,所以我想提供现有解决方案)

答案 2 :(得分:0)

...电解金属锰

这是一个有趣的问题......

查看MenuBar源代码...尤其是方法 openPopup

 private void openPopup(final MenuItem item) {
    // Only the last popup to be opened should preview all event
    if (parentMenu != null && parentMenu.popup != null) {
      parentMenu.popup.setPreviewingAllNativeEvents(false);
    }

    // Create a new popup for this item, and position it next to
    // the item (below if this is a horizontal menu bar, to the
    // right if it's a vertical bar).
    popup = new DecoratedPopupPanel(true, false, "menuPopup") {
      {
        setWidget(item.getSubMenu());
        setPreviewingAllNativeEvents(true);
        item.getSubMenu().onShow();
      }

      @Override
      protected void onPreviewNativeEvent(NativePreviewEvent event) {
        // Hook the popup panel's event preview. We use this to keep it from
        // auto-hiding when the parent menu is clicked.
        if (!event.isCanceled()) {

          switch (event.getTypeInt()) {
            case Event.ONMOUSEDOWN:
              // If the event target is part of the parent menu, suppress the
              // event altogether.
              EventTarget target = event.getNativeEvent().getEventTarget();
              Element parentMenuElement = item.getParentMenu().getElement();
              if (parentMenuElement.isOrHasChild(Element.as(target))) {
                event.cancel();
                return;
              }
              super.onPreviewNativeEvent(event);
              if (event.isCanceled()) {
                selectItem(null);
              }
              return;
          }
        }
        super.onPreviewNativeEvent(event);
      }
    };
    popup.setAnimationType(AnimationType.ONE_WAY_CORNER);
    popup.setAnimationEnabled(isAnimationEnabled);
    popup.setStyleName(STYLENAME_DEFAULT + "Popup");
    String primaryStyleName = getStylePrimaryName();
    if (!STYLENAME_DEFAULT.equals(primaryStyleName)) {
      popup.addStyleName(primaryStyleName + "Popup");
    }
    popup.addPopupListener(this);

    shownChildMenu = item.getSubMenu();
    item.getSubMenu().parentMenu = this;

    // Show the popup, ensuring that the menubar's event preview remains on top
    // of the popup's.
    popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {

      public void setPosition(int offsetWidth, int offsetHeight) {

        // depending on the bidi direction position a menu on the left or right
        // of its base item
        if (LocaleInfo.getCurrentLocale().isRTL()) {
          if (vertical) {
            popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
                + 1, item.getAbsoluteTop());
          } else {
            popup.setPopupPosition(item.getAbsoluteLeft()
                + item.getOffsetWidth() - offsetWidth,
                MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
                    - 1);
          }
        } else {
          if (vertical) {
            popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
                + MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
          } else {
            popup.setPopupPosition(item.getAbsoluteLeft(),
                MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
                    - 1);
          }
        }
      }
    });
  }

将代码段指向

很有意思
...
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {

      public void setPosition(int offsetWidth, int offsetHeight) {

        // depending on the bidi direction position a menu on the left or right
        // of its base item
        if (LocaleInfo.getCurrentLocale().isRTL()) {
          if (vertical) {
            popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
                + 1, item.getAbsoluteTop());
          } else {
            popup.setPopupPosition(item.getAbsoluteLeft()
                + item.getOffsetWidth() - offsetWidth,
                MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
                    - 1);
          }
        } else {
          if (vertical) {
            popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
                + MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
          } else {
            popup.setPopupPosition(item.getAbsoluteLeft(),
                MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
                    - 1);
          }
        }
      }
    });

...

...所以我可能会认为有一种感觉可以围绕MenuItem对象,尤其是其UIObject继承的方法,如getAbsoluteLeft()和getAbsoluteTop(),当然......

我建议以这种方式扩展MenuItem

    //not tested
    public class MyMenuItem extends MenuItem
    {

    private MenuBar aSubMenuBar;//ItemMenu's submenu

    //...


    @Override
        public int getAbsoluteTop() {
            // TODO Auto-generated method stub
            return super.getAbsoluteTop()+movePopupTo();
        }


        private int movePopupTo()
    {
        int moveTo=0;

        int bottom=RootPanel.getBodyElement().getAbsoluteBottom();
        int rest=bottom -(super.getAbsoluteTop()+this.getaSubMenuBar().getOffsetHeight());
        if(rest<0)
        {
            moveTo=rest;
        }

        return moveTo;



    }



    public MenuBar getaSubMenuBar() {
            return aSubMenuBar;
        }

        public void setaSubMenuBar(MenuBar aSubMenuBar) {
            this.aSubMenuBar = aSubMenuBar;
        }


   //...

    }

这不是最终解决方案,而是基本概念。


报告是否有帮助

祝你好运