我最近开始使用Java + Swing构建UI,我目前在使用FlowLayout放置在JPanel上的JTextField存在问题。
在我的例子中,我有一个窗口,包含带按钮的面板。单击该按钮可添加从JPanel派生并包含JTextField的组件。
问题是,当我输入JTextField时,它不会更新(不会调整大小)。但是,当我调整窗口大小或执行其他任何强制窗口/面板重绘的内容时,正在调整文本字段的大小(正是我希望自动发生的事情)。
当我将基类从JPanel更改为JTextField时,它以我尝试实现的方式工作,但我需要将JPanel作为基类,以便我可以利用将子组件放入其中。
我已经在这里检查了不同的问题以及我用Google搜索试图找到解决方案,但它对我不起作用。我已尝试以不同的组合和不同的组件验证/无效/重新验证/重绘,以及尝试对每个键入的字符强制执行重新验证,这对我来说听起来不是正确的方法。到目前为止,我发现它与布局管理器有关。
有谁可以帮助我理解它是如何工作的,我应该阅读有关Swing UI,布局管理和重绘如何工作的内容?
另外,如果有人能帮我解决我的代码问题,我会很高兴。
提前致谢!
以下是我的代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editField.setSize(editField.getSize());
editField.revalidate();
remove(editField);
add(editField);
revalidate();
repaint();
}
});
add(editField, FlowLayout.LEFT);
}
public void place(JPanel panel) {
panel.add(this);
editField.grabFocus();
}
}
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
private JFrame frame;
public MainWindow(JFrame frame) {
mainPanel = new JPanel(new FlowLayout());
btnPlace = new JButton();
btnPlace.setText("Place");
mainPanel.add(btnPlace);
this.frame = frame;
btnPlace.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
v.place(mainPanel);
mainPanel.revalidate();
mainPanel.repaint();
mainPanel.updateUI();
frame.revalidate();
frame.repaint();
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("TextFieldUpdateIssue");
frame.setContentPane(new MainWindow(frame).mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
答案 0 :(得分:1)
如果我是你,当用户输入一些文字时,我不会尝试调整文本字段的大小。
我建议你使用JTextField(int columns)构造函数给它们一个固定的大小,这样你就可以创建一些足够宽的文本字段"。
如果您仍希望在输入某些文本时使它们更宽,则无法使用ActionListener,因为当用户按下ENTER键时它将触发事件,而不是基于输入的文本。
为此,您可以在文本字段的文档中注册Document Listener。
您还可以覆盖getPreferredSize()方法来计算并返回适当的大小。在下面的示例中,我使用JLabel来方便计算首选宽度,但您可以使用FontMetrics。
如果要向面板添加多个标签,还应考虑使用 JScrollPane ,以便在面板需要更多空间时显示滚动条。
看到这个例子(我改变了一下你的代码,因为它不会编译而且一般设计很糟糕,现在我认为它更好,但仍然不好):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class MainWindow
{
public static void main (String [] a) {
SwingUtilities.invokeLater (new Runnable () {
@Override public void run () {
try {
UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());
createAndShowGUI ();
}
catch (Exception e) {
JOptionPane.showMessageDialog (null, "An unexpected error occurred: " + e.getClass ().getSimpleName (), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
}
private static void createAndShowGUI () {
JFrame frame = new JFrame ("TextFieldUpdateIssue");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setContentPane (new MainPanel ());
frame.setExtendedState (JFrame.MAXIMIZED_BOTH);
frame.setLocationRelativeTo (null);
frame.setVisible (true);
}
}
class MainPanel extends JPanel
{
private JPanel tagsPanel;
public MainPanel () {
super (new BorderLayout (0, 10));
add (new JButton (new AbstractAction ("Add tag") {
@Override public void actionPerformed(ActionEvent e) {
addNewTag ();
}
}), BorderLayout.NORTH);
tagsPanel = new JPanel ();
tagsPanel.setLayout (new FlowLayout (FlowLayout.CENTER, 10, 0));
add (tagsPanel, BorderLayout.CENTER);
}
private void addNewTag () {
TagVisual v = new TagVisual ();
tagsPanel.add (v);
v.grabFocusOnField ();
revalidate ();
}
}
class TagVisual extends JPanel
{
private JTextField editField;
public TagVisual() {
super (new FlowLayout (FlowLayout.CENTER, 0, 0));
add (editField = createNewTextField (null), FlowLayout.LEFT);
}
private JTextField createNewTextField (String text) {
JTextField textField = new JTextField (text) {
@Override public Dimension getPreferredSize () {
Dimension d = super.getPreferredSize ();
return new Dimension (new JLabel (getText ()).getPreferredSize ().width + 10, d.height);
}
};
textField.setBackground (Color.RED);
textField.getDocument ().addDocumentListener (new DocumentListener () {
@Override public void changedUpdate (DocumentEvent e) {
revalidate ();
}
@Override public void insertUpdate (DocumentEvent e) {
revalidate ();
}
@Override public void removeUpdate (DocumentEvent e) {
revalidate ();
}
});
return textField;
}
public void grabFocusOnField () {
editField.grabFocus ();
editField.setCaretPosition (editField.getText ().length ());
}
}
屏幕截图(简短文字):
屏幕截图(更长文字):
答案 1 :(得分:0)
请查看代码并注释评论:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
public MainWindow(){
JFrame frame = new JFrame("TextFieldUpdateIssue");
//you can't use components before initializing them
btnPlace = new JButton("Button");
frame.add(btnPlace, BorderLayout.NORTH);
mainPanel = new JPanel();
frame.add(mainPanel, BorderLayout.CENTER);
btnPlace.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
mainPanel.add(v); //add it to main panel
//v.place(mainPanel);
//mainPanel.revalidate();
//mainPanel.repaint();
//mainPanel.updateUI();
//frame.revalidate();
//frame.repaint();
frame.pack();
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new MainWindow();
}
}
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
//give it a preferred size to be used by layout manager
editField.setPreferredSize(new Dimension(150,25));
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//not sure what you want to do here
//not relevant to the question
}
});
add(editField, FlowLayout.LEFT);
}
}