banryu79
10-02-2010, 18:21
Salve,
cerco lumi per capire una cosa che da solo non riesco bene a spiegarmi.
Stavo esercitandomi nell'uso di javax.swing.SwingWorker (fin'ora mi sono sempre smazzato la gestione dei thread per i "task" in Swing "a mano" cioè con l'uso di SwingUtilities.invokeLater e tonnellate di codice [error prone], che probabilmente potrei risparmiarmi) implementando con esso un task che, mentre genera i primi N numeri primi, li stampa in una text area.
Alla fine il task proietta pure una dialog che mostra il tempo impiegato nell'eseguire se stesso.
Il task (uno SwingWorker) ha un riferimeto alla JTextArea della gui, per poterci appendere ogni singolo numero primo calcolato.
Quando deve visualizzare la dialog che mostra il tempo trascorso, lo fa invocando uno dei metodi 'showMessageDialog' di JOptionPane, passando come parametro 'parentComponent' il riferimento alla text area.
Mi aspettavo che la dialog venisse mostrata centrata sul JFrame della mia gui (la text area riferita si trova la dentro :stordita:) ma pare di no: o meglio, viene centrata solo sulle ascisse, ma non sulle ordinate.
Ecco il codice:
package swingworker;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
* SwingWorker example: find first N prime numbers updating a JTextArea during computation.
* @author francesco
*/
@SuppressWarnings("serial")
public class PrimeNumbers
{
JFrame frame;
JTextArea area;
PrimeNumberTask task;
public PrimeNumbers()
{
frame = new JFrame("Brute force prime number finder.");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
area = new JTextArea(15, 33);
area.setEditable(false);
JScrollPane centralPane = new JScrollPane(area);
frame.add(centralPane, BorderLayout.CENTER);
JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
SpinnerNumberModel model = new SpinnerNumberModel(10000,1000,100000,500);
final JSpinner spinner = new JSpinner(model);
JLabel label1 = new JLabel("Find first");
JLabel label2 = new JLabel("prime numbers");
final JButton doButton = new JButton("Do action!");
doButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int N = (Integer) spinner.getValue();
task = new PrimeNumberTask(area, N);
task.addPropertyChangeListener(new TaskListener(doButton));
task.execute(); // on a worker thread
}
});
JButton popButton = new JButton("Pop up!");
popButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Popped up!\nSwing is very responsive, if used well");
}
});
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
area.setText("");
}
});
southPanel.add(label1);
southPanel.add(spinner);
southPanel.add(label2);
southPanel.add(clearButton);
southPanel.add(popButton);
southPanel.add(doButton);
frame.add(southPanel, BorderLayout.SOUTH);
}
private void showUp()
{
SwingUtilities.invokeLater(new Runnable(){
public void run() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static void main(String... argv)
{
PrimeNumbers application = new PrimeNumbers();
application.showUp();
}
class TaskListener implements PropertyChangeListener
{
final JButton button;
TaskListener(JButton b) {
button = b;
}
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())
&& task.getState() == SwingWorker.StateValue.STARTED) {
button.setEnabled(false);
}
if ("state".equals(evt.getPropertyName())
&& task.getState() == SwingWorker.StateValue.DONE) {
button.setEnabled(true);
}
}
}
}
/*
* this is the task (subclass SwingWorker) that:
* 1] computes the prime numbers.
* 2] print each computed prime in a text area.
* 3] when finished show a pop up dialog with time elapesed
*/
final class PrimeNumberTask extends SwingWorker<List<Integer>, Integer>
{
final JTextArea texArea;
final int N;
private boolean finished;
private List<Integer> numbers;
private long startTime;
public PrimeNumberTask(JTextArea textArea, int n) {
this.texArea = textArea;
this.N = n;
finished = false;
numbers = new ArrayList<Integer>(n);
// HOMO ERECTUS DEBUG STRATEGY:
System.out.println(""+textArea.getParent());//JViewport
System.out.println(""+textArea.getParent().getParent());//JScrollPane
System.out.println(""+textArea.getParent().getParent().getParent());//JPanel
System.out.println(""+textArea.getParent().getParent().getParent().getParent());//JLayeredPane
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent());//JRootPane
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent().getParent());//JFrame
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent().getParent().getParent());//null
}
@Override
protected List<Integer> doInBackground() throws Exception
{
startTime = System.nanoTime()/1000000;
while(!finished && !isCancelled()) {
int number = nextPrime();
publish(number);
}
return numbers;
}
@Override
protected void process(List<Integer> chunks)
{
for (int number : chunks) {
texArea.append(String.valueOf(number)+"\n");
}
}
@Override
public void done()
{
long elapsedTime = (System.nanoTime()/1000000) - startTime;
JOptionPane.showMessageDialog(texArea, "Founded first "+N+" primes in "+elapsedTime+" millisec.");
}
private int nextPrime()
{
int prime;
if (numbers.size() > 0) {
prime = numbers.get(numbers.size()-1);
}
else {
prime = 0;
}
boolean found = false;
while (!found) {
prime++;
found = isPrime(prime);
}
numbers.add(prime);
// abbiamo finito?
finished = (numbers.size()==N);
return prime;
}
private boolean isPrime(int candidate)
{
// caso zero
if (candidate == 0) {
return false;
}
// caso numero uno
if (candidate == 1) {
return true;
}
// brute force:
int div = 2;
while (candidate%div != 0) {
div++;
}
return div == candidate;
}
}
Ed ecco il risultato sul mio pc:
http://www.freeimagehosting.net/uploads/18ddd18c7b.png
Qualcuno sa quale è il problema?
cerco lumi per capire una cosa che da solo non riesco bene a spiegarmi.
Stavo esercitandomi nell'uso di javax.swing.SwingWorker (fin'ora mi sono sempre smazzato la gestione dei thread per i "task" in Swing "a mano" cioè con l'uso di SwingUtilities.invokeLater e tonnellate di codice [error prone], che probabilmente potrei risparmiarmi) implementando con esso un task che, mentre genera i primi N numeri primi, li stampa in una text area.
Alla fine il task proietta pure una dialog che mostra il tempo impiegato nell'eseguire se stesso.
Il task (uno SwingWorker) ha un riferimeto alla JTextArea della gui, per poterci appendere ogni singolo numero primo calcolato.
Quando deve visualizzare la dialog che mostra il tempo trascorso, lo fa invocando uno dei metodi 'showMessageDialog' di JOptionPane, passando come parametro 'parentComponent' il riferimento alla text area.
Mi aspettavo che la dialog venisse mostrata centrata sul JFrame della mia gui (la text area riferita si trova la dentro :stordita:) ma pare di no: o meglio, viene centrata solo sulle ascisse, ma non sulle ordinate.
Ecco il codice:
package swingworker;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
* SwingWorker example: find first N prime numbers updating a JTextArea during computation.
* @author francesco
*/
@SuppressWarnings("serial")
public class PrimeNumbers
{
JFrame frame;
JTextArea area;
PrimeNumberTask task;
public PrimeNumbers()
{
frame = new JFrame("Brute force prime number finder.");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
area = new JTextArea(15, 33);
area.setEditable(false);
JScrollPane centralPane = new JScrollPane(area);
frame.add(centralPane, BorderLayout.CENTER);
JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
SpinnerNumberModel model = new SpinnerNumberModel(10000,1000,100000,500);
final JSpinner spinner = new JSpinner(model);
JLabel label1 = new JLabel("Find first");
JLabel label2 = new JLabel("prime numbers");
final JButton doButton = new JButton("Do action!");
doButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int N = (Integer) spinner.getValue();
task = new PrimeNumberTask(area, N);
task.addPropertyChangeListener(new TaskListener(doButton));
task.execute(); // on a worker thread
}
});
JButton popButton = new JButton("Pop up!");
popButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Popped up!\nSwing is very responsive, if used well");
}
});
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
area.setText("");
}
});
southPanel.add(label1);
southPanel.add(spinner);
southPanel.add(label2);
southPanel.add(clearButton);
southPanel.add(popButton);
southPanel.add(doButton);
frame.add(southPanel, BorderLayout.SOUTH);
}
private void showUp()
{
SwingUtilities.invokeLater(new Runnable(){
public void run() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static void main(String... argv)
{
PrimeNumbers application = new PrimeNumbers();
application.showUp();
}
class TaskListener implements PropertyChangeListener
{
final JButton button;
TaskListener(JButton b) {
button = b;
}
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())
&& task.getState() == SwingWorker.StateValue.STARTED) {
button.setEnabled(false);
}
if ("state".equals(evt.getPropertyName())
&& task.getState() == SwingWorker.StateValue.DONE) {
button.setEnabled(true);
}
}
}
}
/*
* this is the task (subclass SwingWorker) that:
* 1] computes the prime numbers.
* 2] print each computed prime in a text area.
* 3] when finished show a pop up dialog with time elapesed
*/
final class PrimeNumberTask extends SwingWorker<List<Integer>, Integer>
{
final JTextArea texArea;
final int N;
private boolean finished;
private List<Integer> numbers;
private long startTime;
public PrimeNumberTask(JTextArea textArea, int n) {
this.texArea = textArea;
this.N = n;
finished = false;
numbers = new ArrayList<Integer>(n);
// HOMO ERECTUS DEBUG STRATEGY:
System.out.println(""+textArea.getParent());//JViewport
System.out.println(""+textArea.getParent().getParent());//JScrollPane
System.out.println(""+textArea.getParent().getParent().getParent());//JPanel
System.out.println(""+textArea.getParent().getParent().getParent().getParent());//JLayeredPane
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent());//JRootPane
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent().getParent());//JFrame
System.out.println(""+textArea.getParent().getParent().getParent().getParent().getParent().getParent().getParent());//null
}
@Override
protected List<Integer> doInBackground() throws Exception
{
startTime = System.nanoTime()/1000000;
while(!finished && !isCancelled()) {
int number = nextPrime();
publish(number);
}
return numbers;
}
@Override
protected void process(List<Integer> chunks)
{
for (int number : chunks) {
texArea.append(String.valueOf(number)+"\n");
}
}
@Override
public void done()
{
long elapsedTime = (System.nanoTime()/1000000) - startTime;
JOptionPane.showMessageDialog(texArea, "Founded first "+N+" primes in "+elapsedTime+" millisec.");
}
private int nextPrime()
{
int prime;
if (numbers.size() > 0) {
prime = numbers.get(numbers.size()-1);
}
else {
prime = 0;
}
boolean found = false;
while (!found) {
prime++;
found = isPrime(prime);
}
numbers.add(prime);
// abbiamo finito?
finished = (numbers.size()==N);
return prime;
}
private boolean isPrime(int candidate)
{
// caso zero
if (candidate == 0) {
return false;
}
// caso numero uno
if (candidate == 1) {
return true;
}
// brute force:
int div = 2;
while (candidate%div != 0) {
div++;
}
return div == candidate;
}
}
Ed ecco il risultato sul mio pc:
http://www.freeimagehosting.net/uploads/18ddd18c7b.png
Qualcuno sa quale è il problema?