0

I'm using the Trident Java Animation Library, because I want a pseudo-accordion effect for a JScrollPane.

Here is my SSCCE: http://pastebin.com/5xfBLmV5
You will need to download the Trident JAR.

Problem

  • My JScrollPane has a viewport view of a JTextArea.
  • I want the JFrame to open with a minimised view of the text.
  • A JButton, when clicked, plays the animation, in either forwards or reverse direction.
  • I added a label at the bottom of the JFrame using BorderLayout.SOUTH`

The JScrollPane does not correctly calculate the real height of the JTextArea and as a result text is cut off and the area is not scrollable.

This is what is happening:

Before

before expansion

After click of "Show details..."

after expansion

Community
  • 1
  • 1
Redandwhite
  • 2,529
  • 4
  • 25
  • 43
  • I am not an expert of the subject but... This looks like a classical control framework problem. At the declaration of visual objects, generally they give miscalculated dimensions. After intializing, an event fires such as (for instance) JTextarea change or ready with the settled the correct dimensions. Maybe this is the problem. – Volkan Mar 15 '13 at 12:03
  • not fan of external sites (Pastebin), `JScrollPane does not correctly calculate the real height of the JTextArea` == doesn't accepting (for example) `new JTextArea (50, 15)`, for better help sooner post an SSCCE, btw I'm post here accordion (can be delayed by Swing Timer) – mKorbel Mar 15 '13 at 12:14
  • The problem isn't to do with Trident, it's with your code. First. Don't use setSize, it's not appropriate for what you are trying todo. Second, the JScrollPane has been added to a container using a BorderLayout. This will override anything you do with setSize or setPreferredSize. Use a layout manager that respects the preferred size of the component – MadProgrammer Mar 15 '13 at 12:23
  • @MadProgrammer not job for [BorderLayout](http://stackoverflow.com/a/10299581/714968), but about your favorite LayoutManager, can assume that BoxLayout (min/max/preff) can do that too – mKorbel Mar 15 '13 at 12:39
  • @mKorbel That's what I thought I said. Don't use BorderLayout. It's late, my back aches, I'm on the iPad, so who knows what I said |P – MadProgrammer Mar 15 '13 at 12:40
  • @MadProgrammer what technique should I use to enlarge the JScrollPane? – Redandwhite Mar 15 '13 at 12:53
  • @Redandwhite Your idea is okay, but your choice of layout manager and the property is not. Don't use a layout manager that isn't going to honor the preferred size of a component and change the preferred size property instead – MadProgrammer Mar 15 '13 at 12:55
  • @MadProgrammer I'm changing `preferredSize`, and I'm trying to use BoxLayout (Y_AXIS), which supposedly respects `PreferredSize`... but it simply isn't changing anything... Do you have any idea which layout manager and property I should use? Wrapping the JSP in another JPanel and applying the changes on that doesn't work either – Redandwhite Mar 15 '13 at 13:08
  • @Redandwhite BoxLayout accepting minimum, maximum and preferredsize, have to (re)validate & repaint, LayoutManager isn't notified somehow about any changes made by user (not talking about implemented in API), – mKorbel Mar 15 '13 at 13:15

1 Answers1

2

Basically, using the right layout manager and making sure that the parent container is invalidated should give you the results you are looking for.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.UUID;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.ease.Spline;

public class ButtonFg extends JFrame {

    private JScrollPane jsp;

    public ButtonFg() {
        JButton button = new JButton("sample");
        button.setForeground(Color.blue);

        JPanel panel = new JPanel(new GridBagLayout());
        this.add(panel);

        String s = UUID.randomUUID().toString();
        for (int i = 0; i < 20; i++) {
            s += "\n" + UUID.randomUUID().toString();

        }
        final JTextArea textArea = new JTextArea(s);
        textArea.setLineWrap(true);
        jsp = new JScrollPane(textArea);

        final JButton label = new JButton("Show details...");
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        panel.add(label, gbc);

        gbc.weighty = 1;
        gbc.anchor = GridBagConstraints.NORTH;
        panel.add(jsp, gbc);

        gbc.weighty = 0;
        gbc.anchor = GridBagConstraints.SOUTH;
        panel.add(new JLabel("End of panel"), gbc);

        final Timeline rolloverTimeline = new Timeline(this);
        rolloverTimeline.addPropertyToInterpolate("animate", new Dimension(400, 15), new Dimension(400, 200));
        rolloverTimeline.setEase(new Spline(0.8f));

        rolloverTimeline.setDuration(1000);
        rolloverTimeline.setInitialDelay(50);

        label.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (label.getText().toLowerCase().contains("show")) {
                    rolloverTimeline.play();
                    label.setText("Hide details...");
                } else {
                    rolloverTimeline.playReverse();
                    label.setText("Show details...");
                }
            }

        });

        rolloverTimeline.playReverse();

        this.setSize(400, 500);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void setAnimate(Dimension size) {
        jsp.setPreferredSize(size);
        jsp.getParent().revalidate();
        repaint();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ButtonFg().setVisible(true);
            }

        });
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • This is very good. I ended up using a different approach, but this is certainly exactly what I was looking for. The use of the "animate" function was a good decision – Redandwhite Mar 17 '13 at 14:35