JScrollPane automagically scrolls down to lowest component in JPanel - java

In my JPanel (which is in a JScrollPane) I have several JTextArea. When launching the program these areas are populated by JTextArea.setText("text");
The problem is that the JScrollPane scrolls down to the JTextArea with the lowest Y-position as if the user would have focus on the JTextArea, no matter when it was populated with text. I thought that I could work around the problem by populating the JTextArea at the bottom first, if the JScrollPane maybe want to scroll to the "current" JTextArea that's being used. It didn't work so I'm assuming it just remembers the lowest point it's been and then just stays there for some reason.
Setting the view like this doesn't make any difference.
JScrollPane.getViewPort().scrollRectToVisible(new Rectangle(0,0,1,1));
I've tested by neglecting to populate the last JTextAreas and the JScrollPane is then viewing the top of the JPanel, as I want.
What's happening, and why is it ignoring my code?
Update, answer selected
You have to set the viewport a tad later when the GUI is ready
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
scrollPane.getViewport().setViewPosition(new Point(0, 0));
}
});

JScrollPane.getViewPort().scrollRectToVisible(new Rectangle(0,0,1,1));
The scrollRectToVisible() method is meant to be used on the component added to the viewport (the panel containing the text areas), not the viewport itself. Not sure what happens when you invoke it directly on the viewport.
Instead I would do the following:
scrollPane.getViewPort().setViewPosition( new Point(0, 0) );
Note, you may need to wrap that statement in a SwingUtilities.invokeLater() to make sure the code is executed on the EDT after all the components have been positioned on the panel by the layout manager.

Related

Overlap Components When Using ComponentResizer

I want to make my jTable expandable while floating/overlay when dragging it using ComponentResizer class. I'm using ComponentResizer class from Rob Camick.
Currently as below after dragging the table:
I tried change my layout to null but the result still same.
In my code, I just added to call the ComponentResizer class:
ComponentResizer cr = new ComponentResizer();
cr.setSnapSize(new Dimension(10, 10));
cr.registerComponent(jScrollPane2);
I expect the dragging table will float and overlay the components below it.
Swing is designed to paint components in 2D space, not 3D space.
So when components are added to the same panel, Swing will paint components in the reverse order the component is added to the panel. In your case it looks like you add the components to the panel before adding the scrollpane to the panel.
So you could:
reverse the order in which you add the components to the panel
use the setComponentZOrder(...) method on the scrollpane to set its value to 0, so it is painted last.
However, this will still cause a problem because if you hover over the button the button will appear because its border is changed. This is because Swing assumes 2D layouts not 3D. If you want to make sure the table is always painted over the button you need to override the isOptimizedDrawingEnable() method of the panel. See Overlap Layout for more information on ZOrder painting.
I solved the problem by put all components in one layered pane and using Border Layout.

JScrollpane mouseListener

I hava a JScrollPane used to dram structures(diagrams) and I want to invoke a method every time user releases mouse click in this JScrollPane drawing area.
I used
yourJScrollPane.getViewport().getView().addMouseListener(yourMouseListener);
as per given here Use JScrollPane mouse listener over viewport components
This works. On every mouse release the desired method is invoked which updates the JTable in the GUI.
But, the problem is, the diagram which user draws moves all around the JScrollPane's available drawing/edit window area. For every click the drawing moves to a new place. If I remove the JScrollPane mouseListener, the structure does not move.
Is there any other way I can listen to the JScrollPane clicks and the view(diagrams) is not affected?
Thank you for the inputs.
Edit:
JScrollPane jScrolPane = (JScrollPane)(((JPanel) readyPanel.getComponent(1)).getComponent(0));
jScrolPane.getViewport().addMouseListener(new calculateDimensions(readyPanel, propertiesTable));
Here, readyPanel is a panel I receive from another method which is all stuffed with tool bars and JScrollPane.
I am trying to get the JScrollPane from this stuffed JPanel and invoke the method to calculate dimensions.

How to make a JFrame scrollable?

I would like to scroll through the contents of my JFrame up and down, preferably with a scroll bar. I don't want to wrap the contents inside a JPanel or JScrollPane, because this causes some visual glitches with my application.
Any idea on how to do this?
JScrollPane would be the easiest way; you say there are glitches, but that probably indicates a problem in your code that will still be a problem even without using a JScrollPane.
If you're absolutely set on not using a JScrollPane, you should create a JPanel using BorderLayout, add a JPanel (call it 'center') with BorderLayout.CENTER and layout set to null. Add your content within 'center', and add another JScrollBar to BorderLayout.EAST, add an AdjustmentListener to the JScrollBar. When the adjustmentListener triggers, you need to move your content (Component.setLocation(...)) that's in center to the relative y offset of the JScrollBar and call repaint on 'center'

Java UI: set swing components behavior on resize

I am having a hard time to properly set the way my swing components behave on resize.
I have two problems with that interface:
A: The toggle button at the beginning of each row is here to collapse/expand the text. All the elements are contained in a JLayeredPane. On the button click, I edit the pane's height to expand or collapse the content (either 31 or 310). Expand works fine an pushes the elements below. On the other hand, collapse does hide the text but leaves all the elements in position. Here is my code:
private void expandText(java.awt.event.ActionEvent evt) {
JToggleButton button = (JToggleButton) evt.getSource();
Container parent = button.getParent();
Dimension size = parent.getSize();
String icon;
if (button.isSelected()) {
size.height = 310;
icon = "/org/cytoscape/ocsana/resources/images/minus.png";
} else {
size.height = 31;
icon = "/org/cytoscape/ocsana/resources/images/plus.png";
}
parent.setSize(size);
try {
button.setIcon(new ImageIcon(ImageIO.read(getClass().getResource(icon)).getScaledInstance(-1, 15, Image.SCALE_SMOOTH)));
} catch (IOException ex) {
}
backgroundPane.revalidate();
backgroundPane.repaint();
}
B: The screenshot above is the minimum size of the window. When I resize the window horizontally, the inner pane only resize to the value of min + (frame.width - min) / 2 meaning my right scrollbar does not stick to the right side of the frame.
See below a demonstration of the both problems:
Well, you could add a listener to the frame so have an action on event when the frame is being resized. And then pack() the frame.
public final class TestFrame extends JFrame {
(...)
this.getRootPane().addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
this.pack();
this.revalidate();
}
});
}
It you are using the paint graphic method, you should as well repaint() your frame.
In that method you can also manyally set the preferred size of the window by computing it based on e.getWidth()
How does your expand/collapse code work? Do you just make component visible/invisible, or do you add remove components from the panel?
On the other hand, collapse does hide the text but leaves all the elements in position.
If you add/remove components then the basic code is:
panel.remove(...);
panel.add(...);
panel.revalidate();
panel.repaint();
meaning my right scrollbar does not stick to the right side of the frame.
It depends on the layout manager you are using. I would guess the easiest would be to use a GrigBagLayout. It allows you to "fill" the space available. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and examples.
All the elements are contained in a JLayeredPane.
Not sure why you are using a layered pane. By default a layered pane doesn't use a layout manager.
According to camickr answer and comments, see how I solved it:
Point A is due to my free layout used in NetBeans. I did not succeed to fix my code so I changed the structure of my elements. It is probably not optimal and does not use all the swing concepts right, but it works the way I want.
I have a JLayeredPane in the background that uses a GridBagLayout. This background pane contains one column of JPanel of height 30 and 260, one for the summary line, the other one for the details.
The expand/collapse function controlled by the JToggleButton works by hiding the below panel belowPanel.setVisibility(false). No need for repack or anything, just that. Here is how the code looks like without changing the button's icon:
private void inverseVisibility(JToggleButton expand, JPanel target) {
if (expand.isSelected()) {
target.setVisible(true);
} else {
target.setVisible(false);
}
}
As I only wanted the elements to resize horizontally, all my panels have Horizontal as Fill value and Northwest as Anchor. I've set the weightX = 1; weightY = 0. Finally I added a panel in the bottom with a Southwest anchor and fill both along with both weights to 1 (not sure it changes anything but this way I am certain that it will fill all the blank space at the bottom it the window is resized at a bigger size than its content).
Point B has been solved by taking my background panel, that fit in my Frame, and putting it into a JScrollPane. The error I had was due to the Netbeans editor that did not properly stick the scroll pane to the side of the frame, due to incoherences in the sizes defined in both the frame and the scroll pane. My advise to you if you are using this tool is to set the fewest values as possible as a lot of values are heavily interconnected by the gui designer.
Get the full code (95,864 bytes)

How to force-refresh/repaint a JScrollPane?

I am adding lots of components (JPanels, JLabels etc.) into a JScrollPane programagically at the start of my program based on some stuff from a database.
It seems that this procedure is too fast for the GUI(?), so the JScrollPane does not always update correctly, i.e the scroll bars are not visible even though the inner JPanel is bigger than the visible area.
Resizing the Window (JFrame) fixes the problem, as I assume Java is re-printing the components when they are resized.
As a test, I have added a debug-button that I can click after the startup of the program has finished. I am trying to force the JScrollPane to "refresh" itself.
I have tried doing:
scrollpane.repaint();
scrollpane.validate();
scrollpane.revalidate();
None of them seems to work. However, if I change the border (or any other layout related to the JScrollPane), it refreshes correctly.
scrollpane.setBorder(new LineBorder(Color.RED));
So I basically have 2 questions.
What is the command for forcing the scrollpane to "refresh"? Obviously it is doing some kind of "repaint" thing when I am adding the border. How can I run that only?
Is there a way of "pausing" the printing of components as they are added and resume it again after I added all the wanted components? As it is now, I basically "see" the components being added on the screen (even though it is really fast). It would be better if I can add all the components I want and THEN tell the program to print it to the screen/JFrame.
The basic code for adding components to a visible panel is:
panel.add(...);
panel.add(...);
panel.revalidate();
panel.repaint();
Adding a component does nothing because the component still has a zero size so there is nothing to paint. When you invoke the revalidate() method the layout manager gets invoked so components will now have a location/size. The repaint() will then paint the components. The revalidate() will also cause the scrollbars to show when required. This of course assumes you are using layout managers.
The components are added to the panel so you invoke the methods on the panel, not the scrollpane.
In my case only
frame.pack();
helped to get the scrollbars on the JScrollPane, when the enclosed JPanel was resized dynamically.

Categories