2013-01-20 44 views
2

我想實現JSplitPane(水平分割),其中右側分量具有恆定的寬度,即當分隔符被拖動時,它將跳回正確的大小,除非分頻器被拖動得足夠遠,在這種情況下,最右邊的分量將具有零寬度。檢測何時正在拖動JSplitPane分隔符,而不是正在調整大小的組件

要重新顯示右分量則用戶可以拖動分隔得足夠遠到左邊。

我有這個主要工作,但當我調整窗口的大小取決於多少和多快我改變窗口大小分頻器跳轉顯示或隱藏正確的組件,在那裏我想要的是它不應該改變「國家」,即如果有合適的成分是不可見的,那麼它應該是不可見的,反之亦然。

我已經嘗試了很多東西,但主要障礙是似乎沒有辦法知道天氣分隔線是由用戶通過鼠標拖動或者如果代碼(我的分隔線邏輯和/或JSplitPane內部邏輯)改變了分隔位置。

這裏是一個自包含的測試用例,運行它,並嘗試拖動水平分隔來隱藏和顯示在右側面板和那些隱藏/顯示嘗試調整窗口。

如預期在Mac OS X的Java 1.6(蘋果)或Java 7(甲骨文)不起作用。對於Oracle來說,渲染速度要慢得多,問題更嚴重。調整窗口大小緩慢工作,但窗口大小快速變化會導致問題。

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.*; 

import net.miginfocom.swing.MigLayout; 

public class SplitTest { 
    public static class MySplitPane extends JSplitPane { 
     boolean m_RightCollapsed; 

     public MySplitPane(int orientation, JComponent left, JComponent right) { 
      super(orientation, left, right); 

      addPropertyChangeListener(new PropertyChangeListener() { 

       @Override 
       public void propertyChange(PropertyChangeEvent evt) { 

       } 
      }); 
      addComponentListener(new ComponentListener() { 

       @Override 
       public void componentShown(ComponentEvent e) { 
        reposDivider(); 
       } 

       @Override 
       public void componentResized(ComponentEvent e) { 
        reposDivider(); 
       } 

       @Override 
       public void componentMoved(ComponentEvent e) { 
        reposDivider(); 
       } 

       @Override 
       public void componentHidden(ComponentEvent e) { 
       } 
      }); 

     } 

     public void reposDivider() { 
      setDividerLocation(getDividerLocation()); 
     } 

     public void setDividerLocation(int location) { 
      int newLocation; 
      m_RightCollapsed = location > getSize().width - getRightComponent().getPreferredSize().width/2; 
      if (m_RightCollapsed) 
       newLocation = getSize().width; 
      else 
       newLocation = getSize().width - getInsets().right - getDividerSize() - getRightComponent().getPreferredSize().width; 
      super.setDividerLocation(newLocation); 
     } 
    } 
    static class MyScrollable extends JPanel implements Scrollable { 
     int m_Height; 

     public MyScrollable(int height) { 
      m_Height = height; 
     } 

     @Override 
     public void paint(java.awt.Graphics g) { 
      super.paint(g); 
      g.setColor(Color.CYAN); 
      g.fillOval(0, 0, getWidth(), 500); 
     } 

     @Override 
     public Dimension getPreferredScrollableViewportSize() { 
      //return super.getPreferredSize(); 
      return new Dimension(100, m_Height); 
     } 

     @Override 
     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 
      // TODO Auto-generated method stub 
      return 10; 
     } 

     @Override 
     public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 
      return 20; 
     } 

     @Override 
     public boolean getScrollableTracksViewportWidth() { 
      return true; 
     } 

     @Override 
     public boolean getScrollableTracksViewportHeight() { 
      return false; 
     } 

    } 

    public static class ShrinkGrow extends JPanel { 
     public ShrinkGrow(final JComponent component, final JSplitPane split) { 
      JButton grow = new JButton("+++"); 
      JButton shrink = new JButton("---"); 
      add(grow); 
      add(shrink); 

      grow.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        Dimension oldSize = component.getPreferredSize(); 
        Dimension newSize = new Dimension(oldSize.width, oldSize.height + 10); 
        component.setPreferredSize(newSize); 
        component.setSize(newSize); 
       } 
      }); 
      shrink.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        Dimension oldSize = component.getPreferredSize(); 
        Dimension newSize = new Dimension(oldSize.width, oldSize.height - 10); 
        component.setPreferredSize(newSize); 
        component.setSize(newSize); 
       } 
      }); 
     } 
    } 

    public static void main(String[] args) { 
     JFrame window = new JFrame(); 

     JPanel mainView = new JPanel(); 
     JPanel top = new JPanel(); 
     top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS)); 
     JPanel bottom = new JPanel(); 
     bottom.setLayout(new BoxLayout(bottom, BoxLayout.Y_AXIS)); 

     final JSplitPane rightSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 

     JPanel topContent = new MyScrollable(200); 
     JPanel topFixed = new ShrinkGrow(topContent, rightSplit); 
     topFixed.setLayout(new BoxLayout(topFixed, BoxLayout.X_AXIS)); 

     JScrollPane topFlexible = new JScrollPane(topContent); 
     topFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 
     topFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 

     JPanel bottomContent = new MyScrollable(300); 
     JPanel bottomFixed = new ShrinkGrow(bottomContent, rightSplit); 
     bottomFixed.setLayout(new BoxLayout(bottomFixed, BoxLayout.X_AXIS)); 

     JScrollPane bottomFlexible = new JScrollPane(bottomContent); 
     bottomFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 
     bottomFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 

     mainView.setBackground(Color.red); 
     topFixed.setBackground(Color.green); 
     topContent.setBackground(Color.green.darker()); 
     bottomFixed.setBackground(Color.blue); 
     bottomContent.setBackground(Color.blue.darker()); 

     mainView.setMinimumSize(new Dimension(100, 100)); 
     mainView.setPreferredSize(new Dimension(400, 300)); 
     mainView.setMaximumSize(new Dimension(10000, 10000)); 

     topFixed.setMinimumSize(new Dimension(topFixed.getMinimumSize().width, 30)); 
     topFixed.setPreferredSize(new Dimension(topFixed.getPreferredSize().width, 30)); 
     topFixed.setMaximumSize(new Dimension(topFixed.getMaximumSize().width, 30)); 

     bottomFixed.setMinimumSize(new Dimension(bottomFixed.getMinimumSize().width, 40)); 
     bottomFixed.setPreferredSize(new Dimension(bottomFixed.getPreferredSize().width, 40)); 
     bottomFixed.setMaximumSize(new Dimension(bottomFixed.getMaximumSize().width, 40)); 

     topContent.setPreferredSize(new Dimension(100, 500)); 
     bottomContent.setPreferredSize(new Dimension(100, 400)); 

     top.add(topFixed); 
     top.add(topFlexible); 
     bottom.add(bottomFixed); 
     bottom.add(bottomFlexible); 
     rightSplit.setLeftComponent(top); 
     rightSplit.setRightComponent(bottom); 

     rightSplit.setMinimumSize(new Dimension(0, 0)); 

     final JSplitPane mainSplit = new MySplitPane(JSplitPane.HORIZONTAL_SPLIT, mainView, rightSplit); 

     window.add(mainSplit); 
     window.pack(); 
     window.setVisible(true); 
    } 
} 

回答

5

不知道是否有可能趕上dragging事件,但是可以肯定你能趕上propertyChange事件。之後你捕獲事件移動JSplitPane的分頻器可以通過JSplitPane的PropertyChangeListener類成爲可能。請確保您提供的DIVIDER_LOCATION_PROPERTY作爲參數,使該監聽器將listent修飾的分隔條位置的事件。 如果您不提供此作爲addPropertyChangeListener()方法中的第一個參數,如果PropertyChangeEventgetPropertyName()方法返回dividerLocation作爲值,則始終可以放置條件語句。

jSplitPane1.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() { 
@Override 
public void propertyChange(PropertyChangeEvent pce) { 
    // do here 
} 
}); 
+1

謝謝,我已經嘗試過這一點。但問題在於,不可能知道屬性是否因拖動分隔符而發生更改,或者由於JSlitPane組件大小發生了更改。如果前一種情況下,我想尊重用戶的選擇,並將其位置放在兩個有效位置中的一個或另一個位置上,並且在後一種情況下,我想將其恢復到更改前的位置。問題是,當窗口大小發生變化時,這些屬性更改有1-4個。 – nyholku

1

...除非分頻器拖動足夠遠,就在這種情況下,正確的 大多數組件將具有零寬度。

要重新顯示正確的組件,用戶可以將分隔線 拖到左側。

聽起來像所有你需要做的就是禁止在將splitPane禁用拖動,

然後setOneTouchExpandable()爲true。您可能需要刪除的「擴張」

按鈕之一禁用擴大走錯了路

2

添加的MouseListener到分頻器JSplitPane的分頻器被拖動時檢測。拖動時,響應屬性更改事件。示例:

https://community.oracle.com/thread/1352161?start=0&tstart=0

SplitPaneUI spui = splitPane.getUI(); 
    if (spui instanceof BasicSplitPaneUI) { 
     // Setting a mouse listener directly on split pane does not work, because no events are being received. 
     ((BasicSplitPaneUI) spui).getDivider().addMouseListener(new MouseAdapter() { 
     public void mouseClicked(MouseEvent e) { 
相關問題