2010-10-13 41 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

相關問題