JTextField появляется в двух местах при создании внутри paintComponent().

Я создаю игру тральщика, и я хочу иметь JTextField, где пользователь вводит свое имя, чтобы его счет был сохранен в файле.

Моя проблема в том, что когда я создаю JTextField и добавляю его в свою Jpanel, он появляется в двух местах. Вот изображение происходящего (https://i.imgur.com/Ao8dRo1.jpg)

Это мой упрощенный код. Я считаю, что я не совсем понимаю, как работает механизм графического интерфейса.

GUI.java

public class GUI extends JFrame {
  //..
  //some variables here
  //...

  public GUI() {
        this.setTitle("Minesweeper Game");
        this.setSize(WIDTH, HEIGHT);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setResizable(false);
        this.setLayout(null);

        //This method does not involve any drawing, it only places data in some arrays that I later use in paintComponent() to draw stuff accordingly to what the data is
        setMinefield();


        Board board = new Board();
        this.setContentPane(board);

        Click click = new Click();
        this.addMouseListener(click);
    }

    public class Board extends JPanel {
        public void paintComponent (Graphics g) {
        //...    
        //Drawing tiles, smiley, counters
        //...

        //And now I draw the area for the JTextField, and I also create it and add it in the Jpanel
        JTextField textField = new JTextField();
        textField.setFont(new Font("Tahoma", Font.PLAIN, 35));
        textField.setBounds(290, 80, 135, 40); //<-- This correctly places the textField where I want. The second textField seems to appear in the exact center of the X axis of my window

        add(textField); //<-- Adding the textField to the Jpanel

        } //End of paintComponent()
    }//End of Board class
}//End of GUI class

Main.java

public class Main implements Runnable {

    GUI gui = new GUI();

    public static void main(String[] args) {
        new Thread (new Main()).start();
    }

    @Override
    public void run() {
        while (true) {
            gui.repaint();
        }
    }

}

person kirios kavouris    schedule 06.06.2019    source источник
comment
Какие значения имеют WIDTH и HEIGHT? Попробуйте удалить setSize(). Я протестировал его, и без setSize() он выглядел намного лучше.   -  person Ralf Renz    schedule 06.06.2019
comment
Вы не должны делать ничего, кроме рисования компонентов в реализации paintComponent.   -  person TT.    schedule 06.06.2019
comment
Ни при каких обстоятельствах вы не должны добавлять компоненты в метод рисования. Вы не контролируете, когда вызывается paintComponent. Его можно вызывать всякий раз, когда пользователь перемещает окно, и даже когда пользователь перемещает мышь над окном. Кроме того, не вызывайте gui.repaint() в тесном цикле без вызовов сна; вы перегрузите очередь событий.   -  person VGR    schedule 06.06.2019
comment
1) Чтобы быстрее получить помощь, изменить, чтобы добавить минимальный воспроизводимый пример или Короткий, автономный, правильный пример. 2) Графические интерфейсы Java должны работать с разными ОС, размером экрана, разрешением экрана и т. д., используя разные PLAF в разных регионах. Как таковые, они не способствуют идеальной компоновке пикселей. Вместо этого используйте менеджеры макетов или их комбинации вместе с отступами и границами макета для пробел. 3) Предоставьте иллюстрацию в формате ASCII или простой рисунок предполагаемой компоновки графического интерфейса.   -  person Andrew Thompson    schedule 06.06.2019
comment
Кстати, только что заметил тег сапер. Я видел хорошие реализации тральщика. Им не требуется пользовательская отрисовка или поток для постоянной перерисовки графического интерфейса. Вот пример.   -  person Andrew Thompson    schedule 06.06.2019


Ответы (2)


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

Было бы лучше добавить текстовое поле в конструктор для вашего класса доски.

person mwarren    schedule 06.06.2019
comment
Спасибо за этот ответ! Я сделал то, что вы сказали, и теперь я получаю только 1 текстовое поле, центральное. Я использую команду textField.setBounds(290, 80, 135, 40);, чтобы разместить его там, где я хочу, но это не работает. Почему это могло произойти? - person kirios kavouris; 06.06.2019
comment
Я думаю, что из-за того, что у вас нет менеджера компоновки на вашем графическом фрейме, он позиционирует панель, которая является вашей доской. Попробуйте установить границы на объекте доски. - person mwarren; 06.06.2019
comment
Не используйте setBounds() и не используйте нулевой макет! - person camickr; 06.06.2019

Я использую команду textField.setBounds(290, 80, 135, 40); разместить его там, где я хочу, но он не работает. Почему это могло произойти?

Swing был разработан для использования с менеджерами компоновки. Менеджером компоновки по умолчанию для JPanel является FlowLayout. FlowLayout проигнорирует оператор setBounds(...) и установит размер/местоположение текстового поля на основе правил FlowLayout.

Поэтому не пытайтесь использовать нулевой макет и не используйте setBounds(). Вместо этого позвольте менеджеру компоновки делать свою работу.

Кроме того, вы должны добавлять компоненты во фрейм ДО того, как сделаете фрейм видимым.

Я бы предложил, чтобы ваш код выглядел примерно так:

JTextField textField = new JTextField(10);
JPanel top = new JPanel();
top.add( textField );

Board board = new Board();

add(top, BorderLayout.PAGE_START);
add(board, BorderLayout.CENTER);
setResizable( false );
pack();
setVisible( true );

Класс Board должен переопределить метод getPreferredSize() Board, чтобы вернуть желаемый размер, чтобы метод pack() работал правильно.

Менеджер компоновки по умолчанию для JFrame — это BorderLayout. Итак, теперь верхняя часть фрейма будет содержать текстовое поле по центру, а основная часть фрейма будет содержать ваш класс Board. Прочтите раздел руководства Swing по Как использовать BorderLayout чтобы понять, как работает приведенный выше код.

Кроме того, в Board следует добавить MouseListener, а не JFrame.

person camickr    schedule 06.06.2019