2017-08-20 2 views
0

J'ai une interface graphique (sur son fil EDT) et un autre thread appelé « Recorder » créé par eventListener de l'interface graphique si un bouton est pressé:passage d'informations entre EDT et autres threads Java avec un gestionnaire

if(actionEvent.getSource().equals(ui.record)) { 
    if(recorderThread == null) { 
     recorder = new Recorder(); 
     recorderThread = new Thread(recorder); 
     recorderThread.start(); 
    } 
} 

En le même écouteur d'événement, j'ai également implémenté un mouseListener.

public void mouseReleased(MouseEvent mEvent) { 
    int x, y; 

    x = mEvent.getXOnScreen(); 
    y = mEvent.getYOnScreen(); 
} 

Je veux transmettre ces variables X et Y à mon objet enregistreur dans mon fil enregistreur lorsque la souris est cliqué. Je pense que je peux casser une solution avec des variables volatiles, mais j'ai lu quelque part que les gestionnaires peuvent être utilisés pour transmettre des informations ou invoquer des méthodes entre deux threads, et était intéressé à apprendre à ce sujet. J'ai trouvé this previous post qui a fait face à un problème similaire au mien.

La solution à la poste, cependant, m'a tout à fait embrouillé. Je pense que la personne passe les objets de fil dans le gestionnaire, de cette façon tout fil peut simplement appeler tous les objets à l'intérieur de ce gestionnaire? Par exemple:

handler(someObj); 

puis dans un autre thread

handler.getSomeObj().methodInObj(); 

Mais je ne suis pas tout à fait sûr que ce soit la façon dont fonctionnent les gestionnaires. En outre, ils semblent également traiter du thread d'arrière-plan de Swing au lieu d'un thread séparé que l'utilisateur crée (si c'est le même concept, des excuses à l'avance). Enfin, la solution semble avoir appelé une classe Handler intégrée à la bibliothèque Java, alors que je veux écrire ma propre classe de gestionnaire pour mieux apprendre comment les threads communiquent (puisque je suis un programmeur très novice enseigné par youtube) . Si quelqu'un peut m'aider, ce serait grandement apprécié. Merci d'avance!

+0

Qu'est-ce exactement Recorder fait en arrière-plan pendant que votre interface graphique est en marche? Quelles activités a-t-il en cours? –

+0

En outre, vous n'envoyez jamais d'informations entre * threads * mais plutôt entre * objects *, une distinction subtile mais très importante. –

+0

Merci pour la clarification! L'enregistreur crée simplement une liste d'objets appelés "Point" qui stockent les positions X et Y du clic de souris, à utiliser plus tard par un autoclicker. – Jeff

Répondre

2

Différencier entre le concept de fil d'une part et le concept de classes (y compris les instances avec leurs membres) d'autre part.

Les threads peuvent communiquer de différentes manières (c'est-à-dire lire ou écrire des variables à un endroit pouvant être écrit ou lu par d'autres threads.) Dans votre exemple, votre classe Recorder exposerait une méthode publique addCoordinates(). un membre de liste privée où sont stockées les coordonnées ajoutées Le véritable problème est l'accès synchronisé à cette liste: Vous devez vous assurer qu'aucun thread ne lit la liste alors que l'autre thread ajoute un nouvel enregistrement - en même temps. est d'avoir une liste synchronisée:

private List<Coordinates> myCoordinates = Collections.synchronizedList(new ArrayList<>()); 

public void addCoordinates(Coordinates coordinates) 
{ 
    // this runs in the context of your GUI thread 
    myCoordinates.add(coordinates); 
    synchronized(this) 
    { 
     this.notify(); // wakes up the recorder thread 
    } 

} 

public void run() 
{ 
    // this runs in the context of the Recorder thread 
    while (true) 
    { 
     synchronized(this) 
     { 
      this.wait(); // waits until the 'this' is notified 
     } 

     for(Coordinates c : myCoordinates) 
     { 
      // do something 
     } 
    } 
} 
2

l'enregistreur crée simplement une liste d'objets appelés « point » qui stockent les X et la position Y du mouseclick, à utiliser plus tard par un autoclicker

Ensuite, l'enregistreur ne doit pas être en cours d'exécution dans son propre thread, car il n'y a pas besoin de le faire, et au lieu que vous écrirons simplement à l'enregistreur directement à partir du GUI sur le fil EDT. Sinon, vous compliquez énormément les choses. L'exception est si Recorder en fait plus, par exemple en cours d'exécution d'un processus externe.

Par exemple:

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class TestRecorder extends JPanel { 
    private static final int GAP = 3; 
    private MyRecorder myRecorder = new MyRecorder(); 
    private boolean recording = false; 

    public TestRecorder() { 
     JPanel btnPanel = new JPanel(new GridLayout(1, 0, GAP, 0)); 
     btnPanel.add(new JButton(new StartAction("Start"))); 
     btnPanel.add(new JButton(new StopAction("Stop"))); 
     btnPanel.add(new JButton(new ShowAction("Show"))); 

     addMouseListener(new MyMouse()); 
     setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP)); 
     setPreferredSize(new Dimension(500, 400)); 
     setLayout(new BorderLayout()); 
     add(btnPanel, BorderLayout.PAGE_END); 
    } 

    private class MyMouse extends MouseAdapter { 
     @Override 
     public void mousePressed(MouseEvent e) { 
      if (recording) { 
       myRecorder.addPoint(e.getPoint()); 
      } 
     } 
    } 

    private class StartAction extends AbstractAction { 
     public StartAction(String name) { 
      super(name); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      recording = true; 
     } 
    } 

    private class StopAction extends AbstractAction { 
     public StopAction(String name) { 
      super(name); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      recording = false; 
     } 
    } 

    private class ShowAction extends AbstractAction { 
     public ShowAction(String name) { 
      super(name); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println("Points:"); 
      for (Point point : myRecorder.getPoints()) { 
       System.out.println(point); 
      } 
      System.out.println(); 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 

    private static void createAndShowGui() { 
     TestRecorder mainPanel = new TestRecorder(); 
     JFrame frame = new JFrame("TestRecorder"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 
} 

public class MyRecorder { 
    private List<Point> points = new ArrayList<>(); 

    public List<Point> getPoints() { 
     return points; 
    } 

    public void addPoint(Point p) { 
     points.add(p); 
    } 
} 
+0

Merci pour la réponse! Ouais je me suis rendu compte qu'après avoir été privé de sommeil et de rage pour essayer de comprendre les fils -.- La chose était que je voulais aussi copier le même processus sur mon thread autoclicker qui utilise la classe de robot, et qui aurait certainement besoin son propre fil. J'ai juste choisi d'utiliser l'enregistreur comme exemple car c'est beaucoup plus simple et n'encombre pas la question. Merci encore pour l'aide! – Jeff

+0

Peut-être que je devrais juste le fusionner avec l'objet robot à la place? De cette façon, la liste créée par l'enregistreur peut être directement accessible par le robot sans autre passage compliqué de listes et de variables. * sidenote: remarqué que vous êtes le mec qui a été extrêmement utile dans presque toutes les questions que j'ai posté, alors je voulais juste donner un SO spécial et merci (: – Jeff

+1

@Crumble: vous faites une grosse erreur débutant, objet confus avec du fil Votre autoclicker est un objet, il peut s'exécuter sur un thread, et certaines méthodes peuvent s'exécuter sur un thread différent Lorsque vous passez des informations dans l'autoclicker, vous ne les passez pas dans un thread, mais dans l'objet et généralement s'il vient de l'interface graphique, il entrera dans l'objet autoclicker sur le fil de l'événement Swing –