2013-06-20 32 views
0

我在我的JFrame中重寫了validate(),這樣我就可以手動控制幾個嵌套JPanel的大小(它們用於將內容滾動到屏幕上,並且沒有我知道的佈局管理器允許您在父容器的邊界)。這在拖動窗口來調整大小時可以正常工作,但是當單擊最大化按鈕時,調用validate()會調用setPreferredSize(),但面板大小不會更新。在XP上看到的問題,在OSX中看不到。當Windows XP上的框架最大化時,setPreferredSize無法在面板上工作?

public void validate() { 
    super.validate(); 

    LOGGER.debug("Validate called on Frame. Resizing panel"); 
    if (inited == true) { 
     Dimension size = panelLeft.getSize(); 
     int referenceHeight = size.height; 
     LOGGER.info("referenceHeight is " + referenceHeight); 
     size = lower.getSize(); 
     size.height = referenceHeight; 
     lower.setPreferredSize(size); 
     lower.setMinimumSize(size); 
     size.height = size.height * 2; 
     movingPanel.setPreferredSize(size); 
     movingPanel.setMinimumSize(size); 
     LOGGER.info("sizes now: panel: " + lower.getSize().height + ", scrollpane: " 
       + movingPanel.getSize().height); 
     if (panelSlideController != null) { 
      panelSlideController.redraw(); 
      LOGGER.debug("redrawing panel slide controller"); 
     } 
    } 
} 

panelLeft是一個由其佈局管理器自動調整大小以成爲框架全高的面板。所以它的高度被用作參考。

相關的面板排列:

---------------------------------- 
|scrollPane      | 
| -------------------------------- | 
||movingPanel      || 
|| ------------------------------ || 
|||upper       ||| 
|||        ||| 
|||        ||| 
|||        ||| 
|| ------------------------------ || 
|| ------------------------------ || 
|||lower       ||| 
|||        ||| 
|||        ||| 
|||        ||| 
|| ------------------------------ || 
| -------------------------------- | 
---------------------------------- 

的用戶只能看到此佈局的上半部分。 movingPanel JPanel位於JScrollPane的視口中。目標是讓上面板佔據所有可見的垂直空間,因此與封閉的JFrame大致相同。下面板準備滾動並保持與上面板相同的高度。通過保持lower.height == panelLeft.height和movingPanel.height == panelLeft.heightx2,這意味着一半的movingPanel正在顯示,而上端在Frame的底部。

就像我說的,工作正常。當拖動窗口,一些示例輸出爲:

2013-06-20 23:15:41,298 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel 
2013-06-20 23:15:41,298 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 617 
2013-06-20 23:15:41,298 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 607, scrollpane: 1214 
2013-06-20 23:15:41,538 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel 
2013-06-20 23:15:41,538 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 640 
2013-06-20 23:15:41,538 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 636, scrollpane: 1272 

當最大化窗口,輸出是這樣的:

2013-06-20 22:08:21,234 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel 
2013-06-20 22:08:21,234 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 783 
2013-06-20 22:08:21,234 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 543, scrollpane: 1086 

我說在那裏了setMinimumSize嘗試更有說服力,但事實並非如此幫幫我。

任何想法非常歡迎

編輯: 新增SSCCE

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JViewport; 
import javax.swing.ScrollPaneConstants; 
import javax.swing.Timer; 
import javax.swing.UIManager; 

class Frame extends JFrame { 

    private JPanel panelLeft; 
    private JScrollPane scrollPane; 
    private JPanel movingPanel; 
    private JPanel upper; 
    private JPanel lower; 
    private boolean inited; 
    private JLabel labelUpper; 
    private JLabel labelLower; 
    private JButton scrollBtn; 
    private Frame.PanelSlideController panelSlideController; 
    private JButton resizeBtn; 

    private boolean lowerShowing = false; 

    public Frame() { 
     getContentPane().setLayout(new BorderLayout()); 

     panelLeft = new JPanel(); 
     panelLeft.setBackground(Color.CYAN); 
     panelLeft.setPreferredSize(new Dimension(300, 400)); 
     getContentPane().add(panelLeft, BorderLayout.WEST); 

     labelUpper = new JLabel("upper"); 
     panelLeft.add(labelUpper); 

     labelLower = new JLabel("lower"); 
     panelLeft.add(labelLower); 

     resizeBtn = new JButton("resize"); 
     resizeBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       doResize(); 
      } 
     }); 
     panelLeft.add(resizeBtn); 

     scrollBtn = new JButton("Scroll"); 
     scrollBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       doScroll(); 
      } 
     }); 
     panelLeft.add(scrollBtn); 

     scrollPane = new JScrollPane(); 
     scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
     scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 

     movingPanel = new JPanel(new GridLayout(2, 1)); 
     movingPanel.setOpaque(false); 
     movingPanel.setPreferredSize(new Dimension(300, 400)); 

     upper = new JPanel(); 
     upper.setBackground(Color.YELLOW); 
     movingPanel.add(upper); 

     lower = new JPanel(); 
     lower.setBackground(Color.RED); 
     movingPanel.add(lower); 

     scrollPane.setViewportView(movingPanel); 

     getContentPane().add(scrollPane, BorderLayout.EAST); 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     pack(); 

     inited = true; 
    } 

    /** 
    * This is a manual step instead of overriding validate() 
    */ 
    protected void doResize() { 
     // Get the height we want 
     int referenceHeight = panelLeft.getSize().height; 

     // Update the height of the lower panel to equal this 
     Dimension size = lower.getSize(); 
     size.height = referenceHeight; 
     lower.setPreferredSize(size); 
     lower.setMinimumSize(size); 

     // Update the height of the surrounding panel 
     size = scrollPane.getSize(); 
     size.height = referenceHeight * 2; 
     movingPanel.setPreferredSize(size); 
     movingPanel.setMinimumSize(size); 

     if (panelSlideController != null) { 
      panelSlideController.redraw(); 
      System.out.println("redrawing panel slide controller"); 
     } 

     upper.invalidate(); 
     lower.invalidate(); 
     scrollPane.revalidate(); 
    } 

    protected void doScroll() { 
     panelSlideController = new PanelSlideController(scrollPane, 20); 
     int scrollDirection = lowerShowing ? -1 : 1; 
     panelSlideController.scrollY(panelLeft.getHeight() * scrollDirection); 
     lowerShowing = !lowerShowing; 
    } 

    @Override 
    public void validate() { 
     super.validate(); 

     System.out.println("Validating"); 
     if (inited) { 
      labelUpper.setText("upper: " + upper.getSize().height); 
      labelLower.setText("lower: " + lower.getSize().height); 
     } 
    } 

    class PanelSlideController implements ActionListener { 

     private final JScrollPane scrollPane; 
     private final int speed; 
     private Timer timer; 
     private int endPos; 

     private boolean scrollingPositive; 

     public PanelSlideController(JScrollPane scrollPane, int speed) { 
      this.scrollPane = scrollPane; 
      this.speed = speed; 
     } 

     public void scrollY(int scrollDistance) { 
      endPos = scrollPane.getViewport().getViewPosition().y + scrollDistance; 
      scrollingPositive = scrollDistance > 0; 
      timer = new Timer(speed, this); 
      timer.start(); 
     } 

     public void redraw() { 
      JViewport viewport = scrollPane.getViewport(); 
      Point position = viewport.getViewPosition(); 

      if (scrollingPositive) { 
       position.y = endPos; 
      } 
      else { 
       position.y = 0; 
      } 
      viewport.setViewPosition(position); 

     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      JViewport viewport = scrollPane.getViewport(); 
      Point position = viewport.getViewPosition(); 
      int offset = scrollingPositive ? 10 : -10; 
      position.y += offset; 
      viewport.setViewPosition(position); 

      if ((scrollingPositive && position.y >= endPos) 
        || (!scrollingPositive && (position.y <= endPos || position.y <= 0))) { 
       timer.stop(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     try { 
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new Frame().setVisible(true); 
      } 
     }); 
    } 
} 

對,所以上面是可運行的。 panelLeft(青色)用作參考高度。我將代碼從validate()移出,而通過單擊調整大小按鈕來運行代碼。

所以你可以選擇紅色面板(下),如果不是是可見的,直到點擊滾動,此時黃色向上滾動,而紅色滾動到視圖中。然後再往相反的方向回來。要做到這一點,我需要黃色的面板佔據所有的垂直高度,如果我可以與佈局經理做到這一點,那麼耶。

我已經更新了原始代碼片段和'圖表'來鏡像這裏使用的名稱。

感謝

+8

哇,你讓你的生活方式比這種實現更難。重寫'validate()'似乎不是一個正確的選擇。你爲什麼不設置一個合適的'LayoutManager'或者甚至實現你自己的?順便說一句,調用'setPreferredSize()'總是一個壞主意,它不保證組件的大小(只有LayoutManager可以確保)。我建議發佈[SSCCE](http://sscce.org)獲取更多幫助。 –

+0

更好地幫助發佈[SSCCE](http://sscce.org/),簡短,可運行,可編譯,僅與JPanels有關的JFrame – mKorbel

+6

另請參閱[*我是否應避免使用set(Preferred | Maximum | Minimum )大小方法*](http://stackoverflow.com/q/7229226/230513)? – trashgod

回答

0

OK,感謝提示使用佈局管理,我沒有在這個方向一些挖掘。原來,JScrollPanes使用JViewports,而JViewports又使用ViewManagerLayout實現了一個LayoutManager。這些可以控制他們委派的'View'組件。從下面的修改後的代碼可以看出,我在這裏重寫layoutContainer方法,現在將我的'movingPanel'與視口相關的高度加倍,並且這種工作明顯比以前更好,並且在XP中最大化。

感謝

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.LayoutManager; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JViewport; 
import javax.swing.ScrollPaneConstants; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.ViewportLayout; 

class Frame extends JFrame { 

    private JPanel panelLeft; 
    private JScrollPane scrollPane; 
    private JPanel movingPanel; 
    private JPanel upper; 
    private JPanel lower; 
    private boolean inited; 
    private JLabel labelUpper; 
    private JLabel labelLower; 
    private JButton scrollBtn; 
    private Frame.PanelSlideController panelSlideController; 
    private JButton resizeBtn; 

    private boolean lowerShowing = false; 

    public Frame() { 
     getContentPane().setLayout(new BorderLayout()); 

     panelLeft = new JPanel(); 
     panelLeft.setBackground(Color.CYAN); 
     panelLeft.setPreferredSize(new Dimension(300, 400)); 
     getContentPane().add(panelLeft, BorderLayout.WEST); 

     labelUpper = new JLabel("upper"); 
     panelLeft.add(labelUpper); 

     labelLower = new JLabel("lower"); 
     panelLeft.add(labelLower); 

     scrollBtn = new JButton("Scroll"); 
     scrollBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       doScroll(); 
      } 
     }); 
     panelLeft.add(scrollBtn); 

     scrollPane = new JScrollPane(); 
     scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
     scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 

     movingPanel = new JPanel(new GridLayout(2, 1)); 
     movingPanel.setOpaque(false); 
     movingPanel.setPreferredSize(new Dimension(300, 400)); 

     upper = new JPanel(); 
     upper.setBackground(Color.YELLOW); 
     movingPanel.add(upper); 

     lower = new JPanel(); 
     lower.setBackground(Color.RED); 
     movingPanel.add(lower); 

     // ------------------------------ 
     // This is the key bit 
     // ------------------------------ 
     JViewport viewport = new JViewport() { 
      @Override 
      protected LayoutManager createLayoutManager() { 
       return new ViewportLayout() { 

        @Override 
        public void layoutContainer(Container parent) { 
         JViewport vp = (JViewport) parent; 
         Component view = vp.getView(); 

         Dimension viewPrefSize = view.getPreferredSize(); 
         Dimension vpSize = vp.getSize(); 
         Dimension viewSize = new Dimension(viewPrefSize); 

         viewSize.width = vpSize.width; 
         viewSize.height = vpSize.height * 2; 

         vp.setViewSize(viewSize); 
        } 
       }; 
      } 

     }; 
     scrollPane.setViewport(viewport); 
     viewport.setView(movingPanel); 
     // ------------------------------ 
     // End of key bit 
     // ------------------------------ 

     getContentPane().add(scrollPane, BorderLayout.EAST); 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     pack(); 

     inited = true; 
    } 

    protected void doScroll() { 
     panelSlideController = new PanelSlideController(scrollPane, 20); 
     int scrollDirection = lowerShowing ? -1 : 1; 
     panelSlideController.scrollY(panelLeft.getHeight() * scrollDirection); 
     lowerShowing = !lowerShowing; 
    } 

    @Override 
    public void validate() { 
     super.validate(); 

     System.out.println("Validating"); 
     if (inited) { 
      labelUpper.setText("upper: " + upper.getSize().height); 
      labelLower.setText("lower: " + lower.getSize().height); 
     } 
    } 

    class PanelSlideController implements ActionListener { 

     private final JScrollPane scrollPane; 
     private final int speed; 
     private Timer timer; 
     private int endPos; 

     private boolean scrollingPositive; 

     public PanelSlideController(JScrollPane scrollPane, int speed) { 
      this.scrollPane = scrollPane; 
      this.speed = speed; 
     } 

     public void scrollY(int scrollDistance) { 
      endPos = scrollPane.getViewport().getViewPosition().y + scrollDistance; 
      scrollingPositive = scrollDistance > 0; 
      timer = new Timer(speed, this); 
      timer.start(); 
     } 

     public void redraw() { 
      JViewport viewport = scrollPane.getViewport(); 
      Point position = viewport.getViewPosition(); 

      if (scrollingPositive) { 
       position.y = endPos; 
      } 
      else { 
       position.y = 0; 
      } 
      viewport.setViewPosition(position); 

     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      JViewport viewport = scrollPane.getViewport(); 
      Point position = viewport.getViewPosition(); 
      int offset = scrollingPositive ? 10 : -10; 
      position.y += offset; 
      viewport.setViewPosition(position); 

      if ((scrollingPositive && position.y >= endPos) 
        || (!scrollingPositive && (position.y <= endPos || position.y <= 0))) { 
       timer.stop(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     try { 
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new Frame().setVisible(true); 
      } 
     }); 
    } 
} 

注:我有一個問題,隨後將其刪除之前開放,而我在這裏包括標題爲SEO的目的:如何使用Swing佈局管理器包含對象幀失?

相關問題