3

I'm struggling to give a good layout to my Swing components. Currently FlowLayout being is used, but it doesn't look pretty. My requirement is to display the label l0 in top line. Then the label l1, combobox c1 and button b1 in second column (center aligned). Finally, the output that gets displayed in Jtable beneath. How do I do this?

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.sql.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class r_search_1 extends JFrame implements ActionListener {

    JFrame frame1;
    JLabel l0, l1, l2;
    JComboBox c1;
    JButton b1;
    Connection con;
    ResultSet rs, rs1;
    Statement st, st1;
    PreparedStatement pst;
    String ids;
    static JTable table  = new JTable();;
    String[] columnNames = {"SECTION NAME", "REPORT NAME", "CONTACT", "LINK"};
    String from;
    Vector v = new Vector();
    JMenuBar menu = new JMenuBar();

    r_search_1() 
    {


          frame1 = new JFrame("yippee");
          frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame1.setLayout(new FlowLayout());

        l0 = new JLabel("Fetching Search Results...");
        l0.setForeground(Color.blue);
        l0.setFont(new Font("Serif", Font.BOLD, 20));
        l1 = new JLabel("Search");
        b1 = new JButton("submit");

        l0.setBounds(100, 50, 350, 40);
        l1.setBounds(75, 110, 75, 20);
        b1.setBounds(150, 150, 150, 20);
        b1.addActionListener(this);

        frame1.add(l0);
        frame1.add(l1);
        //frame1.add(b1);
        frame1.setVisible(true);
        frame1.setSize(1000, 400);


        try 
        {

            File dbFile = new File("executive_db.accdb");
            String path = dbFile.getAbsolutePath();
            con = DriverManager.getConnection("jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)}; DBQ= " + path);
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            st = con.createStatement();
            rs = st.executeQuery("select index_name from Index1");
           while (rs.next())
           {
                ids = rs.getString(1);
                v.add(ids);

            }
            c1 = new JComboBox(v);
            c1.setEditable(true);c1.setSelectedItem("");
            c1.setBounds(150, 110, 150, 20);

            frame1.add(c1);
            frame1.add(b1);
            st.close();
            rs.close();
        } catch (Exception e) {
        }
       // setVisible(true);
    }

    public void actionPerformed(ActionEvent ae) {
        if (ae.getSource() == b1) {
            showTableData();
        }
     }

    public void showTableData()
    {

        // frame1 = new JFrame("Database Search Result");
      //  frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        //frame1.setLayout(new FlowLayout());
        DefaultTableModel model = new DefaultTableModel();
        model.setColumnIdentifiers(columnNames);

        table.setModel(model);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        table.setFillsViewportHeight(true);
        JScrollPane scroll = new JScrollPane(table);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        from = (String) c1.getSelectedItem();

        String section_name = "";
        String report_name = "";
        String contact_name = "";
        String link = "";


        try
        {

        pst = con.prepareStatement("select distinct Section.Section_Name,Report.Report_Name,Report.Link,Contact.Contact_Name "
                        + "FROM (( Section INNER JOIN Report ON Report.Section_ID=Section.Section_ID ) INNER JOIN Contact ON Contact.Contact_ID=Report.Contact_ID )  LEFT JOIN Metrics ON Metrics.Report_ID=Report.Report_ID  "
                        + " WHERE Section.Section_Name LIKE '%"+from+"%' OR Report.Report_Name LIKE '%"+from+"%' OR Metrics.Metric_Name LIKE '%"+from+"%' OR Contact.Contact_Name LIKE '%"+from+"%' ");
            ResultSet rs = pst.executeQuery();
            int i = 0;
            while (rs.next()) {
                section_name = rs.getString("Section_Name");
                report_name = rs.getString("Report_Name");
                contact_name = rs.getString("Contact_Name");
                link = rs.getString("Link");
                model.addRow(new Object[]{section_name, report_name, contact_name, link});
                i++;
            }
            if (i < 1) {
                JOptionPane.showMessageDialog(null, "No Record Found", "Error", JOptionPane.ERROR_MESSAGE);
            }
            if (i == 1) {
                System.out.println(i + " Record Found");
            } else {
                System.out.println(i + " Records Found");
            }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
        frame1.add(scroll);
        frame1.setVisible(true);
      //  frame1.setSize(1000, 400);
        //table.close()
    }

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

This is my requirement:

enter image description here

user1803551
  • 12,965
  • 5
  • 47
  • 74
user3608233
  • 103
  • 2
  • 13
  • 2
    To organize the components for a robust GUI, use layout managers, or **[combinations of layout managers](http://stackoverflow.com/a/5630271/418556)**, along with layout padding & borders for [white space](http://stackoverflow.com/q/17874717/418556). – Andrew Thompson May 19 '14 at 03:22
  • @Andrew Thompson: can u please show me how it can be done here, Just a basic one ! – user3608233 May 19 '14 at 03:24
  • 2
    `} catch (Exception e) {}` 1) Change code of the form `catch (Exception e) { ..` to `catch (Exception e) { e.printStackTrace(); // very informative! ..` *"can u please show me how it can be done"* 2) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete and Verifiable Example). 3) Provide ASCII art (or an image with a simple drawing) of the GUI as it should appear in smallest size and (if resizable) with extra width/height. – Andrew Thompson May 19 '14 at 03:25
  • @Andrew Thompson: I've updated my problem. Now can you please guide me ! Thanks ! – user3608233 May 19 '14 at 04:30
  • (1) Class names should start with uppercase and not contain underscores. (2) Variable names should make sense and not `b1`, `c1` etc.. (3) Don't create fields when local variables will do. (4) Use consecutive `if else` instead of `if` when possible. (5) Don't use raw types, always parametrize. – user1803551 May 19 '14 at 04:46
  • 1
    And about your code, it is not *minimal*, you post a lot of SQL lines when you ask about layout of components. Remove all unnecessary lines. – user1803551 May 19 '14 at 04:47

2 Answers2

2

enter image description here

Notes

  1. It is named PoorlySpecifiedLayout because you forgot the part about.. "and (if resizable) with extra width/height."
  2. The UI is naturally taller than seen above. It was shortened to make a better screenshot.

import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class PoorlySpecifiedLayout {

    // the GUI as seen by the user (without frame)
    JPanel ui = new JPanel(new BorderLayout(5,5));
    String[] comboValues = {
        "String to pad combo."
    };
    String[] tableHeader = {
        "Section Name","Report Name","Contact","Link"
    };
    String[][] tableBody = {{"", "", "", ""}};
        
    PoorlySpecifiedLayout() {
        initUI();
    }

    public final void initUI() {
        ui.setBorder(new EmptyBorder(20,20,20,20));
        
        JPanel top = new JPanel(new BorderLayout(15, 5));
        ui.add(top, BorderLayout.PAGE_START);
        
        top.add(new JLabel(
                "Fetching search results", SwingConstants.CENTER));
        JPanel controls = new JPanel(new FlowLayout(SwingConstants.LEADING, 10, 5));
        top.add(controls, BorderLayout.PAGE_END);
        controls.add(new JLabel("Search:"));
        controls.add(new JComboBox(comboValues));
        JButton submit = new JButton("submit");
        Insets padButton = new Insets(5,20,5,20);
        submit.setMargin(padButton);
        controls.add(submit);
        JTable table = new JTable(tableBody, tableHeader);
        ui.add(new JScrollPane(table));
    }
    
    public final JComponent getUI(){
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
             PoorlySpecifiedLayout psl = new PoorlySpecifiedLayout();   

                JFrame f = new JFrame("Poorly Specified Layout");
                f.add(psl.getUI());
                // Ensures JVM closes after frame(s) closed and
                // all non-daemon threads are finished
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                // See http://stackoverflow.com/a/7143398/418556 for demo.
                f.setLocationByPlatform(true);

                // ensures the frame is the minimum size it needs to be
                // in order display the components within it
                f.pack();
                // should be done last, to avoid flickering, moving,
                // resizing artifacts.
                f.setVisible(true);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    And speaking of correct usage, your `JComboBox` is not parametrized. :) – user1803551 May 19 '14 at 09:59
  • @user1803551 I was musing over your comment earlier re. cutting corners in examples. For the record, I have been know to defend (just about) any level of compromise on 'ideal practices' for the sake of brevity (AKA 'Batteries Not Included'), so I sure understand where you're coming from. The idea of exactly where that line is drawn is quite open to interpretation. :) – Andrew Thompson May 19 '14 at 10:06
  • True, but if we look at the OP's question, we can both give only the 10 lines or so of code that create the panel they requested. In my opinion only those lines should abide by 'ideal practices' as everything else is for ease of use (and the picture). – user1803551 May 19 '14 at 10:21
  • @user1803551 Too true. It's notable that we posted two MCVEs in response to the OP who has yet to *"Remove all unnecessary lines."* - your comment on the question that I had to +1. We're too good to people sometimes. ;) – Andrew Thompson May 19 '14 at 10:25
  • Thank you user1803551 and Andrew Thompson !! Very helpful material ! learnt a lot ! – user3608233 May 19 '14 at 11:43
  • @user3608233 No problem. For future reference, if you want to notify someone in a comment (which is not under their post) use ATusername as I did or else they won't be notified. – user1803551 May 19 '14 at 11:49
  • About "We're too good to people sometimes", there's a serious point behind it, recently discussed [here](http://meta.stackoverflow.com/questions/254287/is-answering-bad-quality-questions-considered-a-positive-or-a-negative-contribut) with points referring to this [here](http://meta.stackoverflow.com/questions/252506/question-quality-is-dropping-on-stack-overflow) and [here](http://meta.stackoverflow.com/questions/251758/why-is-stack-overflow-so-negative-of-late). – user1803551 May 19 '14 at 11:54
2

Edit: as per advice by Andrew Thompson - a picture.

enter image description here


Here is an example of how to do it using BorderLyout for the search / submit row and table, and adding the title in a border title instead of a label:

public class Search extends JFrame  {

    private final static String TITLE = "Fetching Search Results";
    private final static String[] COLUMN_HEADERS = {"Section name", "Report name", "Contact", "Link"};
    private final static String[] SEARCH_OPTIONS = {"AAAAA", "BBBBB"};

    Search() {

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), TITLE, TitledBorder.CENTER, TitledBorder.TOP, new Font("Arial", Font.PLAIN, 20), Color.RED));

        JPanel topPanel = new JPanel();
        JLabel searchLabel = new JLabel("Search:");
        JComboBox<String> searchBox = new JComboBox<>(SEARCH_OPTIONS);
        JButton submitButton = new JButton("Submit");
        topPanel.add(searchLabel);
        topPanel.add(searchBox);
        topPanel.add(submitButton);

        JTable table = new JTable(new String[34][4], COLUMN_HEADERS);

        mainPanel.add(topPanel, BorderLayout.PAGE_START);
        mainPanel.add(new JScrollPane(table));

        setContentPane(mainPanel);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public static void main(String args[]) {

        new Search();
    }
}

If you want the title as a label, you can put another panel for it.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • 1
    GUIs should ideally be constructed on the EDT. See the comments in the `main` of my example for a handy link to Swing Concurrency. Also prefer composition over inheritance - use an instance of `JFrame` instead of extend it. +1 for use of the titled border. Good lateral thinking. :) – Andrew Thompson May 19 '14 at 08:54
  • Oh, but [a picture paints a thousand words](http://meta.stackoverflow.com/questions/99734/how-do-i-create-a-screenshot-to-illustrate-a-post). ;) – Andrew Thompson May 19 '14 at 08:56
  • @AndrewThompson All my code *examples* relax some of the disciplined principles in favor of brevity and conciseness (such as running from the EDT or extending `JPanel` instead of `JFrame`). I do so because I imagine that the user needs only a "copy-paste" of the few lines that touch the subject directly and not all the wrapping (such as my constructor call or my frame). Thanks for the input, I thought that giving the OP another approach than what they asked for was worth it. – user1803551 May 19 '14 at 09:11
  • @AndrewThompson True, I guess I could add screenshots, though it does diminish the awe the user expresses when they first run the code. :) – user1803551 May 19 '14 at 09:13
  • Oh yes, (very) fetching search results. :) I like the row of controls centered as well, it looks better that way. – Andrew Thompson May 19 '14 at 09:34
  • @AndrewThompson Huh, yeah, they are centered by default, I didn't pay attention to it. The alignment in the OP's picture is completely off though. You can put `FlowLayout.CENTER` instead of `SwingConstants.LEADING` in your case to get the same result. – user1803551 May 19 '14 at 09:55