22

次の例に示すように、アプリケーションでいくつかの JLabels をレイアウトしようとしています。

ここに画像の説明を入力

私は常にこのJLabelを真ん中に置き、他のJLabelsの数は1から30まで可変です。適切な数の列/行を選択し、空白にいくつかの空のJLabelsを設定してグリッドレイアウトを試しましたが、私は良い結果を得ることができず、MigLayoutでそれを行う方法を見つけることができません。適切なレイアウトの解決策やその他の解決策がありましたか?

PS : JLabels が円に配置されていることを示すためだけに円を表示したくありません。

4

6 に答える 6

19

これを特にサポートするレイアウト マネージャーは必要ありません。かなり単純な三角法で x、y 位置を自分で計算してから、 などの通常のレイアウトを使用できますSpringLayout

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;

public class CircleLayout {

  /**
   * Calculate x,y positions of n labels positioned in
   * a circle around a central point. Assumes AWT coordinate
   * system where origin (0,0) is top left.
   * @param args
   */
  public static void main(String[] args) {
    int n = 6;  //Number of labels
    int radius = 100;
    Point centre = new Point(200,200);

    double angle = Math.toRadians(360/n);
    List<Point> points = new ArrayList<Point>();
    points.add(centre);

    //Add points
    for (int i=0; i<n; i++) {
      double theta = i*angle;
      int dx = (int)(radius * Math.sin(theta));
      int dy = (int)(-radius * Math.cos(theta));
      Point p = new Point(centre.x + dx, centre.y + dy);
      points.add(p);
    }

    draw(points);
  }

  private static void draw(List<Point> points) {
    JFrame frame = new JFrame("Labels in a circle");
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();;
    SpringLayout layout = new SpringLayout();

    int count = 0;
    for (Point point : points) {
      JLabel label = new JLabel("Point " + count);
      panel.add(label);
      count++;
      layout.putConstraint(SpringLayout.WEST, label, point.x, SpringLayout.WEST, panel);
      layout.putConstraint(SpringLayout.NORTH, label, point.y, SpringLayout.NORTH, panel);
    }

    panel.setLayout(layout);

    frame.add(panel);
    frame.setVisible(true);

  }
}

数学 スクリーンショット

于 2012-04-20T11:19:25.717 に答える
14

あなたの要件は非常に専門的であるため、必要なことを実行できる LayoutManager がないと思われます。自分で作成してみてください!

于 2012-04-20T09:34:20.787 に答える
13

JHラボにはClockLayoutがあります:

これは、特別な目的のために作成された非常にばかげたレイアウトです。コンポーネントを上から時計回りに円形に配置するだけです。

于 2012-04-20T09:41:13.380 に答える
5

@Baqueta と @sacha のアイデアが好きです。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CircleLayoutTest {
  public JComponent makeUI() {
    JPanel panel = new JPanel() {
      @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Insets i = getInsets();
        g.translate(i.left, i.top);
        g.setColor(Color.RED);
        int w = getWidth() - i.left - i.right;
        int h = getHeight() - i.top - i.bottom;
        g.drawOval(0, 0, w, h);
        g.translate(-i.left, -i.top);
      }
    };
    panel.setLayout(new FlowLayout() {
      @Override public void layoutContainer(Container target) {
        synchronized(target.getTreeLock()) {
          int nmembers  = target.getComponentCount();
          if(nmembers<=0) return;
          Insets i = target.getInsets();
          double cx = .5 * target.getWidth();
          double cy = .5 * target.getHeight();
          Component m = target.getComponent(0);
          Dimension d = m.getPreferredSize();
          m.setSize(d.width, d.height);
          m.setLocation((int)(cx+.5-.5*d.width),(int)(cy+.5-.5*d.height));
          if(nmembers-1<=0) return;
          double rw = .5 * (target.getWidth() - i.left - i.right);
          double rh = .5 * (target.getHeight() - i.top - i.bottom);
          double x = 0, y = 0, r = 0;
          double radian = 2.0 * Math.PI / (nmembers-1);
          for(int j=1; j<nmembers; j++) {
            m = target.getComponent(j);
            if(m.isVisible()) {
              d = m.getPreferredSize();
              m.setSize(d.width, d.height);
              x = cx + rw * Math.cos(r) - .5 * d.width;
              y = cy + rh * Math.sin(r) - .5 * d.height;
              m.setLocation((int)(x+.5), (int)(y+.5));
              r += radian;
            }
          }
        }
      }
    });
    JPanel p = new JPanel(new BorderLayout());
    p.add(initPanel(panel));
    return p;
  }
  private static JComponent initPanel(JComponent p) {
    p.setBorder(BorderFactory.createEmptyBorder(50,50,50,50));
    for(int i=0; i<6; i++) {
      p.add(new JLabel("No."+i));
    }
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new CircleLayoutTest().makeUI());
    f.setSize(320 ,320);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
于 2012-04-20T11:17:59.497 に答える
3

Java ツールがインストールされていないため、Windows フォームを使用していますが、考え方は同じです。ボタンの代わりに JLabel を追加していること、およびこれが.NET フォーム。

レイアウト用に 800 x 800 ピクセルの領域を想定すると、コードは次のようになります。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.Load += new EventHandler(Form1_Load);
    }

    void Form1_Load(object sender, EventArgs e)
    {
        int numberItems = 18;
        int centreX = 400;
        int centreY = 400;


        double offset = Math.PI;
        double step = Math.PI * 2 / numberItems;


        Button b = null;
        for (int i = 0; i < numberItems; i++)
        {
            b = new Button();
            b.Width = 30;
            b.Height = 30;
            SetPosition(b, 370, offset, i, step);
            this.Controls.Add(b);
        }

        b = new Button();
        b.Width = 30;
        b.Height = 30;
        b.Location = new Point(centreX, centreY);
        this.Controls.Add(b);
    }


    private void SetPosition(Button button, int legLength, double offset, double posOffSet, double step)
    {

        int x = (int)(legLength + Math.Sin(offset + posOffSet * step) * legLength);
        int y = (int)(legLength + Math.Cos(offset + posOffSet * step) * legLength);

        button.Location = new Point(x, y);
    }
}
于 2012-04-20T09:59:58.537 に答える
2
  1. MigLayout は、コンポーネントの制約として「pos xy [x2] [y2]」を使用して絶対配置を行うことができます。MigLayout は、実際にそれらすべてを支配するレイアウト マネージャーです。彼らのフロント ページにある webstart デモをチェックしてください。絶対的な配置がよく示されています。カスタム レイアウト マネージャーのアイデアのように、コンポーネントの位置を計算する必要があります。

  2. また、レイアウトをオフにすることもできます。

  3. 本当にクリエイティブになりたい場合は、JHotDrawを見ることができます。

于 2012-04-20T14:02:11.923 に答える