1

このコードを Swing で使用して、 OpenCloudワード クラウドを Java で表示できる段階になりました。ファイルからテキストを 1 行ずつロードし、それをむさぼり食い、表示したい単語を吐き出します。これはクラウドに渡され、一連の行が読み取られるたびに追加され、更新されます。現在、デフォルトのレイアウトマネージャーを使用していますが、新しい単語をウィンドウの下部に追加するだけで、最終的にウィンドウの下部に流れます。これは私が望むものではありません。

私が求めているのは、ワードルのようなものです:

ここに画像の説明を入力

理想的には、次のことを望んでいます。

  • JPanelの中​​心を狙う
  • 放射状に外側に単語を追加する
  • 「1行あたり」に複数の単語を許可します(方法希望の間に、現在新しい行に1つあることに注意してください。)
  • トリッキー: エッジに達したときに適合しないスコアの低い単語を削除します。

リンクしたソリューションに従って、これらを各タグの重みに基づいたフォントで JLabels として追加しました。

私はさまざまな Swing レイアウト マネージャーをすべて閲覧しましたが、どれもプログラムに適しているようには見えません。レイアウトをカスタマイズしたい場合の私の唯一のオプションは、Swing で立ち往生しているため (はい、ほぼ完全に立ち往生しています)、絶対レイアウトの配置を使用することです。これは、飼いならすのが難しい獣のようです。残念ながら、素晴らしい非標準の LayoutManager を提案したい人のために、開発マシンにパッケージを追加したり、インターネットにアクセスしたりすることはできません。私がする必要があると思うのは、ページのどこかに単語をランダムに追加してから、他の単語についても同じことを行い、ウィンドウの端で互いに衝突しないように調整することです。

だから私は知る必要があるようです:

  • 標準のレイアウト マネージャーの 1 つを使用して、この種のランダム/遅延調整を行う「既知の」方法はありますか?
  • レイアウトマネージャーなしでこの種のレイアウトを行う方法はありますか? これは簡単ですか?
  • 独自のレイアウト マネージャーを作成するのは簡単ですか? 確かにそれは大変な作業ですよね?

これが大皿での解決策を求めているだけのように思われる場合は、お詫び申し上げます。私は Java に少し慣れていないため (それを言ってどれだけの時間を逃れることができますか!)、この種のことをどこから始めればよいかわかりません。こと、および任意のヘルプ/ヒントをいただければ幸いです。

4

1 に答える 1

3

これは、正常に機能しているように見えるWrapLayoutを使用した例です。

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import org.mcavallo.opencloud.Cloud;
import org.mcavallo.opencloud.Tag;

public class TestOpenCloud {

    private static final String[] WORDS = { "art", "australia", "baby", "beach", "birthday", "blue", "bw", "california", "canada", "canon",
            "cat", "chicago", "china", "christmas", "city", "dog", "england", "europe", "family", "festival", "flower", "flowers", "food",
            "france", "friends", "fun", "germany", "holiday", "india", "italy", "japan", "london", "me", "mexico", "music", "nature",
            "new", "newyork", "night", "nikon", "nyc", "paris", "park", "party", "people", "portrait", "sanfrancisco", "sky", "snow",
            "spain", "summer", "sunset", "taiwan", "tokyo", "travel", "trip", "uk", "usa", "vacation", "water", "wedding" };

    protected void initUI() {
        JFrame frame = new JFrame(TestOpenCloud.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JPanel panel = new JPanel(new WrapLayout());
        Cloud cloud = new Cloud();
        final Random random = new Random();
        for (String s : WORDS) {
            for (int i = random.nextInt(50); i > 0; i--) {
                cloud.addTag(s);
            }
        }
        for (Tag tag : cloud.tags()) {
            final JLabel label = new JLabel(tag.getName());
            label.setOpaque(false);
            label.setFont(label.getFont().deriveFont((float) tag.getWeight() * 10));
            panel.add(label);
        }
        JScrollPane scrollPane = new JScrollPane(panel);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        frame.add(scrollPane);
        frame.setSize(500, 550);
        frame.setVisible(true);
        Timer t = new Timer(1000, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                final JLabel label = new JLabel(WORDS[random.nextInt(WORDS.length)]);
                label.setOpaque(false);
                int fontSize = random.nextInt(20) + 8;
                label.setFont(label.getFont().deriveFont((float) fontSize));
                panel.add(label);
                panel.revalidate();
                panel.repaint();
            }
        });
        t.start();
    }

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

    public class WrapLayout extends FlowLayout {
        private Dimension preferredLayoutSize;

        /**
         * Constructs a new <code>WrapLayout</code> with a left alignment and a default 5-unit horizontal and vertical gap.
         */
        public WrapLayout() {
            super();
        }

        /**
         * Constructs a new <code>FlowLayout</code> with the specified alignment and a default 5-unit horizontal and vertical gap. The value
         * of the alignment argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>, or <code>WrapLayout</code>.
         * 
         * @param align
         *            the alignment value
         */
        public WrapLayout(int align) {
            super(align);
        }

        /**
         * Creates a new flow layout manager with the indicated alignment and the indicated horizontal and vertical gaps.
         * <p>
         * The value of the alignment argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>, or <code>WrapLayout</code>.
         * 
         * @param align
         *            the alignment value
         * @param hgap
         *            the horizontal gap between components
         * @param vgap
         *            the vertical gap between components
         */
        public WrapLayout(int align, int hgap, int vgap) {
            super(align, hgap, vgap);
        }

        /**
         * Returns the preferred dimensions for this layout given the <i>visible</i> components in the specified target container.
         * 
         * @param target
         *            the component which needs to be laid out
         * @return the preferred dimensions to lay out the subcomponents of the specified container
         */
        @Override
        public Dimension preferredLayoutSize(Container target) {
            return layoutSize(target, true);
        }

        /**
         * Returns the minimum dimensions needed to layout the <i>visible</i> components contained in the specified target container.
         * 
         * @param target
         *            the component which needs to be laid out
         * @return the minimum dimensions to lay out the subcomponents of the specified container
         */
        @Override
        public Dimension minimumLayoutSize(Container target) {
            Dimension minimum = layoutSize(target, false);
            minimum.width -= getHgap() + 1;
            return minimum;
        }

        /**
         * Returns the minimum or preferred dimension needed to layout the target container.
         * 
         * @param target
         *            target to get layout size for
         * @param preferred
         *            should preferred size be calculated
         * @return the dimension to layout the target container
         */
        private Dimension layoutSize(Container target, boolean preferred) {
            synchronized (target.getTreeLock()) {
                // Each row must fit with the width allocated to the containter.
                // When the container width = 0, the preferred width of the container
                // has not yet been calculated so lets ask for the maximum.

                int targetWidth = target.getSize().width;

                if (targetWidth == 0) {
                    targetWidth = Integer.MAX_VALUE;
                }

                int hgap = getHgap();
                int vgap = getVgap();
                Insets insets = target.getInsets();
                int horizontalInsetsAndGap = insets.left + insets.right + hgap * 2;
                int maxWidth = targetWidth - horizontalInsetsAndGap;

                // Fit components into the allowed width

                Dimension dim = new Dimension(0, 0);
                int rowWidth = 0;
                int rowHeight = 0;

                int nmembers = target.getComponentCount();

                for (int i = 0; i < nmembers; i++) {
                    Component m = target.getComponent(i);

                    if (m.isVisible()) {
                        Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();

                        // Can't add the component to current row. Start a new row.

                        if (rowWidth + d.width > maxWidth) {
                            addRow(dim, rowWidth, rowHeight);
                            rowWidth = 0;
                            rowHeight = 0;
                        }

                        // Add a horizontal gap for all components after the first

                        if (rowWidth != 0) {
                            rowWidth += hgap;
                        }

                        rowWidth += d.width;
                        rowHeight = Math.max(rowHeight, d.height);
                    }
                }

                addRow(dim, rowWidth, rowHeight);

                dim.width += horizontalInsetsAndGap;
                dim.height += insets.top + insets.bottom + vgap * 2;

                // When using a scroll pane or the DecoratedLookAndFeel we need to
                // make sure the preferred size is less than the size of the
                // target container so shrinking the container size works
                // correctly. Removing the horizontal gap is an easy way to do this.

                Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);

                if (scrollPane != null) {
                    dim.width -= hgap + 1;
                }

                return dim;
            }
        }

        /*
         *  A new row has been completed. Use the dimensions of this row
         *  to update the preferred size for the container.
         *
         *  @param dim update the width and height when appropriate
         *  @param rowWidth the width of the row to add
         *  @param rowHeight the height of the row to add
         */
        private void addRow(Dimension dim, int rowWidth, int rowHeight) {
            dim.width = Math.max(dim.width, rowWidth);

            if (dim.height > 0) {
                dim.height += getVgap();
            }

            dim.height += rowHeight;
        }
    }
}
于 2012-10-09T15:24:58.327 に答える