ProgressMonitor i watki

0

Witam
Mam taki problem:
stworzylem klase dziedziczaca po JDialog i posiadajaca funkcjonalnosc ProgressMonitor.
jednym slowem okienko pokazuje mi stan odczytu/zapisu z pliku.
taki odczyt/zapis z jasnych przyczyn umieszczony jest w watku, gdyz w innym wypadku nie nastepuje odswierzenie komponentow.
lecz jest maly problem - chce aby dalsze wykonanie programu nastapilo dopiero gdy watek sie zakonczy.
Probowalem juz wait(), join(), while(thread.isAlive()); - wszystko skutkuje zwieszeniem programu lub w najlepszym wypadku okienko dialogowe jest cale szare i pod koniec sie zamyka, lecz postep nie jest widoczny.
I tu moje pytanie - jak zatrzymac wateg glowny programu, tak aby nie zatrzymywac watku AWT (lub umieszczajac JDialog w jakims innym watku ktory bedzie to repaint()'owal)?

pozdrawiam

0

Włącz okno dialogowe w tryb modalny setModal(true). Dzięki temu nie będzie możliwe przejście do głównego okna aplikacji bez jego zamknięcia.

0

Odpada - przeciez metoda zmiany postepu wywolywana jest z watku. Efekt - zanim okienko nie zostanie zamkniete - plik nie jest wczytywany (a wiadomo ze okienko zamyka sie po wczytaniu z pliku ;))
Pewnie moznaby zrobic osobne okienko do wczytywania danych A, osobne do B i takie same do ich zapisu (aby caly proces odbywal sie w modalnym okienku), ale preferowalbym po prostu jedna klase z metoda setProgress()...

pozdrawiam

0
eximius napisał(a)

Odpada - przeciez metoda zmiany postepu wywolywana jest z watku.
A w czym to przeszkadza?

eximius napisał(a)

Efekt - zanim okienko nie zostanie zamkniete - plik nie jest wczytywany (a wiadomo ze okienko zamyka sie po wczytaniu z pliku ;))
Nie widzę problemu. Trzeba tylko odpowienio połączyć wątek z progressem. Wydaje się, że tryb modalny jest jedynym sensownym rozwiązaniem.

0

pozwole sobie wkleic troche kodu:

public class ProgressDialog extends JDialog{
	private static final long serialVersionUID = 4682348576951695187L;
	private long destination;
	private JProgressBar progressBar;
	private JButton cancel;
	private boolean disposed;
	protected ProgressDialog(JFrame frame,String title,long destination){
		super(frame);
		setTitle("Postep...");
		Toolkit tool=Toolkit.getDefaultToolkit();
		setSize(300,100);
		setLocation(tool.getScreenSize().width/2-150,tool.getScreenSize().height/2-50);
		//setModal(true);
		setResizable(false);
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		this.destination=destination;
		disposed=false;
		setLayout(new GridLayout(3,1));
		Box labelBox=Box.createHorizontalBox();
		labelBox.add(Box.createGlue());
		labelBox.add(new JLabel(title));
		labelBox.add(Box.createGlue());
		add(labelBox);
		progressBar=new JProgressBar(0,100);
		progressBar.setStringPainted(true);
		add(progressBar);
		cancel=new JButton("Anuluj");
		cancel.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				disposed=true;
				dispose();
			}
		});
		add(cancel);
		setAlwaysOnTop(true);
		setVisible(true);
	}
	public void setProgres(long progress){
		progressBar.setValue((int)(progress*100/destination));
		repaint();
		if (progressBar.getValue()==100){
			disposed=true;
			dispose();
		}
	}
	public boolean isDisposed(){
		return disposed;
	}
}

To jest klasa odpowiedzialna za okienko z postepem, natomiast to:

public void loadFromFile() throws MyException{
try {
final FileInputStream fstream=new FileInputStream("test");
final ObjectInputStream in= new ObjectInputStream(fstream);
final Thread mainThread=Thread.currentThread();
products=new TreeSet<Product>();
ProgressDialog prg;
final Thread thread=new Thread(){
public void run(){
try {
	long available=fstream.available();
	ProgressDialog prg=null;
	if (available>0)
	prg=new ProgressDialog(null,"Wczytywanie",available);
	while(fstream.available()>0&&!prg.isDisposed()){
		products.add((Product)in.readObject());
		prg.setProgres(available-fstream.available());
		//	sleep(10);
	}
	in.close();
	//	synchronized(this) {mainThread.notify();}
	// 	} catch (InterruptedException e) {
} catch (IOException e) {e.printStackTrace();
} catch (ClassNotFoundException e) {e.printStackTrace();
//	} catch (InterruptedException e) {e.printStackTrace();
}
//mainThread.notifyAll();
}
};
thread.setDaemon(true);
thread.run();			
//     mainThread.wait(1000);
//     thread.join();
//	synchronized (this) {
//		mainThread.wait();
//	}
//	while(thread.isAlive()) ;
} catch (FileNotFoundException e) {
throw new MyException("Nie znaleziono pliku!");
} catch (IOException e) {
throw new MyException("Blad przy odczycie!");
}
}

jest kod odpowiedzialny za wyswietlenie okienka.
niestety albo program czeka az dialog zrobi dispose(), lecz jest ono cale szare, albo dialog sie wyswietla, lecz zanim plik zdazy sie wczytac - juz wykonuja sie inne operacje na bazie!
czy moglbym prosic o poprawienie mojego kodu/sugestie w jaki sposob sprawic aby sprawic ze dalsze wykonanie programu bedzie uzaleznione od zamkniecia okienka?

pozdrawiam

PS. nie mam pojecia dlaczego sie tak kod rozjezdza i skad te "Null>"null"........

0

Kod progressa po modyfikacji:

class ProgressDialog extends JDialog{
        private static final long serialVersionUID = 4682348576951695187L;
        private long destination;
        private JProgressBar progressBar;
        private JButton cancel;
        private boolean disposed;
        protected ProgressDialog(JFrame frame,String title,long destination){
                super(frame);
                setTitle("Postep...");
                Toolkit tool=Toolkit.getDefaultToolkit();
                setSize(300,100);
                setLocation(tool.getScreenSize().width/2-150,tool.getScreenSize().height/2-50);
                setModal(true);
                setResizable(false);
                setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
                this.destination=destination;
                disposed=false;
                getContentPane().setLayout(new GridLayout(3,1));
                Box labelBox=Box.createHorizontalBox();
                labelBox.add(Box.createGlue());
                labelBox.add(new JLabel(title));
                labelBox.add(Box.createGlue());
                getContentPane().add(labelBox);
                progressBar=new JProgressBar(0,100);
                progressBar.setStringPainted(true);
                getContentPane().add(progressBar);
                cancel=new JButton("Anuluj");
                cancel.addActionListener(new ActionListener(){
                        public void actionPerformed(ActionEvent e) {
                                disposed=true;
                                dispose();
                        }
                });
                getContentPane().add(cancel);
        }
        public void setProgres(long progress){
                progressBar.setValue((int)(progress*100/destination));
                repaint();
                if (progressBar.getValue()==100){
                        disposed=true;
                        dispose();
                }
        }
        public boolean isDisposed(){
                return disposed;
        }
        
        public void setVisible(boolean visible) {
            
            
            if (visible) {
                final Thread thread=new Thread(){
                    public void run(){
                    try {
                        for (int i=0; i<=100; i++) {  //tu oczywiście powinna byc Twoja metoda odczytu pliku          
                        setProgres(i);
                        sleep(50);
                    }
        
                    } catch (InterruptedException ex) {}
                }};

                thread.start(); //wątek włącza się start(), a nie run()
            }
            super.setVisible(visible);
        }            
}

Wywołanie z głównego programu:

ProgressDialog prg = new ProgressDialog(this,"Wczytywanie",(long)100);
prg.setVisible(true);

W konstruktorze musisz przekazać nazwę pliku, aby wewnętrzny wątek wiedział co ma czytać. Jeśli włączony jest tryb modalny to wywołanie setVisible podowduje zatrzymanie do zamknięcia okna, dlatego najpierw włączany jest wątek, a potem pokazywane okno.

0

co do tego run() to wczesniej mialem Runnable() i zapomnialem zmienic ;-)
natomiast taka modyfikacja zmusza mnie do przekazania dialogowi nazwy pliku do odczytu oraz TreeSet'a gdzie beda dane zapisywane. Podobnie musialbym stworzyc osobna klase dla zapisywania i rowniez przekazac jej TreeSeta i plik.
to chyba troche nieladne rozwiazanie... ?

czy mozna to rozwiazac w jakis inny sposob?
pozdrawiam

0
eximius napisał(a)

co do tego run() to wczesniej mialem Runnable() i zapomnialem zmienic ;-)

Jeśli używasz interfejsu Runnable to również jawnie nie wywołujesz metody run() ;).

eximius napisał(a)

natomiast taka modyfikacja zmusza mnie do przekazania dialogowi nazwy pliku do odczytu oraz TreeSet'a gdzie beda dane zapisywane.

Dialog musi mieć jakiś dostęp do pliku czy wątku, więc przekaż wątek albo jakiś handler. Pytasz czy to jest ładne rozwiązanie. Zawsze jest tak, że masz jakąś manipulacje na danych, a potem łączysz to z GUI. Tak było i w moim poprzednim rozwiązaniu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1