I'm using Java Swing. I have a textarea in a panel. I don't need a horizontal scrollbar for that textArea, only a vertical scrollbar is needed. I disabled auto scrollbar options, but still the horizontal scrollbar is working. Please help me in thz.
ta.setLineWrap(true)
Sets the line-wrapping policy of the
text area. If set to true the lines
will be wrapped if they are too long
to fit within the allocated width. If
set to false, the lines will always be
unwrapped
Scroll bar comes into text area when you are making your text area too small. This is because your the default column number in netbeans text area is 20.
If you don't want the scroll bar being displayed , then take the textarea properties and change the column number to a value according to your size (say 10).
And the scrollbar will not be shown.
Two examples, the line wrap method and the scroll pane method:
public class Test {
public static void main(String[] args) {
// example text
String rep = "The quick brown fox jumps over the lazy dog.";
String all = rep;
for(int i = 0; i < 100; i++)
all += "\n" + rep;
// create the line wrap example
JTextArea first = new JTextArea(all);
first.setLineWrap(true);
// create the scroll pane example
JScrollPane second =
new JScrollPane(new JTextArea(all),
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// lay it out
JFrame f = new JFrame("Test");
f.setLayout(new GridLayout(1,2));
f.add(first);
f.add(second);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
JTextPane don't have a method to enable or disable line wrap, one best choice is:
private JTextPane noWrapTextPane = new JTextPane() {
#Override
public boolean getScrollableTracksViewportWidth() {
return getUI().getPreferredSize(this).width
<= getParent().getSize().width;
}
};
Related
I'm making a simple GUI and have a problem.
This is my code :
JFrame jFrame = new JFrame();
jFrame.setTitle("Simple Editor");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocation(50,50);
jFrame.setResizable(true);
Box box = new Box(BoxLayout.Y_AXIS);
JTextArea jTextArea = new JTextArea();
jTextArea.setPreferredSize(new Dimension(470,500));
JLabel jLabel = new JLabel();
box.add(jTextArea);
box.add(jLabel);
jLabel.setText("Font type : " + Main.fontType + " font size : " + Main.size
+ " background color : " + Main.backgroundColor
+ " font color : " + Main.fontColor);
jFrame.setContentPane(box);
jFrame.pack();
jFrame.setVisible(true);
When I typing something in JTextArea, text in JLabel is moving. I can't figure out how to solve this. Maybe some component between them? Any advice and help is welcome.
This looks like an artifact of how the Box is calculating sizes and locations. Note that some components and layout managers do not use setPreferredSize, or only take it as a hint, or use it as only one part of a computation, or etc. so it cannot be depended upon as a reliable method to set the size of a component.
In this case, I would hypothesize what is going on is something like: BoxLayout generally uses minimum/maximum sizes, not preferred sizes, and the min/max of a JTextArea is computed based on its text content. As the text changes, the size is recalculated so the layout changes too.
In general if you have a text area, you should put it in a JScrollPane instead:
Box box = new Box(BoxLayout.Y_AXIS);
JTextArea jTextArea = new JTextArea();
JScrollPane jScrollPane = new JScrollPane(jTextArea);
jScrollPane.getViewport().setPreferredSize(new Dimension(470,500));
JLabel jLabel = new JLabel();
box.add(jScrollPane);
box.add(jLabel);
This way when the text content changes in the JTextArea it can simply do its thing, recalculating its size, and flow out the side of the scroll pane.
Also see How to Use Scroll Panes, How to Use Text Areas.
Per Andrew's comment, here are a couple ways to set the initial size of the scroll pane which are perhaps more reliable than setting the viewport's preferred size explicitly:
// specify rows & columns
JTextArea jTextArea = new JTextArea(20, 20);
// specify preferred scrollable viewport size
JTextArea jTextArea = new JTextArea() {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(470,500);
}
};
jTextArea.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
jLabel.setText(jTextArea.getText());
}
});
where,
jTextArea - your name object of JTextArea class
jLabel - your name object of JLabel class
You add text in the textarea and text in the label is changing. I think, this code help you to decide your problem.
So im writing a small test program for fun replicating a inventory from games like minecraft and runescape. Basically a frame with another one inside it, and pictures of your items in it, and a scroll bar to scroll down through all the stuff you have in your inventory. The "Stuff" i would have in my inventory would be buttons added later on with their own functionality, so you can scroll through vertically and see all the "stuff." Right now i have some test buttons being added to deomsntrate the error. Basically i want the buttons to be 100,100 and for them to be in a row of 4, and go onto the next column. I though GridLayout would be the best choice, but it seems to add more rows after being added into a scrollpane. Well heres the code skimmed down:
public class inventory extends JFrame{
public static void main(String[] args){
new inventory();
}
JPanel mainInv = new JPanel();
JScrollPane sp;
public inventory(){
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit tk = this.getToolkit();
setLocation(tk.getScreenSize().width/2-getWidth()/2, tk.getScreenSize().height/2-getHeight()/2);
setLayout(null);
mainInv.setSize(getWidth()-10, 1000);
mainInv.setBackground(Color.blue);
mainInv.setLayout(new GridLayout(8,4));
sp = new JScrollPane(mainInv, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sp.setMaximumSize(new Dimension(400,400));
sp.setBounds(5, 5, 500-10, 500-130);
JButton[] testButs = new JButton[100];
for(int i = 0; i < 50; i++){
testButs[i] = new JButton("Test Button " + i);
testButs[i].setSize(100,100);
mainInv.add(testButs[i]);
}
add(sp);
setVisible(true);
}
}
With GridLayout the number of rows is the dominating factor.
If you have 8 rows and 4 columns that can only fit 48 buttons, if you try to add a 49th button it will create a 5th column not a 9th row.
You can solve your problem by setting up the GridLayout with more rows.
I am adding a JPanel in a JScrollPane in my project.
All is working fine, but there is one problem about mouse scroll using the mouse-Wheel in JPanel. It's speed is very slow on scrolling. How to make it faster?
My code is :
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
objCheckBoxList = new CheckBoxList();
BaseTreeExplorer node = (BaseTreeExplorer)projectMain.objCommon.tree.getLastSelectedPathComponent();
if (node.getObject() != null) {
cmbList.setSelectedItem(node.getParent().toString());
} else {
if (node.toString().equalsIgnoreCase("List of attributes")) {
cmbList.setSelectedIndex(0);
} else {
cmbList.setSelectedItem(node.toString());
}
}
panel.add(objCheckBoxList);
JScrollPane myScrollPanel = new JScrollPane(panel);
myScrollPanel.setPreferredSize(new Dimension(200, 200));
myScrollPanel.setBorder(BorderFactory.createTitledBorder("Attribute List"));
You can set your scrolling speed with this line of code myJScrollPane.getVerticalScrollBar().setUnitIncrement(16);
Here is details.
This bug seems to occur because swing interprets the scroll speed in pixels instead of lines of text. If you are looking for a more accessible alternative to the accepted solution, you can use the following function to calculate and set the actual desired scroll speed in pixels:
public static void fixScrolling(JScrollPane scrollpane) {
JLabel systemLabel = new JLabel();
FontMetrics metrics = systemLabel.getFontMetrics(systemLabel.getFont());
int lineHeight = metrics.getHeight();
int charWidth = metrics.getMaxAdvance();
JScrollBar systemVBar = new JScrollBar(JScrollBar.VERTICAL);
JScrollBar systemHBar = new JScrollBar(JScrollBar.HORIZONTAL);
int verticalIncrement = systemVBar.getUnitIncrement();
int horizontalIncrement = systemHBar.getUnitIncrement();
scrollpane.getVerticalScrollBar().setUnitIncrement(lineHeight * verticalIncrement);
scrollpane.getHorizontalScrollBar().setUnitIncrement(charWidth * horizontalIncrement);
}
Note that swing does calculate the scroll speed correctly when it contains a single component like a JTable or JTextArea. This fix is specifically for when your scroll pane contains a JPanel.
Problem: I have a method that creates a list from the parsed ArrayList. I manage to show the list in the GUI, without scrollbar. However, I am having problem setting it to show only the size of ArrayList. Meaning, say if the size is 6, there should only be 6 rows in the shown List. Below is the code that I am using. I tried setting the visibleRowCount as below but it does not work. I tried printing out the result and it shows that the change is made.
private void createSuggestionList(ArrayList<String> str) {
int visibleRowCount = str.size();
System.out.println("visibleRowCount " + visibleRowCount);
listForSuggestion = new JList(str.toArray());
listForSuggestion.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listForSuggestion.setSelectedIndex(0);
listForSuggestion.setVisibleRowCount(visibleRowCount);
System.out.println(listForSuggestion.getVisibleRowCount());
listScrollPane = new JScrollPane(listForSuggestion);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
JList theList = (JList) mouseEvent.getSource();
if (mouseEvent.getClickCount() == 2) {
int index = theList.locationToIndex(mouseEvent.getPoint());
if (index >= 0) {
Object o = theList.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
}
};
listForSuggestion.addMouseListener(mouseListener);
textPane.add(listScrollPane);
repaint();
}
To summarize: I want the JList to show as many rows as the size of the parsed ArrayList, without a scrollbar.
Here is the picture of the problem:
Here's the link to the other 2 as the picture resolution is quite big I'm scared it will distort the view:
JList 1 & JList 2
The JList 1 and 2 pictures shows it clearly. The JList displays empty rows, which I do not want it to happen.
Any ideas? Please help. Thanks. Please let me know if a picture of the problem is needed in case I did not phrase my question correctly.
--
Edit:
JScrollPane scrollPane = new JScrollPane(textPane);
scrollPane.setPreferredSize(new Dimension(200, 200));
//Create the text area for the status log and configure it.
changeLog = new JTextArea(5, 30);
changeLog.setEditable(false);
JScrollPane scrollPaneForLog = new JScrollPane(changeLog);
//Create a split pane for the change log and the text area.
JSplitPane splitPane = new JSplitPane(
JSplitPane.VERTICAL_SPLIT,
scrollPane, scrollPaneForLog);
splitPane.setOneTouchExpandable(true);
//Create the status area.
JPanel statusPane = new JPanel(new GridLayout(1, 1));
CaretListenerLabel caretListenerLabel =
new CaretListenerLabel("Caret Status");
statusPane.add(caretListenerLabel);
//Add the components.
getContentPane().add(splitPane, BorderLayout.CENTER);
getContentPane().add(statusPane, BorderLayout.PAGE_END);
How the textPane is included into the container, if that helps
Another edit:
public void showSuggestionList(JScrollPane pane, Rectangle caretCoords) {
pane.setVisible(false);
pane.setBounds(caretCoords.x - 5, caretCoords.y + 25, 400, 250);
pane.setVisible(true);
repaint();
}
showSuggestionList() is being called my CaretListener, to show the JScrollPane when the caret moves.
I suspect it's the layout-management of textPane that is the issue. From what I can see, the listForSuggestions should not occupy more space than it needs to display those items, if it's preferred size is respected.
So the JTextPane is a Container, that is, you can add subcomponents to it. But how are those subcomponents layed out? That is up to the layout manager currently in use. If the layout manager respects the preferred dimension of the listForSuggestios I think you should be ok. Not sure though.
From what I can see, you get the "null-layout" by just instantiating a JTextPane, which means that unless you set another layout manager explicitly, you would need to take care of placement / resizing of the subcomponents yourself.
You could try to do something like
Dimension dim = listForSuggestions.getPreferredSize();
listForSuggestions.setBounds(xPos, yPos, dim.getWidth(), dim.getHeight());
Here is a complete example
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class FrameTest {
public static void main(String[] args) {
JFrame f = new JFrame("Frame Test");
ArrayList<String> str = new ArrayList<String>();
for (int i = 0; i < 20; i++)
str.add("number " + i);
JTextPane tp = new JTextPane();
int visibleRowCount = str.size();
System.out.println("visibleRowCount " + visibleRowCount);
JList listForSuggestion = new JList(str.toArray());
listForSuggestion.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listForSuggestion.setSelectedIndex(0);
listForSuggestion.setVisibleRowCount(5);
System.out.println(listForSuggestion.getVisibleRowCount());
JScrollPane listScrollPane = new JScrollPane(listForSuggestion);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
JList theList = (JList) mouseEvent.getSource();
if (mouseEvent.getClickCount() == 2) {
int index = theList.locationToIndex(mouseEvent.getPoint());
if (index >= 0) {
Object o = theList.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
}
};
listForSuggestion.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
listForSuggestion.addMouseListener(mouseListener);
Dimension dim = listForSuggestion.getPreferredSize();
listForSuggestion.setBounds(20, 20, (int) dim.getWidth(), (int) dim.getHeight());
tp.add(listForSuggestion);
f.add(tp);
f.setSize(400, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
I think the most elegant way of doing this is to roll your own layout-manager. (It's actually quite simple.) And then, instead of doing textPane.add(list), you do textPane.add(list, YourLayoutManager.POPUP_LIST). The layout-manager then remembers the fact that list was supposed to be layed out according to it's preferred size, and layes it out accordingly in its layoutContainer-method. (If you give the YourLayoutManager a reference to the JTextPane that it is attached to, you could probably even make it layout the list right beside the current caret location.)
If you are dynamically (via code) filling your list, it is bad idea not to use scrollbar. It might work as you want f.e. for 20 list items, but imagine what happens once you need use more data - like 2000. Your GUI will be ruined.
I've got a Jlist inside a JScrollPane and I've set a prototype value so that it doesn't have to calculate the width for big lists, but just uses this default width.
Now, the problem is that the Jlist is for some reason replacing the end of an element with dots (...) so that a horizontal scrollbar will never be shown.
How do I disable with "wrapping"? So that long elements are not being replaced with dots if they are wider than the Jlist's width?
I've reproduced the issue in a small example application. Please run it if you don't understand what I mean:
import javax.swing.*;
import java.awt.*;
public class Test
{
//window
private static final int windowWidth = 450;
private static final int windowHeight = 500;
//components
private JFrame frame;
private JList classesList;
private DefaultListModel classesListModel;
public Test()
{
load();
}
private void load()
{
//create window
frame = new JFrame("Test");
frame.setSize(windowWidth, windowHeight);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
//classes list
classesListModel = new DefaultListModel();
classesList = new JList(classesListModel);
classesList.setPrototypeCellValue("prototype value");
classesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
classesList.setVisibleRowCount(20);
JScrollPane scrollClasses = new JScrollPane(classesList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (int i = 0; i < 200; i++)
{
classesListModel.addElement("this is a long string, does not fit in width");
}
//panel
JPanel drawingArea = new JPanel();
drawingArea.setBackground(Color.white);
drawingArea.add(scrollClasses);
frame.add(drawingArea);
//set visible
frame.setVisible(true);
}
}
Even if you force horizontal scrollbar, you still won't be able to scroll because the element is actually not wider than the width because of the dot (...) wrapping.
Thanks in advance.
Scrollbars appear automatically when the preferred size of the component added to the scrollpane is greater than the size of the scrollpane.
By using the setPrototypeCellValue(...) method you are affecting the way the list calculates its preferred size, which means you are responsible for providing the proper value that ensures the strings will not be truncated.
So the simple solution is not not use that method, but in addition you will need to set the preferred size of the scrollpane to be whatever you want. Then the horizontal scrollbars will appear if required.
My answer to that question is that first find the longest element in the list then use
setPrototype method on that elements
When you call classesList.setPrototypeCellValue("prototype value") you are telling the JList classesList to limit its maximum width to the length of the string "prototype value". (See javadocs)
Then later on when you populate the list with the strings "this is a long string, does not fit in width", no wonder it does not fit in the width! Because the width of the prototype you gave it is smaller than the width of the string you are filling the list with.
The JScrollPane will automatically show the scrollbars and you usually don't need to adjust their behavior. The JList will also automatically adjust its width to try and show the maximum width item in the list. The problem occurs when you tell the JList to fix its width by calling the setPrototypeCellValue().
If you comment out
classesList.setPrototypeCellValue("prototype value");
or replace it with
classesList.setPrototypeCellValue("this is a long string, does not fit in width");
then it will function as you expected it to.