我想要一個 TextField,它按其寬度顯示允許的輸入字符的最大值。
我使用 Font.getStringBounds 來計算最大長度的寬度。但令我驚訝的是,示例中的結果寬度看起來像是省略了一個完整的字符!
- 使用 FontMetrics.stringWidth 提供相同的寬度值。
- 僅使用 JTextField(int columns) 建構式創建 textField 會得到更好的結果,但該欄位仍然太小??。
有什么不見了?
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import javax.swing.*;
public class InputWidthTextField extends JFrame {
public InputWidthTextField() {
setSize(250, 230);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new FlowLayout(FlowLayout.CENTER, 60, 20));
Font font= new Font(Font.MONOSPACED, Font.PLAIN, 12);
int max= 4;
JLabel lb= new JLabel("Enter up to " max " characters:");
add(lb);
MaxInputWidthTextField tf= new MaxInputWidthTextField(font, max);
add(tf);
setVisible(true);
}
public static void main(String... args) {
EventQueue.invokeLater(InputWidthTextField::new);
}
class MaxInputWidthTextField extends JTextField {
public MaxInputWidthTextField(Font font, int maxCount) {
super();
if (font==null)
font= getFont();
else
setFont(font);
FontMetrics fm= getFontMetrics(font);
FontRenderContext frc= fm.getFontRenderContext();
String buf= "8".repeat(maxCount);
Rectangle2D rect= font.getStringBounds(buf, frc);
Dimension dim= new Dimension((int)rect.getWidth(), (int)rect.getHeight());
setPreferredSize(dim);
System.out.println((int)rect.getWidth() ", " (int)rect.getHeight());
System.out.println(fm.stringWidth(buf));
System.out.println(getGraphics());
}
}
}
uj5u.com熱心網友回復:
我什至不會嘗試找出您代碼中的所有錯誤,相反,我將演示您應該做什么。
看一眼 
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JTextField(8), gbc);
add(new MaxInputWidthTextField(null, 8), gbc);
}
}
class MaxInputWidthTextField extends JTextField {
public MaxInputWidthTextField(Font font, int maxCount) {
super();
if (font == null) {
font = getFont();
} else {
setFont(font);
}
FontMetrics fm = getFontMetrics(font);
FontRenderContext frc = fm.getFontRenderContext();
String buf = "8".repeat(maxCount);
Rectangle2D rect = font.getStringBounds(buf, frc);
Dimension dim = new Dimension((int) rect.getWidth(), (int) rect.getHeight());
setPreferredSize(dim);
}
}
}
我推薦的是查看預先存在的實作
該JTextField#getPreferredSize實施看起來像...
/**
* Returns the column width.
* The meaning of what a column is can be considered a fairly weak
* notion for some fonts. This method is used to define the width
* of a column. By default this is defined to be the width of the
* character <em>m</em> for the font used. This method can be
* redefined to be some alternative amount
*
* @return the column width >= 1
*/
protected int getColumnWidth() {
if (columnWidth == 0) {
FontMetrics metrics = getFontMetrics(getFont());
columnWidth = metrics.charWidth('m');
}
return columnWidth;
}
/**
* Returns the preferred size <code>Dimensions</code> needed for this
* <code>TextField</code>. If a non-zero number of columns has been
* set, the width is set to the columns multiplied by
* the column width.
*
* @return the dimension of this textfield
*/
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (columns != 0) {
Insets insets = getInsets();
size.width = columns * getColumnWidth()
insets.left insets.right;
}
return size;
}
而不是“設定”首選大小,我會“考慮”覆寫getPreferredSize并將您的“自定義”作業流程注入
uj5u.com熱心網友回復:
@Camickr
Rob,你昨天似乎很嚴格。;-)
但可以肯定的是,不理解也在我這一邊。因為當我告訴你在等寬字體中“W”和“i”具有相同的寬度時,這對你來說肯定不是什么新鮮事。所以我不明白你為什么要我要 MRE 或者為什么只有“WWWW”不適合你。我只能想象,您沒有使用等寬字體,但是在給定最大字符數的情況下,對于用戶將輸入的任何字串,在預先計算最大可能寬度時,這是一個必要條件。
我希望,由于解析度或比例差異,我們不會在螢屏上看到不同的東西。所以我發送了一張它在我的網站上的樣子的照片。每當我在其中一個文本欄位中輸入最后一個字符時,整個字串都會向左移動,因此第一個字符會被部分隱藏。因此在我的例子中,零總是被切斷。您可能認為這是可以接受的,但我更希望每個角色都完全可見。

import java.awt.*;
import javax.swing.*;
public class FieldWidthTest extends JFrame {
public FieldWidthTest() {
setSize(250, 230);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new GridLayout(4, 1));
Font font= new Font(Font.MONOSPACED, Font.PLAIN, 12);
int max= 4;
for (int i=0; i<4; i ) {
JPanel p= new JPanel();
JTextField tf= new JTextField(max );
tf.setFont(font);
p.add(tf);
add(p);
}
setVisible(true);
}
public static void main(String... args) {
EventQueue.invokeLater(FieldWidthTest::new);
}
}
uj5u.com熱心網友回復:
@MadProgrammer
重寫getPreferredSize(),如你所說,運轉良好; 但使用setPreferredSize()也完成了作業并保存了覆寫。
如果引數為空,則不創建和設定等寬字體是錯誤的。然而,解決方案是將 2 添加到維度的寬度,這適用于所有字體大小。Camickr 稱其為“使用幻數”是有道理的,但我不知道從哪里得到這個數字。
謝謝大家。
class MaxInputWidthTextField extends JTextField {
public MaxInputWidthTextField(Font monoFont, int maxCount) {
super();
if (monoFont==null) monoFont= new Font(Font.MONOSPACED, Font.PLAIN, 13);
setFont(monoFont);
FontMetrics fm= getFontMetrics(monoFont);
FontRenderContext frc= fm.getFontRenderContext();
String buf= "8".repeat(maxCount);
Rectangle2D rect= monoFont.getStringBounds(buf, frc);
// Insets insets= getMargin(); // Parameters are all 0.
Insets insets= getInsets();
int iWidth= insets.left (int)rect.getWidth() insets.right 2;
int iHeight= insets.top (int)rect.getHeight() insets.bottom;
Dimension dim= new Dimension(iWidth, iHeight);
setPreferredSize(dim);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/323034.html
