是什么阻止了java swing组件在添加到JComponent时被绘制?

时间:2018-05-12 20:14:36

标签: java swing paintcomponent jcomponent

添加到JComponent的JTextField,JSlider,JComboBox等不会显示在包含JComponent的JFrame中。似乎只有Graphics参数绘制允许绘画。包含的测试程序在我努力发现如何显示添加到JComponent的组件时,使用JPanel与JComponent进行比较。有没有办法让这些组件显示出来?

public class TestPaints {
    public static void main(String[] args) {
        new TestPaints();
    }

    JTextField _text1;
    JLabel _label1 = new JLabel("Text1");
    JTextField _text2;
    JLabel _label2 = new JLabel("Text2");

TestPaints() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Paint a Widget");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(3, 2));
                GridBagConstraints  grid = new GridBagConstraints();
                frame.add(new JLabel("TextField in JComponent   "));
                grid.gridx = 2;
                frame.add(new JLabel("TextField in JPanel"), grid);
                grid.gridy = 2;
                grid.gridx = 1;
                frame.add(new TestJComponent(), grid);
                grid.gridx = 2;
                frame.add(new TestJPanel(), grid);
                grid.gridy = 3;
                grid.gridx = 1;
     /* tabbing between the two TextFields shows that keystrokes are seen */
                frame.add(_label1, grid);
                grid.gridx = 2;
                frame.add(_label2, grid);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
}

public class TestJComponent extends JComponent {
    public TestJComponent() {
        setPreferredSize(new Dimension(100, 30));
        _text1 = new JTextField(6);
        _text1.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                _label1.setText(_text1.getText());
                _label1.repaint();
            }
        });
        _text1.setOpaque(true);
        _text1.setVisible(true);
        add(_text1);
/* This doesn't work            
        JPanel panel = new JPanel();
        panel.add(_text1);
        add(panel);    */
        setOpaque(true);
        setVisible(true);
        setBackground(Color.green);
    }
    public void paint(Graphics g) {
        super.paint(g);  // did not do background.                          Rectangle r = g.getClipBounds(); // needs this
        g.setColor(getBackground());
        g.fillRect(r.x, r.y, r.width, r.height);
            /* Variations such as these don't work */       
        _text1.setOpaque(true);
        _text1.setVisible(true);
        _text1.paintComponents(g);
    }
}

class TestJPanel extends JPanel {
    TestJPanel() {
        _text2 = new JTextField(6);
        _text2.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                _label2.setText(_text2.getText());
                _label2.repaint();
            }
        });
        add(_text2);
        setBackground(Color.blue);          
    }
  }
}

1 个答案:

答案 0 :(得分:3)

编辑:您需要为JComponent提供一个布局,例如FlowLayout,以便组件正确显示,因为它没有像JPanel那样的默认布局。因此,将setLayout(new FlowLayout())添加到JComponent的构造函数

你有:

frame.setLayout(new GridLayout(3, 2));

然后尝试使用GridBagConstraints将组件添加到JFrame的contentPane,这没有意义。如果你想使用这些约束,那么容器需要使用GridBagLayout,而不是GridLayout。

这也是危险的代码:

public void paint(Graphics g) {
    super.paint(g);  // did not do background.                          Rectangle r = g.getClipBounds(); // needs this
    g.setColor(getBackground());
    g.fillRect(r.x, r.y, r.width, r.height);
        /* Variations such as these don't work */       
    _text1.setOpaque(true);
    _text1.setVisible(true);
    _text1.paintComponents(g);
}

你应该重写JComponent的paintComponent方法,而不是它的paint方法(调用super.paintComponent),不应该在任何绘制方法中直接设置组件可见性或调用组件的paintComponents方法。

另一个问题:不要在Swing文本组件中使用KeyListeners,而是将DocumentListener添加到组件的Document中。否则,您可能会破坏文本组件的某些功能,并且您的侦听器也无法复制/粘贴,而DocumentListener将会这样做。

另一个问题,主要问题:您需要为JComponent提供布局。它不像JPanel那样默认为FlowLayout。这就是添加的组件未显示在其中的原因。

例如:

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class TestPaints2 {
    private JTextField textField1 = new JTextField(8);
    private JTextField textField2 = new JTextField(8);
    private JLabel label1 = new JLabel("Text1");
    private JLabel label2 = new JLabel("Text2");

    public TestPaints2() {
        textField1.getDocument().addDocumentListener(new MyDocListener(label1));
        textField2.getDocument().addDocumentListener(new MyDocListener(label2));

        TestJComponent2 jComponent = new TestJComponent2();
        jComponent.add(textField1);

        TestJPanel2 jPanel = new TestJPanel2();
        jPanel.add(textField2);

        JPanel mainPanel = new JPanel(new GridLayout(0, 2));
        mainPanel.add(new JLabel("JComponent"));
        mainPanel.add(new JLabel("JPanel"));
        mainPanel.add(jComponent);
        mainPanel.add(jPanel);
        mainPanel.add(label1);
        mainPanel.add(label2);

        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private class MyDocListener implements DocumentListener {
        private JLabel label;

        public MyDocListener(JLabel label) {
            this.label = label;
        }

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

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

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

        private void updateLabel(DocumentEvent e) {
            Document doc = e.getDocument();
            int offset = doc.getLength();
            try {
                String text = doc.getText(0, offset);
                label.setText(text);
            } catch (BadLocationException e1) {
                e1.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TestPaints2());
    }
}

class TestJComponent2 extends JComponent {
    private static final Color BG = Color.GREEN;
    private static final int GAP = 5;

    public TestJComponent2() {
        setOpaque(true);
        setBackground(BG);
        setLayout(new FlowLayout());
        setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
    }
}

class TestJPanel2 extends JPanel {
    private static final Color BG = Color.BLUE;
    private static final int GAP = 5;

    public TestJPanel2() {
        setBackground(BG);
        setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
    }
}