2

カスタマイズされた 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() を呼び出すにはどうすればよいでしょうか。

//より詳しい情報

何が起こるはずですか:

  1. ユーザーがファイルを選択して開く
  2. JLabel と JProgressBar が更新され、不確定な進行状況が再生され始めます。
  3. makeALongCalcualtion(file) が null を返す場合、ユーザーはエラー ウィンドウで警告されますが、JFileChooser が開いたままになり、エラー ウィンドウが閉じられたときに再度選択できるようになります。
  4. それ以外の場合は、super.approveSelection() が呼び出され、チューザーを閉じることができます。
  5. ドキュメントが作成されます (ただし、何か問題が発生した場合、ドキュメントを作成するメソッドは null を返します)。
  6. すべてが正常であれば、JLabel が更新され、progressBar アニメーションが停止します (不確定は false に設定されます)。
  7. 何か問題が発生した場合、手順 6 と同じことが起こりますが、JLabel のメッセージが異なります。

何が起こるのですか:

  1. 同じ
  2. 同じ
  3. 同じですが、makeALongCalculation(file); の場合。開始すると、progressBar がフリーズします。
  4. 同じ
  5. 同じ
  6. 同じですが、アニメーションは停止されず (プログレスバーが凍結されているため)、凍結された「画像」のみが削除され、プログレスバーは以前の状態に戻ります。
  7. 同じ

編集

プログラムにいくつかの変更を加えたところ、次のようになりました。

承認選択():

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

1 に答える 1

2

「問題を解決するには、SwingWorker 内で makeALongCalcualtion(file) を呼び出す必要があります。コードのその部分を問題なく SwingWorker に移動することはできましたが、(コード ロジックのために) 移動する必要がありました。 super.approveSelection() と一緒に」

いいえ、まったくそうではありません。super.approveSelection()SwingWorker 内で呼び出す必要はありません。

単純に SwingWorker を作成し、PropertyChangeListener を追加して、SwingWorker の状態が完了したら、必要にsuper.approveSelection()応じて呼び出してみませんか?

OK、これが私の例です。続く説明:

import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;

import javax.swing.*;
import javax.swing.text.*;

@SuppressWarnings("serial")
public class ApproveSelectionTest extends JPanel {
   private JTextArea textArea = new JTextArea(30, 60);

   public ApproveSelectionTest() {
      textArea.setEditable(false);
      textArea.setFocusable(false);

      JPanel btnPanel = new JPanel();
      btnPanel.add(new JButton(new MyGetFileAction("Get Text File Text")));

      setLayout(new BorderLayout());
      add(new JScrollPane(textArea), BorderLayout.CENTER);
      add(btnPanel, BorderLayout.PAGE_END);
   }

   private class MyGetFileAction extends AbstractAction {
      public MyGetFileAction(String text) {
         super(text);
      }

      public void actionPerformed(java.awt.event.ActionEvent arg0) {
         MyFileChooser myFileChooser = new MyFileChooser();
         int result = myFileChooser.showOpenDialog(ApproveSelectionTest.this);
         if (result == JFileChooser.APPROVE_OPTION) {
            Document doc = myFileChooser.getDocument();
            textArea.setDocument(doc);
         }
      };
   }

   private static void createAndShowGui() {
      ApproveSelectionTest mainPanel = new ApproveSelectionTest();

      JFrame frame = new JFrame("ApproveSelectionTest");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class MyFileChooser extends JFileChooser {
   private WorkOpen workOpen = null;
   private JDialog progressDialog = null;

   public MyFileChooser() {
   }

   @Override
   public void approveSelection() {
      JProgressBar progBar = new JProgressBar();
      progBar.setIndeterminate(true);
      Window win = SwingUtilities.getWindowAncestor(this);
      progressDialog = new JDialog(win, "Checking File", ModalityType.APPLICATION_MODAL);
      progressDialog.getContentPane().add(progBar);
      progressDialog.pack();
      progressDialog.setLocationRelativeTo(null);


      File file = getSelectedFile();

      workOpen = new WorkOpen(file);

      workOpen.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (SwingWorker.StateValue.DONE == pcEvt.getNewValue()) {
               if (progressDialog != null) {
                  progressDialog.dispose();
               }

               try {
                  boolean bool = workOpen.get().booleanValue();
                  if (bool) {
                     superApproveSelection();
                  } else {
                     JOptionPane.showMessageDialog(MyFileChooser.this, "Invalid File Chosen");
                  }
               } catch (InterruptedException e) {
                  e.printStackTrace();
               } catch (ExecutionException e) {
                  e.printStackTrace();
               }
            }
         }
      });

      workOpen.execute();
      progressDialog.setVisible(true);

   }

   // ****** this is key *****
   private void superApproveSelection() {
      super.approveSelection();
   }

   public Document getDocument() {
      if (workOpen == null) {
         return null;
      } else {
         return workOpen.getDocument();
      }
   }
}

class WorkOpen extends SwingWorker<Boolean, Void> {
   private static final long SLEEP_TIME = 4 * 1000;
   private Document document = null;
   private File file = null;

   public WorkOpen(File file) {
      this.file  = file;
   }

   @Override
   protected Boolean doInBackground() throws Exception {
      if (file == null || !file.exists()) {
         return Boolean.FALSE;
      }
      Thread.sleep(SLEEP_TIME);
      String fileName = file.getName();
      if (fileName.contains(".txt")) {
         Scanner scan = new Scanner(file);
         StringBuilder stringBuilder = new StringBuilder();
         while (scan.hasNextLine()) {
            stringBuilder.append(scan.nextLine() + "\n");
         }

         document = new PlainDocument();
         document.insertString(0, stringBuilder.toString(), null);
         return Boolean.TRUE;
      }
      return Boolean.FALSE;
   }

   public Document getDocument() {
      return document;
   }

}

私の例からの説明と重要なポイント:

  • この例は非常に単純に動作します。ファイルを選択し、そのファイルが存在し、名前に「.txt」が含まれている場合は、ドキュメントを読み取り、テキストを JTextField に表示します。
  • それ以外の場合、警告メッセージが表示されますが、JFileChooser は表示されたままになります
  • おそらく重要なポイント: MyFileChooser クラスに、PropertyChangeListener から呼び出せるプライベートsuperApproveSelection()メソッドを指定しました。これにより、スーパーのapproveSelection()メソッドが内部クラスに公開されます。これは、あなたが抱えていた問題の 1 つです。
  • approveSelection()私のオーバーライドでは、コードを呼び出す順序が重要です。
  • このメソッドでは、最初に JProgressBar とそのダイアログを作成しますが、まだすぐには表示しません。最初に作成する必要はありませんが、最後に表示する必要があります。
  • SwingWorker、workOpen を作成しましたが、まだ実行していません。
  • SwingWorker を実行する前に、PropertyChangeListener を SwingWorker に追加します。
  • 次に、SwingWorker を実行します
  • 次に、不確定な JProgressBar を使用してモーダル JDialog を表示します。
  • 私の SwingWorker は、その doInBackground がドキュメントではなくブール値を返すように構造化されています。
  • テキストファイルのコンテンツを保持するすべてが正常に機能する場合は(非常に単純な)ドキュメントを作成し、ゲッターメソッドで取得可能なプライベート「doc」フィールドを設定し、すべてが正常に機能する場合は doInBackground に Boolean.TRUE を返すようにします.
  • doInBackground に Thread.sleep(4000) を与えたのは、そのアクションに多くの時間がかかるふりをするためだけです。もちろん、あなたのものにはこれがありません。
  • SwingWorker が DONE の場合、PropertyChangeListener でプログレス バー ダイアログを破棄get()し、SW を呼び出してブール値の結果を取得します。
  • Boolean.TRUE の場合は、superApproveSelection()上記のメソッドを呼び出します。
  • それ以外の場合は、エラー メッセージを表示します。スーパーのapproveSelection()が呼び出されないため、ファイル選択ダイアログが表示されたままになることに注意してください。
  • ApproveSelection が呼び出されると、ファイル チューザー ダイアログを表示するコードが適切な戻り値を取得し、ファイル チューザーからドキュメントを抽出し、ドキュメントを JTextArea に表示します。
于 2013-03-28T02:07:01.600 に答える