カスタマイズされた JFileChooser があります
その approvalSelection() メソッドはわずかに変更されています。
public void approveSelection()
{
File file = getSelectedFile();
changeGui();
final Object a = makeALongCalcualtion(file);
if (a != null)
{
super.approveSelection();
SwingWorker<Document, Void> open = new SwingWorker<Document, Void>()
{
@Override
protected Document doInBackground() throws Exception
{
return createADocument(a);
}
@Override
protected void done()
{
try
{
if(get() != null)
{
changeGui();
}
else
{
//TODO error message
changeGui();
}
}
catch (InterruptedException | ExecutionException e)
{
//TODO error message
changeGui();
}
}
};
open.execute();
}
else
{
//TODO error message
changeGui();
}
}
changeGui() メソッドは、JProgressBar を不確定に設定し、JLabel を新しい文字列で更新します。
makeALongCalcualtion(file) に提供されたファイルが無効なタイプの場合、null が返されます。それ以外の場合は、SwingWorker に渡される情報が返されます。SwingWorker は、それを使用して、プログラム内のファイル (Document オブジェクト) の表現を実際に作成できます。
ただし、makeALongCalcualtion(file) が SwingWorker メソッド内で呼び出されず、EDT がブロックされるため、これは正常に機能しません。
この問題を解決するには、SwingWorker 内で makeALongCalcualtion(file) を呼び出す必要があります。コードのその部分を問題なく SwingWorker に移動できましたが、(私のコード ロジックのために) super.approveSelection() を一緒に移動する必要がありました。
つまり、この特定のケースで doInBackground() 内から super.approveSelection() を呼び出すにはどうすればよいでしょうか。
//より詳しい情報
何が起こるはずですか:
- ユーザーがファイルを選択して開く
- JLabel と JProgressBar が更新され、不確定な進行状況が再生され始めます。
- makeALongCalcualtion(file) が null を返す場合、ユーザーはエラー ウィンドウで警告されますが、JFileChooser が開いたままになり、エラー ウィンドウが閉じられたときに再度選択できるようになります。
- それ以外の場合は、super.approveSelection() が呼び出され、チューザーを閉じることができます。
- ドキュメントが作成されます (ただし、何か問題が発生した場合、ドキュメントを作成するメソッドは null を返します)。
- すべてが正常であれば、JLabel が更新され、progressBar アニメーションが停止します (不確定は false に設定されます)。
- 何か問題が発生した場合、手順 6 と同じことが起こりますが、JLabel のメッセージが異なります。
何が起こるのですか:
- 同じ
- 同じ
- 同じですが、makeALongCalculation(file); の場合。開始すると、progressBar がフリーズします。
- 同じ
- 同じ
- 同じですが、アニメーションは停止されず (プログレスバーが凍結されているため)、凍結された「画像」のみが削除され、プログレスバーは以前の状態に戻ります。
- 同じ
編集
プログラムにいくつかの変更を加えたところ、次のようになりました。
承認選択():
public void approveSelection()
{
File file = getSelectedFile();
Main.getStatusBar().startOpen();
final WorkOpen open = new WorkOpen(file);
open.execute();
open.addPropertyChangeListener(new PropertyChangeListener()
{
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())) {
if (evt.getNewValue().equals("DONE"))
{
if (open.failed())
{
//TODO error message
Main.getStatusBar().endOpen(false);
}
else
{
Main.getStatusBar().endOpen(true);
}
}
}
}
});
}
SwingWorker:
class WorkOpen extends SwingWorker<Document, Void>
{
boolean failed = false;
File file;
public boolean failed()
{
return failed;
}
@Override
protected Document doInBackground() throws Exception
{
ArrayList<String> data = Opener.extractData(file);
if (data != null)
{
//My little path/name/similar managing system
FileComplex fullPath = new FileComplex(file.toString());
return Opener.createDocument(fullPath.getFullName(), fullPath.getFullPath(), data);
}
else
{
failed = true;
return null;
}
}
@Override
protected void done()
{
try
{
if(get() != null)
{
Main.addDocument(get());
}
}
catch (InterruptedException | ExecutionException e)
{
failed = true;
}
}
WorkOpen(File file)
{
this.file = file;
}
}
問題は、super.approveSelection() をどこで呼び出すかです。ワーカーの実行が完了するまで待つ必要がありますが、プロパティ変更リスナーから呼び出すことはできません。
ここで何をしますか?
編集2
HovercraftFullOfEels が提案したように、コードを修正し、コンパイルして実行しました。しかし、JProgressBar のフリーズの問題は残りました。また、持っているべきかどうかわからないものを紹介しなければなりませんでした:
private void superApproveSelection()
{
super.approveSelection();
}
public void approveSelection()
{
final File file = getSelectedFile();
class OpenWorker extends SwingWorker<Boolean, Void>
{
Document document;
Document getDocument()
{
return document;
}
@Override
protected Boolean doInBackground() throws Exception
{
ArrayList<String> data = Opener.extractData(file);
if (data != null)
{
//I had to start the progressBar here, because if invalid
//file was selected (extractData(file) returns null if it was),
//nothing should happen (maybe an error
//window later, handled with a new Runnable() same as this:
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
Main.getStatusBar().startOpen();
}
});
FileComplex fullPath = new FileComplex(file.toString());
document = Opener.createDocument(fullPath.getFullName(), fullPath.getFullPath(), data);
return true;
}
else
{
return false;
}
}
};
final OpenWorker opener = new OpenWorker();
opener.addPropertyChangeListener(new PropertyChangeListener()
{
@Override
public void propertyChange(PropertyChangeEvent evt)
{
if ("state".equals(evt.getPropertyName()))
{
if (evt.getNewValue() == SwingWorker.StateValue.DONE)
{
if(opener.getDocument() != null)
{
superApproveSelection();
Main.addDocument(opener.getDocument());
Main.getStatusBar().endOpen(true);
}
else
{
try
{
//I'm retrieveing doInBackground()'s value to see if
//progressBar needs stoping (it also displays some
//text, so it must not be called unless the
//progressBar was started).
if (opener.get())
{
Main.getStatusBar().endOpen(false);
}
}
catch (InterruptedException | ExecutionException e)
{
//TODO error something went wrong
}
}
}
}
}
});
opener.execute();
}