Search code examples
javaswingscrolljframewindow

JScrollPane Not Appearing


I have looked at many of the other threads that are related to this, however none of the suggested fixes worked.
I have tried doing contentPanel.revalidate(); and contentPanel.repaint();, after adding it. I have tried adding both the JScrollPane and JTextArea to the contentPanel, and I have tried individually. I have tried changing from a JTextArea to a JTextPane, however none of that worked. The JTextArea shows up fine without the JScrollPane, but when I add it, the JTextArea completely disappears.
I am using a null layout, and I think that could be the issue, but if there is a solution that doesn't involve changing the layout, I would much prefer that. If there is no way to fix it other that changing the layout, please let me know. Thanks.

Here is the code (It is a JDialog window that is a popup off of the main window):

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.SimpleDateFormat;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.ArrayList;
import java.util.Calendar;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;

public class TransactionsDialog extends JDialog
{
    private static final long serialVersionUID = 6939141004692809959L;
    private final JPanel contentPanel = new JPanel();
    private SimpleDateFormat monthDate = new SimpleDateFormat("MMMM");
    private JTextArea txtTransactions;
    private JComboBox<String> comboStartMonth;
    private JComboBox<Integer> comboStartDay;
    private JComboBox<Integer> comboStartYear;
    private JComboBox<String> comboEndMonth;
    private JComboBox<Integer> comboEndDay;
    private JComboBox<Integer> comboEndYear;
    private JCheckBox chckbxStartDate;
    private JCheckBox chckbxEndDate;

    /**
     * Create the dialog.
     */
    public TransactionsDialog(BankAccount account)
    {
        setResizable(false);
        /**
         * Populating (Day, Month, Year) Arrays.
         */
        ArrayList<String> monthList = new ArrayList<String>();
        for(int month = 0; month < 12; month++)
        {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.MONTH, month);
            String monthName = monthDate.format(calendar.getTime());

            monthList.add(monthName);
        }

        ArrayList<Integer> dayList = new ArrayList<Integer>();
        for(int day = 1; day <= 31; day++)
        {
            dayList.add(day);
        }

        ArrayList<Integer> yearList = new ArrayList<Integer>();
        for(int year = 1980; year <= Calendar.getInstance().get(Calendar.YEAR); year++)
        {
            yearList.add(year);
        }

        setTitle("Transactions of " + account);
        setBounds(100, 100, 404, 300);
        getContentPane().setLayout(new BorderLayout());
        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        getContentPane().add(contentPanel, BorderLayout.CENTER);
        contentPanel.setLayout(null);

        comboStartMonth = new JComboBox<String>();
        comboStartMonth.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        comboStartMonth.setModel(new DefaultComboBoxModel<String>(monthList.toArray(new String[monthList.size()])));
        comboStartMonth.setEnabled(false);
        comboStartMonth.setBounds(100, 8, 118, 20);
        contentPanel.add(comboStartMonth);

        comboStartDay = new JComboBox<Integer>();
        comboStartDay.setModel(new DefaultComboBoxModel<Integer>(dayList.toArray(new Integer[dayList.size()])));
        comboStartDay.setEnabled(false);
        comboStartDay.setBounds(228, 8, 71, 20);
        comboStartDay.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        contentPanel.add(comboStartDay);

        comboStartYear = new JComboBox<Integer>();
        comboStartYear.setModel(new DefaultComboBoxModel<Integer>(yearList.toArray(new Integer[yearList.size()])));
        comboStartYear.setSelectedIndex(comboStartYear.getItemCount() - 1);
        comboStartYear.setEnabled(false);
        comboStartYear.setBounds(309, 8, 71, 20);
        comboStartYear.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        contentPanel.add(comboStartYear);

        comboEndMonth = new JComboBox<String>();
        comboEndMonth.setModel(new DefaultComboBoxModel<String>(monthList.toArray(new String[monthList.size()])));
        comboEndMonth.setEnabled(false);
        comboEndMonth.setBounds(100, 34, 119, 20);
        comboEndMonth.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        contentPanel.add(comboEndMonth);

        comboEndDay = new JComboBox<Integer>();
        comboEndDay.setModel(new DefaultComboBoxModel<Integer>(dayList.toArray(new Integer[dayList.size()])));
        comboEndDay.setEnabled(false);
        comboEndDay.setBounds(228, 34, 71, 20);
        comboEndDay.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        contentPanel.add(comboEndDay);

        comboEndYear = new JComboBox<Integer>();
        comboEndYear.setModel(new DefaultComboBoxModel<Integer>(yearList.toArray(new Integer[yearList.size()])));
        comboEndYear.setSelectedIndex(comboEndYear.getItemCount() - 1);
        comboEndYear.setEnabled(false);
        comboEndYear.setBounds(309, 34, 71, 20);
        comboEndYear.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                listTransactions(account);
            }
        });
        contentPanel.add(comboEndYear);

        txtTransactions = new JTextArea();
        txtTransactions.setFont(new Font("Courier New", Font.PLAIN, 11));
        txtTransactions.setEditable(false);
        txtTransactions.setBounds(10, 63, 368, 187);

        JScrollPane txtTScrollPane = new JScrollPane(txtTransactions);
        contentPanel.add(txtTScrollPane);
        contentPanel.revalidate();
        contentPanel.repaint();

        chckbxStartDate = new JCheckBox("Start Date:");
        chckbxStartDate.setBounds(6, 7, 89, 23);
        chckbxStartDate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if(chckbxStartDate.isSelected())
                {
                    comboStartMonth.setEnabled(true);
                    comboStartDay.setEnabled(true);
                    comboStartYear.setEnabled(true);            
                }
                else
                {
                    comboStartMonth.setEnabled(false);
                    comboStartDay.setEnabled(false);
                    comboStartYear.setEnabled(false);
                }

                listTransactions(account);
            }
        });
        contentPanel.add(chckbxStartDate);

        chckbxEndDate = new JCheckBox("End Date:");
        chckbxEndDate.setBounds(6, 33, 89, 23);
        chckbxEndDate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(chckbxEndDate.isSelected())
                {
                    comboEndMonth.setEnabled(true);
                    comboEndDay.setEnabled(true);
                    comboEndYear.setEnabled(true);
                }
                else
                {
                    comboEndMonth.setEnabled(false);
                    comboEndDay.setEnabled(false);
                    comboEndYear.setEnabled(false);
                }

                listTransactions(account);
            }
        });
        contentPanel.add(chckbxEndDate);

        listTransactions(account);
    }

    private void listTransactions(BankAccount account)
    {       
        LocalDateTime startTime;
        LocalDateTime endTime;
        String startMonthName = (String) comboStartMonth.getSelectedItem();
        int startDay = (int) comboStartDay.getSelectedItem();
        int startYear = (int) comboStartYear.getSelectedItem();
        String endMonthName = (String) comboEndMonth.getSelectedItem();
        int endDay = (int) comboEndDay.getSelectedItem();
        int endYear = (int) comboEndYear.getSelectedItem();

        if(chckbxStartDate.isSelected())
        {
            int startMonth = Month.valueOf(startMonthName.toUpperCase()).getValue();    

            try
            {
                startTime = LocalDateTime.of(startYear, startMonth, startDay, 0, 0);
            }
            catch(DateTimeException e)
            {
                txtTransactions.setText("INVALID DATE");
                return;
            }
        }
        else
        {
            startTime = null;
        }

        if(chckbxEndDate.isSelected())
        {
            int endMonth = Month.valueOf(endMonthName.toUpperCase()).getValue();

            try
            {
                endTime = LocalDateTime.of(endYear, endMonth, endDay, 23, 59);
            }
            catch(DateTimeException e)
            {
                txtTransactions.setText("INVALID DATE");
                return;
            }
        }
        else
        {
            endTime = null;
        }

        ArrayList<Transaction> transactionList = account.getTransactions(startTime, endTime);
        String output = "";
        int maxAmountDigits = 1;

        for(Transaction t : transactionList)
        {
            String stringAmount = String.format("%.2f", t.getAmount());

            if(stringAmount.length() > maxAmountDigits)
                maxAmountDigits = stringAmount.length();
        }

        output += String.format("%-10s %-8s %-" + (maxAmountDigits + 1) + "s %s\n", "Date", "Time", "Amount", "Description");   
        //https://stackoverflow.com/questions/37791455/java-string-format-adding-spaces-to-integers
        output += String.format("%0" + 100 + "d\n", 0).replace("0", "-");

        for(Transaction t : transactionList)
        {
            output += String.format("%d.%02d.%02d %02d:%02d:%02d $%-" + maxAmountDigits + ".2f %s\n", t.getTransactionTime().getYear(),
                                                                                                      t.getTransactionTime().getMonthValue(),
                                                                                                      t.getTransactionTime().getDayOfMonth(),
                                                                                                      t.getTransactionTime().getHour(),
                                                                                                      t.getTransactionTime().getMinute(),
                                                                                                      t.getTransactionTime().getSecond(),
                                                                                                      t.getAmount(),
                                                                                                      t.getDescription());
        }

        txtTransactions.setText(output);
    }
}

Solution

  • contentPanel.setLayout(null);
    

    First you set the layout to null:

        JScrollPane txtTScrollPane = new JScrollPane(txtTransactions);
        contentPanel.add(txtTScrollPane);
        //contentPanel.revalidate();
        //contentPanel.repaint();
    

    Then you add the scrollpane to the content panel. However, you didn't use setBounds() on the scrollpane and the default size of a component is (0, 0) so there is nothing to paint.

    However, the solution is not to add the setBounds(...). The solution is to not use a null layout. It may seem easier with a null layout but then you get into problems like this and components don't work properly when used in a scrollpane.

    So the proper solution is to fix your code and use Layout Managers. Swing was designed to be used with layout managers. Then the layout manager will set the size and location of the component so you don't have to worry about it.

    The revalidate() and repaint() is only used when adding components to a visible GUI to invoke the layout manager so they are not needed.

    Also when creating the text area do something like:

    //txtTransactions = new JTextArea();
    txtTransactions = new JTextArea(5, 20);
    

    This will let the text area determine its own preferred size based on the rows/columns and font of the text area. Then the layout manager can do a better job.