线程和按钮:如何在程序运行完毕后重新启动它

时间:2011-10-11 03:58:02

标签: java multithreading swing quicksort swingworker

我的程序直观地演示了众所周知的QuickSort算法的顺序版本,有两个新的可视化演示:(I)QuickSort的并行版本,使用低级Thread API和SwingUtilities实现,以及(II)QuickSort的并行版本,使用SwingWorker API实现。

我正试图在成功运行后重新启动程序。目前,在排序操作开始时按钮被禁用,这是正确的,但它们永远不会重新启用,所以我想知道是否有一种方法可以在成功运行后启用所有按钮?部分代码如下:

// http://www.java2s.com/Code/Java/Collections-Data-Structure/Animationforquicksort.htm
// http://www.sorting-algorithms.com/quick-sort

import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.atomic.*;

public class QuickSortVisualizer implements Runnable {
    static int LENGTH = 32;
    static int LEFT = 500;
    static int RIGHT = 500;
    static int SWAP = 1000;

    int[] Values;
    AtomicInteger WorkerThreads = new AtomicInteger();

    public static void main(String[] args) {
        try {
            if (args.length == 0) {             
                LENGTH = 32;
                LEFT = 500;
                RIGHT = 500;
                SWAP = 1000;

            } else if (args.length == 4) { 
                //dw about this



            } else {
                throw new Exception("incorrect command-line argument count"); 
            }

            System.err.format("... LENGTH=%d LEFT=%d RIGHT=%d SWAP=%d%n", LENGTH, LEFT, RIGHT, SWAP);
            SwingUtilities.invokeAndWait(new QuickSortVisualizer());
            System.err.format("... GUI started%n");

        } catch (Exception ex) {
            System.err.format("*** %s%n", ex.getMessage());
        }
    }

    JButton BoredButton;
    JButton WorkerButtonSequential;
    JButton WorkerButtonThreads;
    JButton WorkerButtonSwingWorkers;
    SorterPanel MySortPanel;
    JLabel StatusBar;

    public void run() {
        JFrame frame = new JFrame();
        frame.setTitle("My Quick Sort Visualizer");
        Font font = new Font("Monospaced", Font.BOLD, 18);

        BoredButton = new JButton("I am bored");
        BoredButton.setFont(font);
        BoredButton.setPreferredSize(new Dimension(180, 30));
        BoredButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                BoredButton_Click();
            }
        });

        WorkerButtonSequential = new JButton("QS Sequential");
        WorkerButtonSequential.setFont(font);
        WorkerButtonSequential.setPreferredSize(new Dimension(185, 30));
        WorkerButtonSequential.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonSequential_Click();
            }
        });

        WorkerButtonThreads = new JButton("QS Threads");
        WorkerButtonThreads.setFont(font);
        WorkerButtonThreads.setPreferredSize(new Dimension(185, 30));
        WorkerButtonThreads.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonThreads_Click();
            }
        });

        WorkerButtonSwingWorkers = new JButton("QS SwingWorkers");
        WorkerButtonSwingWorkers.setFont(font);
        WorkerButtonSwingWorkers.setPreferredSize(new Dimension(200, 30));
        WorkerButtonSwingWorkers.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonSwingWorkers_Click();
            }
        });

        JPanel strip = new JPanel(new FlowLayout(FlowLayout.CENTER));
        strip.add(BoredButton);
        strip.add(WorkerButtonSequential);
        strip.add(WorkerButtonThreads);
        strip.add(WorkerButtonSwingWorkers);
        frame.getContentPane().add(strip, BorderLayout.NORTH);

        StatusBar = new JLabel();
        StatusBar.setFont(font);
        StatusBar.setPreferredSize(new Dimension(800, 20));
        frame.getContentPane().add(StatusBar, BorderLayout.SOUTH);

        MySortPanel = new SorterPanel();
        frame.getContentPane().add(MySortPanel, BorderLayout.CENTER);

        frame.getRootPane().setDefaultButton(BoredButton);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 400);
        frame.setResizable(true);
        frame.setVisible(true);
    }

    public void BoredButton_Click() {
        String text = Calendar.getInstance().getTime().toString();
        StatusBar.setText(text);
        System.err.format("... now %s%n", text);
    }

    public void WorkerButtonSequential_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        System.err.format("... sequential%n");

        QSSequential();
    }

    public void WorkerButtonThreads_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        int processors = Runtime.getRuntime().availableProcessors();
        int threshold = processors * 2;
        System.err.format("... parallel threads: processors=%d threshold=%d%n", processors, threshold);
        QSThreads(threshold);
    }

    public void WorkerButtonSwingWorkers_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        int processors = Runtime.getRuntime().availableProcessors();
        int threshold = processors * 2;
        System.err.format("... parallel swingworkers: processors=%d threshold=%d%n", processors, threshold);
        QSSwingWorkers(threshold);
    }

    void QSInit() {
        Values = new int[LENGTH];
        for (int i = 0; i < Values.length; i++) {
            Values[i] = (int)Math.round(Math.random() * (MySortPanel.getHeight()-10));
        }
        print("... initial values");                

        MySortPanel.setValues(Values);      
    }

    void QSSequential() {
        QSInit();

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                QuickSortSequential qss = new QuickSortSequential(Values, 0, Values.length - 1, MySortPanel);
                System.err.format("... started%n");
                qss.run();

                DoneAll();
            }
        });
    }

    void QSThreads(int threshold) {
        QSInit();

        QuickSortThread qst = new QuickSortThread(Values, 0, Values.length - 1, threshold, MySortPanel);
        WorkerThreads.set(0);
        incWorkerThreads();
        System.err.format("... started%n");
        qst.start();
    }

    void QSSwingWorkers(int threshold) {
        QSInit();

        QuickSortWorker qsw = new QuickSortWorker(Values, 0, Values.length - 1, threshold, MySortPanel);
        WorkerThreads.set(0);
        incWorkerThreads();
        System.err.format("... started%n");
        qsw.execute();      
    }

    void print(String caption) {
        System.err.format("%s%n", caption);
        for (int i=0; i<Values.length; i++) {
            System.err.format(" %d:%d", i, Values[i]);
        }
        System.err.format("%n");
    }

    void incWorkerThreads() {
        int w = WorkerThreads.incrementAndGet();
        System.err.format("... workers=%d%n", w);
    }

    void decWorkerThreads() {
        int w = WorkerThreads.decrementAndGet();
        System.err.format("... workers=%d%n", w);
        if (w <= 0) DoneAll();
    }

    void DoneAll() {
        print("... sorted values");                 
        WorkerButtonSequential.setEnabled(true);    
        WorkerButtonThreads.setEnabled(true);       
        WorkerButtonSwingWorkers.setEnabled(true);      
        System.err.format("%n");
    }

    // === SorterPanel

    /* colour codes
    pivot : YELLOW
    left item : GREEN
    right item : BLUE
    left item just before swap : PINK
    right item just before swap : PINK
    left item just after swap : RED
    right item just after swap : RED
    */

    class SorterPanel extends JComponent {
        int[] Values;       
        int width;
        Graphics2D g2;
        Color pen;
        Color back;

        public void setValues(int[] Values) {
            this.Values = Values;
            width = super.getWidth() / Values.length;
            repaint();
        }

        @Override 
        public void paintComponent(Graphics g) {
            if (Values == null) return;

            g2 = (Graphics2D) g;
            pen = Color.BLACK; // g2.getColor();
            back = g2.getBackground();

            for (int i = 0; i < Values.length; i++) {
                g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
            }
        }

        public void mark(int i, int value, Color m) {
            g2 = (Graphics2D) super.getGraphics();
            pen = g2.getColor();
            g2.setColor(m);
            //g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, Values[i]-2));
            g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, value-2));
            g2.setColor(pen);
        }

        public void unmark(final int i, final int value) {
            mark(i, value, back);
        }

        public void erase(int i, int value) {
            g2 = (Graphics2D) super.getGraphics();
            //g2.clearRect(width*i+1, 0, width-1, Values[i]+1);
            g2.clearRect(width*i+1, 0, width-1, value+1);
        }

        public void redraw(int i, int value) {
            g2 = (Graphics2D) super.getGraphics();
            //g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
            g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, value));
            mark(i, value, back);
        }
    }

    // === QuickSort Sequential

    class QuickSortSequential implements Runnable { 
        int[] array;
        int left;
        int right;

        // === GUI stuff

        SorterPanel sortpan;

        void publish(Runnable gui_update) {
            gui_update.run();
        }

        void mark(final int idx, final Color color) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.mark(idx, value, color); 
                }
            });
        }

        void unmark(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.unmark(idx, value); 
                }
            });
        }

        void erase(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.erase(idx, value); 
                }
            });
        }

        void redraw(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.redraw(idx, value); 
                }
            });
        }

        void sleep(int period) {
            try { 
                Thread.sleep(period); 
            } catch (Exception ex) { 
                System.err.format("%s%n", ex.getMessage()); 
            }                   
        }

        // === stuff

        public QuickSortSequential(final int array[], final int left, final int right, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.sortpan = sortpan;
        }

        public void run() {
            QuickSort();
        }

        // === QuickSort stuff

        void QuickSort() {
            if (left >= right) return;
            final int pivot = Partition();
            if (pivot < 0) return;

            QuickSortSequential lquick = new QuickSortSequential(array, left, pivot-1, sortpan);
            QuickSortSequential rquick = new QuickSortSequential(array, pivot, right, sortpan);

            lquick.run();
            rquick.run();
        }

        int Partition() {
            int leftIdx = left;
            int rightIdx = right;
            int pivotIdx = (left + right) / 2;
            final int pivot = array[pivotIdx]; 

            while (true) {
                if (leftIdx > rightIdx) break;

                mark(pivotIdx, Color.YELLOW);
                mark(leftIdx, Color.GREEN);
                mark(rightIdx, Color.BLUE);
                sleep(LEFT);

                while (true) {
                    if (array[leftIdx] >= pivot) break;
                    else {
                        unmark(leftIdx);
                        leftIdx += 1;
                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.GREEN);
                        sleep(LEFT);
                    }
                }

                while (true) {
                    if (pivot >= array[rightIdx]) break;
                    else {
                        unmark(rightIdx);
                        rightIdx -= 1;
                        mark(pivotIdx, Color.YELLOW);
                        mark(rightIdx, Color.BLUE);
                        sleep(RIGHT);
                    }
                }

                unmark(pivotIdx);
                unmark(leftIdx);
                unmark(rightIdx);

                if (leftIdx <= rightIdx) {                  
                    if (leftIdx < rightIdx) {
                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.PINK);
                        mark(rightIdx, Color.PINK);
                        sleep(SWAP);

                        erase(leftIdx);
                        erase(rightIdx);

                        int temp = array[rightIdx];
                        array[rightIdx] = array[leftIdx];
                        array[leftIdx] = temp;

                        if (pivotIdx == leftIdx) pivotIdx = rightIdx;
                        else if (pivotIdx == rightIdx) pivotIdx = leftIdx;

                        redraw(leftIdx);
                        redraw(rightIdx);

                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.RED);
                        mark(rightIdx, Color.RED);
                        sleep(SWAP);

                    }

                    unmark(pivotIdx);
                    unmark(leftIdx);
                    unmark(rightIdx);

                    leftIdx += 1;
                    rightIdx -= 1;
                }
            }

            return leftIdx;
        }
    }

    // === QuickSort with Threads

    class QuickSortThread extends Thread { 
        int[] array;
        int left;
        int right;
        int threshold;

        // === GUI stuff

        SorterPanel sortpan;



        // === Thread etc stuff

        public QuickSortThread(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.sortpan = sortpan;
            this.threshold = threshold;
        }

        @Override
        public void run() {

            decWorkerThreads();
        }


    }

    // === QuickSort with SwingWorkers

    class QuickSortWorker extends SwingWorker<Boolean, Runnable> {  
        int[] array;
        int left;
        int right;
        int threshold;

        // === GUI stuff 

        SorterPanel sortpan;



        // === SwingWorker stuff

        public QuickSortWorker(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.threshold = threshold;
            this.sortpan = sortpan;

        }

        @Override
        public Boolean doInBackground() {


            return true;
        }

        @Override
        public void process(java.util.List<Runnable> gui_updates) {

        }

        @Override
        public void done() {

            decWorkerThreads();
        }


    }
}

1 个答案:

答案 0 :(得分:1)

不是直接回答你的问题,但在那里我看到了三个方面,我认为你的代码错过了

通知请阅读How to get Exception from SwingWorker