Simple GUI guidance. Can I stay with BorderLayout or do I need something else?

advertisements

I'm trying to create a GUI for a personal project. I have a file chooser, a console area, a text field (with label), a button panel(2 buttons) and finally a "drop zone" area.

The GUI is divided vertically in half with the console on the right. On the UpperLeft I have FileChooser positioned at BorderLayout.CENTER, followed by the ButtonPanel at BorderLayout.SOUTH.

Below that is the "drop zone"

It currently looks something like this:

 _________________
|  file  | console|
| chooser|        |
| buttons|        |
|--------|        |
| drop   |        |
| zone   |        |
|________|________|

I want to add a new text field between the file chooser and the button panel, but when I change file chooser to NORTH, jtextfield to CENTER and buttons to SOUTH, the file chooser is weirdly small and the jtextfield is much to large. I think this is just due to the inherent properties of BorderLayout, but I am not sure. Should I use a different Layout and what kind of changes would I make?

I've included the code I'm working with below. Thank you for any help in advance!

import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.*;

import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.*;
import java.util.*;
import java.nio.*;

public class ConsolidatorDemo extends JPanel implements ActionListener {
    JFileChooser fc;
    JButton clear;
    JButton ok;
    JTextArea console;

    JList<File> dropZone;
    DefaultListModel listModel;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;

    JTextField wordCount;
    JLabel lblCount;

  public ConsolidatorDemo() {
    super(new BorderLayout());
    fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);

    JPanel fcPanel = new JPanel(new BorderLayout());
    fcPanel.add(fc, BorderLayout.CENTER);

    clear = new JButton("Clear All");
    clear.addActionListener(this);

    JPanel buttonPanel = new JPanel(new BorderLayout());
    buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    buttonPanel.add(clear, BorderLayout.LINE_END);

    ok = new JButton("OK");
    ok.addActionListener(this);
    buttonPanel.add(ok, BorderLayout.WEST);

    JPanel sizePanel = new JPanel(new BorderLayout());
    sizePanel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));

    wordCount = new JTextField();
    sizePanel.add(wordCount, BorderLayout.LINE_END);

//    lblCount = new JLabel("Word Counter");
//    buttonPanel.add(lblCount, BorderLayout.CENTER);

    JPanel leftUpperPanel = new JPanel(new BorderLayout());
    leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    leftUpperPanel.add(fcPanel, BorderLayout.NORTH);
    leftUpperPanel.add(sizePanel, BorderLayout.CENTER);
    leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);

    JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
    leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

    listModel = new DefaultListModel();
    dropZone = new JList(listModel);
    dropZone.setCellRenderer(new FileCellRenderer());
    dropZone.setTransferHandler(new ListTransferHandler(dropZone));
    dropZone.setDragEnabled(true);
    dropZone.setDropMode(javax.swing.DropMode.INSERT);
    dropZone.setBorder(new TitledBorder("Selected files/folders"));
    leftLowerPanel.setViewportView(new JScrollPane(dropZone));

    childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            leftUpperPanel, leftLowerPanel);
    childSplitPane.setDividerLocation(400);
    childSplitPane.setPreferredSize(new Dimension(480, 650));

    console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));

    add(parentSplitPane, BorderLayout.CENTER);

    this.redirectSystemStreams();

}
  private void updateTextArea(final String text) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        console.append(text);
      }
    });
  }

  private void redirectSystemStreams() {
    OutputStream out = new OutputStream() {
      @Override
      public void write(int b) throws IOException {
        updateTextArea(String.valueOf((char) b));
      }

      @Override
      public void write(byte[] b, int off, int len) throws IOException {
        updateTextArea(new String(b, off, len));
      }

      @Override
      public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
      }
    };

    System.setOut(new PrintStream(out, true));
    System.setErr(new PrintStream(out, true));
  }

  public void setDefaultButton() {
    getRootPane().setDefaultButton(ok);
  }

public void actionPerformed(ActionEvent e) {
    if (e.getSource() == clear) {
        listModel.clear();
    }
    if(e.getSource() == ok){
     try{
      if(dropZone.isSelectionEmpty() == true){
       int start = 0;
       int end = dropZone.getModel().getSize() - 1;
       if (end >= 0) {
        dropZone.setSelectionInterval(start, end);
       }
      }
      List<File> list = dropZone.getSelectedValuesList();
      for (File file : list) {
       //StringEditing.editDocument(file, Integer.parseInt(wordCount.getText()));
      }
     }
     catch(NumberFormatException nfe){
       System.out.println("You did not input a number");
     }
     catch(Exception ef){
      System.out.println("Something is wrong!");
     }
    }
}

/**
 * Create the GUI and show it. For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    try {
      //UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    }catch (Exception e){
      e.printStackTrace();
    }

    //Create and set up the window.
    JFrame frame = new JFrame("Consolidator!");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    //Create and set up the menu bar and content pane.
    ConsolidatorDemo demo = new ConsolidatorDemo();
    demo.setOpaque(true); //content panes must be opaque
    frame.setContentPane(demo);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
    demo.setDefaultButton();
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}
}

class FileCellRenderer extends DefaultListCellRenderer {

    public Component getListCellRendererComponent(JList list,
        Object value,
        int index,
        boolean isSelected,
        boolean cellHasFocus) {

        Component c = super.getListCellRendererComponent(
            list,value,index,isSelected,cellHasFocus);

        if (c instanceof JLabel && value instanceof File) {
            JLabel l = (JLabel)c;
            File f = (File)value;
            l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
            l.setText(f.getName());
            l.setToolTipText(f.getAbsolutePath());
        }

        return c;
    }
}

class ListTransferHandler extends TransferHandler {

    private JList list;

    ListTransferHandler(JList list) {
        this.list = list;
    }

    @Override
    public boolean canImport(TransferHandler.TransferSupport info) {
        // we only import FileList
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            return false;
        }
        return true;
    }

    @Override
    public boolean importData(TransferHandler.TransferSupport info) {
        if (!info.isDrop()) {
            return false;
        }

        // Check for FileList flavor
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            displayDropLocation("List doesn't accept a drop of this type.");
            return false;
        }

        // Get the fileList that is being dropped.
        Transferable t = info.getTransferable();
        List<File> data;
        try {
            data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
        }
        catch (Exception e) { return false; }
        DefaultListModel model = (DefaultListModel) list.getModel();
        for (Object file : data) {
            model.addElement((File)file);
        }
        return true;
    }

    private void displayDropLocation(String string) {
        System.out.println(string);
    }
}

I ended up using GridBagLayout using the various answers here, thank you for your help!

I've got a ton of extra/ unused stuff in this example, mostly because I was starting to implement the functions I needed when I figured I'd post an update here. Should still compile and run fine though.

One problem I have is that the GUI spawns with the button panel / drop zone divider sort of eating into each other. On top of that, there is a text field which has no width despite it working perfectly fine before I used the split panes. If anyone had any knowledge of how to get around these bugs I'd appreciate it!

import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.*;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.*;

import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.*;
import java.util.*;
import java.nio.*;

public class TestGridBagLayout {
  final static boolean shouldFill = true;
  final static boolean shouldWeightX = true;
  final static boolean RIGHT_TO_LEFT = false;

  public static void addComponentsToPane(Container pane) {
    if (RIGHT_TO_LEFT) {
      pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    }
    JButton clear;
    JButton ok;
    JLabel num;
    JTextField input;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;
    JTextArea console;
    JList<File> dropZone;
    DefaultListModel listModel;

    pane.setLayout(new GridBagLayout());

    JPanel leftUpperPanel = new JPanel(new GridBagLayout());
    leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    GridBagConstraints c = new GridBagConstraints();
    if (shouldFill) {
      //natural height, maximum width
      c.fill = GridBagConstraints.HORIZONTAL;
    }

    JFileChooser fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);

    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 40;      //make this component tall
    c.weightx = 0.0;
    c.gridwidth = 4;
    c.gridx = 0;
    c.gridy = 1;
    leftUpperPanel.add(fc, c);

    ok = new JButton("OK");
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 0;       //reset to default
    c.anchor = GridBagConstraints.PAGE_END; //bottom of space
    c.insets = new Insets(10,0,0,0);  //top padding
    c.weightx = 0.5;
    c.gridx = 0;       //aligned with button 2
    c.gridwidth = 1;
    c.gridy = 2;       //third row
    leftUpperPanel.add(ok, c);

    num = new JLabel("Word Count:");
    c.fill = GridBagConstraints.NONE;
    c.anchor = GridBagConstraints.PAGE_END;
    c.insets = new Insets(10,0,0,0);  //top padding
    c.weightx = 0.25;
    c.gridx = 1;
    c.gridy = 2;
    leftUpperPanel.add(num, c);

    input = new JTextField("", 50);
    c.fill = GridBagConstraints.HORIZONTAL;
    c.anchor = GridBagConstraints.PAGE_END;
    c.insets = new Insets(10,0,0,0);  //top padding
    c.weightx = 0.25;
    c.gridx = 2;
    c.gridy = 2;
    leftUpperPanel.add(input, c);

    clear = new JButton("Clear All");
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 0;
    c.anchor = GridBagConstraints.PAGE_END;
    c.insets = new Insets(10,0,0,0);  //top padding
    c.weightx = 0.5;
    c.gridx = 3;
    c.gridy = 2;
    leftUpperPanel.add(clear, c);

    JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
    leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

    listModel = new DefaultListModel();
    dropZone = new JList(listModel);
    dropZone.setCellRenderer(new FileCellRenderer());
    dropZone.setTransferHandler(new ListTransferHandler(dropZone));
    dropZone.setDragEnabled(true);
    dropZone.setDropMode(javax.swing.DropMode.INSERT);
    dropZone.setBorder(new TitledBorder("Selected files/folders"));
    leftLowerPanel.setViewportView(new JScrollPane(dropZone));

    childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            leftUpperPanel, leftLowerPanel);
    childSplitPane.setDividerLocation(400);
    childSplitPane.setPreferredSize(new Dimension(480, 650));

    console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));

    pane.add(parentSplitPane);

  }

  public static void initUI() {

    JFrame frame = new JFrame("GridBagLayoutDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    addComponentsToPane(frame.getContentPane());

    //Display the window.
    frame.pack();
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        TestGridBagLayout testMultiplePanels = new TestGridBagLayout();
        testMultiplePanels.initUI();

      }
    });
  }

}


You could start by using a GridLayout setup to display two columns and one row. This would start out as the primary display/container/panel for the vertical split. You would then need another JPanel, possibly with a GridLayout setup to display one column and two rows, this would display the file chooser and drop zone.

You would then add this panel and the text area to the primary panel.

You could also do this using a single GridBagLaout, but you might find using compound GridLayouts easier.

See How to Use GridLayout and How to Use GridBagLayout for more details