2016-05-14 20 views
1

Ich mache eine Java GUI Anwendung zu bekommen. Zum Lesen von zwei Dateitypen, die als Eingabe benötigt werden, verwende ich die Klasse SwingWorker, die die Operation in zwei verschiedenen Hintergrundthreads ausführt. Einmal sind die beiden Arten von Dateien zu lesen, gibt es eine Menge von Komponenten, die mit den Daten in der grafischen Benutzeroberfläche aktualisiert, und ein HeatMap in einen der JPanel. Diese JPanel enthält zwei JRadioButton, die beim Umschalten die zwei verschiedenen Heatmaps anzeigen sollten, die aus den beiden von der Anwendung gelesenen Dateien erhalten wurden. Ich kann die Heatmap der ersten Datei sehen, wenn der Benutzer die Datei lädt. Aber wenn ich die zweite Datei lade, wird Heatmap für die zweite Datei in nicht dargestellt (ist leer), wenn das zweite Optionsfeld aktiv ist. Gleiches passiert für die JTabbedPane, die die Unterdateien aus den beiden Dateien anzeigen. Ich benutzeJPanel mit einem bestimmten JRadioButton nicht aktualisiert, nachdem resultieren aus Swingworker Thread

imagePanel.removeAll(); 
imagePanel.add(preprocessedIntensityMap, BorderLayout.CENTER); 
panel.repaint(); 
panel.revalidate(); 

während in dem zweiten Hintergrund-Thread, um die JPanel zu aktualisieren, aber das tut nichts. Ich versuchte auch Getter und Setter-Methode für die JPanel, aber das änderte nichts. Irgendwelche Vorschläge?

Hier ist der Wettbewerbscode meiner zweiten SwingWorker Klasse:

public class PeaklistReadWorker extends SwingWorker<REXP, Object> { 

    private RConnection rc1; 
    private GUIMain guiClassObject; 
    private File fileName; 
    private JTree tree; 
    private String currentPath; 
    private REXP preprocessedSpectrumObjects; 
    private float minMzValue; 
    private float maxMzValue; 
    volatile HeatMap preprocessedIntensityMap; 
    private JLabel coordinates; 
    private JScrollPane spectralFilesScrollPane; 
    private final JPanel peakPickedFilesPanel; 
    private JTabbedPane tabbedSpectralFiles; 
    private final JLabel statusLabel; 
    private JMenuItem CGMenuItem; 
    private JMenuItem TGMenuItem; 
    private JPanel imagePanel; 
    private GenerateIntensityMap gim = new GenerateIntensityMap(); 
    private SortFile sf = new SortFile(); 
    private JDialog progressDialog; 

    public PeaklistReadWorker(GUIMain guiClassObject, File fileName, JTree tree, String currentPath, REXP 
      preprocessedSpectrumObjects, float minMzValue, float maxMzValue, HeatMap preprocessedIntensityMap, JLabel coordinates, 
           JScrollPane spectralFilesScrollPane, JPanel peakPickedFilesPanel, JTabbedPane tabbedSpectralFiles, 
           JLabel statusLabel, JMenuItem CGMenuItem, JMenuItem TGMenuItem, JPanel imagePanel, JDialog progressDialog) 
    { 
     this.guiClassObject = guiClassObject; 
     this.fileName = fileName; 
     this.tree = tree; 
     this.currentPath = currentPath; 
     this.preprocessedSpectrumObjects = preprocessedSpectrumObjects; 
     this.minMzValue = minMzValue; 
     this.maxMzValue = maxMzValue; 
     this.preprocessedIntensityMap = preprocessedIntensityMap; 
     this.coordinates = coordinates; 
     this.spectralFilesScrollPane = spectralFilesScrollPane; 
     this.peakPickedFilesPanel = peakPickedFilesPanel; 
     this.tabbedSpectralFiles = tabbedSpectralFiles; 
     this.statusLabel = statusLabel; 
     this.CGMenuItem = CGMenuItem; 
     this.TGMenuItem = TGMenuItem; 
     this.imagePanel = imagePanel; 
     this.progressDialog = progressDialog; 
    } 

    @Override 
    protected REXP doInBackground() throws Exception { 

     try { 
      rc1 = new RConnection(); 
      rc1.assign("importPreprocessedSpectra", currentPath.concat("/importPreprocessedSpectra.R")); 
      rc1.eval("source(importPreprocessedSpectra)"); 
      rc1.assign("inputFileDirectory", fileName.toString()); 
      preprocessedSpectrumObjects = rc1.eval("importPreprocessedSpectra(inputFileDirectory)"); 

      preprocessedIntensityMap = gim.generateIntensityMap(preprocessedSpectrumObjects, currentPath, minMzValue, maxMzValue, Gradient.GRADIENT_Rainbow, "PROCESSED");   
     } catch (RserveException e1) { 
      e1.printStackTrace(); 
     } catch (REXPMismatchException e1) { 
      e1.printStackTrace(); 
     } 
     return preprocessedSpectrumObjects; 
    } 

    /** 
    * Process method to take care of intermediate results - works in EDT 
    * @param chunks 
    */ 
    @Override 
    protected void process(List<Object> chunks) { 
    } 

    @Override 
    public void done() { 

     try { 
      REXP preprocessedSpectrumObjects = get(); 
      guiClassObject.returnFromBackgroundPeaklistObjects(preprocessedSpectrumObjects); 

      // list only files with .txt extension from the directory selected 
      File[] filesInDirectory = fileName.listFiles(new FilenameFilter() { 
       public boolean accept(File dir, String name) { 
        return name.toLowerCase().endsWith(".txt"); 
       } 
      }); 
      guiClassObject.setPreprocessedIntensityMap(preprocessedIntensityMap); 

      // Calls sortByNumber method in class SortFile to list the files number wise 
      filesInDirectory = sf.sortByNumber(filesInDirectory); 
      tree = new JTree(guiClassObject.addNodes(null, filesInDirectory, fileName)); 
      guiClassObject.setTree(tree); 
      DefaultMutableTreeNode firstLeaf = ((DefaultMutableTreeNode) tree.getModel().getRoot()).getFirstLeaf(); 
      tree.setSelectionPath(new TreePath(firstLeaf.getPath())); 
      guiClassObject.updateSpectralTableandChartPICKED(firstLeaf); 

      // Add a tree selection listener 
      tree.addTreeSelectionListener(new TreeSelectionListener() { 

       public void valueChanged(TreeSelectionEvent e) { 
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath().getLastPathComponent(); 
        guiClassObject.updateSpectralTableandChartPICKED(node); 
       } 
      }); 

      imagePanel.removeAll(); 
      imagePanel.add(preprocessedIntensityMap, BorderLayout.CENTER); 
      guiClassObject.panelRefresh(imagePanel); 
      coordinates.setBounds(31, 31, preprocessedIntensityMap.getWidth() - 31, preprocessedIntensityMap.getHeight() - 31); 

      preprocessedIntensityMap.addMouseListener(guiClassObject); 
      preprocessedIntensityMap.addMouseMotionListener(guiClassObject); 
      spectralFilesScrollPane.setViewportView(tree); 
      spectralFilesScrollPane.setPreferredSize(peakPickedFilesPanel.getSize()); 
      peakPickedFilesPanel.add(spectralFilesScrollPane); 
      tabbedSpectralFiles.validate(); 
      tabbedSpectralFiles.repaint(); 

      CGMenuItem.setEnabled(true); // active now 
      TGMenuItem.setEnabled(true); // active now 
      progressDialog.dispose();//close the modal dialog 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Minimal Beispiel

Dieses minimale Beispiel gar nicht einmal die imagePanel anzeigt, wo die JLabel (HeatMap im Original Code) sollte angezeigt werden. Aber das Gesamtlayout dieses Beispiels ähnelt meinem Hauptskript. Die JLabel ist in der SwingWorker Klasse selbst erzeugt und dann wird die imagePanel hinzugefügt.

import javax.swing.*; 
    import java.awt.*; 
    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 
    import java.awt.image.BufferedImage; 

    public class GuiClass { 

     public static void main(String[] args) { 
      new GuiClass(); 
     } 
     public GuiClass() { 
      EventQueue.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } catch (InstantiationException e) { 
         e.printStackTrace(); 
        } catch (UnsupportedLookAndFeelException e) { 
         e.printStackTrace(); 
        } catch (ClassNotFoundException e) { 
         e.printStackTrace(); 
        } { 
        } 
        JFrame frame = new JFrame("Testing"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.add(new TestPane()); 
        frame.pack(); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } 
      }); 
     } 

     public class TestPane extends JPanel { 

      public TestPane() { 

       final String raw = "Raw"; 
       final String preprocessed = "Preprocessed"; 

       final JRadioButton rawImage = new JRadioButton(raw, true); 
       JRadioButton peakPickedImage = new JRadioButton(preprocessed); 
       rawImage.setActionCommand(raw); 
       peakPickedImage.setActionCommand(preprocessed); 

       ButtonGroup radioButtonGroup = new ButtonGroup(); 
       radioButtonGroup.add(rawImage); 
       radioButtonGroup.add(peakPickedImage); 

       JPanel buttons = new JPanel(new 
         FlowLayout(FlowLayout.CENTER, 5, 5)); 
       buttons.add(rawImage); 
       buttons.add(peakPickedImage); 

       add(buttons, BorderLayout.SOUTH); 

       final CardLayout cl = new CardLayout(); 
       final JPanel imagePanel = new JPanel(cl); 
       imagePanel.setSize(100,100); 
       add(imagePanel); 
       imagePanel.setVisible(true); 

       ActionListener al = new ActionListener() { 
        public void actionPerformed(ActionEvent ae) { 
         if (rawImage.isSelected() && rawImage.isEnabled()) { 
          ImageCreaterRaw icr = new ImageCreaterRaw(imagePanel, raw, cl); 
          icr.execute(); 

         } else { 
          ImageCreaterPreprocessed icp = new ImageCreaterPreprocessed(imagePanel, preprocessed, cl); 
          icp.execute(); 
         } 
        } 
       }; 
       rawImage.addActionListener(al); 
       peakPickedImage.addActionListener(al); 
      } 
     } 
    } 

    class ImageCreaterRaw extends SwingWorker<Void, Void> { 

    private JPanel imagePanel; 
    // private HeatMap rawHeatMap; 
    private JLabel labelR; 
    private String raw; 
    private CardLayout cl; 

    public ImageCreaterRaw(JPanel imagePanel, String raw, CardLayout cl) 
    { 
     this.imagePanel = imagePanel; 
     this.raw = raw; 
     this.cl = cl; 

    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     double[][] data = HeatMap.generateSinCosData(200); 
     boolean useGraphicsYAxis = true; 
     // System.out.println("I am herr"); 
     // rawHeatMap = new HeatMap(data, useGraphicsYAxis, Gradient.GRADIENT_BlackToWhite); 
     labelR = new JLabel("Label for Raw"); 
     try { Thread.currentThread().sleep(3000); } 
     catch(InterruptedException e) {} 
     return null; 
    } 

    public void done() 
    { 
     // imagePanel.add(rawHeatMap, raw); 
     imagePanel.add(labelR, raw); 
     cl.show(imagePanel, raw); 
    } 
} 

// First SwingWorker Class 

class ImageCreaterPreprocessed extends SwingWorker<Void, Void> { 

    private JPanel imagePanel; 
    private JLabel labelP; 
    private String preprocessed; 
    private CardLayout cl; 

    public ImageCreaterPreprocessed(JPanel imagePanel, String preprocessed, CardLayout cl) 
    { 
     this.imagePanel = imagePanel; 
     this.preprocessed = preprocessed; 
     this.cl = cl; 
    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     double[][] data = HeatMap.generateSinCosData(200); 
     // boolean useGraphicsYAxis = true; 
     // preprocessedHeatMap = new HeatMap(data, useGraphicsYAxis, Gradient.GRADIENT_BlueToRed); 
     labelP = new JLabel("Label for Preprocessed"); 
     try { Thread.currentThread().sleep(3000); } 
     catch(InterruptedException e) {} 
     return null; 
    } 

    public void done() 
    { 
     //imagePanel.add(preprocessedHeatMap, preprocessed); 
     imagePanel.add(labelP, preprocessed); 
     cl.show(imagePanel, preprocessed); 
    } 
} 
+2

1) Für bessere Hilfe, früher, ein [MCVE] oder [kurze, selbständige, korrekte Beispiel] (http://www.sscce.org/). 2) Bitte lerne die übliche Java-Nomenklatur (Benennungskonventionen - z.B. 'EachWordUpperCaseClass',' firstWordLowerCaseMethod() ',' firstWordLowerCaseAttribute', es sei denn, es handelt sich um ein 'UPPER_CASE_CONSTANT') und benutze es konsistent. –

+2

Sie fragen: "Warum wird mein JRadioButton nicht ausgewählt, so dass meine Daten angezeigt werden?", Und dann eine Tonne Code veröffentlichen, die meisten davon völlig unabhängig von dem Problem und es für Leute schwierig, wenn nicht unmöglich machen helfen. Ich zweitens @ AndrewThompsons Empfehlung oben - vereinfachen Sie Ihren Code und Ihr Problem, indem Sie eine [mcve] oder [sscce] (http://sscce.org) erstellen und veröffentlichen. –

+2

@AndrewThompson Ja, ich bereite ein minimales Beispiel vor. Aktualisiert die Frage, sobald ich sie fertig geschrieben habe. – novicegeek

Antwort

2

Ihr Etikett oder JPanel ist zeigt wahrscheinlich, aber Sie sehen es nicht, weil die GUI Größe neu nicht, es zu werden. Ich schlage vor, dass Sie beim Start eine Dummy-Heatmap, eine leere, in das CardLayout legen, eine, die die passende Größe für die hinzugefügten Karten hat, und sie dann vom CardLayout tauschen lassen.

Beachten Sie, wenn Sie nur Bilder austauschen, dann würde ich nicht einmal ein CardLayout, sondern ein einzelnes JLabel verwenden, und dann ImageIcons einfach austauschen, das über setIcon(...) angezeigt wird.

Weitere Themen:

  • nicht Größen der Dinge festgelegt, sondern am besten, wenn Sie Komponenten selbst haben können Größe.
  • Keine Notwendigkeit setVisible(true) auf dem imagePanel JPanel zu nennen, da JPanels durch sichtbaren Standard ist.
  • besser, wenn Sie rig Ihre Swingworker das Objekt von Interesse zurückzukehren, anstatt null oder Void. Auf diese Weise können Sie get() für den Worker aufrufen, wenn dies erledigt ist, und dadurch Ausnahmen abfangen, die Ihnen sonst fehlen könnten.
  • Myself, ziehe ich es zwingende done() in meinem Swingworker viel zu vermeiden und stattdessen rig meine Swingworker mit einem PropertyChangeWorker für SwingWorker.StateValue.DONE hören. Dadurch kann ich vermeiden, GUI-Code in meinem SwingWorker zu haben, was es wiederverwendbar macht.

z.B.,

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Window; 
import java.awt.Dialog.ModalityType; 
import java.awt.Dimension; 
import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 
import java.awt.image.BufferedImage; 
import java.awt.image.DataBufferInt; 
import java.awt.image.Raster; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.util.Random; 
import java.util.concurrent.ExecutionException; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class GuiLongRunning extends JPanel { 
    public static final int IMG_W = 800; 
    public static final int IMG_H = 500; 
    BufferedImage blankImage = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB); 
    private Icon blankIcon = new ImageIcon(blankImage); 
    private JLabel imageLabel = new JLabel(blankIcon); 
    private ButtonGroup buttonGroup = new ButtonGroup(); 
    private JDialog runningDialog = null; 

    public GuiLongRunning() { 
     JPanel topPanel = new JPanel(); 
     for (ImageType imageType : ImageType.values()) { 
      JRadioButton radioButton = new JRadioButton(imageType.getName()); 
      radioButton.addItemListener(new RadioItemListener(imageType)); 
      topPanel.add(radioButton); 
      buttonGroup.add(radioButton); 
      int mnemonic = imageType.getName().charAt(0); 
      radioButton.setMnemonic(mnemonic); 
     } 

     setLayout(new BorderLayout()); 
     add(topPanel, BorderLayout.PAGE_START); 
     add(imageLabel, BorderLayout.CENTER); 
    } 

    public void workerRunning(boolean running) { 
     if (!running) { 
      if (runningDialog != null) { 
       runningDialog.dispose(); 
      } 
     } else { 
      if (runningDialog == null) { 
       JProgressBar progressBar = new JProgressBar(); 
       progressBar.setPreferredSize(new Dimension(300, 30)); 
       progressBar.setIndeterminate(true); 
       Window thisWindow = SwingUtilities.getWindowAncestor(GuiLongRunning.this); 
       runningDialog = new JDialog(thisWindow, "Creating Image", ModalityType.APPLICATION_MODAL); 
       runningDialog.add(progressBar); 
       runningDialog.pack(); 
       runningDialog.setLocationRelativeTo(thisWindow); 
      } 
      runningDialog.setVisible(true); 
     } 
    } 

    private class RadioItemListener implements ItemListener { 
     private ImageType imageType; 

     public RadioItemListener(ImageType imageType) { 
      this.imageType = imageType; 
     } 

     @Override 
     public void itemStateChanged(ItemEvent e) { 
      if (e.getStateChange() == ItemEvent.SELECTED) { 
       int w = GuiLongRunning.IMG_W; 
       int h = GuiLongRunning.IMG_H; 
       ProcessImageWorker worker = new ProcessImageWorker(imageType, w, h); 
       worker.addPropertyChangeListener(new WorkerListener()); 
       worker.execute(); 
       workerRunning(true); 
      } 
     } 
    } 

    private class WorkerListener implements PropertyChangeListener { 
     @Override 
     public void propertyChange(PropertyChangeEvent evt) { 
      if (SwingWorker.StateValue.DONE == evt.getNewValue()) { 
       ProcessImageWorker worker = (ProcessImageWorker) evt.getSource(); 
       try { 
        Icon icon = worker.get(); 
        imageLabel.setIcon(icon); 
       } catch (InterruptedException | ExecutionException e) { 
        e.printStackTrace(); 
       } 
       // delay it a little so won't call this before the dialog is 
       // visible 
       SwingUtilities.invokeLater(() -> workerRunning(false)); 
      } 
     } 
    } 

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

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

class ProcessImageWorker extends SwingWorker<Icon, Void> { 
    private static final float DELTA_H = 0.01f; 
    private static final long SLEEP_TIME = 1500; 
    private ImageType imageType; 
    private int width; 
    private int height; 
    private Random random = new Random(); 

    public ProcessImageWorker(ImageType imageType, int width, int height) { 
     this.imageType = imageType; 
     this.width = width; 
     this.height = height; 
    } 

    @Override 
    protected Icon doInBackground() throws Exception { 
     BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
     Raster raster = img.getData(); 
     DataBufferInt dataBuffer = (DataBufferInt) raster.getDataBuffer(); 
     int[][] data = dataBuffer.getBankData(); 

     if (imageType == ImageType.RAW) { 
      rawProcess(data); 
     } else if (imageType == ImageType.PREPROCESSED) { 
      colorProcess(data); 
     } 
     img.setData(raster); 
     Thread.sleep(SLEEP_TIME); // !! 

     return new ImageIcon(img); 
    } 

    private int[][] rawProcess(int[][] data) { 
     for (int i = 0; i < data.length; i++) { 
      for (int j = 0; j < data[i].length; j++) { 
       int randInt = (int) (256 * Math.random()); 
       data[i][j] = new Color(randInt, randInt, randInt).getRGB(); 
      } 
     } 
     return data; 
    } 

    // some random colors 
    private int[][] colorProcess(int[][] data) { 
     float h = 0f; 
     for (int i = 0; i < data.length; i++) { 
      float h2 = h; 
      for (int j = 0; j < data[i].length; j++) { 
       h2 += DELTA_H * random.nextFloat(); 
       h2 += 1f; 
       h2 %= 1f; 

       Color c = Color.getHSBColor(h2, 1f, 1f); 
       int randInt = c.getRGB(); 
       data[i][j] = randInt; 
      } 
     } 
     return data; 
    } 
} 

enum ImageType { 
    RAW("Raw"), PREPROCESSED("Preprocessed"); 
    private String name; 

    private ImageType(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    @Override 
    public String toString() { 
     return name; 
    } 
} 

Beachten Sie, dass der SwingWorker völlig GUI Agnostic ist.

+0

Ich habe gerade ein Bild meiner GUI hochgeladen, als ich es starte. Die Sache ist, wenn ich Daten von der ersten Datei hochlade, kann ich die 'HeatMap' in der richtigen' JPanel' sehen, ohne irgendwelche Probleme bezüglich der Größenänderung oder irgendetwas. Aber wenn ich Daten von der zweiten Datei hochlade, ist der zweite vorverarbeitete 'JRadioButton' aktiv, aber es gibt keine Heatmap, es zeigt ein leeres' JPanel' an. Ich möchte hinzufügen, dass dies nicht das Problem war, wenn ich 'SwingWorker' Threads zum Lesen der beiden Dateitypen nicht implementiert hatte. Der Bildwechsel funktionierte perfekt. – novicegeek

+0

Ich denke, es gibt ein Problem mit Variablen aus dem Hintergrund Thread an die EDT zurückgegeben, dass was ich mir vorstellen kann. – novicegeek

+0

@novicegeek: Sie müssen möglicherweise Ihre [mcve] verbessern, so dass es Ihr Problem reproduziert, da derzeit nicht. –