2011-12-04

Ultimate Swing, Teil 5

Wenn jemand einen Blogpost mit einer scheinbar leicht zu beantwortenden Frage beendet, ist es fast schon offensichtlich, dass die Antwort nicht wie erwartet ausfällt. Natürlich ist es keine gute Idee, Swing-Anwendungen ausschließlich auf dem EDT ablaufen zu lassen. Sehen Sie sich hierzu das folgende Programm an:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

@SuppressWarnings("serial")
public class Bad extends JFrame {

  public Bad() {
    super("So besser nicht");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    JPanel cp = new JPanel(new BorderLayout());
    cp.add(new JLabel(
        "bitte das Fenster nach Belieben vergrößern und verkleinern"),
        BorderLayout.NORTH);
    cp.add(new JPanel() {
      @Override
      protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.drawLine(0, 0, getWidth() - 1, getHeight() - 1);
        g.drawLine(0, getHeight() - 1, getWidth() - 1, 0);
      }
    }, BorderLayout.CENTER);
    final JButton button = new JButton("Hintergrundaktion durchführen");
    button.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        button.setEnabled(false);
        try {
          Thread.sleep(10000);
        } catch (InterruptedException e1) {
        }
        button.setEnabled(true);
      }
    });
    cp.setPreferredSize(new Dimension(400, 300));
    cp.add(button, BorderLayout.SOUTH);
    setContentPane(cp);
    pack();
    setLocationRelativeTo(null);
  }

  public static void main(String[] args) {
    Toolkit.getDefaultToolkit().setDynamicLayout(true);
    new Bad().setVisible(true);
  }
}

Wenn Sie es starten, erscheint das in der folgenden Abbildung dargestellte Fenster.

Screenshot des Programms Bad
Screenshot des Programms Bad

Spielen Sie bitte mit dem Fenster, indem Sie seine Größe verändern. Das rote Kreuz passt sich recht flott an die neuen Ausmaße an. Allerdings nur, bis Sie die Schaltfläche am unteren Rand anklicken. Danach passiert 10 Sekunden lang gar nichts mehr. Selbst das Anklicken des Schließen-Knopfes zeigt in dieser Zeit keine Wirkung. Was passiert hier?

Die entscheidende Zeile ist Thread.sleep(10000);. Diese Anweisung sorgt dafür, dass der aktuelle Thread schlafen gelegt wird. Da Swing, wie Sie wissen, eine single threaded library ist, ist diese Auszeit sozusagen umfassend. Deshalb wird nichts gezeichnet und auch ein etwaiges Klicken auf das Schließen-Feld wird nicht weitergeleitet. Ich behaupte, zu einem großen Teil geht der schlechte Ruf von Swing auf die über viele Jahre lang praktizierte falsche Nutzung zurück. Entschuldigend muss aber angemerkt werden, dass Sun sich lange sehr schwer getan hat, wirkliche Best Practices für Swing zusammenzustellen.

Die Anweisung Toolkit.getDefaultToolkit().setDynamicLayout(true); ist übrigens unter modernen Java-Versionen unnötig. Ich habe sie nur der Vollständigkeit halber eingefügt. Sie müssen sie in Ihren Programmen nicht verwenden.

Nachtrag: Ich weiß bei Blogger nie so genau, ob meine Antworten auf Kommentare den Lesern angezeigt werden. Wenn Sie mir geschrieben haben, schauen Sie doch ein paar Tage später bei den Kommentaren ruhig mal nach.

2 comments:

  1. Gegen das Blogger-Problem gibt's eine einfache Abhilfe: Einfach nicht mehr moderieren :) Ich weiß, du magst das nicht, aber es wäre die naheliegendste Lösung :)

    ReplyDelete
  2. > Ich weiß, du magst das nicht,
    > aber es wäre die naheliegendste Lösung :)

    Naja, "nicht mögen" trifft es nicht ganz; das Problem sehe ich einfach darin, dass mich unmoderierte Kommentare ziemlich in die Bredouille bringen könnten - selbstverständlich nicht durch meine Stammleser; aber leider kann auch ein zufällig vorbei surfender Spaßvogel Schaden anrichten.

    ReplyDelete