1

This question, Java Swing: Vertical Layout with fixed width and variable height, gave me an opportunity to try Apache Pivot. I have exactly one day's experience with Pivot.

Here's the GUI I've been able to create.

Segments GUI

My questions are:

  1. How do I size the TextArea that's part of the Expander, so that the Expander, ScrollPane, and TextArea fill the width of the window, and the TextArea is tall enough to hold an arbitrary amount of text?

  2. How do I size the height of the ScrollPane of the Expander so that when all of the text areas are expanded, the 3 Expanders fit the height of the window?

Here is the source code that created the GUI. I'm using version 2.0.2 of Apache Pivot.

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import org.apache.pivot.collections.Map;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.BoxPane;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Expander;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.ScrollPane;
import org.apache.pivot.wtk.TextArea;
import org.apache.pivot.wtk.Window;

public class Segments implements Application {

    protected SectionCollection collection;

    protected Window window;

    @Override
    public void startup(Display display, Map<String, String> properties) {
        collection = new SectionCollection();
        new SectionCollectionCreator(collection);

        window = new Window();
        window.setTitle("Segments");
        window.setMaximized(true);

        BoxPane boxPane = new BoxPane();
        boxPane.setOrientation(Orientation.VERTICAL);

        for (int i = 0; i < collection.size(); i++) {
            SectionText sectionText = collection.get(i);

            TextArea textArea = new TextArea();
            textArea.setEditable(false);
            textArea.setPreferredSize(400, 220);
            try {
                textArea.setText(sectionText.getTopic());
            } catch (IOException e) {
                e.printStackTrace();
            }

            ScrollPane textScrollPane = new ScrollPane();
            textScrollPane.setPreferredSize(420, 100);
            textScrollPane.setVerticalScrollBarPolicy(
                    ScrollPane.ScrollBarPolicy.AUTO);
            textScrollPane.setView(textArea);

            Expander expander = new Expander();
            expander.setTitle(sectionText.getTitle());
            expander.setContent(textScrollPane);
            expander.setExpanded(false);

            boxPane.add(expander);  
        }

        ScrollPane expanderScrollPane = new ScrollPane();
        expanderScrollPane.setHorizontalScrollBarPolicy(
                ScrollPane.ScrollBarPolicy.AUTO);
        expanderScrollPane.setVerticalScrollBarPolicy(
                ScrollPane.ScrollBarPolicy.AUTO);
        expanderScrollPane.setView(boxPane);

        window.setContent(expanderScrollPane);
        window.open(display);
    }

    @Override
    public boolean shutdown(boolean optional) {
        if (window != null) {
            window.close();
        }
        return false;
    }

    @Override
    public void suspend() {
    }

    @Override
    public void resume() {
    }

    public static void main(String[] args) {
        DesktopApplicationContext.main(Segments.class, args);
    }

    public class SectionText {
        protected String title;
        protected Reader topic;

        public SectionText(String title, Reader topic) {
            this.title = title;
            this.topic = topic;
        }

        public String getTitle() {
            return title;
        }

        public Reader getTopic() {
            return topic;
        }
    }

    public class SectionCollection {
        protected List<SectionText> collection;

        public SectionCollection() {
            this.collection = new ArrayList<SectionText>();
        }

        public void add(SectionText sectionText) {
            collection.add(sectionText);
        }

        public int size() {
            return collection.size();
        }

        public SectionText get(int index) {
            return collection.get(index);
        }
    }   

    public class SectionCollectionCreator {
        protected SectionCollection collection;

        protected static final String text = "Attributes, Styles and Style Contexts\n\n"
                + "The simple PlainDocument class that you saw in the previous "
                + "chapter is only capable of holding text. The more complex text "
                + "components use a more sophisticated model that implements the "
                + "StyledDocument interface. StyledDocument is a sub-interface of "
                + "Document that contains methods for manipulating attributes that "
                + "control the way in which the text in the document is displayed. "
                + "The Swing text package contains a concrete implementation of "
                + "StyledDocument called DefaultStyledDocument that is used as the "
                + "default model for JTextPane and is also the base class from which "
                + "more specific models, such as the HTMLDocument class that handles "
                + "input in HTML format, can be created. In order to make use of "
                + "DefaultStyledDocument and JTextPane, you need to understand how "
                + "Swing represents and uses attributes.";

        public SectionCollectionCreator(SectionCollection collection) {
            this.collection = collection;

            String title = "Title ";

            for (int i = 1; i <= 3; i++) {
                SectionText sectionText = new SectionText(title + i, 
                        new StringReader(text));
                collection.add(sectionText);
            }
        }   
    }

}
Community
  • 1
  • 1
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111

2 Answers2

0

I finally solved the puzzle.

By setting the width of the text area, the height was calculated to fit the text.

By setting the height of the text area scroll pane, I could cause the text area scroll pane to appear, and reduce the size of the expander to the title bar plus the text area scroll pane.

So now, all I had to do is figure out the width of the text area and the height of the text area scroll pane based on the width and height of the window.

That's where a component listener came into play. The listener adjusted the width of the text area and the height of the text area scroll pane. I cheated and used magic constants to account for scroll bars and margins. It would have been nice if I could have gotten these values as I created the components.

Anyway, here's the code that sizes the GUI components to the window.

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.pivot.collections.Map;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.Bounds;
import org.apache.pivot.wtk.BoxPane;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.Component.StyleDictionary;
import org.apache.pivot.wtk.ComponentListener;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Expander;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.ScrollPane;
import org.apache.pivot.wtk.TextArea;
import org.apache.pivot.wtk.Window;

public class Segments implements Application {

    protected List<SectionComponent> expanderComponents;

    protected SectionCollection collection;

    protected Window window;

    @Override
    public void startup(Display display, Map<String, String> properties) 
            throws IOException {
        getStyles(display);

        collection = new SectionCollection();
        new SectionCollectionCreator(collection);
        expanderComponents = new ArrayList<SectionComponent>();

        window = new Window();
        window.setTitle("Segments");
        window.setMaximized(true);

        ComponentSizeListener listener = new ComponentSizeListener();   
        window.getComponentListeners().add(listener.getListener());

        BoxPane boxPane = new BoxPane();
        boxPane.setOrientation(Orientation.VERTICAL);

        for (int i = 0; i < collection.size(); i++) {
            SectionComponent sectionComponent =
                    new SectionComponent(collection.get(i), 400, 100); 
            expanderComponents.add(sectionComponent);
            boxPane.add(sectionComponent.getExpander());
        }

        listener.setComponents(expanderComponents);

        ScrollPane expanderScrollPane = new ScrollPane();
        expanderScrollPane.setHorizontalScrollBarPolicy(
                ScrollPane.ScrollBarPolicy.AUTO);
        expanderScrollPane.setVerticalScrollBarPolicy(
                ScrollPane.ScrollBarPolicy.AUTO);
        expanderScrollPane.setView(boxPane);

        window.setContent(expanderScrollPane);
        window.open(display);
    }

    protected void getStyles(Component component) {
        StyleDictionary dictionary = component.getStyles();
        System.out.println(component);
        Iterator<String> iter = dictionary.iterator();
        List<String> list = new ArrayList<String>();
        while (iter.hasNext()) {
            list.add(iter.next());
        }
        Collections.sort(list);
        for (String style : list) {
            System.out.println("    " + style);
        }
    }

    @Override
    public boolean shutdown(boolean optional) {
        if (window != null) {
            window.close();
        }
        return false;
    }

    @Override
    public void suspend() {
        Bounds bounds = window.getClientArea();
        System.out.println(bounds);
    }

    @Override
    public void resume() {
    }

    public static void main(String[] args) {
        DesktopApplicationContext.main(Segments.class, args);
    }

    public class ComponentSizeListener {
        protected int newWidth;
        protected int newHeight;

        protected ComponentListener listener;

        protected List<SectionComponent> components;

        public ComponentSizeListener() {
            this.newWidth = 425;
            this.newHeight = 131;

            this.listener = new ComponentListener.Adapter() {
                @Override
                public void sizeChanged(Component component, 
                        int previousWidth, int previousHeight) {
                    newWidth = component.getWidth();
                    newHeight = component.getHeight();
                    for (SectionComponent sectionComponent : components) {
                        sectionComponent.setTextAreaWidth(newWidth - 25);
                        int paneHeight = (newHeight / components.size()) - 34;
                        sectionComponent.setTextScrollPaneHeight(paneHeight);
                    }
                }
            };
        }

        public void setComponents(List<SectionComponent> components) {
            this.components = components;
        }

        public ComponentListener getListener() {
            return listener;
        }
    }

    public class SectionComponent {
        protected int textAreaWidth;
        protected int textScrollPaneHeight;

        protected Expander expander;
        protected ScrollPane textScrollPane;
        protected SectionText sectionText;
        protected TextArea textArea;

        public SectionComponent(SectionText sectionText, 
                int textAreaWidth, int textScrollPaneHeight) 
                        throws IOException {
            this.sectionText = sectionText;
            this.textAreaWidth = textAreaWidth;
            this.textScrollPaneHeight = textScrollPaneHeight;
            createPartControl();
        }

        protected void createPartControl() throws IOException {
            textArea = new TextArea();
            textArea.setEditable(false);
            textArea.setPreferredWidth(textAreaWidth);
            textArea.setText(sectionText.getTopic());

            textScrollPane = new ScrollPane();
            textScrollPane.setPreferredHeight(textScrollPaneHeight);
            textScrollPane.setVerticalScrollBarPolicy(
                    ScrollPane.ScrollBarPolicy.AUTO);
            textScrollPane.setView(textArea);

            expander = new Expander();
            expander.setTitle(sectionText.getTitle());
            expander.setContent(textScrollPane);
            expander.setExpanded(false);
        }

        public Expander getExpander() {
            return expander;
        }

        public void setTextAreaWidth(int textAreaWidth) {
            this.textAreaWidth = textAreaWidth;
            textArea.setPreferredWidth(textAreaWidth);
        }

        public void setTextScrollPaneHeight(int textScrollPaneHeight) {
            this.textScrollPaneHeight = textScrollPaneHeight;
            textScrollPane.setPreferredHeight(textScrollPaneHeight);
        }

    }

    public class SectionText {
        protected String title;
        protected Reader topic;

        public SectionText(String title, Reader topic) {
            this.title = title;
            this.topic = topic;
        }

        public String getTitle() {
            return title;
        }

        public Reader getTopic() {
            return topic;
        }
    }

    public class SectionCollection {
        protected List<SectionText> collection;

        public SectionCollection() {
            this.collection = new ArrayList<SectionText>();
        }

        public void add(SectionText sectionText) {
            collection.add(sectionText);
        }

        public int size() {
            return collection.size();
        }

        public SectionText get(int index) {
            return collection.get(index);
        }
    }   

    public class SectionCollectionCreator {
        protected SectionCollection collection;

        protected static final String text = "Attributes, Styles and Style Contexts\n\n"
                + "The simple PlainDocument class that you saw in the previous "
                + "chapter is only capable of holding text. The more complex text "
                + "components use a more sophisticated model that implements the "
                + "StyledDocument interface. StyledDocument is a sub-interface of "
                + "Document that contains methods for manipulating attributes that "
                + "control the way in which the text in the document is displayed. "
                + "The Swing text package contains a concrete implementation of "
                + "StyledDocument called DefaultStyledDocument that is used as the "
                + "default model for JTextPane and is also the base class from which "
                + "more specific models, such as the HTMLDocument class that handles "
                + "input in HTML format, can be created. In order to make use of "
                + "DefaultStyledDocument and JTextPane, you need to understand how "
                + "Swing represents and uses attributes.";

        public SectionCollectionCreator(SectionCollection collection) {
            this.collection = collection;

            String title = "Title ";

            for (int i = 1; i <= 3; i++) {
                SectionText sectionText = new SectionText(title + i, 
                        new StringReader(text));
                collection.add(sectionText);
            }
        }   
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
0

You might also want to consider putting your components inside a FillPane, which causes them to be sized to fill the available area. This seems to be the Pivot way of doing things.

angelatlarge
  • 4,086
  • 2
  • 19
  • 36