2016-11-05 3 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 к пока оба JPanels в rest являются минимальным размером. Однако, если вы попытаетесь сделать наоборот, ничего не произойдет. См. Изображения ниже, чтобы увидеть проблему.

Если gui выглядит так, вы можете перетащить разделитель main.

enter image description here

И вы получите результат этого.

enter image description here

Однако если это выглядит, и вы пытаетесь перетащить rest делитель ничего не происходит.

enter image description here

Это происходит потому, что обе стороны rest JSplitPane уже при их минимальном размере.

Вопрос
Как я могу сделать это так, что, когда я перетащить rest делитель это производит main JSplitPane так, что обе операции показано выше изображения возможны?

ответ

2

Насколько я знаю, поведение, которое вы описываете, является нормальным поведением для разделенных видов. Посмотрите, как ведут себя деления профессиональных приложений, таких как Eclipse.

В любом случае я создал обходное решение для вашего желаемого поведения, управляя движениями вашего отдыха JSplitPane. Вам просто нужно добавить эти строки кода после создания вашего отдыха JSplitPane в вашем методе createLayout().

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 и добавить пользовательские MouseMotionListener к нему. Нам нужен объект U12 , потому что реальный 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

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