Przechwytuj wyjątki w aplikacji javax.swing

Pracuję z javax.swing nad aplikacją, która generuje formularze ze schematu XML (przy użyciu biblioteki JAXFront) i przechowuje dane wypełnione przez użytkownika w dokumentach XML.

Kiedy tego potrzebuję, umieszczam bloki try-catch-finally, ale mam mały problem z wychwytywaniem wyjątków, gdy kończy się główny wątek (wątki AWT nadal działają).

Mam dwie klasy, które wykonują główną pracę i inne klasy, które nie są ważne dla tego pytania:

  • Klasa główna: ma następującą strukturę. Inicjuje aplikację i uruchamia ramkę główną

    public class Main { 
        public static void main(String[] args) {
            readArgs(); // An INI file with the app config
            Model model = initializeElements(args); // My model class
            try {
                MyFrame mfr = new MyFrame(title,model);
                mfr.visualize(); // Assembling view and setting visible
            } catch( Excepion e ) {
                doCleanUp();
                System.exit(-1);
            }
        }
    }
  • Klasa ramki: generuje zdarzenia przeglądania i słuchania

    public class MyFrame extends JFrame implements ActionListener,MenuListener { 
        // Some attributes
        // Other mthods without importance
        /**
         * Compose the elements, add listeners and set visible the frame
         */
        public void visualize() {
            generateFormPanel();
            setListeners();
            validate();
            setVisible(true);
        }
    
        public MyFrame(String title, Modele model) {
            super(title);
            createElementsUsing(model);
        }
    
        public void actionPerformed(ActionEvent e) {
            // Code to manage events
        }
    }

Cóż, problem jest następujący: Kiedy funkcja wizualizacji jest wykonywana z metody głównej, widok jest generowany i pokazywany. W tym momencie tracę kontrolę nad łapaniem wyjątków. Następnie moje pytanie brzmi: czy istnieje jakiś sposób na przechwycenie możliwych wyjątków RuntimeException zgłoszonych po tym punkcie.

Mam nadzieję, że rozumiesz mój angielski i potrafisz odpowiedzieć na pytanie.

Z góry dziękuję.


person Charliemops    schedule 26.07.2011    source źródło


Odpowiedzi (3)


Najprostsza wersja polega na ustawieniu domyślnej procedury obsługi nieprzechwyconych wyjątków:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        // do something
    }
});

Ale to wychwytuje nieprzechwycone wyjątki zgłoszone również w innych częściach programu.

Można jednak przechwytywać tylko wyjątki środowiska wykonawczego wyrzucane z wątku wywołującego zdarzenia swing przy użyciu serwera proxy (zobacz ta strona, gdzie znajdziesz więcej informacji, skopiowałem stamtąd kod):

class EventQueueProxy extends EventQueue {

    protected void dispatchEvent(AWTEvent newEvent) {
        try {
            super.dispatchEvent(newEvent);
        } catch (Throwable t) {
            // do something more useful than: t.printStackTrace();
        }
    }
}

Teraz instaluję to w ten sposób:

Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueueProxy());
person dacwe    schedule 26.07.2011
comment
Wielkie dzięki. Twoje pierwsze rozwiązanie rozwiązuje mój problem. Nie mogę oddać na Ciebie głosu, ale weź go! - person Charliemops; 26.07.2011

Po wywołaniu visualize() jedynym działającym wątkiem jest wątek wysyłania zdarzeń Swing/AWT. Jeśli chcesz wychwycić wyjątki, musisz to zrobić w dowolnej metodzie odbiornika wywoływanej w tym wątku, np.

public void actionPerformed(ActionEvent e) {
  try {
    // Some code here
  } catch(RuntimeException e) {
    // Handling code here
  }
}

Aby zapobiec szablonom, możesz mieć ten kod w super klasie.

Pamiętaj, że możesz także ustawić domyślny moduł obsługi nieprzechwyconych wyjątków, jeśli chcesz przechwycić wszystko, czym nie zajął się jeszcze wątek Swing/AWT.

Należy również zauważyć, że ogólnie najlepszą praktyką jest nie wychwytywanie podklas RuntimeException, jeśli można tego uniknąć.

person Bringer128    schedule 26.07.2011

Spróbuj dodać:

setDefaultCloseOperation(EXIT_ON_CLOSE);

do konstruktora MyFrame. Nie jestem jednak pewien, ale warto spróbować.

person LeleDumbo    schedule 26.07.2011
comment
Aby kontrolować zdarzenia wyjściowe, mam setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); i addWindowListener(new WindowAdapter(){...});, które sprzątają. - person Charliemops; 26.07.2011