JSplitPane slide only to one side - java

Im not sure why, but the slider only goes to the left and even locks the new position.
It uses a modificated version of the NestedJSplitPane tutorial with JTree and JEditorPane.
My guess is, that the JEditorPane causes the problem...
public frameMenu(){
JEditorPane htmlPane;
JTree parkSelect;
JTree triggerSelect;
URL helpURL;
DefaultMutableTreeNode left = new DefaultMutableTreeNode("Tree Left");
DefaultMutableTreeNode triggerTree = new DefaultMutableTreeNode("Tree Down");
//nNode.createNodes();
int HORIZSPLIT = JSplitPane.HORIZONTAL_SPLIT;
int VERTSPLIT = JSplitPane.VERTICAL_SPLIT;
boolean continuousLayout = true;
parkSelect = new JTree(left);
parkSelect.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
htmlPane = new JEditorPane();
htmlPane.setEditable(true);
triggerSelect = new JTree(triggerTree);
triggerSelect.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
JSplitPane splitPane1 = new JSplitPane(VERTSPLIT, continuousLayout, htmlPane, triggerSelect);
splitPane1.setOneTouchExpandable(true);
splitPane1.setDividerSize(2);
splitPane1.setDividerLocation(0.5);
JSplitPane splitPane2 = new JSplitPane(HORIZSPLIT, parkSelect, splitPane1);
splitPane2.setOneTouchExpandable(true);
splitPane2.setDividerLocation(0.4);
splitPane2.setDividerSize(2);
JFrame frame = new JFrame("Trigger Editor");
frame.setSize(600, 400);
frame.add(splitPane2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
This is more of an snipped, but the problem is the same.
Im not sure, how much code i could put in one post.
The up and down split can be slided without problems, but left and right causes problems.

the slider only goes to the left and even locks the new position
A JSplitPane respects the minimums size of a component.
My guess is, that the JEditorPane causes the problem...
Correct, the minimum size of the JEditorPane appears to be equal to its preferred size.
You will need to override the getMinimumSize() method of you JEditorPane to return a more reasonable value for your requirments:
htmlPane = new JEditorPane()
{
#Override
public Dimension getMinimumSize()
{
Dimension d = super.getMinimumSize();
d.width = 100;
return d;
}
};

Related

How can I display a JTable on a JFrame

I've spent hours online and I'm afraid I can't quite figure out how to make my JTable show up next to my JButton on a JFrame, if anyone has a simple or comprehensive way to explain why and how to fix the problem Id really appreciate it.
Extensive online research including downloading samples and applying various suggestions; also reached out to my teacher for help but she doesn't have much experience with java.
public class canvas extends JTable{
static void displayJFrame(){
//set variables
int i = 0;
String[][] strArray = new String[3][i];
String[] labelArray = new String[3];
labelArray[0] = "Name: ";
labelArray[1] = "Subject: ";
labelArray[2] = "Average: ";
//create JFrame
JFrame f = new JFrame("Test Average");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setBackground(Color.WHITE);
f.setPreferredSize(new Dimension(600, 600));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
//create JButton
JButton button=new JButton("Enter New Grade");
button.setBounds(450,15,140, 40);
button.addActionListener(e -> average(strArray, i));//gets info from user and adds to strArray
button.addActionListener(e -> count(i));//increases counter
f.add(button);
//create JTable
JTable j = new JTable(strArray, labelArray);
JScrollPane scrollPane = new JScrollPane(j);
j.setBounds(30, 40, 200, 300);
j.setSize(500, 200);
j.setVisible(true);
}
}
all of my code runs as expected except there is no table, I've also tried so many things that didn't work so this basically where I started so that its not crowded by tons of incorrect stuff
You have several problems. First, by default a JFrame uses a BorderLayout. Using the default add(component) method places that component in the center. Using the same add() method again just replaces the new component at the center.
Second, do not pack or set the frame visible until AFTER you have created the entire GUI.
You would do better to create a JPanel and add the components to that panel, then add the panel to the frame. The default layout manager for JPanel is a FlowLayout.

How can get components to stretch across an entire row using BoxLayout?

I'm looking at the How To Use BoxLayout documentation, which clearly says that
What if none of the components has a maximum width? In this case, if
all the components have identical X alignment, then all components are
made as wide as their container.
Let's assume we're adding a lot of JButton instances to a JPanel. If the maximum width of these buttons are none AND we invoke setAlignmentX(Component.LEFT_ALIGNMENT) on all of these buttons - then each of these buttons should stretch across its entire row. The documentation even illustrates this using the below picture.
I can't get this to work!
I've tried doing setMaximumSize(null) and setMaximumSize(new Dimension(-1,-1)) and setMaximumSize(new Dimension(0,0)) on the buttons but nothing gives me the described behaviour.
What excactly does the documentation mean when it says :
What if none of the components has a maximum width?
What is a maximum width of none?
The best I've been able to produce is the below. Reading the documentation I would expect that the buttons should be able to stretch across their entire rows. I know I can use other layout managers as well for this, but I would like to achieve this with BoxLayout (granted the documentation is right / I've understood the documentation right).
public class CustomList extends JPanel {
private final Box box = Box.createVerticalBox();
public CustomList() {
for (int i = 0; i < 10; i++) {
JButton b = new JButton("Button item" + i);
//b.setMaximumSize(new Dimension(0,0));
b.setAlignmentX(Component.LEFT_ALIGNMENT);
box.add(b);
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(box, BorderLayout.CENTER);
}
public static void main(String[] args) {
CustomList l = new CustomList();
l.setSize(200, 200);
l.setBackground(Color.red);
JFrame frame = new JFrame("Vertical Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(l, BorderLayout.CENTER);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Your buttons actually have a maximum width.
What you can do is create JPanel objects with BorderLayout in your loop, add each button to each panel (to BorderLayout.CENTER, which is the default anyway).
BorderLayout.CENTER doesn't care about the maximum size of its child Component, so you end up with a JPanel whose whole content is filled by a JButton.
Since the JPanel itself has a huge default maximum size of new Dimension(Short.MAX_VALUE, Short.MAX_VALUE) (this is width=32767,height=32767 !!) which is the default maximum size of Component, you will get the expected result :
public CustomList() {
for (int i = 0; i < 10; i++) {
JPanel panel = new JPanel(new BorderLayout());
JButton b = new JButton("Button item" + i);
//b.setMaximumSize(new Dimension(0,0));
b.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(b);
box.add(panel);
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(box, BorderLayout.CENTER);
}

Inconsistent JFrame layout

I have a JFrame which displays two JSplitPanes (one inside the other).
For some reason the divider location is inconsistent.
What I mean by that is that sometimes its displayed on the correct position where I have set it, while other times it doesn't. When the position is wrong, its wrong for both split panels. Here is the code I am using for the JSplitPanes:
JPanel javaPanel = core.getComponentPanel(2);
JSplitPane splitA = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
javaPanel.getComponent(0), javaPanel.getComponent(1));
double pos = (screenDim.getHeight() * 72) / 100;
splitA.setDividerLocation((int) pos);
JSplitPane mainSplitP = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
new JScrollPane(getCoreComponents()), splitA);
return mainSplitP;
On the JFrame I have a JPanel with CardLayout. To add the mainSplitP I use the following method:
private void setFrameContent(Container content, String title) {
appContent.add(content, title);
CardLayout cl = (CardLayout) (appContent.getLayout());
cl.show(appContent, title);
appFrame.pack();
}
What could be causing this inconsistency ?
JComponents knows own size after pack(), or when they're once time visible on the screen
wrap JSplitPane's setDividerLocation to the invokeLater

How to increase the slow scroll speed on a JScrollPane?

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.

Set the amount of rows JList show (Java)

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.

Categories