2013-06-20 2 views
0

Я переопределил validate() в своем JFrame, чтобы вручную управлять размером нескольких вложенных JPanels (они используются для прокрутки содержимого на экране, и никакой менеджер компоновки, который я знаю, позволяет вам компоновать компоненты за пределами границы родительского контейнера). Это отлично работает при перетаскивании окна, чтобы изменить его размер, но при нажатии кнопки «Максимизировать» вызывается метод validate(), вызывается вызов setPreferredSize(), но размеры панели не обновляются. Проблема, наблюдаемая в XP, не наблюдается в OSX.setPreferredSize не работает с панелями при максимальном увеличении фрейма в Windows XP?

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       ||| 
|||        ||| 
|||        ||| 
|||        ||| 
|| ------------------------------ || 
| -------------------------------- | 
---------------------------------- 

Пользователь видит только верхнюю половину этого макета. MovePanel JPanel находится в окне просмотра JScrollPane. Цель состоит в том, чтобы верхняя панель занимала все видимое вертикальное пространство, поэтому примерно такая же высота, как и охватывающая JFrame. Нижняя панель готова прокручиваться и удерживается на той же высоте, что и верхняя панель. Сохраняя lower.height == panelLeft.height и movingPanel.height == panelLeft.heightx2, это означает, что отображается половина MovePanel, а верхние - в нижней части кадра.

Как я уже сказал, работает нормально. При перемещении окна, некоторые из примеров выход:

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 в там, чтобы попытаться быть более убедительным, но он не сделал Помогите.

Любые мысли очень приветствую

EDIT: Добавлено 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(), и вместо этого он запускается нажатием кнопки изменения размера.

Таким образом, вы можете использовать красную панель (нижняя), чтобы не был видна до тех пор, пока не будет нажата кнопка прокрутки, после чего желтый цвет прокручивается, а красный - прокручивается. А потом снова в обратном направлении. Для этого мне нужна желтая панель, занимающая всю вертикальную высоту, и если я смогу сделать это с менеджером компоновки, тогда yay.

Я обновил исходный фрагмент и «диаграмму», чтобы отразить имена, используемые здесь.

Благодаря

+8

Ничего себе, вы делаете свой путь жизни более сложным, чем это может быть с реализацией такого рода. Переопределение 'validate()' не похоже на правильный выбор. Почему бы вам просто не установить правильный «LayoutManager» или даже реализовать свой собственный? Btw, вызывающий 'setPreferredSize()' всегда плохая идея, и это не гарантирует размер вашего компонента (только LayoutManager может это обеспечить). Я бы рекомендовал опубликовать [SSCCE] (http://sscce.org) для получения дополнительной помощи. –

+0

для лучшей помощи скорее отправить сообщение [SSCCE] (http://sscce.org/), краткое, выполнимое, компилируемое, только о JFrame с JPanels – mKorbel

+6

См. Также [* Следует ли мне избегать использования set (Preferred | Maximum | Minimum) Метод размера *] (http://stackoverflow.com/q/7229226/230513)? – trashgod

ответ

0

OK, благодаря подсказкам использовать LayoutManager, я сделал некоторые раскопки в этом направлении. Оказывается, что JScrollPanes использует JViewports, которые, в свою очередь, используют реализацию ViewportLayout LayoutManager. Они контролируют свой делегированный компонент «Просмотр». Как видно из приведенного ниже кода, я переопределяю метод 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 Layout Менеджерам содержать объекты из кадра?

Смежные вопросы