2015-05-02 2 views
1

У меня есть пользовательский JPanel, который не вызывает super.paintComponent() в его переопределенном методе paintComponent. Я знаю, что это во многих ситуациях не рекомендуется, но мне интересно, почему следующие:эффекты не вызова super.paintComponent в пользовательских JPanel

встречается,

Когда я запускаю два потока, что каждый создать JFrame и настраиваемую панель, панели как-то смешать их содержимое. В этом примере программа создаст два кадра, каждый из которых отобразит панель с «ONE» и «TWO» в качестве содержимого. Но я ожидал, что у меня будет один кадр с «ONE» и один кадр с «TWO» в качестве контента.

public class CustomPanel extends JPanel implements Runnable { 

public static void main(String[] args) { 
    //create two threads constantly repainting the custom panel 
    //expected two panels with different content 
    //but got two panels with same content 
    new Thread(new CustomPanel("ONE", 20)).start(); 
    new Thread(new CustomPanel("TWO", 40)).start(); 

} 
/** creates a frame and adds the custom panel with specified text **/ 
public CustomPanel(String text, int y) { 
    setPreferredSize(new Dimension(200,50)); 
    this.text = text; 
    this.y = y; 
    JFrame f = new JFrame(text); 
    f.add(this); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.pack(); 
    f.setVisible(true); 
} 

private String text;//the text to draw 
private int y;//where to draw 

/** draw the component **/ 
@Override 
public void paintComponent(Graphics g) { 
    g.setColor(Color.red); 
    g.drawString("Hello " + text, 50, y);//this line will be drawn twice on each panel (with text and y from the other) 
    g.dispose(); 
} 

/** constantly repaint the custom panels **/ 
@Override 
public void run() { 
    while (true) { 
     this.repaint(); 
     try { 
      Thread.sleep(200); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 

}

Result 

Frame1     Frame2 
++++++++++++++++++  ++++++++++++++++++ 
+ Hello ONE +  + Hello ONE + 
+ Hello TWO +  + Hello TWO + 
++++++++++++++++++  ++++++++++++++++++ 

Expected Result 

Frame1     Frame2 
++++++++++++++++++  ++++++++++++++++++ 
+ Hello ONE +  +    + 
+    +  + Hello TWO + 
++++++++++++++++++  ++++++++++++++++++ 

Так как на земле две панели окрашены таким же образом?

Примечание стороны 1: вызов super.paint() в краске() сделает пользовательские панели выглядят по-разному

Примечание стороны 2: Перемещение рамки двух другой экран, сделает его панель рисовать, как и ожидалось (только будет показан его собственный текст), тогда как другой останется прежним.

Update Этот тест был сделан на ОС Windows 8.1 и JRE 1.7

+0

Невозможно воспроизвести ваши наблюдения (может быть зависит от ОС?). Некоторые другие соображения a) создайте свой пользовательский интерфейс на EDT b) не удаляйте объект Graphics в методе рисования. c) переопределить 'paintComponent', а не' paint' – copeg

+1

Возможно, задний буфер снова используется (я не могу его воспроизвести). Вы не подчиняетесь [непрозрачному контракту] (http://stackoverflow.com/questions/2451990/setopaquetrue-false-java), поэтому сломанный рендеринг не является неожиданностью. – kiheru

+0

Вы не создаете свой пользовательский интерфейс на EDT, так что не удивительно, что происходят странные вещи. Я предлагаю вам проверить книгу/учебник о том, как использовать Swing. Это не так просто, как вы могли бы подумать вначале (то же самое случилось со мной кстати). – m0skit0

ответ

2

вызов setOpaque (ложь) на пользовательской панели или рисовать графический объект, полное содержание компонентах

Проблема с кода что он не почитает непрозрачное имущество http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#paintComponent(java.awt.Graphics).

+0

EDT - это сообщение о событии, который отправляет события компонентам и не имеет ничего общего с картиной, кроме расписания запроса. Ваше решение будет работать, но не является правильным решением (см. Мой ответ для правильного решения).Это работает, потому что логика рисования реализует, что компонент прозрачен, поэтому он смотрит на родительский компонент, пока не найдет непрозрачный компонент, затем он окрасит этот родитель, чтобы фон был правильно нарисован, и, наконец, он рисует детей. Это не очень эффективно. Не используйте прозрачность, если вам это действительно нужно. – camickr

+0

вопрос был не о эффективности. Если EDT отправляет только сообщения, то на самом деле тогда изображает материал для рисования. Я предполагаю, что это часть структуры Swing? – jannikb

+0

'вопрос был не об эффективности..' Я не говорил, что это было. Я дал вам еще одну причину, почему ваше решение было не очень хорошим. Вы не понимаете полного смысла своего решения, и я не хочу, чтобы другие люди его копировали. Просто потому, что что-то работает, не означает, что вы должны использовать этот подход, особенно когда есть простой более общий хорошо известный подход. 'Я предполагаю, что его часть рамки Swing?' Читайте статью о [Живопись в AWT и Swing] (http://www.oracle.com/technetwork/java/painting-140037.html). – camickr

0

на заказ картина делается путем переопределения метода paintComponent() (не краска()), а затем вы вызываете super.paintComponent():

@Override 
protected void paintComponent(Graphics g) 
{ 
    super.paintComponent(g); 
    // add your painting code 
} 

super.paintComponent (г) удостоверяется фон компонент окрашивается в фоновый цвет. Цвет компонента. Это очищает область любого мусора, который может быть там.

Edit:

Вы также можете прочитать раздел из свинга учебника по A Closer Look at the Paint Mechanism вы теряете функциональность этих 3 методов.

+0

Несмотря на то, что во многих ситуациях рекомендуемый подход, я явно просил ситуацию, когда super.paint не вызывается (или super.paintComponent, здесь неважно) – jannikb

+0

@yyannecc, см. Edit. – camickr

+0

Я заменил краску на PaintComponent в моем вопросе. вызов super.paintComponent, однако, не является решением, согласно определению вопроса – jannikb

Смежные вопросы