2017-07-29 42 views
0

我最近开始使用Java + Swing构建用户界面,而我目前在JPanel上使用FlowLayout放置JTextField时遇到问题。Swing:JPanel中的JTextField,重绘问题

在我的例子中,我有一个窗口,包含带按钮的面板。单击该按钮将添加一个派生自JPanel并包含JTextField的组件。

问题是,当我键入JTextField时,它不会被更新(不会被调整大小)。但是,当我调整窗口大小或做其他任何强制窗口/面板重绘的东西时,文本字段被调整大小(正如我期望自动发生的那样)。

当我将基类从JPanel更改为JTextField时,它以我尝试实现的方式工作,但我需要将JPanel作为基类,以便可以利用将子组件添加到基类中。

我已经检查了不同的问题,以及我已经谷歌试图找到解决方案,但它没有为我工作。我尝试过使用不同的组合和不同的组件对validate/invalidate/revalidate/repaint进行尝试,以及试图对每个输入的字符执行重新验证,这对我来说听起来并不正确。到目前为止,我强调这与布局管理器有关。

任何人都可以请帮助我了解这是如何工作的,我应该阅读关于如何摆动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

所以你希望你的文本字段根据输入的文本增加其大小?这不是正常的行为,作为一个用户,我会发现它很讨厌... – Ansharja

+0

是的,这是我想要的。我正在创建标签编辑器组件,预计在键入时会增加它的大小。 –

+0

欢迎来到SO。请发布[mcve]。此代码不会运行('btnPlace'和'mainPanel'永远不会初始化也不会添加到框架中) – c0der

回答

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()); 
    } 
} 

截图(短文本):

enter image description here

截图(长文本):

enter image description here

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); 
    } 
} 
+2

'“//给它一个布局管理器使用的首选大小” - 对文本组件使用不好的事情,因为它使用钝的仪器对组件的固有行为粗心大意。通过设置字体和列属性来更好地“设置大小”。例如,如果该组件在JScrollPane内进行过,则您的建议将保证它不会正确运行。 –

+0

谢谢,在我为这里描述的JTextField应用autoresize之后为我工作:https://stackoverflow.com/questions/22128813/set-a-jtextfield-width-in-maner-to-wrap-a-given-text –