JComponent не рисует в JPanel

У меня есть пользовательский компонент, который расширяет JComponent, который переопределяет метод paintComponent(Graphics g), но когда я пытаюсь добавить его в свою JPanel, он просто не работает, ничего не рисуется. Вот мой код:

public class SimpleComponent extends JComponent{

int x, y, width, height;

public SimpleComponent(int x, int y, int width, int height){
    this.x = x;
    this.y = y;
}

@Override
public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.BLACK);
    g2.fillRect(x, y, width, height);
}
}


public class TestFrame{
public static void main(String[] args){
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.setPreferredSize(new Dimension(400, 400));
    frame.add(panel);
    frame.pack();
    frame.setResizable(false);

    SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
    panel.add(comp);
    frame.setVisible(true);
}
}

person lilroo    schedule 06.10.2012    source источник


Ответы (2)


Он отлично работает — компонент добавляется в JPanel, но насколько он велик? Если вы проверите это после того, как графический интерфейс был отрендерен, вы, вероятно, обнаружите, что размер вашего компонента равен 0, 0.

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
panel.add(comp);
frame.setVisible(true);

System.out.println(comp.getSize());

Подумайте о том, чтобы ваш JComponent переопределял getPreferredSize и возвращал Dimension, который имеет смысл:

public Dimension getPreferredSize() {
  return new Dimension(width, height);
}

Если вы хотите использовать x и y, вы также можете переопределить getLocation().

Редактировать
Вам также необходимо установить поля ширины и высоты!

public SimpleComponent(int x, int y, int width, int height) {
  this.x = x;
  this.y = y;
  this.width = width; // *** added
  this.height = height; // *** added
}
person Hovercraft Full Of Eels    schedule 06.10.2012
comment
Это действительно странно, я воспроизвел эту проблему на Windows и Mac, и она всегда одна и та же. - person lilroo; 06.10.2012
comment
Ах, ширина и высота установлены на ноль - person lilroo; 06.10.2012
comment
После того, как я вспомнил установить поля ширины и высоты, это все еще не сработало, но когда я переопределил метод getPreferredSize(), он сработал. - person lilroo; 06.10.2012
comment
@lillroo: да, вам нужно сделать и то, и другое. - person Hovercraft Full Of Eels; 06.10.2012
comment
Также звоните super.paintComponent - person MadProgrammer; 07.10.2012
comment
Смотрите мой ответ, почему это абсолютно неправильный ответ! - person mike rodent; 18.02.2016

Ого! Абсолютно неправильный ответ!

Первый абсолютный КАРДИНАЛЬНЫЙ ГРЕХ, который вы совершили, — это сделать все это в треде, отличном от EDT!!! Здесь нет места, чтобы объяснять это... в Сети всего около 30 миллиардов мест, где можно узнать об этом.

Как только весь этот код выполняется в Runnable в EDT (поток отправки событий), затем:

Вам не нужно переопределять preferredSize (хотя вы можете это сделать, если хотите)... но вам нужно установить его.

Вы абсолютно не должны устанавливать размеры (height и width или setSize()) напрямую!

Что вам DO нужно сделать, так это заставить java.awt.Container, panel в вашем примере "раскладываться"... есть метод Container.doLayout(), но, как сказано в документации API:

Заставляет этот контейнер размещать свои компоненты. Большинство программ не должны вызывать этот метод напрямую, а вместо этого должны вызывать метод проверки.

поэтому решение такое:

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
comp.setPreferredSize( new Dimension( 90, 90 ) );
panel.add(comp);

// the key to unlocking the mystery
panel.validate();

frame.setVisible(true);

Между прочим, пожалуйста, воспользуйтесь моим опытом: я часами рвал на себе волосы, пытаясь понять все эти validate, invalidate, paintComponent, paint и т. д.... и я все еще чувствую, что только поцарапал поверхность.

person mike rodent    schedule 18.02.2016
comment
См. stackoverflow.com/questions/10866762/ - person Hovercraft Full Of Eels; 19.02.2016
comment
Хорошо, спасибо... но если вы были тем человеком, который проголосовал за мой ответ здесь, это не очень помогло будущим посетителям этого вопроса: мой ответ намного, намного лучше, чем принятый ответ, и нюанс в отношении setPreferredSize/getPreferredSize не меняется тот. - person mike rodent; 19.02.2016
comment
О ... Я вижу, вы ответили на принятый ответ! Но с репутацией 214k вы наверняка должны знать, что каждый пункт, который я изложил, верен, и что ваш ответ действительно, гм, как бы это выразиться, оставляет место для улучшения! - person mike rodent; 19.02.2016