Swing Problem mit Warten-Dialog

Bitte aktiviere JavaScript!
Hallo,

in meinem Programm gibt es einige Aktivitäten, die etwas länger dauern. Dies soll dem Anwender über einen nicht modalen Dialog angezeigt werden, also "Ich mach jetzt das oder jenes, Bitte etwas warten".
Den Dialog habe ich unter NetBeans mit dem GUI-Builder erstellt. Der Code sieht so aus:
Java:
public class HinweisWarten extends JDialog {
    private static final long serialVersionUID = 1L;
    public HinweisWarten(java.awt.Frame parent) {
        super(parent, true);
        initComponents();
        setModal(false); // testhalber von mir eingesetzt
        setLocationRelativeTo(parent);
    }

    public void zeigeHinweis(String txt){
        labelText.setText(txt);
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                        
    private void initComponents() {
        labelText = new javax.swing.JLabel();
    // es folgt der generierte Code, den ich ausblende
}
Obwohl ich bei den Eigenschaften die Option "modal" nicht aktiviert habe, wird der Dialog modal ausgeführt. Das heißt, das Warten-Fenster wird angezeigt, aber damit wird das Programm, der Teil also, wegen dem der Anwender warten muss, nicht ausgeführt. Der Dialog verhält sich modal.

Wenn ich unter den Eigenschaften für modalityType null festlege oder zusätzlich wie oben zu sehen in meinem Code setModal(false) hinzufüge, dann funktioniert das Verhalten des Dialoges einerseits so, wie es zu erwarten wäre, während der Dialog steht, kann der zeitaufwendige Teil abgearbeitet werden, aber der Hinweis-Text wird nicht angezeigt.

Was muss gemacht werden, dass beides funktioniert, dass der Text angezeigt wird, der Dialog aber die Fortsetzung des Programms nicht verhindert?

Danke vorweg,
kodela
 
A

Anzeige




Vielleicht hilft dir unser Java-Tutorial hier weiter —> (hier klicken)
Ergänzung:
Grundsätzlich wäre es wünschenswert, dass das Warten-Fenster modal ist, damit der Anwender keine Möglichkeit hat, den Prozess im Hintergrund zu stören. Bei einem Teil der Hintergrundprozesse, z.b. Prüfung auf eindeutige Lösbarkeit einer Aufgabe muss die aufrufende Methode auf das Ergebnis warten.
 
Hallo mihe7,

danke für den interessanten Tipp, ich werde ihn mir vormerken, falls ich einmal so eine Fortschrittsanzeige brauche, aber für meine Fälle tut es ein ganz einfacher Hinweis, dass es einen Moment dauern kann, bis der Anwender weiter machen kann. Wie lange das ist, wäre in einigen Fällen in etwa berechenbar, in anderen überhaupt nicht, zum Beispiel, wenn ein extrem schweres Str8ts gelöst und anschließend geprüft werden muss, ob die gefundene Lösung eindeutig ist. Es ist auch nicht vorhersehbar, wann eine solche Situation auftritt und der Anwender weiß es ja auch nicht und ohne einen Hinweis ist er dann irritiert, dass da plötzlich überhaupt nichts geschieht.

Mir wäre sehr geholfen, wenn ich wüsste, wie man es anstellt, dass während der Anzeige eines solchen Warte-Hinweises im Hintergrund das erledigt wird, weswegen der Hinweis ja kommt oder zumindest, als zweitbeste Lösung wenn der Dialog nicht modular ist, dass dann der Hinweis im Dialogfenster auch gezeigt wird. Im Augenblick kommt nur ein leeres Fenster.

Ich habe übrigens gesehen, dass man von der von Dir verlinkten Seite noch eine ganze Menge anderer hoch interessanter Seiten erreichbar sind. Zu meinem speziellen Problem habe ich aber leider, zumindest bisher, nichts gefunden.

Gruß, kodela
 
Zuletzt bearbeitet:
Java:
import java.awt.BorderLayout;
import java.awt.Window;
import javax.swing.*;

public class Test {

    private JLabel result;

    private class UnknownLengthTask extends SwingWorker<Integer, Void> {
        @Override
        public Integer doInBackground() {
            // lange Berechnung
            try { Thread.sleep(2000); } catch (InterruptedException ex) {}
            return (int)(Math.random()*Integer.MAX_VALUE);
        }

        @Override
        public void done() {
            try {
                result.setText("Ergebnis: " + get());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public void calculate(Window parent) {
        JDialog dialog = new JDialog(parent, "Bitte warten");
        dialog.add(new JLabel("Dauert einen Moment"));
        dialog.pack();
        dialog.setModal(true);
      
        UnknownLengthTask task = new UnknownLengthTask();
        task.addPropertyChangeListener(e -> {
            if ("state".equals(e.getPropertyName())) {
                if (SwingWorker.StateValue.DONE == e.getNewValue()) {
                    dialog.dispose();
                }
            }
        });

        task.execute();
        dialog.setVisible(true);

        JOptionPane.showMessageDialog(parent, "Danke");
    }

    public void run() {
        result = new JLabel(" ");
        JPanel output = new JPanel();
        output.add(result);

        final JButton start = new JButton("Start");
        start.addActionListener(e -> calculate(SwingUtilities.getWindowAncestor(start)));
      
        JPanel input = new JPanel();
        input.add(start);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(input, BorderLayout.NORTH);
        frame.add(output, BorderLayout.SOUTH);
        frame.setSize(400, 200);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 
Danke mihe7,

ich habs schon mal ausprobiert, und Morgen werde ich das Beispiel dann auch studieren.

Gruß, kodela
 
Hallo,

@mihe7, ich habe Deinen Code, für den ich mich nochmal herzlich bedanken möchte, etwas überarbeitet, damit er besser zu meinen Verhältnissen passt. Er sieht jetzt so aus:
Java:
import java.awt.BorderLayout;
import java.awt.Window;
import javax.swing.*;

public class Test {

    private JLabel result;
    private javax.swing.JLabel labelText;

    private class UnknownLengthTask extends SwingWorker<Boolean, Void> {
        @Override
        public Boolean doInBackground() {
            // lange Berechnung (Eindeutigkeitsprüfung)
            try {
                Thread.sleep(2000);
            }
            catch (InterruptedException ex) {
            }
            return (int)(Math.random()*Integer.MAX_VALUE) % 2 == 0;
        }

        @Override
        public void done() {
            try {
                result.setText("Ergebnis: " + get());
            }
            catch (Exception ex) {
            }
        }
    }

    /**
     * Damit wird der Warten-Dialog erzeugt und angezeigt und
     * die im Hintergrund laufende Aktion angestoßen
     * @param parent
     */
    public void calculate(Window parent) {
        // zuerst den Warten-Dialog erzeugen
        JDialog dialog = new JDialog(parent);
        labelText = new javax.swing.JLabel();

        dialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        dialog.setTitle("Hinweis");
//        dialog.setName("dialogWarten");
        dialog.setResizable(false);

        labelText.setFont(new java.awt.Font("Tahoma", 1, 12));
        labelText.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        labelText.setText("<html><center><b>Prüfe Str8ts auf Eindeutigkeit.<br><br>"
                + "Bitte solange warten.</b></center></html>");
        labelText.setMaximumSize(new java.awt.Dimension(116, 45));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(dialog.getContentPane());
        dialog.getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(labelText, javax.swing.GroupLayout.PREFERRED_SIZE,
                        233, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(labelText,
                        javax.swing.GroupLayout.DEFAULT_SIZE, 76, Short.MAX_VALUE)
                .addGap(24, 24, 24))
        );
        dialog.pack();
        dialog.setLocationRelativeTo(parent);
        dialog.setModal(true);
     
        // in meinem Fall die Eindeutigkeitsprüfung
        UnknownLengthTask task = new UnknownLengthTask();
        task.addPropertyChangeListener(e -> {
            if ("state".equals(e.getPropertyName())) {
                if (SwingWorker.StateValue.DONE == e.getNewValue()) {
                    dialog.dispose();
                }
            }
        });
        task.execute();
        dialog.setVisible(true);
    }

    /**
     * Damit werden die Voraussetzungen für den Test geschaffen
     */
    public void run() {
        result = new JLabel(" ");
        JPanel output = new JPanel();
        output.add(result);
        // zum Anstoßen des Testes
        final JButton start = new JButton("Start");
        start.addActionListener(
                e -> calculate(SwingUtilities.getWindowAncestor(start)));
  
        JPanel input = new JPanel();
        input.add(start);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(input, BorderLayout.NORTH);
        frame.add(output, BorderLayout.SOUTH);
        frame.setSize(400, 200);
        frame.setLocation(600, 400);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
Das könnte ich vermutlich so ähnlich in meinen Code integrieren. Allerdings sollte der Warten-Dialog auch für andere Aktionen verwendbar sein und deshalb habe ich dafür eine eigene Klasse erstellt. Die sieht so aus:
Java:
import javax.swing.JDialog;

/**
* Gibt Warten-Dialog aus
* @author Konrad
*/
public class HinweisWarten extends JDialog {

    private static final long serialVersionUID = 1L;
    public HinweisWarten(java.awt.Frame parent) {
        super(parent, true);
        initComponents();
//        setModal(false);
//        damit verhindert der Dialog den Hintergrundorozess nicht,
//        zeigt aber den Text nicht an
        setLocationRelativeTo(parent);
    }

    public void zeigeHinweis(String txt){
        labelText.setText(txt);
    }


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                        
    private void initComponents() {

        labelText = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Hinweis");
        setName("dialogWarten"); // NOI18N
        setResizable(false);

        labelText.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
        labelText.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        labelText.setText("<html><center><b>Erzeuge Str8ts-Aufgaben.<br><br>Bitte solange warten.</b></center></html>");
        labelText.setMaximumSize(new java.awt.Dimension(116, 45));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(labelText, javax.swing.GroupLayout.PREFERRED_SIZE, 233, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(labelText, javax.swing.GroupLayout.DEFAULT_SIZE, 76, Short.MAX_VALUE)
                .addGap(24, 24, 24))
        );

        labelText.getAccessibleContext().setAccessibleName("<html><center><b>Erzeuge Str8ts-Aufgaben.<br><br>Bitte solange warten.</b></center></html>");

        pack();
    }// </editor-fold>                      
    // Variables declaration - do not modify                   
    private javax.swing.JLabel labelText;
    // End of variables declaration                 
}
Zum weiteren Verständnis hier noch der Code für die im Hintergrund auszuführende Eindeutigkeitsprüfung:
Java:
package str8ts;

import static str8ts.GlobaleObjekte.LWF;
import static str8ts.GlobaleObjekte.LWRT;

/**
* Überprüft Str8ts auf Eindeutigkeit
* @author Konrad
*/
public class EindeutigkeitChecken extends Thread
                                implements Runnable, GlobaleObjekte {
    private LevelLoeser strLoeser;
    private final int[] aufgabe;
    private final int[] loesung;
  
    /**
     * Konstruktor
     * @param mf    Referenz auf Hauptklasse der Anwendung
     * @param hnw   Referenz auf Warten-Dialog
     * @param af    Bitcodierte Str8ts Aufgabe
     * @param ls    Bitcodierte Str8ts Lösung
     */
    EindeutigkeitChecken(Str8tsApp mf, HinweisWarten hnw, int[] af, int[] ls) {
        aufgabe = new int[81];
        kopieren(af, aufgabe);
        loesung = new int[81];
        kopieren(ls, loesung);      
        hnw.zeigeHinweis("<html><center><b>Eindeutigkeit wird überprüft."
                + "<br><br>Bitte solange warten.</b></center></html>");
        hnw.setVisible(true);
    }
  
    @Override
    public void run() {
    }  
    /**
     * Überprüft das aktuelle Str8ts auf Eindeutigkeit.
     * @return true wenn eindeutig, ansonsten false
     */
    public boolean checkEindeutigkeit() {
        int afg[] = new int[81];
        int lsg[] = new int[81];
        kopieren(aufgabe, afg);
        for (int i = 0; i < 81; i++) {          
            int lw = loesung[i] & ~LWF;
            if (loesung[i] <= LWRT && loesung[i] > 9) {
                for (int k = 1; k <= 9; k++) {
                    if (lw != k) {
                        kopieren(aufgabe, afg);
                        afg[i] = k | LWF;
                        bereinigeKListe(afg, k, i);                      
                        strLoeser = new LevelLoeser(null, afg, lsg, true);
                        int lev = strLoeser.loeseAufgabe();
                        if (lev > 0) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
  
    /**
     * Entfernt für eine Zelle alle durch einen gesetzten Wert unmöglichen
     * Kandidaten aus allen Zellen im Sichtbereich dieser Zelle.
     * @param strfld    zu bearbeitendes Str8tsfeld
     * @param knd       zu entfernender Kandidat
     * @param pos       Index der Zelle, welcher der Wert zugewiesen wurde
     */
    private void bereinigeKListe(int strfld[], int knd, int pos) {
        knd &= ~SZELLE;
        int z = (pos / 9) * 9;
        int s = pos % 9;
        // erst aus der Zeile entfernen
        for (int i = z; i <= z + 8; i++) {
            if (i == pos) {
                continue;
            }
            if ((strfld[i] & LK_MASKE[knd]) == LK_MASKE[knd]) {
                strfld[i] &= ~LK_MASKE[knd];
                strfld[i] -= 1;
            }
        }
        // jetzt aus der Spalte entfernen
        for (int i = s; i < s + 73; i += 9) {
            if (i == pos) {
                continue;
            }
            if ((strfld[i] & LK_MASKE[knd]) == LK_MASKE[knd]) {
                strfld[i] &= ~LK_MASKE[knd];
                strfld[i] -= 1;
            }
        }
    }
  
    /**
     * Kopiert die Werte und nicht nur die Referenzen für ein Str8tsfeld.
     * @param aufgabe   die zu kopierende Aufgabe
     * @param ziel      der Bereich, in den kopiert wird
     */
    @SuppressWarnings("ManualArrayToCollectionCopy")
    private void kopieren(int[]aufgabe, int ziel[]) {
        for (int i = 0; i < aufgabe.length; i++) {
            ziel[i] = aufgabe[i];
        }
    }      
}
@mihe7 oder jeder andere Interessierte: Das alles funktioniert bestens, nur die verdammte Anzeige des Warten-Dialoges. Im Augenblick habe ich auch keine Idee, wie ich das Konzept von mihe7 so umsetzen könnte, dass die Warten-Klasse allgemein anwendbar ist.

Vielleicht kann mir jemand einen Denkanstoß geben, wie ich hier am besten vorgehen sollte.

Danke schon einmal vorweg und Gruß,
kodela
 
Bei dem im Hintergrund auszuführenden Code handelt es sich um Anwendungslogik. Die hat nichts mit dem User Interface zu tun und dem entsprechend auch nichts davon zu wissen.

Die Anwendungslogik wird von Deinem UI aus aufgerufen und an der Stelle kann ein Hinweis angezeigt werden. Du musst lediglich dafür sorgen, dass der Hinweis verschwindet/aktualisiert wird, nachdem die aufgerufene Logik vollständig abgearbeitet wurde. Das UI muss also mitbekommen, wenn eine Hintergrundaufgabe erledigt ist.

Unter Swing bietet sich hierfür ein SwingWorker an. Der kann als Wrapper für die tatsächliche Anwendungslogik dienen. Alles, was Du dann tun musst, ist auf die "state"-Property lauschen, und den Hinweis schließen/aktualisieren.

Im Fall oben bräuchtest Du in calculate nur einen HinweisDialog statt einem JDialog zu erzeugen.
 
Danke mihe7!
Was Du zur Anwendungslogik schreibst, ist mir klar und ich habe von der Klasse, die den Prozess startet, ist nicht die UI, die Klasse für die Meldung bereits initialisiert. In meinem sehr ähnlichen Sudoku-Programm und auch im Str8ts-Programm funktioniert das ja grundsätzlich. Allerdings brauche ich in all den funktionierenden Fällen keinen Rückgabewert. Der macht mir jetzt erstmals Schwierigkeiten.

Aber da hilft mir Dein Hinweis auf den SwingWorker offentlich weiter. Damit habe ich allerdings keine Erfahrung. Aber das kann man ja nachholen. Ich weiß nur, dass es die Aufgabe des SwingWorker's sein soll, eine Aufgabe im Hintergrund abzuarbeiten während der Anwender weiter arbeiten kann. Das darf bei mir nicht sein, im Gegenteil, das muss verhindert werden, denn nach der Feststellung der Eindeutigkeit muss ergebnisabhängig reagieren. Das ist ganz anders bei den bereits erwähnten anderen Fällen, wo der Warten-Hinweis zum Beispiel ausgegeben wird, wenn der Anwender z.B. 100 Str8ts ausdrucken will und zuvor der Drucker initialisiert wird oder eine große Anzahl von Str8ts aus einer Liste eingelesen werden soll. Das und ähnliche Aufgaben, auch die Eindeutigkeitsprüfung, laufen bei mir in eigenen Threads. Außer bei der Eindeutigkeitsprüfung wird aber nie auf ein auszuwertendes Ergebnis gewartet.

Frage, was meinst Du mit "im Fall oben" und "HinweisDidalog statt JDialog"? Da habe ich momentan scheinbar ein Brett vor dem Kopf.

Gruß, kodela
 
Ich weiß nur, dass es die Aufgabe des SwingWorker's sein soll, eine Aufgabe im Hintergrund abzuarbeiten während der Anwender weiter arbeiten kann.
Jein. Es geht erst einmal nur darum, dass der Event Dispatch Thread (EDT) des UIs nicht blockiert wird. Ansonsten würde z. B. Dein Fenster nicht neu gezeichnet, wenn Du beispielsweise kurz mal zu einer anderen Anwendung (z. B. Browser) und wieder zurück wechselst. Was der Benutzer in der Zeit mit Deiner Anwendung machen kann, hängt damit zwar zusammen, ist aber eine andere Frage.

Das und ähnliche Aufgaben, auch die Eindeutigkeitsprüfung, laufen bei mir in eigenen Threads. Außer bei der Eindeutigkeitsprüfung wird aber nie auf ein auszuwertendes Ergebnis gewartet.
Der SwingWorker verwendet ebenfalls einen eigenen Thread. Der Vorteil besteht lediglich darin, dass er sich "EDT-konform" verhält (bestimmte Methoden werden intern mit invokeLater aufgerufen, so dass Du das nicht mehr machen musst) und gleich Methoden zum Informieren über den "Ausführungszustand" mitbringt.

ich habe von der Klasse, die den Prozess startet, ist nicht die UI, die Klasse für die Meldung bereits initialisiert.
Korrigiere mich, wenn ich falsch liege: ich gehe davon aus, dass über das UI eine Aktion gestartet wird und diese eine Zeit lang dauert.
 
Frage, was meinst Du mit "im Fall oben" und "HinweisDidalog statt JDialog"? Da habe ich momentan scheinbar ein Brett vor dem Kopf.
Oops, das habe ich ganz übersehen: damit meinte ich das von Dir angepasste Beispiel. Statt
Java:
    public void calculate(Window parent) {
        // zuerst den Warten-Dialog erzeugen
        JDialog dialog = new JDialog(parent);
        ...
musst Du doch lediglich Deinen HinweisWarten-Dialog verwenden:
Java:
    public void calculate(Window parent) {
        // zuerst den Warten-Dialog erzeugen
        HinweisWarten dialog = new HinweisWarten(parent);
        dialog.setModal(true);
        dialog.zeigeHinweis("Warten");
        UnknownLengthTask task = new UnknownLengthTask();
        task.addPropertyChangeListener(e -> {
            if ("state".equals(e.getPropertyName())) {
                if (SwingWorker.StateValue.DONE == e.getNewValue()) {
                    dialog.dispose();
                }
            }
        });
        task.execute();
        dialog.setVisible(true);
    }
 
Danke mihe7 für Dein Bemühen, mir zu helfen!

Korrigiere mich, wenn ich falsch liege: ich gehe davon aus, dass über das UI eine Aktion gestartet wird und diese eine Zeit lang dauert.
Jein, gut das UI ist ja meistens irgend wie dabei, und insofern ist Deine jetzige Aussage, dass über das UI eine Aktion gestartet würde, richtig. Nicht richtig ist, dass die Anwendungslogik von meinem UI aus aufgerufen würde. Zur Erklärung muss ich etwas ausholen.

Der Anwender kann zum Beispiel eine Str8tsaufgabe neu eingeben oder über die Zwischenablage einfügen, er kann Str8ts aber auch verändern und in all diesen Fällen wird das Str8ts sofort von einer eigenen Klasse, sie nennt sich sinnigerweise "Str8ts", übernommen, deren Aufgabe es unter anderem auch ist, festzustellen, ob es sich überhaupt um ein gültiges Str8ts handelt und wenn ja, welchem von fünf Schwierigkeitsgraden es zuzuordnen ist. Dafür wird von der Str8ts-Klasse aus die Klasse "LevelLoeser" aufgerufen.Dabei werden den ersten vier Levels solche Str8ts zugeordnet, die mit logischen Lösungsstrategien lösbar sind. Für diese Levels wird eine (nicht zulässige) Mehrdeutigkeit erkannt. Alle Str8ts welche auf diese Weise nicht gelöst werden können, werden über einen Backtracking-Solver gelöst. Dabei kann aber nicht festgestellt werden, ob es ausser der gefundenen Lösungen noch weitere gibt. Das muss aber geklärt sein und diese Aufgabe fällt der Klasse "EindeutigkeitChecken" zu, die nun ebenfalls von der Str8ts-Klasse aufgerufen wird.

Der Eindeutigkeitscheck läuft in der Form ab, dass für jede der 81 Zellen jeder der 9 möglichen Lösungswerte, die für die vorliegende Lösung gefundenen Lösungswerte ausgenommen, eingesetzt und dann überprüft wird, ob sich das Str8ts mit diesem "Testwert" lösen lässt. Wenn ja, dann ist das betreffende Str8ts nicht eindeutig, der Scheck wird abgebrochen und die Str8ts-Klasse übernimmt das weitere Vorgehen. Dabei kann durchaus das UI wieder ins Spiel kommen.

Mit Deinen beiden anderen Aussagen muss ich mich erst noch beschäftigen.

Ich frage mich allerdings immer wieder, warum (bei mir) ein JDialog, der sich modal oder nicht modal verwenden lässt, dann wenn er nicht modal eingestellt ist, zwar das ganze Dialogfenster anzeigt, nicht aber den Text eines Labels. Das macht doch keinen Sinn. Da der Eindeutigkeitscheck ja keine Ewigkeit dauert, könnte ich die Möglichkeit, dass der User bei fehlender Modalität etwas Unrechtes macht, in Kauf nehmen. Am längsten dauert der Check, wenn das Str8ts eindeutig lösbar ist, da dann alle Zellen mit allen Kandidaten geprüft werden müssen, das sind dann aber vielleicht 5 Sekunden, die aber als störend empfunden werden, wenn man nicht weiß, warum sich nichts tut.

Ja, Hoppla, ich bin fertig und sehe, dass von Dir noch eine Antwort da ist. Die muss ich mir aber erst zu Gemüte führen.

Gruß, kodela
 
Statt [erstes Codeschnipsel]
musst Du doch lediglich Deinen HinweisWarten-Dialog verwenden:
Ja, das war mir bewusst, ich wollte aber alles in einer (Deiner) Datei erledigen.

Aber Dein zweiter Code, wo baue ich den ein, in der Str8ts-Klasse, hier mal der Code der verantwortlichen Methode:
Java:
    /**
     * Überprüft nach der Neueingabe oder Bearbeitung eines Str8ts, ob und mit
     * welchem Level die Aufgabe gelöst werden kann.
     * @param   tstEindeutigkeit true wenn auf Eindeutigkeit geprüft werden soll
     * @return  eindeutig gelöst: Level,
     *          nicht eindeutig gelöst: negativer Level
     *          nicht gelöst, also fehlerhaft: 0
     */
    public int loeseStr8ts(boolean tstEindeutigkeit) {
        System.arraycopy(aufgabe, 0, str8ts, 0, 81);
        erstelleKndListe(str8ts);
        for (int i = 0; i < 81; i++) {
            loesung[i] = 0;
        }
        strLoeser = new LevelLoeser(this, str8ts, loesung, true);
        level = strLoeser.loeseAufgabe();
        if (tstEindeutigkeit && level == 5) {
            boolean eindeutig = true;
            if (getVorgabewerte() > 0) {
                HinweisWarten hnw = new HinweisWarten(strApp);
                EindeutigkeitChecken echeck = new EindeutigkeitChecken(
                    strApp, hnw, str8ts, loesung);
                echeck.start();
                // das funktioniert natürlich jetzt noch nicht
                eindeutig = echeck.is_eindeutig();
                hnw.setVisible(false);
            }
            if (!eindeutig) {
                return level*-1;
            }          
        }     
        return level;
    }
Hier wird also derzeit der Warten-Dialog erzeugt und wenn "EindeutigkeitChecken" seinen Job erledigt hat, auch wieder entfernt. Das ist aber noch "Wunschdenken", denn das Ganze funktioniert natürlich so nicht. In der Klasse "EindeutigkeitChecken" habe ich mittlerweile den Steuerungscode für den Check in den run-Block gelegt.

Wie schön war es vorher, als mit eindeutig = echeck.checkEindeutigkeit(); alles bis auf das Warten-Dialogfenster ohne Text funktionierte.

Zurück zu Deinem zweiten Codeteil. Kann der hier eingebaut werden?

Gruß, kodela
 
Nicht richtig ist, dass die Anwendungslogik von meinem UI aus aufgerufen würde.
Ich kann in Deiner Beschreibung nichts erkennen, was dagegen sprechen würde. Präziser wäre die Formulierung, dass die Anwendungslogik von der Präsentationsschicht Deiner Anwendung aufgerufen wird.

Zurück zu Deinem zweiten Codeteil. Kann der hier eingebaut werden?
Können kann man vieles... Er sollte hier nicht eingebaut werden, denn hier bist Du mitten in Deiner Anwendungslogik.

Ich mach es mal einfacher: Du solltest Dein Spiel so schreiben, dass es unabhängig vom User Interface funktioniert. Das wäre dann im Wesentlichen die Anwendungslogik (nennen wir es mal die "Str8ts-Engine", dann kann man sich das ggf. besser vorstellen).

An diese Engine hängst du Dein UI (Präsentationsschicht) dran. Dazu bietet Deine Anwendungsschicht entsprechende Schnittstellen an. So kann Deine Anwendungslogik auch die "Außenwelt" (z. B. das UI) über bestimmte Aktivitäten via Listener oder Callbacks informieren.

Wie schön war es vorher, als mit eindeutig = echeck.checkEindeutigkeit(); alles bis auf das Warten-Dialogfenster ohne Text funktionierte.
Für den Fall, dass hier Anfänger mitlesen: deshalb ist es keine gute Idee, mit GUI-Programmierung einzusteigen. Ihr habt zu Beginn ganz andere Probleme.

Hast Du das Projekt irgendwo liegen, dass man sich das mal im Ganzen ansehen kann?
 
hallo mihe7,

das Problem ist gelöst. Danke, dass Du mir die Nase auf SwingWorker gestoßen hast. Damit klappt alles und es war doch wesentlich einfacher als vermutet.

Hier der entscheidende Code von der aufrufenden Methode:
Java:
if (tstEindeutigkeit && level == 5) {
    HinweisWarten hnw = new HinweisWarten(strApp);
    EindeutigkeitChecken echeck = new EindeutigkeitChecken(
            strApp, hnw, str8ts, loesung);
    echeck.execute();
    hnw.setVisible(true);
    eindeutig = echeck.is_eindeutig();
}
Als erstes eine Instanz für den Warten-Dialog erzeugt, dann eine Instanz für den Eindeutigkeitscheck.
Den Eindeutigkeitscheck über execute() gestartet, dann den Warten-Dialog mit setVisible(true) anzeigen lassen und zum Schluss das Ergebnis der Prüfung mit eindeutig = echeck.is_eindeutig() abgefragt.

Nun noch die wichtigen Teile von der Klasse EindeutigkeitChecken:
Java:
public class EindeutigkeitChecken extends SwingWorker<Boolean, Object>
                                implements Runnable, GlobaleObjekte {
    private boolean eindeutig;
    HinweisWarten hnwDialog;
  
    EindeutigkeitChecken(Str8tsApp mf, HinweisWarten hnw, int[] af, int[] ls) {
        eindeutig = true;
        hnwDialog = hnw;
        hnwDialog.zeigeHinweis("<html><center><b>Eindeutigkeit wird überprüft."
                + "<br><br>Bitte solange warten.</b></center></html>");
    }
  
    @Override
    public Boolean doInBackground() {
        for (int i = 0; i < 81; i++) {          
                for (int k = 1; k <= 9; k++) {
                    if (lw != k) {
                        if (lev > 0) {
                            eindeutig = false;
                            hnwDialog.setVisible(false);
                            return false;
                        }
                    }
                }
            }
        }
        eindeutig = true;
        hnwDialog.setVisible(false);
        return true;
    }  

    public boolean is_eindeutig() {
        return eindeutig;
    }
}
Hier erst einmal den Klassentyp Thread durch SwingWorker ersetzt und auf Runnable verzichtet.
Dann Variable für die Eindeutigkeit und den Warten-Dialog deklariert und im Konstruktor initialisiert.
Als nächstes die run-Methode mit dem steuernden Code als überschriebene doInBackground-Methode umbenannt.
Im Code selbst, wenn Eindeutigkeit feststeht, eindeutig auf true, ansonsten auf false gesetzt, den Warten-Dialog mit setVisible(false) nicht mehr angezeigt und return mit dem Ergebnis.

Als Letztes war noch die Methode is_eindeutig() zu schreiben.

Als Rückgabetyp habe ich Boolean verwendet, was aber nicht entscheidend ist. Ich hätte genau so gut Integer verwenden können, wird ja bei mir nicht ausgewertet, denn eindeutig = echeck.execute(); funktioniert nicht.

Gruß, kodela

PS:
Wenn Du Dir das Programm ansehen willst, auf meiner Homepage steht die Beta-Version zum Download, allerdings noch nicht in der aktuellen Fassung, die wird erst in einigen Tagen zur Verfügung stehen. Das Projekt selbst werde ich mit der ersten nicht Beta-Version zum Download anbieten.
 
Zuletzt bearbeitet:
@mihe7, danke für die Blumen, aber auch für Deine Denkanstöße.

Mittlerweile habe ich meinen Warten-Dialog auch um eine Fortschrittsanzeige erweitert. Auf diesen Gedanken hast auch Du mich gebracht. Danke!

Gruß, kodela
 
A

Anzeige




Hier lernst du alle wichtigen Java-Grundlagen.
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben