6

私は現在、GUI のようなオブジェクト用の非常にシンプルなエディターが必要なプロジェクトに取り組んでいます。このエディターは、よく知られている GUI ウィジェットを配置できるキャンバスになります。たとえば、そこにボタンとテキストフィールドを配置し、それらを移動してサイズを変更できます。ウィジェット自体を操作する必要はありません。

私は非常に単純なペイント チュートリアルを適応させることでこれを達成しようとしてきました。この方法で実装するのは簡単だと思っていましたが、キャンバスにカスタム シェイプとテキストを描画し、それらのシェイプをドラッグ アンド ドロップする際に多くの問題に遭遇しました。

JPanel で実際の Swing ウィジェットを再利用して、ユーザーがそれらを配置、移動、サイズ変更できるようにできないかと考えていました。もしそうなら、私は何を調べるべきですか?

これはほとんど情報がないように思えるかもしれませんが、正直なところ、解決策を探すのに行き詰まっています。

4

3 に答える 3

6

古き良きSwingの時代を思い出し、この概念実証を書くのを少し楽しんでください。メインパネルにボタンを追加してから移動し、基本的なサイズ変更を行うことができます。

これは概念実証にすぎませんが、すでに持っている多くの質問に答えます。次に何をすべきかわかるように、そこにいくつかのTODOを追加しました。

楽しみ...

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;

public class UIBuilder {
  private static final int NONE = -1;

  private static final int BORDER = 3;

  private JFrame frame = new JFrame("Builder");

  private JToolBar toolbar = new JToolBar();

  private JPanel main = new JPanel();

  private int startX = NONE;

  private int startY = NONE;

  private int prevX = NONE;

  private int prevY = NONE;

  private boolean resize = false;

  public UIBuilder() {
    frame.setBounds(100, 100, 600, 450);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(new BorderLayout());
    frame.getContentPane().add(toolbar, BorderLayout.PAGE_START);
    frame.getContentPane().add(main, BorderLayout.CENTER);
    frame.setVisible(true);
    buildToolbox();
    buildMainPanel();
  }

  private void buildToolbox() {
    JButton button = new JButton("Button");
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JButton btn = new JButton("Button");
        addComponent(btn);
      }
    });
    toolbar.add(button);
  }

  private void buildMainPanel() {
    main.setLayout(null);
  }

  private void addComponent(JComponent comp) {
    comp.setBounds(10, 10, 80, 24);

    comp.addMouseListener(new MouseAdapter() {
      public void mouseReleased(MouseEvent e) {
        startX = NONE;
        startY = NONE;
        ((JComponent) e.getSource()).setCursor(Cursor.getDefaultCursor());
      }

      public void mousePressed(MouseEvent e) {
        startX = e.getX();
        startY = e.getY();
      }
    });

    comp.addMouseMotionListener(new MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        JComponent source = (JComponent) e.getSource();
        int x = e.getX();
        int y = e.getY();
        Rectangle bounds = source.getBounds();
        resize = x < BORDER || y < BORDER || Math.abs(bounds.width - x) < BORDER || Math.abs(bounds.height - y) < BORDER;
        if (resize) {
          // TODO: there are a lot of resize cursors here, this is just of proof of concept
          source.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
        } else {
          source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        }
      }

      public void mouseDragged(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        if (startX != NONE && startY != NONE) {
          JComponent source = (JComponent) e.getSource();
          Rectangle bounds = source.getBounds();
          int deltaX = x - startX;
          int deltaY = y - startY;
          if (resize) {
            // TODO: handle all resize cases, left, right,...
            source.setSize(Math.max(10, bounds.width + x - prevX), Math.max(10, bounds.height + y - prevY));
          } else {
            source.setLocation(bounds.x + deltaX, bounds.y + deltaY);
          }
          // TODO: make sure you don't resize it as much as it disappears
          // TODO: make sure you don't move it outside the main panel
        } else {
          startX = x;
          startY = y;
        }
        prevX = x;
        prevY = y;
      }
    });
    main.add(comp);
    main.validate();
    main.repaint();
  }

  public static void main(String[] args) {
    new UIBuilder();
  }

}
于 2012-08-16T17:17:49.947 に答える
2

これは楽しいプロジェクトのようですね。

レイアウトをnullに設定して、コンテナとしてJPanelを使用することは間違いありません。JButton、JLabel などのコンポーネントをコンテナー内で移動できるようにするには、追加されたコンポーネントで MouseListener および MouseMotionListener イベントをリッスンし、それに応じて処理する必要があります。1 つのコンポーネントが移動またはサイズ変更されるたびに、コンテナーで validate() および repaint() を呼び出す必要があります。

于 2012-08-16T15:26:45.727 に答える
1

これを混合アプローチで実装します。マウスの応答 (ドラッグ、サイズ変更) を実装するクラスを作成します。このクラスは、ユーザー インタラクションを管理する責任があります。

コンポーネントの実際の描画には、実際のSwing コンポーネントを使用します (ユーザー インタラクション クラスは、それが表すはずのコンポーネントへの参照を持ち、実際のレンダリングをそのコンポーネントに委譲します)。

このアプローチにより、元の Swing コンポーネントを拡張するときに発生する複雑さのほとんどが回避されますが、それでもすべての描画コードを再利用できます。

于 2012-08-16T15:28:08.447 に答える