Unable to get JScrollPane working on JFrame - java

Please look into the small code below. The scroll pane appears, but the sliders do not.
Even if I resize the frame the sliders do not. Please help.
import javax.swing.*;
public class sample {
static JFrame frame;
public static void main(String[] args) {
String Msg = "Sample Message To Test Scrolling";
frame = new JFrame("Sample Program");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
JPanel panel = new JPanel();
panel.setLayout(null);
for (int ypos = 0, i = 0; i < 40; i++) {
JLabel label = new JLabel("" + i + " " + Msg);
label.setFont(new Font("Courier", Font.BOLD, 12));
panel.add(label);
label.setBounds(10, ypos + 5,
label.getPreferredSize().width,
label.getPreferredSize().height);
ypos += label.getPreferredSize().height;
}
JScrollPane scroll = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
frame.setLayout(new BorderLayput());
frame.add(scroll);
frame.setVisible(true);
}
}

The sliders will only appear if and when the component contained by the JScrollPane's viewport is larger than the viewport. Based on your posted code, I don't see why your component would be larger than the viewport as the panel's size will be based on its preferredSize, something that will never change since for one, you're adding components to it with it using a null layout.
As an aside you should almost never use null layout.
For example:
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class Sample2 {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int MAX_ROWS = 400;
private static final String TEXT_BODY = "Sample Message To Test Scrolling";;
private static void createAndShowGui() {
JPanel panel = new JPanel(new GridLayout(0, 1));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
for (int i = 0; i < MAX_ROWS; i++) {
String text = String.format("%03d %s", i, TEXT_BODY);
JLabel label = new JLabel(text);
panel.add(label);
}
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setPreferredSize(new Dimension(PREF_W, PREF_H));
JFrame frame = new JFrame("Sample2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

Java Swing GridLayout Change Grid Sizes

I'm trying to create a program that lists movies in a Netflix style to learn Front-End coding.
How I want it to look in the end:
My guess is that every movie is a button component with an image a name label and a release year label.
I'm struggling to recreate this look. This is how it looks when I try it:
The navigationbar in my image is at the page start of a border layout. Below the navigationbar the movie container is in the center of the border layout.
My idea was creating a GridLayout and then create a button for each movie and adding it to the GridLayout.
You can recreate this with this code:
public class Main {
private static JFrame frame;
public static void main(String[] args) throws HeadlessException {
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setBackground(new Color(32, 32, 32));
JPanel navigationPanel = createNavigationBar();
frame.add(navigationPanel, BorderLayout.PAGE_START);
JPanel moviePanel = createMoviePanel();
frame.add(moviePanel, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(1920, 1080));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Example App");
frame.pack();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
public static JPanel createMoviePanel() {
JPanel moviePanel = new JPanel();
GridLayout layout = new GridLayout(0, 10);
layout.setHgap(3);
layout.setVgap(3);
moviePanel.setLayout(layout);
moviePanel.setBackground(new Color(32, 32, 32));
ArrayList<String> exampleList = new ArrayList<>();
// Add stuff to the example list
for(int i = 0; i < 120; i++) {
exampleList.add(Integer.toString(i));
}
final File root = new File("");
for(final String movie : exampleList) {
JLabel picLabel = new JLabel();
try {
File imageFile = new File(root.getAbsolutePath() + "\\src\\images\\" + "imageName.jpg"); // Try to find the cover image
if(imageFile.exists()) {
BufferedImage movieCover = ImageIO.read(imageFile);
picLabel = new JLabel(new ImageIcon(movieCover));
} else {
BufferedImage movieCover = ImageIO.read(new File(root.getAbsolutePath() + "\\src\\images\\temp.jpg")); // Get a temp image
picLabel = new JLabel(new ImageIcon(movieCover));
}
} catch (IOException e) {
e.printStackTrace();
}
JLabel movieName = new JLabel("New Movie");
movieName.setForeground(Color.WHITE);;
JButton movieButton = new JButton();
movieButton.setLayout(new GridLayout(0, 1));
//movieButton.setContentAreaFilled(false);
//movieButton.setBorderPainted(false);
//movieButton.setFocusPainted(false);
movieButton.add(picLabel);
movieButton.add(movieName);
moviePanel.add(movieButton);
}
return moviePanel;
}
public static JPanel createNavigationBar() {
JPanel navBar = new JPanel();
navBar.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 20));
navBar.setBackground(new Color(25, 25, 25));
JButton homeButton = new JButton("Home");
homeButton.setContentAreaFilled(false);
homeButton.setBorderPainted(false);
homeButton.setFocusPainted(false);
JButton movieButton = new JButton("Movies");
movieButton.setContentAreaFilled(false);
movieButton.setBorderPainted(false);
movieButton.setFocusPainted(false);
// Add all the buttons to the navbar
navBar.add(homeButton);
navBar.add(movieButton);
return navBar;
}
}
I noticed that the GridLayout always tries to fit everything onto the window.
All that's needed is a properly configured JButton in a GridLayout.
E.G.
public static JPanel createMoviePanel() {
JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
movieLibraryPanel.setBackground(new Color(132, 132, 132));
int m = 5;
BufferedImage image = new BufferedImage(9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
for (int ii = 1; ii < 21; ii++) {
JButton picButton = new JButton("Mov " + ii, new ImageIcon(image));
picButton.setMargin(new Insets(0,0,0,0));
picButton.setForeground(Color.WHITE);
picButton.setContentAreaFilled(false);
picButton.setHorizontalTextPosition(JButton.CENTER);
picButton.setVerticalTextPosition(JButton.BOTTOM);
movieLibraryPanel.add(picButton);
}
return movieLibraryPanel;
}
Here is a complete source for the above with a tweak to put the year on a new line. It uses HTML in the JButton to break the button text into two lines.
The input focus is on the first button, whereas the mouse hovers over the '2009' movie:
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
class MovieGrid {
MovieGrid() {
JFrame f = new JFrame("Movie Grid");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.add(createMoviePanel());
f.pack();
f.setVisible(true);
}
public static JPanel createMoviePanel() {
JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
movieLibraryPanel.setBackground(new Color(132, 132, 132));
int m = 5;
BufferedImage image = new BufferedImage(
9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
for (int ii = 2001; ii < 2021; ii++) {
JButton picButton = new JButton(
"<html>Movie<br>" + ii, new ImageIcon(image));
picButton.setMargin(new Insets(0,0,0,0));
picButton.setForeground(Color.WHITE);
picButton.setContentAreaFilled(false);
picButton.setHorizontalTextPosition(JButton.CENTER);
picButton.setVerticalTextPosition(JButton.BOTTOM);
movieLibraryPanel.add(picButton);
}
return movieLibraryPanel;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new MovieGrid();
}
};
SwingUtilities.invokeLater(r);
}
}
Same idea's from Andrew Thompson answer but with some minor text alignment changes and hover effect
final class Testing
{
public static void main(String[] args)
{
JFrame frame=new JFrame("NEFLIX");
frame.setContentPane(new GridDisplay());
frame.pack();
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static final class GridDisplay extends JPanel implements ActionListener
{
private GridDisplay()
{
super(new GridLayout(0,5,20,20));
setBackground(new Color(0,0,0,255));
BufferedImage image=new BufferedImage(150,200,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d=(Graphics2D)image.getGraphics();
g2d.setColor(Color.BLUE);
g2d.fillRect(0,0,image.getWidth(),image.getHeight());
HoverPainter painter=new HoverPainter();
for(int i=0;i<10;i++)
{
TVShowCard card=new TVShowCard(image,"Show "+i,"199"+i);
card.addMouseListener(painter);
add(card);
}
}
//highlight only on hover
private final class HoverPainter extends MouseAdapter
{
#Override
public void mouseExited(MouseEvent e) {
((TVShowCard)e.getSource()).setBorderPainted(false);
}
#Override
public void mouseEntered(MouseEvent e) {
((TVShowCard)e.getSource()).setBorderPainted(true);
}
}
private final class TVShowCard extends JButton
{
private TVShowCard(BufferedImage preview,String name,String year)
{
super();
setContentAreaFilled(false);
setBackground(new Color(0,0,0,0));
setFocusPainted(false);
setBorderPainted(false);
//I didn't use image icon & text horizontal alignment because the text always horizontally centered aligned but from the expected output it was left so created 2 labels for the job
setLayout(new GridBagLayout());
addIcon(preview);
addLabel(name,year);
addActionListener(GridDisplay.this);
}
private void addIcon(BufferedImage preview)
{
JLabel icon=new JLabel();
icon.setIcon(new ImageIcon(preview));
add(icon,new GridBagConstraints(0,0,1,1,1.0f,0.0f,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
}
private void addLabel(String name,String year)
{
JLabel label=new JLabel("<html><body>"+name+"<br>"+year+"</body></html>");
label.setForeground(Color.white);
label.setBackground(new Color(0,0,0,0));
add(label,new GridBagConstraints(0,1,1,1,1.0f,1.0f,GridBagConstraints.SOUTHWEST,GridBagConstraints.NONE,new Insets(5,0,0,0),0,0));
}
}
#Override
public void actionPerformed(ActionEvent e)
{
TVShowCard card=(TVShowCard)e.getSource();
//do stuff with it
}
}
}

JScrollPane not showing scrollbars when an Array of JPanels are added to it

Im adding an array of JPanels inside a JScrollPane. The array of JPanels are being added to the JScrollPane but the scroll bars just wont show.
public class MyFrame extends JFrame {
private JPanel contentPane;
private JPanel panel_1;
private JScrollPane scrollPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyFrame frame = new MyFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 288, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel_1 = new JPanel();
panel_1.setBounds(10, 114, 434, 136);
panel_1.setLayout(null);
scrollPane = new JScrollPane(panel_1);
scrollPane.setBounds(52, 57, 164, 126);
scrollPane.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Histogram", TitledBorder.LEADING, TitledBorder.TOP, null, Color.BLUE));
scrollPane.setLayout(new ScrollPaneLayout());
contentPane.add(scrollPane);
buildBar();
}
JPanel[] barPanel;
private void buildBar(){
int x=0,y=22,w=100,h=80,s=10,n=3;
barPanel = new JPanel[n];
for(int i=0; i<n; i++){
barPanel[i] = new JPanel();
barPanel[i].setBounds(x, y, w, h);
barPanel[i].setBackground(new Color(255,0,0));
panel_1.add(barPanel[i]);
panel_1.revalidate();
panel_1.repaint();
x = x + w + s;
}
}
}
I have been working on it for hours . Maybe there is something that I've missed out.
You're shooting yourself in the foot with these two lines:
panel_1.setBounds(10, 114, 434, 136);
panel_1.setLayout(null);
Both of which will mess up the JScrollPane's ability to use and display scrollbars. What you need to do is: not to use setBounds but rather have the components use their preferredSize, and avoid using null layout, since this won't change the container's preferredSize.
Yet another reason to studiously avoid null layouts.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class MyPanel2 extends JPanel {
private static final int PREF_W = 388;
private static final int PREF_H = PREF_W;
public static final int INNER_PREF_W = 434;
public static final int INNER_PREF_H = 126;
private static final int HISTO_PANEL_COUNT = 6;
private static final Dimension VP_SZ = new Dimension(164, 126);
private JPanel holderPanel = new JPanel(new GridLayout(0, 1));
public MyPanel2() {
int w = INNER_PREF_W;
int h = INNER_PREF_H;
for (int i = 0; i < HISTO_PANEL_COUNT; i++) {
holderPanel.add(new InnerPanel(w, h));
}
JScrollPane scrollPane = new JScrollPane(holderPanel);
scrollPane.getViewport().setPreferredSize(VP_SZ);
setLayout(new GridBagLayout());
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class InnerPanel extends JPanel {
private int w;
private int h;
public InnerPanel(int w, int h) {
this.w = w;
this.h = h;
setBorder(BorderFactory.createLineBorder(Color.BLUE));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0, y = 22, w = 100, h = 80, s = 10, n = 3;
g.setColor(Color.RED);
for (int i = 0; i < n; i++) {
g.fillRect(x, y, w, h);
x = x + w + s;
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(w, h);
}
}
private static void createAndShowGui() {
MyPanel2 mainPanel = new MyPanel2();
JFrame frame = new JFrame("MyPanel2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
JScrollPane relies on the preferredSize of your container to determine the scroll bar width. If you use a Layout, the preferredSize will be determined for you when components are added to the panel.
However, when you use:
contentPane.setLayout(null);
You are preventing the preferredSize from changing based on added components.
Try to use a layout which is applicable for your case.
In case you are very certain you do not want to use a Layout, in order to see the scroll bar, you may set the preferredSize of the container for every components you added by manually adjusting the preferredSize. That way, the scrollbar will still extend with newly added components.

GridLayout is causing my components to disappear

I'm trying to create a window with a scrollable JTextArea and a JTextField below it. I want the frame to look like a chat window; one, large scrollable text area and a single lined text frame. I've tried variations but I can't get the text area scrollable without making the entire window scrollable. It's incredibly annoying. My current iteration only draws one panel to the screen:
private void buildGUI() {
Container chatClientContainer = getContentPane();
chatClientContainer.setLayout(new BorderLayout());
JPanel messagesReceivedPanel = new JPanel();
messagesReceivedPanel.setLayout(new GridLayout(1, 1, 5, 5));
JTextArea messagesReceived = new JTextArea("area");
messagesReceivedPanel.add(messagesReceived);
JPanel draftPanel = new JPanel();
draftPanel.setLayout(new GridLayout(1, 1, 5, 5));
JTextField draftMessage = new JTextField("field");
draftPanel.add(draftMessage);
chatClientContainer.add(new JScrollPane(messagesReceivedPanel));
chatClientContainer.add(draftPanel);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int windowWidth = 400;
int windowHeight = 600;
int posX = ((int) screenSize.getWidth())/2 - windowWidth/2;
int posY = (int) screenSize.getHeight()/2 - windowHeight/2;
setBounds(posX, posY, windowWidth, windowHeight);
setResizable(true);
setVisible(true);
}
How can I position this the way I want?
Why not just use BorderLayout? Place the JTextArea's JScrollPane BorderLayout.CENTER and the JTextField (not JTextFrame) BorderLayout.PAGE_END.
For example:
import java.awt.BorderLayout;
import javax.swing.*;
public class ChatPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final int ROWS = 15;
private static final int COLS = 30;
private JTextArea textArea = new JTextArea(ROWS, COLS);
private JTextField textField = new JTextField(COLS);
public ChatPanel() {
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(textField, BorderLayout.PAGE_END);
}
private static void createAndShowGUI() {
ChatPanel paintEg = new ChatPanel();
JFrame frame = new JFrame("ChatPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Getting locations of JLabel added to JPanel

I am working on a Java Application.
I am adding some labels after setting up the frame and making it visible.
I've also called revalidate() on the JPanel, on which I am adding the labels.
But, not all of the labels are returning correct position.
Here is my code.
public class Test {
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
JScrollPane scrollPane = new JScrollPane();
JPanel view = new JPanel();
view.setLayout(new MigLayout());
scrollPane.setViewportView(view);
frame.setContentPane(scrollPane);
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
List<JComponent> labels = update(view);
printLocations(labels);
}
public static List<JComponent> update(JPanel view) {
view.removeAll();
List<JComponent> labels = new ArrayList<>();
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Label " + i);
view.add(label);
labels.add(label);
}
view.revalidate();
view.repaint();
return labels;
}
private static void printLocations(List<JComponent> labels) {
for (JComponent label : labels) {
System.out.println(label.getLocation());
}
}
}
Here is the output:
java.awt.Point[x=7,y=7]
java.awt.Point[x=52,y=7]
java.awt.Point[x=97,y=7]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=0]
In this code, If I add some delay between updating and printing components' location, all components return correct position.
But, in my application, even delay is not working!
It turns out, we must need to call revalidate() on the root component.
Then, this problem is solved.
In this example, root component is frame. So, the code will be as follows:
public class Test {
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
JScrollPane scrollPane = new JScrollPane();
JPanel view = new JPanel();
view.setLayout(new MigLayout());
scrollPane.setViewportView(view);
frame.setContentPane(scrollPane);
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
List<JComponent> labels = update(view);
frame.revalidate();
printLocations(labels);
}
public static List<JComponent> update(JPanel view) {
view.removeAll();
List<JComponent> labels = new ArrayList<>();
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Label " + i);
view.add(label);
labels.add(label);
}
view.repaint();
return labels;
}
private static void printLocations(List<JComponent> labels) {
for (JComponent label : labels) {
System.out.println(label.getLocation());
}
}
}

Auto-scroll JTextArea with ScrollPane?

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:
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.
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);
}
}

Categories