4

I'm trying to build a dynamic log window (basically a auto-scrolling jtext-area).

The problem I'm having is that although I'm printing 500 lines in the text area, it displays as below:

enter image description here

Below you have my code:

    import java.awt.Dimension;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.DefaultCaret;


public class Main {

    private static JFrame mainFrame;

    public static void main(String args[]) {
        mainFrame = new JFrame();
        mainFrame.setSize(500, 500);

        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        ControlPanel cp = new ControlPanel();
        mainFrame.add(cp);
        mainFrame.setVisible(true);
    }
}

class ControlPanel extends JPanel {

private JButton resetButton = new JButton("Reset");

private JPanel logPanel = new JPanel();

private JLabel actionLogsLabel = new JLabel("Action Log");

private JLabel pointsLogsLabel = new JLabel("Points Log");

private JTextArea actionLog = new JTextArea();

private JTextArea pointsLog = new JTextArea();

private JScrollPane actionScroll;

private JScrollPane pointsScroll;

public ControlPanel() {
    init();

    this.add(resetButton);
    this.add(logPanel);
}

private void init() {
    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    this.setAlignmentX(LEFT_ALIGNMENT);
    this.logPanel.setLayout(new BoxLayout(logPanel, BoxLayout.Y_AXIS));
    this.logPanel.setAlignmentX(LEFT_ALIGNMENT);

    actionLog.setPreferredSize(new Dimension(500, 300));
    actionLog.setMaximumSize(actionLog.getPreferredSize());
    actionLog.setEditable(false);
    actionLog.setWrapStyleWord(true);
    DefaultCaret caret = (DefaultCaret) actionLog.getCaret();
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

    pointsLog.setPreferredSize(new Dimension(500, 300));
    pointsLog.setMaximumSize(pointsLog.getPreferredSize());
    pointsLog.setEditable(false);
    pointsLog.setWrapStyleWord(true);

    pointsScroll = new JScrollPane(pointsLog, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    actionScroll = new JScrollPane(actionLog, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    logPanel.add(actionLogsLabel);
    logPanel.add(actionScroll);

    for(int i = 0; i < 500; i++) {
        actionLog.setText(actionLog.getText() + "Line: " + i + "\n");
    }

    logPanel.add(pointsLogsLabel);
    logPanel.add(pointsScroll);
}
}

Hopefully someone with a bit more Swing experience can take the time to point me the right way with this.

Eugen
  • 1,537
  • 7
  • 29
  • 57

1 Answers1

4

Never do this:

actionLog.setPreferredSize(new Dimension(500, 300));

Since by doing this you artificially restrict the size of the JTextArea causing the effect that is currently vexing you. Note also that it's generally a good idea to avoid setting preferred sizes on anything.

Instead set the column and row counts of the JTextARea. This can be done via setter methods or via a simple constructor call: JTextArea myTextArea = new JTextArea(rows, columns);

As an aside: I wonder if a JList will work better for you.


MCVE Example:

import javax.swing.*;
import javax.swing.text.DefaultCaret;

public class Main2 {

   private static void createAndShowGUI() {
      JPanel mainPanel = new ControlPanel();

      JFrame frame = new JFrame("Main2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGUI();
         }
      });
   }
}

class ControlPanel extends JPanel {
   private static final int LOG_ROWS = 15;
   private static final int LOG_COLS = 40;
   private JButton resetButton = new JButton("Reset");
   private JPanel logPanel = new JPanel();
   private JLabel actionLogsLabel = new JLabel("Action Log");
   private JLabel pointsLogsLabel = new JLabel("Points Log");
   private JTextArea actionLog = new JTextArea();
   private JTextArea pointsLog = new JTextArea();
   private JScrollPane actionScroll;
   private JScrollPane pointsScroll;

   public ControlPanel() {
      init();
      this.add(resetButton);
      this.add(logPanel);
   }

   private void init() {
      this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      this.setAlignmentX(LEFT_ALIGNMENT);
      this.logPanel.setLayout(new BoxLayout(logPanel, BoxLayout.Y_AXIS));
      this.logPanel.setAlignmentX(LEFT_ALIGNMENT);
      // !! actionLog.setPreferredSize(new Dimension(500, 300));
      // !! actionLog.setMaximumSize(actionLog.getPreferredSize());
      actionLog.setRows(LOG_ROWS); // !!
      actionLog.setColumns(LOG_COLS); // !!

      actionLog.setEditable(false);
      actionLog.setWrapStyleWord(true);
      DefaultCaret caret = (DefaultCaret) actionLog.getCaret();
      caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
      // !! pointsLog.setPreferredSize(new Dimension(500, 300));
      // !! pointsLog.setMaximumSize(pointsLog.getPreferredSize());
      pointsLog.setRows(LOG_ROWS); // !!
      pointsLog.setColumns(LOG_COLS); // !!

      pointsLog.setEditable(false);
      pointsLog.setWrapStyleWord(true);
      pointsScroll = new JScrollPane(pointsLog,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      actionScroll = new JScrollPane(actionLog,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      logPanel.add(actionLogsLabel);
      logPanel.add(actionScroll);
      for (int i = 0; i < 500; i++) {
         actionLog.setText(actionLog.getText() + "Line: " + i + "\n");
      }
      logPanel.add(pointsLogsLabel);
      logPanel.add(pointsScroll);
   }
}

Edit
Example with nested layouts and JLists:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.*;

public class Main2B {

   private static void createAndShowGUI() {
      ControlPanel2B controlPanel = new ControlPanel2B();
      controlPanel.setBorder(BorderFactory.createEtchedBorder());

      JPanel mainPanel = new JPanel(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      mainPanel.add(controlPanel, gbc);

      JFrame frame = new JFrame("Main2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGUI();
         }
      });
   }
}

@SuppressWarnings("serial")
class ControlPanel2B extends JPanel {
   private static final int LOG_ROWS = 15;
   private static final int LIST_WIDTH = 500;
   private JButton resetButton = new JButton("Reset");
   private JPanel logPanel = new JPanel();
   private JLabel actionLogsLabel = new JLabel("Action Log");
   private JLabel pointsLogsLabel = new JLabel("Points Log");

   private DefaultListModel<String> actionLogListModel = new DefaultListModel<>();
   private JList<String> actionLogList = new JList<String>(actionLogListModel);
   private DefaultListModel<String> pointsLogListModel = new DefaultListModel<>();
   private JList<String> pointsLogList = new JList<String>(pointsLogListModel);
   private JScrollPane actionScroll;
   private JScrollPane pointsScroll;

   public ControlPanel2B() {
      init();
      this.add(resetButton);
      this.add(logPanel);
   }

   private void init() {
      actionLogList.setVisibleRowCount(LOG_ROWS);
      pointsLogList.setVisibleRowCount(LOG_ROWS);
      actionLogList.setFixedCellWidth(LIST_WIDTH);

      this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      this.setAlignmentX(LEFT_ALIGNMENT);
      this.logPanel.setLayout(new BoxLayout(logPanel, BoxLayout.Y_AXIS));
      this.logPanel.setAlignmentX(LEFT_ALIGNMENT);
      pointsScroll = new JScrollPane(pointsLogList,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      actionScroll = new JScrollPane(actionLogList,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      logPanel.add(actionLogsLabel);
      logPanel.add(actionScroll);
      for (int i = 0; i < 500; i++) {
         actionLogListModel.addElement("Line: " + i);
      }
      logPanel.add(pointsLogsLabel);
      logPanel.add(pointsScroll);
   }
}
Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • The problem I'm having now is that I can not keep it on a fixed size. The JText area expanded downwards too much (even after setting maxSize(new Dimension(X, Y)); Also, I want to keep a text area for now. It suits the sort of logs I'm receiving from the application better. – Eugen Jan 12 '14 at 11:56
  • @Eugen: you've got more problems then the original question leads us to be, and it sounds as if you're using layouts incorrectly. I urge you to create and post a [minimal, complete, valid example](http://stackoverflow.com/help/mcve) so we can experience your problem for ourselves. – Hovercraft Full Of Eels Jan 12 '14 at 11:58
  • @Eugen: no, better a [MCVE](http://stackoverflow.com/help/mcve) then your full code. Please read the link first. – Hovercraft Full Of Eels Jan 12 '14 at 12:00
  • @Eugen: Please re-read the link. Don't force us to have to create our own MCVE -- this is **your** question and so the effort should be on **you**. – Hovercraft Full Of Eels Jan 12 '14 at 12:04
  • I just saw your edit/comment now :). I'll create that example right away, unfortunately I have to select parts of the code as there are some security concerns in there as well. – Eugen Jan 12 '14 at 12:06
  • The code is (very) dirty but should do for easy testing so you can better understand what my issue is. – Eugen Jan 12 '14 at 12:14
  • 1
    @Eugen: that's the key to creating an MCVE, it should not contain your original code, but just new code that reproduces your problem. For example, please see the code that I've just posted above. – Hovercraft Full Of Eels Jan 12 '14 at 12:14
  • The problem I'm having when giving up setPreferedSize / setMaximumSize (textArea.getPrefredeSize()); I can no longer keep the JTextArea with a fixed size (do not want it to change when resizing). It does display all 500 lines, but creates this as a secondary problem. – Eugen Jan 12 '14 at 12:18
  • I will. I was hoping on a simpler/cleaner solution that wouldn't mean adding another layout/panel/whatever. – Eugen Jan 12 '14 at 12:28
  • @Eugen: it's not that complicated and certainly cleaner than directly setting preferred, max and min sizes. Please see edit to answer. – Hovercraft Full Of Eels Jan 12 '14 at 12:36
  • Got it! Thanks for taking the time and providing such an excellent and detailed answer! – Eugen Jan 12 '14 at 12:40