I am creating a console and need to have two JTextArea
s inside a JPanel
inside a JScrollPane
. Since setLineWrap(true)
does not work when it is not directly inside the JScrollPane
, I found a neat workaround here. This allows the LineWrap property to work, but sadly breaks the BorderLayout.CENTER
property for one of the JTextArea
s. So now the second JTextArea
won't fill the entire Pane.
Here is the stripped down code for the console:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Console2Fix extends JPanel{
public final String def_text;
private final Font font = new Font("Source Code Pro", Font.PLAIN, 12);
public JTextArea outPane, inPane;
private JScrollPane conScroll;
private ScrollablePanel scrollPanel;
public Console2Fix(String title){
super();
def_text = title + "";
//UI
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
System.out.println("catdch 1");
} catch (InstantiationException e1) {
System.out.println("catdch 2");
} catch (IllegalAccessException e1) {
System.out.println("catdch 3");
} catch (UnsupportedLookAndFeelException e1) {
System.out.println("catdch 4");
}
SwingUtilities.updateComponentTreeUI(this);
setLayout(new BorderLayout(0, 0));
//Output Area
outPane = new JTextArea();
outPane.setLineWrap(true);
outPane.setWrapStyleWord(true);
outPane.setBackground(new Color(40,40,40));
outPane.setForeground(Color.LIGHT_GRAY);
outPane.setFont(font);
outPane.setEditable(false);
//Input Area
inPane = new JTextArea();
inPane.setLineWrap(true);
inPane.setWrapStyleWord(true);
inPane.setBackground(new Color(42,42,42));
inPane.setForeground(Color.WHITE);
inPane.setFont(font);
inPane.setCaretColor(Color.WHITE);
//Modified JPanel to support Linewraping
scrollPanel = new ScrollablePanel();
scrollPanel.setLayout(new BorderLayout(0, 0));
scrollPanel.add(outPane, BorderLayout.NORTH);
scrollPanel.add(inPane, BorderLayout.CENTER);
//ScrollPane
conScroll = new JScrollPane(scrollPanel);
conScroll.setBorder(BorderFactory.createEmptyBorder());
conScroll.getHorizontalScrollBar().setPreferredSize(new Dimension(0, 13));
conScroll.getVerticalScrollBar().setPreferredSize(new Dimension(13, 0));
conScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
this.add(conScroll, BorderLayout.CENTER);
outPane.setText(def_text);
createWindow();
}
//Creates JFrame for demonstration
public void createWindow() {
JFrame frame = new JFrame(def_text);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(this);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
//Bonus question: How can I get this to work?
//- When this is called it should scroll the conScroll to the bottom
public void down(){
inPane.scrollRectToVisible(new Rectangle(inPane.getSize()));
}
public static void main(String[] args){
new Console2Fix("Console2Fix");
}
}
And this is the modified JPanel:
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.JPanel;
import javax.swing.Scrollable;
public class ScrollablePanel extends JPanel implements Scrollable{
public Dimension getPreferredScrollableViewportSize() {
return super.getPreferredSize(); //tell the JScrollPane that we want to be our 'preferredSize' - but later, we'll say that vertically, it should scroll.
}
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 16;//set to 16 because that's what you had in your code.
}
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 16;//set to 16 because that's what you had set in your code.
}
public boolean getScrollableTracksViewportWidth() {
return true;//track the width, and re-size as needed.
}
public boolean getScrollableTracksViewportHeight() {
return false; //we don't want to track the height, because we want to scroll vertically.
}
}
PS: I am aware that changing getScrollableTracksViewportHeight()
to true
seems to solve the problem, but it actually breaks the VerticalScrollBar...
PSPS: I just noticed that it behaves really strange when scrolling around real fast. Seems like it needs a repaint() somewhere...
Thanks in advance for your time.