2016-11-05 46 views
6

下面是使用幾個嵌套的JSplitPanes創建的簡單佈局的代碼。允許嵌套的JSplitPanes控制父JSplitPanes

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JSplitPane; 

public class CDBurner extends JFrame { 
    private static final long serialVersionUID = -6027473114929970648L; 
    JSplitPane main, folder, rest; 
    JPanel centeral, folders, favourites, tasks; 
    JLabel label; 

    private CDBurner() { 
     super("Dan's CD Burner"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLayout(new GridLayout(1, 1)); 
     getContentPane().setBackground(Color.black); 

     createLayout(); 

     pack(); 
     setMinimumSize(getSize()); 
     setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH); 
     setVisible(true); 
     requestFocus(); 
    } 

    private void createLayout() { 
     createPanels(); 
     rest = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centeral, tasks); 
     rest.setResizeWeight(1); 
     rest.setContinuousLayout(true); 
     rest.setOneTouchExpandable(true); 
     folder = new JSplitPane(JSplitPane.VERTICAL_SPLIT, favourites, folders); 
     folder.setResizeWeight(0.35); 
     folder.setContinuousLayout(true); 
     folder.setOneTouchExpandable(true); 
     main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, folder, rest); 
     main.setResizeWeight(0); 
     main.setContinuousLayout(true); 
     main.setOneTouchExpandable(true); 
     getContentPane().add(main); 
    } 

    private void createPanels() { 
     createFolders(); 
     createCenter(); 
     createTaskSpool(); 
     createFavourites(); 
    } 

    private void createFolders() { 
     folders = new JPanel(new GridLayout(1, 1)); 
     label = new JLabel("Folder"); 
     folders.setMinimumSize(new Dimension(300, 100)); 
     folders.add(label); 
    } 

    private void createCenter() { 
     centeral = new JPanel(new GridLayout(1, 1)); 
     label = new JLabel("Central"); 
     centeral.add(label); 
     centeral.setMinimumSize(new Dimension(300, 100)); 
    } 

    private void createTaskSpool() { 
     tasks = new JPanel(new GridLayout(1, 1)); 
     label = new JLabel("Task"); 
     tasks.setMinimumSize(new Dimension(300, 100)); 
     tasks.add(label); 
    } 

    private void createFavourites() { 
     favourites = new JPanel(new GridLayout(1, 1)); 
     label = new JLabel("Fav"); 
     favourites.setMinimumSize(new Dimension(300, 100)); 
     favourites.add(label); 
    } 

    public static void main(String[] args) { 
     new CDBurner(); 
    } 
} 

由於線rest.setResizeWeight(1);你可以拖動main (JSplitPane)分頻器的權利,這將縮小tasks JPanel到直到兩個在restJPanels是最小尺寸。但是,如果您嘗試做相反的事情,則什麼都不會發生。請參閱下面的圖片以查看問題。

如果GUI看起來像這樣,您可以拖動main分頻器。

enter image description here

,你會得到這樣的結果。

enter image description here

但是,如果它看起來像這一點,並試圖拖動rest分頻器沒有任何反應。

​​

這是因爲rest JSplitPane雙方已經在他們的最小尺寸。

問題
我怎樣才能讓這個當我拖動rest分隔它會影響main JSplitPane,這樣既所示的操作在上面的圖像是可能的嗎?

回答

2

就我所知,您所描述的行爲是分割視圖的正常行爲。看看如Eclipse之類的專業應用程序的分隔線是如何工作的。

無論如何,我通過以編程方式控制您的休息JSplitPane divider的動作,爲您的期望行爲創建瞭解決方法。 您只需在您的createLayout()方法中創建休息JSplitPane後添加這些代碼行。

SplitPaneUI spui = rest.getUI(); 
if (spui instanceof BasicSplitPaneUI) {   
    ((BasicSplitPaneUI) spui).getDivider().addMouseMotionListener(new MouseAdapter(){   
     @Override 
     public void mouseDragged(MouseEvent E){ 
      int newPos = E.getPoint().x;      
      if(newPos < 0 && folder.getSize().width > 300 && centeral.getSize().width <= 300){ 
       main.setDividerLocation(main.getDividerLocation() + newPos); 
       validate();      
      } 
      if(centeral.getSize().width > 300 && tasks.getSize().width > 300){ 
       rest.setDividerLocation(rest.getDividerLocation() + newPos); 
       validate(); 
      } 
     } 
    }); 
} 

解釋:
在第一線,我們採取的JSplitPane分頻器的UI對象和一個自定義MouseMotionListener添加到它。我們需要 用戶界面對象,因爲真正JSplitPane不直接獲取任何鼠標事件。
在偵聽器內部,我們重寫mouseDragged方法,並在拖動 除法器時接收鼠標的實際X位置。
如果它的負值,我們拖動分頻器到左邊。在這種情況下,如果 中央面板已縮小至最小尺寸300,並且左側文件夾面板仍大於其最小尺寸,我們還希望主分隔線移動。
如果中央和右側的任務面板仍然大於其最小尺寸300,則應該可以移動其餘分隔線。

+0

但是,謝謝你的回答,但它似乎不太好。其餘的分頻器現在非常跳躍,隨機停止移動,你必須重新點擊它。雖然,這看起來似乎是正確的道路。我會研究它 – Dan

1
  • 下面是使用JLayer
    • 這個例子僅考慮JSplitPane.HORIZONTAL_SPLIT
    • 注意的情況下,一個可能的實現:這只是表現爲一種思想,將需要大量的工作,使其可用
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.plaf.*; 
import javax.swing.plaf.basic.BasicSplitPaneDivider; 

public class CDBurner2 extends JFrame { 
    JSplitPane main, folder, rest; 
    JPanel centeral, folders, favourites, tasks; 
    JLabel label; 

    private CDBurner2() { 
    super("Dan's CD Burner"); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    createLayout(); 
    setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH); 
    setVisible(true); 
    } 

    private void createLayout() { 
    createPanels(); 
    rest = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centeral, tasks); 
    rest.setResizeWeight(1); 
    rest.setContinuousLayout(true); 
    rest.setOneTouchExpandable(true); 

    folder = new JSplitPane(JSplitPane.VERTICAL_SPLIT, favourites, folders); 
    folder.setResizeWeight(0.35); 
    folder.setContinuousLayout(true); 
    folder.setOneTouchExpandable(true); 

    main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, folder, rest); 
    main.setResizeWeight(0); 
    main.setContinuousLayout(true); 
    main.setOneTouchExpandable(true); 

    //getContentPane().add(main); 
    getContentPane().add(new JLayer<JSplitPane>(
     main, new SplitPaneDividerDragLayerUI())); 
    } 

    private void createPanels() { 
    createFolders(); 
    createCenter(); 
    createTaskSpool(); 
    createFavourites(); 
    } 

    private void createFolders() { 
    folders = new JPanel(new GridLayout(1, 1)); 
    label = new JLabel("Folder"); 
    folders.setMinimumSize(new Dimension(300, 100)); 
    folders.add(label); 
    } 

    private void createCenter() { 
    centeral = new JPanel(new GridLayout(1, 1)); 
    label = new JLabel("Central"); 
    centeral.add(label); 
    centeral.setMinimumSize(new Dimension(300, 240)); 
    centeral.setPreferredSize(new Dimension(600, 240)); 
    } 

    private void createTaskSpool() { 
    tasks = new JPanel(new GridLayout(1, 1)); 
    label = new JLabel("Task"); 
    tasks.setMinimumSize(new Dimension(300, 240)); 
    tasks.setPreferredSize(new Dimension(600, 240)); 
    tasks.add(label); 
    } 

    private void createFavourites() { 
    favourites = new JPanel(new GridLayout(1, 1)); 
    label = new JLabel("Fav"); 
    favourites.setMinimumSize(new Dimension(300, 100)); 
    favourites.add(label); 
    } 

    public static void main(String... args) { 
    EventQueue.invokeLater(() -> new CDBurner2()); 
    } 
} 

class SplitPaneDividerDragLayerUI extends LayerUI<JSplitPane> { 
    private int dividerLocation; 
    private final Point startPt = new Point(); 
    @Override public void installUI(JComponent c) { 
    super.installUI(c); 
    if (c instanceof JLayer) { 
     ((JLayer) c).setLayerEventMask(
      AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 
    } 
    } 
    @Override public void uninstallUI(JComponent c) { 
    if (c instanceof JLayer) { 
     ((JLayer) c).setLayerEventMask(0); 
    } 
    super.uninstallUI(c); 
    } 
    @Override protected void processMouseEvent(
     MouseEvent e, JLayer<? extends JSplitPane> l) { 
    super.processMouseEvent(e, l); 
    JSplitPane splitPane = l.getView(); 
    Component c = e.getComponent(); 
    if (e.getID() == MouseEvent.MOUSE_PRESSED && c instanceof BasicSplitPaneDivider) { 
     JSplitPane sp = (JSplitPane) SwingUtilities.getUnwrappedParent(c); 
     if (!splitPane.equals(sp) && sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { 
     startPt.setLocation(SwingUtilities.convertPoint(c, e.getPoint(), sp)); 
     dividerLocation = splitPane.getDividerLocation(); 
     } 
    } 
    } 
    @Override protected void processMouseMotionEvent(
     MouseEvent e, JLayer<? extends JSplitPane> l) { 
    super.processMouseEvent(e, l); 
    JSplitPane splitPane = l.getView(); 
    Component c = e.getComponent(); 
    if (e.getID() == MouseEvent.MOUSE_DRAGGED && c instanceof BasicSplitPaneDivider) { 
     JSplitPane sp = (JSplitPane) SwingUtilities.getUnwrappedParent(c); 
     if (!splitPane.equals(sp) && sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { 
     Point pt = SwingUtilities.convertPoint(c, e.getPoint(), sp); 
     int delta = pt.x - startPt.x; 
     startPt.setLocation(pt); 
     if (delta < 0 && sp.getMinimumDividerLocation() == sp.getDividerLocation()) { 
      //System.out.println("delta: " + delta); 
      dividerLocation = Math.max(
       splitPane.getMinimumDividerLocation(), dividerLocation + delta); 
      splitPane.setDividerLocation(dividerLocation); 
      EventQueue.invokeLater(() -> { 
      sp.setDividerLocation(sp.getMinimumDividerLocation()); 
      }); 
     } 
     } 
    } 
    } 
} 
+0

就像你說的和其他答案這是在正確的方向,但仍然需要工作。謝謝你的回答 – Dan

+0

嗯,我想這是最接近的答案,最好不要讓50分去浪費 – Dan