Что мешает Java-компонентам качаться при добавлении в JComponent? - PullRequest
0 голосов
/ 12 мая 2018

JTextField, JSlider, JComboBox и т. Д., Добавленные в JComponent, не отображаются в JFrame, содержащем JComponent.Кажется, только рисование по параметру Graphics позволяет рисоватьВключенная тестовая программа сравнивает использование JPanel с JComponent в моих попытках выяснить, как отображать компоненты, добавленные в 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 голосов

Редактировать: вам нужно дать вашему JComponent макет, такой как FlowLayout, чтобы компоненты отображались правильно, поскольку у него нет макета по умолчанию, как у JPanel. Так что добавьте setLayout(new FlowLayout()) в конструктор вашего JComponent

У вас есть:

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

, а затем попробуйте добавить компоненты в contentPane JFrame, используя GridBagConstraints, и это не имеет смысла. Если вы хотите использовать эти ограничения, тогда контейнер должен использовать 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);
}

Вы должны переопределять метод paintComponent JComponent, а не его метод рисования (вызов super.paintComponent) и не должны устанавливать видимость компонента или вызывать метод paintComponents компонента непосредственно в любом методе рисования.

Другая проблема: не используйте KeyListener в текстовых компонентах Swing, а просто добавьте DocumentListener в Document компонента. В противном случае вы рискуете нарушить некоторые функции текстового компонента, а также ваш слушатель не будет работать для копирования / вставки, в то время как DocumentListener будет работать.

И еще одна проблема, ваша основная проблема: вам нужно задать макет JComponent. Это не по умолчанию FlowLayout, как JPanel. Вот почему добавленные компоненты не отображаются внутри него.

Например:

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