2010-10-13 39 views
2

我的GWT应用程序使用DockLayoutPanel作为主要布局,页面本身不滚动。我有一个带有MenuBar的PopupPanel,有时当选择一个MenuItem时,子菜单栏会突然从屏幕底部突然强制一个新的滚动条进入浏览器并搞乱布局。如何获得GWT菜单弹出窗口以保留在浏览器窗口中?

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

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

+0

这是怎么回事?你找到了获取尺寸的方法吗? – user592704 2012-08-14 01:16:54

回答

3

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

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

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

  • 创建一个复位()方法,其中:

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

+0

在该线程中发布的代码是关于在GWT 1.1中右键单击上下文菜单的。对菜单定位的唯一参考是代码底部的这个显着的注释:“// TODO:如果我们靠近窗口的底部,然后将Y偏移到待绘制菜单的高度处” – Mocky 2010-10-14 12:56:17

+0

是的,对不起,我没有仔细观察。我们的代码扩展了这篇文章的观点。我已经在上面编辑了我的回答,以显示我们采取的方法。 – jgindin 2010-10-14 15:15:26

+0

它可以在onAttach()方法中使用延迟命令的重定位。然而,重新定位发生在菜单被渲染之后,并且强制围绕新的滚动条重新布置页面。在推迟的命令修复它之后,另一个完整页面重新布局返回到原来的状态。我需要一种方式来定位弹出后,它被附加,但在它被设置为可见之前。 – Mocky 2010-10-19 12:21:31

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(),当然...

我会建议延长菜单项的东西这样

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


    //... 

    } 

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


举报,帮助

好运

+0

不会工作,因为getAbsoluteTop调用完成的方式... GWT代码调用仅限于MenuBar类实现(因为** MenuBar **。this .getAbsoluteTop()'语法) – 2014-02-20 16:34:26

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

(我知道这是一个老问题,但如果你搜索这个还是来了,所以我想提供本方案的)

+0

我在哪里放这个方法? – 2014-02-19 21:42:38

+0

这取决于。你可以扩展一个'Composite'并覆盖现有的'onContextMenu()',你可以'执行ContextMenuHander'并通过'.addHandler(new YourCustomContextMenuHandler())'将它添加到组件。 – membersound 2014-02-19 22:04:39

+0

啊...我用的是MenuBar 谢谢 – 2014-02-20 16:32:01

相关问题