Question

Je l'ai utilisé l'approche suivante pour créer des composants et des valeurs de retour de Swing / de l'extérieur du EDT. Par exemple, la méthode suivante pourrait être une extension JFrame, pour créer un JPanel et l'ajouter à la JFrame mère:

public JPanel threadSafeAddPanel() {

    final JPanel[] jPanel = new JPanel[1];

    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }

    return jPanel[0];
}

Le tableau 1 la longueur locale est utilisée pour transférer le « résultat » à l'intérieur du Runnable, qui est appelé dans le EDT. Eh bien, il semble « un peu » aki, et donc mes questions:

  1. Est-ce que ce sens? Quelqu'un est-il en train de faire autre chose comme ça?
  2. Est-ce le tableau 1 longueur une bonne façon de transférer le résultat?
  3. Y at-il un moyen plus facile de le faire?
Était-ce utile?

La solution

  • Avaler exceptions sans même les connecter: mauvais !! - vous vous déteste quand vous tombez sur quelque chose comme ça après 2 heures bug chasse
  • Non, le tableau n'est pas une bonne façon; pour une chose, il offre pas de méthode facile pour le code appelant à attendre le fil EDT pour exécuter le Runnable avant de récupérer le résultat
  • Il y a une classe conçue explicitement pour ce genre de chose:

Autres conseils

Bien que cette méthode peut donner un sens dans certaines situations, il sera inutile la plupart du temps.

La raison en est que la création de la plupart (sinon la totalité) de vos composants existeront toujours de l'EDT, à la suite d'une action de l'utilisateur (élément de menu ou le bouton cliqué) qui sont toujours exécuté à partir du EDT.

Dans le cas où vous avez un grand travail à effectuer avant de créer votre panneau et vous ne voulez pas bloquer l'EDT, alors vous devriez, comme suggéré par quelqu'un d'autre, utilisez SwingWorker ou un cadre Swing qui offrent un soutien pour les tâches longues ( généralement basé sur SwingWorker en interne de toute façon, mais pas nécessairement).

En ce qui concerne votre question 2, malheureusement, vous n'avez pas beaucoup de façons de le faire:

  • Utilisez un tableau 1 élément que vous avez fait, c'est le plus facile, mais aussi la solution la plus laide
  • Créer une classe ItemHolder (voir ci-dessous) qui fait presque la même chose, nécessite un peu plus de travail et est propre, à mon avis
  • Enfin, l'utilisation java.util.concurrent (installations futures et remboursables par anticipation); ce serait le cleaniest je pense, mais aussi il faut le plus d'efforts

Voici, simplifié, la classe ItemHolder:

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
  1. a) Il est logique. b) pas que je connais.
  2. aussi bon que.
  3. Créer les JPanel en dehors de l'appel invokeAndWait

// Cette ligne ajoutée pour apaiser démarquage

public JPanel threadSafeAddPanel() {
    final JPanel jPanel = new JPanel();
    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                add(jPanel);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }
    return jPanel;
}

Vous pouvez facilement vérifier si le thread courant est l'EDT, puis d'exécuter correctement et plus simplement dans ce contexte. Quant à l'utilisation du tableau final pour obtenir la valeur de retour, qui est la façon la plus simple lorsque vous devez utiliser une classe interne anonyme comme celui-ci.

public JPanel threadSafeAddPanel() throws InterruptedException, 
        InvocationTargetException {
    if (EventQueue.isDispatchThread()) {
        JPanel panel = new JPanel();
        add(panel);

        return panel; 
    } else {
        final JPanel[] jPanel = new JPanel[1];
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });

        return jPanel[0];
    }
}
scroll top