0

ユーザーがテキストフィールドにテキストを入力すると、KeyPressed イベントで JTextField のサイズを拡張する必要があります。これを実現する方法を教えてください。

前もって感謝します

4

4 に答える 4

5

さて、それに飛びつきます:-)

質問が

JTextField の幅を常にコンテンツの幅に合わせて調整する方法は?

いつもの協力者

  • 子のサイズを優先サイズ fi FlowLayout で設定する LayoutManager
  • JTextField は、コンテンツに合わせた優先サイズを報告します
  • 自動魔法のサイズ変更が期待される

簡単な例:

JTextField field = new JTextField("something");
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

type ... 何も起こりません: size は初期サイズのままです。これは驚きです。何らかの理由で、フィールドの自動検証が行われません。実際、変更通知を受け取ったときにフィールドを手動で再検証しても (注: ここでの唯一の正しいリスナー タイプは DocumentListener です)、フィールドも変更されません。

final JTextField field = new JTextField("something");
DocumentListener l = new DocumentListener() {

    private void updateField(JTextField field)
        // has no effect
        field.revalidate();
    }


    @Override
    public void removeUpdate(DocumentEvent e) {
        updateField(field);
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        updateField(field);
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
   }
};

field.getDocument().addDocumentListener(l);
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

@Gagandeep Bali は、再検証が必要なのは親であることを発見しました:

private void updateField(JTextField field) {
    field.getParent().revalidate();
}

予想外なので、次の質問は悪名高い理由です。ここで: なぜ無効化は、validateRoot が見つかるまでコンテナー階層をバブルアップしないのですか? 答えはAPIドキュメントにあります:

textfield 自体からの revalidate の呼び出しは、textfield が JViewport 内に含まれている場合を除き、textfield を検証することによって処理されます。

言い換えれば、フィールド自体validateRoot であるため、バブルアップしていません。オーバーライドして無条件に false を返す他のオプションを残します。

JTextField field = new JTextField("something") {

    @Override
    public boolean isValidateRoot() {
        return false;
    }
};
JComponent parent = new JPanel(); // has FlowLayout by default
parent.add(field);
frame.add(parent);
// just to ensure it's bigger 
frame.setSize(400, 400);

これに対して支払う代償は、スクロールが機能しないことです。これは、テキストが常にフィールドに収まるため、このコンテキストでは大したことではありません。または、もう少しインテリジェントに実装し、実際の幅が設定よりも小さい場合は true を返します。

于 2012-07-30T12:57:28.260 に答える
3

私が考えることができる最善の方法は、1つのCaretListener関係JTextFieldするものに追加することDocumentです.Increase/DecreaseJTextFieldIncrease/DecreaseJTextField

これを達成する方法を示す一例を次に示します。

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

public class JTextFieldColumnExample
{
    private int columns = 1;
    private JTextField tfield;

    private void displayGUI()
    {
        JFrame frame =  new JFrame("JTextField Columns Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel contentPane = new JPanel();
        tfield = new JTextField();
        tfield.setColumns(columns);
        tfield.addCaretListener(new CaretListener()
        {
            public void caretUpdate(CaretEvent ce)
            {
                int len = tfield.getDocument().getLength();
                if (len > columns)
                    tfield.setColumns(++columns);
                else
                {
                    if (--columns != 0)
                        tfield.setColumns(columns);
                    else
                    {
                        columns = 1;
                        tfield.setColumns(columns);
                    }   
                }   
                contentPane.revalidate();
                contentPane.repaint();
            }
        });

        contentPane.add(tfield);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new JTextFieldColumnExample().displayGUI();
            }
        });
    }
}
于 2012-07-30T11:41:13.203 に答える
2

1) KeyListenerfor JTextComponent、 use DocumentListener、他には決して使用しない

FontMetrics2) 、TextLayout、を使用できますSwingUtilities

LayoutManager3) サイズ変更後、通知する必要があります。

4) にのみJTextField使用する場合pack()Top-Level Container

JPanel5)それ以外の場合(ネストされた otherが複数ある場合JComponents)、コンテナ全体を re_layout しrevalidate()repaint()から

  • そのコンテンツで継続的にサイズを変更pack()する場合は、を呼び出しますTop-Level Container

  • サイズを変更したくないが、使用が必要な場合は をpack()呼び出さないでくださいTop-Level ContainerJScrollPane

6) 文字列の値が非常に長くなる可能性がある場合JTextComponent、GUI への複数行出力をサポートする適切な方法を使用するには、プレーンではなくJTextArea(in ) を使用します。JScrollPaneJTextField

于 2012-07-30T07:47:51.860 に答える
2

LayoutManager を使用しているかどうかによって異なります。そうでない場合は、文字列の長さ (ピクセル単位) を計算KeyListenerし、フィールドJTextFieldkeyRelease更新する必要があるかどうかを判断する必要があります。

addDocumentListener(new DocumentListener() {

    public void changedUpdate(DocumentEvent e) {
        updateField();
    }

    public void insertUpdate(DocumentEvent e) {
        updateField();
    }

    public void removeUpdate(DocumentEvent e) {
        updateField();
    }

    public void updateField() {

        FontMetrics fm = getFontMetrics(getFont());
        String text = getText();

        int length = fm.stringWidth(text);

        Dimension size = getPreferredSize();
        Insets insets = getInsets();
        if (length < min) {

            size.width = min;

        } else {

            size.width = length + (insets.left + insets.right);

        }

        setSize(size);
        invalidate();
        repaint();

    }

});

おそらく、より賢明な解決策は次のとおりです。

addDocumentListener(new DocumentListener() {

    public void changedUpdate(DocumentEvent e) {
        updateField();
    }

    public void insertUpdate(DocumentEvent e) {
        updateField();
    }

    public void removeUpdate(DocumentEvent e) {
        updateField();
    }

    public void updateField() {

        setColumns(getText().length());

    }

});

また、クレオパトラと mKorbel の発言にも注意を払いたいと思います。良いアイデアのように思えるかもしれませKeyListenerんが、通知されない状況が非常に多くあります。これがsetText主な状況です。

于 2012-07-30T07:09:11.383 に答える