I'm trying to get a JTextPane to adjust its height according to whatever content I feed it. All I can do is to set a fixed height in pixels using Dimension.
How do I make the JTextPane collapse/expand so it will fit to contents?
I might add that I use this in a GridBagLayout'ed JPanel that has been added to a JScrollPane.
I don't know any direct way to do it, but this may give you some ideas:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class TextPanePerfectSize extends JFrame
{
JTextField textField;
JTextPane textPane;
public TextPanePerfectSize()
{
textField = new JTextField(20);
textField.setText("add text");
getContentPane().add(textField, BorderLayout.NORTH );
textField.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
Document doc = textPane.getDocument();
doc.insertString(doc.getLength(), " " + textField.getText(), null);
textField.setText("");
Dimension d = textPane.getPreferredSize();
Rectangle r = textPane.modelToView( textPane.getDocument().getLength() );
d.height = r.y + r.height;
textPane.setPreferredSize( d );
getContentPane().validate();
// pack();
}
catch(Exception e2) {}
}
});
JLabel label = new JLabel("Hit Enter to Add Text to Text Pane");
getContentPane().add(label);
JPanel south = new JPanel();
textPane = new JTextPane();
textPane.setText("Some text");
textPane.setEditable( false );
textPane.setPreferredSize( new Dimension(120, 23) );
south.add( textPane );
getContentPane().add(south, BorderLayout.SOUTH);
}
public static void main(String[] args)
{
JFrame frame = new TextPanePerfectSize();
frame.setSize(200, 200);
frame.setLocationRelativeTo( null );
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
JTextPane tp = new JTextPane();
setLayout(new BorderLayout()); // set layout on parent
add(tp, BorderLayout.CENTER);
This works for me.
Related
i have problem with my JTextArea i java. When i print output in the text area, it doesn't automatically scroll to the bottom. And when it reaches the bottom of text area i cannot scroll it with scroll panel. Here is my GUI Code:
public void initializeWindow()
{
JPanel pan;
JPanel colorBox;
JPanel consolePanel;
JLabel panText;
JFrame frame = new JFrame();
JScrollPane scroll;
gridPanels = new JPanel[sizeX][sizeY];
boardPanel = new JPanel();
legend = new JPanel();
consolePanel = new JPanel();
consoleOutput = new JTextArea(25,20);
consoleOutput.setEditable(false);
consoleOutput.setPreferredSize(new Dimension( 200,300));
consoleOutput.setAutoscrolls(true);
scroll = new JScrollPane(this.consoleOutput, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
consolePanel.setBorder(BorderFactory.createLineBorder(Color.black));
consolePanel.add(consoleOutput);
consolePanel.add(scroll);
boardPanel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
boardPanel.setLayout(new GridLayout(sizeX,sizeY));
legend.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
legend.setPreferredSize( new Dimension(300,boardPanel.getHeight()));
PrintStream printStream = new PrintStream(new CustomOutputStream(consoleOutput));
for (Organizm org: legendOrgs)
{
pan = new JPanel();
colorBox = new JPanel();
panText = new JLabel();
pan.setMaximumSize(new Dimension(100,70));
pan.setAlignmentX(Component.LEFT_ALIGNMENT);
pan.setLayout(new FlowLayout(FlowLayout.LEADING));
colorBox.setBackground(org.getOrgColor());
colorBox.setAlignmentX(Component.LEFT_ALIGNMENT);
colorBox.setPreferredSize(new Dimension(30,30));
colorBox.setMaximumSize(new Dimension(30,30));
panText.setPreferredSize(new Dimension(100,15));
panText.setText(" - " + org.getName());
panText.setAlignmentX(Component.RIGHT_ALIGNMENT);
pan.add(colorBox);
pan.add(panText);
legend.add(pan);
}
legend.add(consolePanel);
for(int i=0; i<sizeY; i++)
{
for(int j=0; j<sizeX; j++)
{
gridPanels[i][j] = new JPanel();
if(organizmy[i][j]!=null)
gridPanels[i][j].setBackground(organizmy[i][j].getOrgColor());
else gridPanels[i][j].setBackground(Color.white);
boardPanel.add(gridPanels[i][j]);
}
}
System.setOut(printStream);
System.setErr(printStream);
frame.add(boardPanel);
frame.add(legend,BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Wirtualny świat");
frame.pack();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
worldFrame = frame;
}
And here is my Custom output Stream class which is used to print everything i print via System.out.println to my text Area:
public class CustomOutputStream extends OutputStream
{
private final JTextArea textArea;
public CustomOutputStream(JTextArea textArea)
{
this.textArea = textArea;
}
#Override
public void write(int b)
{
textArea.append(String.valueOf((char)b));
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
Here is link to image what it looks like in GUI:
You need to remove this line from your code:
consoleOutput.setPreferredSize(new Dimension( 200,300));
Unfortunately, it prevents your JTextArea from being scrollable because you set static size to that element.
P.S. Stay away from Swing - there are better options in Java
It works for me.
import javax.swing.*;
public class Scrollin{
public static void main(String[] args){
JFrame frame = new JFrame("scrolling");
JTextArea area = new JTextArea(20, 20);
frame.add(new JScrollPane(area));
frame.setVisible(true);
frame.pack();
Timer t = new Timer( 150, evt->{
area.setCaretPosition( area.getDocument().getLength() );
area.append("word is born\n");
});
t.start();
}
}
As text is added, the window will scroll to the end provided the cursor is at the end of the document.
Maybe you can start with something as short as this to demonstrate your issue?
I am trying to set my JTextArea to take up the max horz length of the screen, so that the next thing, in this case a button, will start on a new line, but I have no clue how to do it. I have messed around by setting the size of the JTextArea to change from, say, 20 to 1000 but that does not do anything.
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row? Here is what I have so far...
MyFrame(){//constructor
super("Simple Calculator");
p = new JPanel();
grid = new GridLayout(4, 4, 3, 3);
p.setLayout(grid);
setSize(400, 500);
setResizable(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUpTextScreen();
//create buttons
for(int i = 0; i < buttonValues.length; i++){
p.add(new JButton(buttonValues[i]));
}
add(p);
setVisible(true);
}
private void setUpTextScreen() {
textOnScreen = new JTextArea(7, 1000);
textOnScreen.setText("0");//default
textOnScreen.setEditable(false);
p.add(textOnScreen);
}
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row?
Break your layout up into logical pieces. Start with your main panel using a BorderLayout.
First I would use a JTextField for the calculator display, not a JTextArea. Then you can add the text field using: mainPanel.add(textField, BorderLayout.PAGE_START);
Then you create a JPanel using a GridLayout for the buttons. Then you add the buttons to the button panel and use: maonPanel.add(buttonPanel, BorderLayout.CENTER);
For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
// display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(30, 30) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Hava a look at Nested layouts, you can add one panel with a BorderLayout (there are other options too though) and add the textarea to it. Then you only need one more panel with a GridLayout that displays the buttons. This is an example: (Note that a few lines are unnecessary in this code, but they help understand layouts)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
public class Example extends JFrame {
Example() {//
super("Simple Calculator");
// The Main Panel where the 2 other panels will be on
JPanel mainPanel = new JPanel(new BorderLayout());
// The textarea will be inside this panel
JPanel areaPanel = new JPanel(new BorderLayout());
JTextArea area = new JTextArea(
"This is a JTextArea -Long text to show it works -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works-");
area.setBorder(new LineBorder(Color.BLACK));
area.setWrapStyleWord(true);
area.setLineWrap(true);
// Fill the whole space of the panel with the area
areaPanel.add(area, BorderLayout.CENTER);
// The buttons will be inside this panel
JPanel buttonPanel = new JPanel(new GridLayout(4, 4, 3, 3));
for (int i = 0; i < 16; i++) { // Adding buttons
buttonPanel.add(new JButton("Button" + i));
}
// The textarea-panel should be on top of the main panel
mainPanel.add(areaPanel, BorderLayout.NORTH);
// The panel with the buttons should fill the remaining space
mainPanel.add(buttonPanel, BorderLayout.CENTER);
getContentPane().add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
You can also use html tags like:
JButton button = new JButton("<html><b><u>T</u>wo</b><br>lines</html>");
Or in any other JComponent like you got.
So you can use <BR> tag you achieve your need.
I am using setBorder(BorderFactory.createTitledBorder(title)) in my JPanel in order to group its content in a rectangle with a title above it. How can I set a tooltip text for the title?
A possible approach is nesting components. As Borders are not components they can not have tooltips, but you can have a component with the sole purpose of holding border and the tooltip:
JPanel outer = new JPanel();
outer.setBorder(BorderFactory.createTitledBorder("Title"));
outer.setToolTipText("sample text");
JPanel inner = new JPanel();
outer.add(inner);
and then use inner as the container for the components you want to group.
You can override the getToolTipText() method of the panel to check if the mouse of over the title text:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class TitledBorderTest
{
private static void createAndShowUI()
{
UIManager.getDefaults().put("TitledBorder.titleColor", Color.RED);
Border lowerEtched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
TitledBorder title = BorderFactory.createTitledBorder(lowerEtched, "Title");
// title.setTitleJustification(TitledBorder.RIGHT);
Font titleFont = UIManager.getFont("TitledBorder.font");
title.setTitleFont( titleFont.deriveFont(Font.ITALIC + Font.BOLD) );
JPanel panel = new JPanel()
{
#Override
public String getToolTipText(MouseEvent e)
{
Border border = getBorder();
if (border instanceof TitledBorder)
{
TitledBorder tb = (TitledBorder)border;
FontMetrics fm = getFontMetrics( tb.getTitleFont() );
int titleWidth = fm.stringWidth(tb.getTitle()) + 20;
Rectangle bounds = new Rectangle(0, 0, titleWidth, fm.getHeight());
return bounds.contains(e.getPoint()) ? super.getToolTipText() : null;
}
return super.getToolTipText(e);
}
};
panel.setBorder( title );
panel.setToolTipText("Title With ToolTip");
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
This code assumes the title is on the left. If you want the title on the right then you would need to adjust the X value of the text bounds.
I don't think you can add setToolTipText to TitledBorder. you can provide tooltip for JComponent but TitledBorder is not derived from JComponent.
You can try to use JPanel instead:
ToolTipManager.sharedInstance().registerComponent(new JPanel());
//ToolTipManager.sharedInstance().setDismissDelay(800000);
TollTip isn't right Components for experiments, all goog workaround for popup or tooltips are based on JWindow/ undecorated JDialog
maybe not necessary, keys in UIManager are accesible, but in this case all TollTips has the same settings
import java.awt.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.*;
public class ColoredToolTipExample extends JFrame {
private static final long serialVersionUID = 1L;
public ColoredToolTipExample() {
Border line, raisedbevel, loweredbevel, title, empty;
line = BorderFactory.createLineBorder(Color.black);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
title = BorderFactory.createTitledBorder("");
empty = BorderFactory.createEmptyBorder(1, 1, 1, 1);
Border compound;
compound = BorderFactory.createCompoundBorder(empty, line);
UIManager.put("ToolTip.foreground", new ColorUIResource(Color.red));
UIManager.put("ToolTip.background", new ColorUIResource(Color.yellow));
UIManager.put("ToolTip.font", new FontUIResource(new Font("Verdana", Font.PLAIN, 18)));
UIManager.put("ToolTip.border", new BorderUIResource(compound));
JButton button = new JButton("Hello, world");
button.setToolTipText("<html> - myText <br> - myText <br> - myText <br>");
getContentPane().add(button);
JFrame frame = new JFrame("Colored ToolTip Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 100);
frame.setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ColoredToolTipExample();
}
});
}
}
I have a text editor with Netbeans where i load a text to a JtextPane. If text is too big u can read it with the help of an horizontal scroll.Is there any way to split the text into pages of 24 lines for example so that every page is visible without scrolling and use a next page button for changing page (like eBooks do)?
It is easier to use a JTextArea to do this because you can easily specify the number of lines to display each time you scroll to a new page.
The basic solution is to add a text area to a scroll pane than then hide the scrollbars. You can then use the defaults Actions of the vertical scrollbar to do the scrolling for you. The code below uses code from the Action Map Action blog entry to easily create an Action that you can add to a JButton:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class TextAreaScroll extends JPanel
{
private JTextArea textArea;
public TextAreaScroll()
{
setLayout( new BorderLayout() );
textArea = new JTextArea(10, 80);
textArea.setEditable( false );
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_NEVER );
add(scrollPane);
JButton load = new JButton("Load TextAreaScroll.java");
load.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
FileReader reader = new FileReader( "TextAreaScroll.java" );
BufferedReader br = new BufferedReader(reader);
textArea.read( br, null );
br.close();
}
catch(Exception e2) { System.out.println(e2); }
}
});
add(load, BorderLayout.NORTH);
// Add buttons to do the scrolling
JScrollBar vertical = scrollPane.getVerticalScrollBar();
Action nextPage = new ActionMapAction("Next Page", vertical, "positiveBlockIncrement");
nextPage.putValue(AbstractAction.MNEMONIC_KEY, KeyEvent.VK_N);
JButton nextButton = new JButton(nextPage);
Action previousPage = new ActionMapAction("Previous Page", vertical, "negativeBlockIncrement");
previousPage.putValue(AbstractAction.MNEMONIC_KEY, KeyEvent.VK_N);
JButton previousButton = new JButton(previousPage);
JPanel south = new JPanel();
add(south, BorderLayout.SOUTH);
south.add( previousButton );
south.add( nextButton );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TextAreaScroll());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
I have a javax.swing.text.Document and I want to calculate the size of the bounding box that document needs to render itself.
Is that possible?
It is almost trivial for plain text (height = line count * line height, width = max width over each line) But how can I do this with RTF, HTML or any other document?
This code might give you some ideas:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class TextPanePerfectSize extends JFrame
{
JTextField textField;
JTextPane textPane;
public TextPanePerfectSize()
{
textField = new JTextField(20);
textField.setText("add text");
getContentPane().add(textField, BorderLayout.NORTH );
textField.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
Document doc = textPane.getDocument();
doc.insertString(doc.getLength(), " " + textField.getText(), null);
textField.setText("");
Dimension d = textPane.getPreferredSize();
Rectangle r = textPane.modelToView( textPane.getDocument().getLength() );
d.height = r.y + r.height;
textPane.setPreferredSize( d );
getContentPane().validate();
// pack();
}
catch(Exception e2) {}
}
});
JLabel label = new JLabel("Hit Enter to Add Text to Text Pane");
getContentPane().add(label);
JPanel south = new JPanel();
textPane = new JTextPane();
textPane.setText("Some text");
textPane.setEditable( false );
// textPane.setPreferredSize( new Dimension(120, 23) );
south.add( textPane );
// getContentPane().add(south, BorderLayout.SOUTH);
getContentPane().add(textPane, BorderLayout.SOUTH);
}
public static void main(String[] args)
{
JFrame frame = new TextPanePerfectSize();
frame.setSize(200, 200);
frame.setLocationRelativeTo( null );
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
The Document interface is a model for a text component, so the Document doesn't really have a boundary; but the View has a number of methods that "translate between the model and view coordinate systems." Depending on the goal, something there may help.
Try to use this to measure height for fixed widht.
http://java-sl.com/tip_text_height_measuring.html
The getPreferred will return you the width and height.