Деформация текстового поля при перерисовке

У меня есть довольно простой JFrame (он состоит только из одного текстового поля и множества вещей, которые я рисую), хотя всякий раз, когда вызывается repaint(), текстовое поле изменяется. Я почти уверен, что это repaint(), так как это происходит, даже когда я перетаскиваю кадр с одного монитора на другой, а также всякий раз, когда я вызываю его в коде.

Он начинается нормально, когда я запускаю программу:

Однако всякий раз, когда вызывается repaint(), происходит следующее:

Если я начну печатать в поле, остальные сразу же всплывают и работают нормально. В конечном счете, моя конечная цель - сбросить большую часть моего кадра к тому, что нарисовано в paintComponent(), при этом текстовое поле все еще остается видимым.

Я относительно новичок в графике и живописи, любая помощь очень ценится!

ИЗМЕНИТЬ

При создании SSCCE я обнаружил, что проблема с текстовым полем была вызвана поворотом метода Graphics2D, который был в моем методе paintComponent. Я не знаю, почему это происходит, но я могу обойти это и считать, что проблема решена.

Теперь у меня новая проблема: мой метод paintComponent вызывается слишком много раз. Ниже приведен SSCCE этой проблемы, порядок, который я хочу, чтобы это произошло:

  1. Вызов paintComponent()
  2. (когда кнопка нажата) Вызвать перерисовку()
  3. (когда кнопка нажата, но после перерисовки) Вызов paintStuff()

Все это происходит, однако после этого каким-то образом вызывается paintComponent, стирая все, нарисованное paintStuff().

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class tester extends JFrame {

    private JPanel contentPane;
    private JButton button;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    tester frame = new tester();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public tester() {
        setBounds(100, 100, 450, 300);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        contentPane = new JPanel(){
            public void paintComponent(Graphics g1) {
                System.out.println("draw rectangle - should be first");
                super.paintComponent(g1);

                g1.drawRect(50,50,50,50);
            }
        };
        contentPane.setLayout(null);
        setContentPane(contentPane);

        button = new JButton("Click me!");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("repaint - should be second");
                repaint();

                paintStuff(contentPane.getGraphics());
            }
        });
        button.setBounds(10, 11, 95, 20);
        contentPane.add(button);
    }

    public void paintStuff(Graphics g){
        System.out.println("draw circle - should be last");
        g.drawOval(100,100,10,10);
    }

}

person Kalashnikov    schedule 23.01.2016    source источник
comment
Убедитесь, что вы вызываете super.paintComponent(...) в начале вашего метода paintComponent(). Если это не поможет, опубликуйте правильный SSCCE, демонстрирующий проблему.   -  person camickr    schedule 23.01.2016
comment
1) У меня есть довольно простой JFrame (он состоит только из одного текстового поля.. Где? Этот код показывает JButton, но не JTextField. 2) Лучший способ установить размер текстового поля заключается в том, чтобы установить количество столбцов (символов), которые необходимо отобразить. Другой способ настроить его размер — изменить размер Font, который он использует. Но в целом.. 3) ..   -  person Andrew Thompson    schedule 23.01.2016
comment
.. 3) Графические интерфейсы Java должны работать с разными ОС, размером экрана, разрешением экрана и т. д., используя разные PLAF в разных локалях. Как таковые, они не способствуют идеальной компоновке пикселей. Вместо этого используйте менеджеры макетов или их комбинации вместе с отступами и границами макета для пробел.   -  person Andrew Thompson    schedule 23.01.2016
comment
Спасибо за советы, буду иметь их в виду. Я изменил его на кнопку в SSCCE, чтобы упростить понимание моей второй проблемы.   -  person Kalashnikov    schedule 23.01.2016


Ответы (1)


paintStuff(contentPane.getGraphics());

Нет, не используйте метод getGraphics() для рисования. Чтобы перекрасить компонент, вы просто используете:

contentPane.repaint();

а затем вы перемещаете оператор drawOval(...) в метод paintComponent().

Если вы хотите нарисовать овал условно, вам нужно создать логическое свойство для вашего пользовательского рисования. Тогда код будет выглядеть примерно так:

super.paintComponent(g1);

g1.drawRect(50,50,50,50);

if (drawOval)
    g1.drawOval(100,100,10,10);    

Затем в вашем классе вы должны создать такой метод, как:

public void setDrawOval(Boolean drawOval)
{
    this.drawOval = drawOval;
    repaint();
}

Итак, в ActionListener вы просто используете:

contentPane.setDrawOval(true);
person camickr    schedule 23.01.2016