Swing/MonospacedTextField の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/MonospacedTextField へ行く。
- Swing/MonospacedTextField の差分を削除
--- category: swing folder: MonospacedTextField title: JFormattedTextFieldに等幅フォントを設定する tags: [JFormattedTextField, JTextField, Font] author: aterai pubdate: 2023-10-16T03:32:20+09:00 description: JFormattedTextFieldやJTextFieldの推奨サイズを列数とフォントのサイズから計算します。 image: https://drive.google.com/uc?id=1zsVcOAr0GDuWKenXy9aBptvPnqJHd53b --- * 概要 [#summary] `JFormattedTextField`や`JTextField`の推奨サイズを列数とフォントのサイズから計算します。 #download(https://drive.google.com/uc?id=1zsVcOAr0GDuWKenXy9aBptvPnqJHd53b) * サンプルコード [#sourcecode] #code(link){{ String code = "BC89FE5A"; JFormattedTextField field0 = new JFormattedTextField(code); field0.setHorizontalAlignment(SwingConstants.RIGHT); field0.setColumns(8); JFormattedTextField field1 = new JFormattedTextField(code); field1.setHorizontalAlignment(SwingConstants.RIGHT); Font mono = new Font(Font.MONOSPACED, Font.PLAIN, field1.getFont().getSize()); field1.setFont(mono); field1.setColumns(8); JFormattedTextField field2 = new JFormattedTextField(code); field2.setHorizontalAlignment(SwingConstants.RIGHT); Map<TextAttribute, Object> attr = new ConcurrentHashMap<>(); attr.put(TextAttribute.TRACKING, -.021f); field2.setFont(mono.deriveFont(attr)); field2.setColumns(8); JFormattedTextField field3 = new JFormattedTextField(code) { @Override public Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); d.width += 2; return d; } }; field3.setHorizontalAlignment(SwingConstants.RIGHT); field3.setFont(mono); field3.setColumns(8); JFormattedTextField field4 = new JFormattedTextField(code); field4.setHorizontalAlignment(SwingConstants.RIGHT); field4.setFont(mono); field4.setColumns(9); }} * 解説 [#explanation] - `Default` -- 日本語`Windows`環境のデフォルトでは`12px`の`MS UI Gothic`が使用され、小文字`m`の幅が`9px`(`12/2=6px`にならない)となるので、余白を除いた推奨サイズ幅は`JFormattedTextField#setColumns(8)`で設定した`8`列を掛けて`72px`となる --- `Ubuntu`環境では`13px*8列=104px` -- `Font#getStringBounds("BC89FE5A", frc)`で計算される実際の文字列幅は`56.0`(7px*8文字?)となるので推奨サイズ幅に余りが発生してしまう -- `Font#getStringBounds("BC89FE5A", frc)`で計算される実際の文字列幅は`56.0`(`7px*8文字`?)となるので推奨サイズ幅に余りが発生してしまう #code{{ // @see JTextField protected int getColumnWidth() { if (columnWidth == 0) { FontMetrics metrics = getFontMetrics(getFont()); columnWidth = metrics.charWidth('m'); } return columnWidth; } public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); if (columns != 0) { Insets insets = getInsets(); size.width = columns * getColumnWidth() + insets.left + insets.right; } return size; } }} - `MONOSPACED` -- `new Font(Font.MONOSPACED, Font.PLAIN, field1.getFont().getSize())`で作成した等幅フォントを設定し、小文字`m`の幅が`7px`となるので、余白を除いた推奨サイズ幅は`JFormattedTextField#setColumns(8)`で設定した`8`列を掛けて`56px`となる -- `Font#getStringBounds("BC89FE5A", frc)`で計算される実際の文字列幅は`56.0`(`7px*8文字`?)と推奨サイズ幅と一致するため、キャレット`1px`?分が不足して文字列選択などでスクロールが発生する - `TRACKING-.011f` -- `Font`のトラッキングを変更して`-1.1%`字詰めを適用し、文字列幅を`54.944px`と`1px`余裕を持たせるよう設定 -- `Java 17`環境では`1px`の余裕では足りず`-2%`字詰めして`2px`余裕がないとスクロールが発生してしまう? - `PreferredSize+1` -- `JFormattedTextField#getPreferredSize()`をオーバーライドして余白を除く推奨サイズ幅をプラス`1px`した値となるよう設定 -- `Java 17`環境では`1px`の余裕では足りず`2px`余裕がないとスクロールが発生してしまう? - `Columns+1` -- `JFormattedTextField#setColumns(8+1)`と列を`1`文字分増加してスクロールの発生を防ぐよう設定 -- [[JColorChooserのRGB色選択パネル内に表示される16進数カラーコードにAlpha値を追加する>Swing/ColorChooserRgbaHexCode]]のように`16`進数カラーコードを表示する`JFormattedTextField`をオーバーライドしたり、推奨サイズを参照しないレイアウトマネージャを使用することが難しい場合は`JFormattedTextField#setColumns(...)`で列数を`1`文字分増加する方法がスクロールの発生を防ぐ最も手軽な回避方法かもしれない * 参考リンク [#reference] - [[JComboBoxなどの幅をカラム数で指定>Swing/SetColumns]] - [[Fontから文字列の境界を取得する>Swing/StringBounds]] - [[Fontにトラッキングを設定して文字列幅を詰めて描画する>Swing/Tracking]] - [[JPasswordFieldでPINコード入力欄を作成する>Swing/PinCodeInputField]] * コメント [#comment] #comment #comment