从SwingWorker线程获取结果后,带有特定JRadioButton的JPanel不会更新 [英] JPanel with a specific JRadioButton does not update after getting result from SwingWorker thread

查看:125
本文介绍了从SwingWorker线程获取结果后,带有特定JRadioButton的JPanel不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在申请Java GUI.为了读取作为输入所需的两种类型的文件,我正在使用SwingWorker类,该类在两个不同的后台线程中执行操作.一旦读取了两种类型的文件,就会有很多组件在GUI中使用数据和JPanel之一中的HeatMap进行更新.该JPanel包含两个JRadioButton,它们在切换时应显示从应用程序读取的两个文件获得的两个不同的热图.当用户加载文件时,我可以看到第一个文件的热图.但是,当我加载第二个文件时,第二个单选按钮处于活动状态时,第二个文件的热图未显示(为空).对于显示两个文件中的子文件的JTabbedPane,也会发生相同的情况.我用

I am making a Java GUI application. For reading two types of files required as an input, I am using the SwingWorkerclass which performs the operation in two different background threads. Once, the two types of files are read, there are a lot of components which get updated in the GUI with data and a HeatMap in one of the JPanel. This JPanel contains two JRadioButton, which on switching should display the two different heat maps obtained from the two files read by the application. I can see the heatmap of the first file when the user loads the file. But when I load the second file, heatmap for the second file in not represented (is empty) when the second radio button is active. Same happens, for the JTabbedPane which display the sub files from the two files. I use

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

同时在第二个后台线程中更新JPanel,但这无济于事.我也尝试了JPanel的getter和setter方法,但这并没有改变.有什么建议吗?

while in the second background thread to update the JPanel, but this does nothing. I also tried getter and setter method for the JPanel but this did not change things. Any suggestions?

这是我第二个SwingWorker类的竞赛代码:

Here is the compete code of my second SwingWorker class:

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();
        }
    }
}

最小示例

这个最小的示例甚至根本不显示imagePanel,应该在其中显示JLabel(原始代码中的HeatMap).但是,此示例的总体布局与我的主脚本相似. JLabel是在SwingWorker类本身中生成的,然后添加到imagePanel中.

This minimal example does not even display the imagePanel at all, where the JLabel (HeatMap in the original code) should be displayed. But, the overall layout of this example is similar to my main script. The JLabel is generated in the SwingWorker class itself and then is added to the imagePanel.

    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);
    }
}

推荐答案

您的标签或JPanel 可能会显示,但您没有看到它,因为GUI不会调整大小以适应它.我建议您在启动时在CardLayout中放置一个虚拟的热图,一个空白的热图,一个适合于所添加图的大小的热图,然后让CardLayout交换它们.

Your label or JPanel is likely showing up, but you're not seeing it because the GUI does not re-size to accommodate it. I suggest that you place a dummy heat map, a blank one into the CardLayout at start up, one that is the appropriate size for the added maps, and then let the CardLayout swap them.

请注意,如果您要做的只是交换图像,那么我什至不使用CardLayout而是使用一个JLabel,然后只需交换通过setIcon(...)显示的ImageIcons.

Note if all you're doing is swapping images, then I wouldn't even use a CardLayout but rather a single JLabel, and then simply swap ImageIcons that it displays via setIcon(...).

其他问题:

  • 不要设置事物的大小,但是如果您可以自己设置组件的大小,那最好.
  • 由于在默认情况下,JPanel是可见的,因此无需在imagePanel JPanel上调用setVisible(true).
  • 最好将您的SwingWorker绑定为返回感兴趣的对象,而不是返回null或Void.这样,您可以在工作程序完成后在其上调用get(),从而捕获否则可能会丢失的异常.
  • 我自己,我更希望避免在SwingWorker中覆盖done(),而是使用PropertyChangeWorker来监听SwingWorker.StateValue.DONE来绑定我的SwingWorker.这使我避免在SwingWorker中包含GUI代码,从而使其更可重用.
  • Don't set sizes of things but rather best if you can have components size themselves.
  • No need to call setVisible(true) on the imagePanel JPanel since JPanels are by default visible.
  • Better if you rig your SwingWorker to return the object of interest rather than null or Void. This way you can call get() on the worker when its done, and thereby catch exceptions that you otherwise could be missing.
  • Myself, I much prefer to avoid overriding done() in my SwingWorker and instead rig my SwingWorker with a PropertyChangeWorker listening for SwingWorker.StateValue.DONE. This allows me to avoid having GUI-code within my SwingWorker, making it more re-usable.

例如

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;
    }
}

请注意,SwingWorker完全与GUI无关.

Note that the SwingWorker is completely GUI agnostic.

这篇关于从SwingWorker线程获取结果后,带有特定JRadioButton的JPanel不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆