【问题标题】:How do I get a GWT menu popup to stay within the browser window?如何让 GWT 菜单弹出窗口留在浏览器窗口中?
【发布时间】:2010-10-13 14:59:34
【问题描述】:

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

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

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

【问题讨论】:

  • 进展如何?您找到获取尺码的方法了吗?

标签: gwt menu positioning


【解决方案1】:

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

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

更新:还有更多工作要做。具体来说:

  • 创建一个 reposition() 方法,该方法:

    • 确定所有菜单项的最大宽度
    • 检查菜单的左边缘+最大宽度;如果大于窗口的宽度,则使用 "DOM.setStyleAttribute(elem, "left", left + "px");"移动菜单
    • 获取菜单的高度;如果菜单顶部 + 菜单高度 > 窗口高度,则使用 "DOM.setStyleAttribute(elem, "top", top + "px");"向上移动。
  • 在 onAttach() 方法中,使用延迟命令调用 reposition() 方法。

【讨论】:

  • 该线程中发布的代码是关于 GWT 1.1 中的右键单击上下文菜单。对菜单定位的唯一参考是代码底部的显着注释:“// TODO : 如果我们靠近窗口底部,则将 Y 偏移待绘制菜单的高度”
  • 是的,抱歉,我看的不够仔细。我们的代码扩展了该帖子中的想法。我在上面编辑了我的答案,以展示我们采取的方法。
  • 在 onAttach() 方法中使用延迟命令的重新定位确实有效。但是,重新定位发生在菜单被渲染并强制围绕新滚动条重新布局页面之后。在 deferred 命令修复它之后,另一个完整的页面重新布局会恢复到原来的状态。我需要一种方法来在弹出窗口附加后但设置为可见之前定位它。
  • 在附加尺寸之前,我还没有找到获取尺寸的方法。您可能可以在菜单上设置一种样式,使其一开始不可见,进行计算,然后更改可见性。 (从未尝试过,所以 YMMV。)
【解决方案2】:

您可以在弹出窗口显示之前截取它,但在它的大小已经创建之后。这样你就有了弹出窗口的宽度,并且可以将它移动到另一个位置:

@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);
        }
    });
}

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

【讨论】:

  • 这个方法放在哪里?
  • 视情况而定。您可以扩展Composite 并覆盖其现有的onContextMenu(),也可以implement ContextMenuHander 并通过.addHandler(new YourCustomContextMenuHandler()) 将其添加到组件中。
  • 啊...我正在使用 MenuBar 谢谢
  • @membersound 我在 2015 年遇到了同样的定位问题,我仍然想知道我将把它放在哪里来拦截由 MenuBar 创建的 MenuPopup。我如何访问popupMenu 对象,以便我可以调用PopupPanel#setPopupPositionAndShow(PositionCallback),因为它是MenuBar 中私有类的实例并且在MenuBar 中也具有私有访问权限?
  • 我不记得了,但我认为你必须扩展 Popup 类并覆盖 onContextMenu 方法,但不要指望我。由于太多烦人的问题,我终于退出了 gwt 开发,并搬到了vaadin(它当然是建立在 gwt 之上的,但克服了所有这些问题)。我真的可以推荐看看这个!
【解决方案3】:

嗯……

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

查看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);
          }
        }
      }
    });
  }

有趣的是把sn-p指向

...
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;
        }


   //...

    }

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


报告是否有帮助

祝你好运

【讨论】:

  • 不起作用,因为 getAbsoluteTop 调用的完成方式...调用 GWT 代码仅限于 MenuBar 类实现(因为 **MenuBar**.this.getAbsoluteTop() 语法)
猜你喜欢
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多