Swing Problem mit Warten-Dialog

kodela

Bekanntes Mitglied
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
 

kodela

Bekanntes Mitglied
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.
 

kodela

Bekanntes Mitglied
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:

mihe7

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

kodela

Bekanntes Mitglied
Danke mihe7,

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

Gruß, kodela
 

kodela

Bekanntes Mitglied
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
 

mihe7

Top Contributor
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.
 

kodela

Bekanntes Mitglied
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
 

mihe7

Top Contributor
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.
 

mihe7

Top Contributor
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);
    }
 

kodela

Bekanntes Mitglied
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
 

kodela

Bekanntes Mitglied
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
 

mihe7

Top Contributor
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?
 

kodela

Bekanntes Mitglied
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:

kodela

Bekanntes Mitglied
@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
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G Problem mit der Anzeige von jLabel. Unlesbar wenn der Text geändert wird. AWT, Swing, JavaFX & SWT 28
H 2D-Grafik Problem mit Paint AWT, Swing, JavaFX & SWT 1
S Layout - Problem AWT, Swing, JavaFX & SWT 1
Tassos JavaFX/Problem mit der Maussteuerung in Stackpane AWT, Swing, JavaFX & SWT 7
sserio Java Fx - Problem AWT, Swing, JavaFX & SWT 3
A Problem Spiel auf Panel der GUI zu bringen AWT, Swing, JavaFX & SWT 1
A JavaFX Controller Problem AWT, Swing, JavaFX & SWT 1
TheWhiteShadow JavaFX ListView Problem beim Entfernen von Elementen AWT, Swing, JavaFX & SWT 1
E LayoutManager Welcher Layout-Mix löst mein Problem? AWT, Swing, JavaFX & SWT 3
Umb3rus JavaFX Problem mit PropertyValueFactory: can not read from unreadable property AWT, Swing, JavaFX & SWT 1
T Problem mit paintComponent() AWT, Swing, JavaFX & SWT 17
AmsananKING Java Menü-Problem AWT, Swing, JavaFX & SWT 1
K JavaFX Resizing-Problem beim BorderLayout (Center Component) beim Arbeiten mit mehreren FXMLs AWT, Swing, JavaFX & SWT 2
G Instance OF Problem AWT, Swing, JavaFX & SWT 9
FrittenFritze Ein Problem mit der CSSBox, die Größe wird nicht angepasst AWT, Swing, JavaFX & SWT 5
M Problem mit dem Anzeigen von Frames im Vordergrund AWT, Swing, JavaFX & SWT 5
Badebay Problem mit JButton AWT, Swing, JavaFX & SWT 2
newJavaGeek Grid-Layout problem AWT, Swing, JavaFX & SWT 7
J JavaFX Löschen im Tabelview macht Problem AWT, Swing, JavaFX & SWT 15
JavaTalksToMe JavaFx ExekutorService Problem AWT, Swing, JavaFX & SWT 2
Zrebna Problem bei Eventhandling (Value soll nach jedem erneutem Klick gelöscht werden) AWT, Swing, JavaFX & SWT 4
B Problem mit JavaFX AWT, Swing, JavaFX & SWT 5
J css Problem AWT, Swing, JavaFX & SWT 5
B JavaFX habe mein Problem fett markiert AWT, Swing, JavaFX & SWT 2
A Swing Filter-Problem AWT, Swing, JavaFX & SWT 1
temi JavaFX Problem mit IntelliJ und JavaFx 11 unter XUbuntu AWT, Swing, JavaFX & SWT 3
L Java FX Problem mit Ubuntu 18 und JavaFx AWT, Swing, JavaFX & SWT 27
H JTable TableCellEditor-Problem AWT, Swing, JavaFX & SWT 0
B JavaFx Scene Builder Problem AWT, Swing, JavaFX & SWT 2
B [Problem] Java öffnet Word-Datein nicht AWT, Swing, JavaFX & SWT 14
T DataBinding Problem AWT, Swing, JavaFX & SWT 5
Blender3D Problem mit € Symbol Font Gotham Windows 10 Swing AWT, Swing, JavaFX & SWT 11
T Problem mit JTable Sortierung AWT, Swing, JavaFX & SWT 2
J Problem mit Platfrom run later AWT, Swing, JavaFX & SWT 15
J Problem mit Platfrom run later AWT, Swing, JavaFX & SWT 0
D Swing SwingUtils / Thread Problem AWT, Swing, JavaFX & SWT 3
L JavaFX Problem beim Aufrufen einer Methode AWT, Swing, JavaFX & SWT 5
T Swing Problem mit Datum und FormattedTextField AWT, Swing, JavaFX & SWT 2
S AWT Java print dialog Problem AWT, Swing, JavaFX & SWT 0
olfibits JavaFX Problem mit HTMLEditor AWT, Swing, JavaFX & SWT 0
W SWT hover-background-problem with first column in TreeViewer AWT, Swing, JavaFX & SWT 0
M Problem mit Add JScrollPane AWT, Swing, JavaFX & SWT 25
Mario1409 Swing JTextArea scroll Problem AWT, Swing, JavaFX & SWT 0
N Swing Problem mit loop AWT, Swing, JavaFX & SWT 2
S Swing Problem mit Button und ActionListener AWT, Swing, JavaFX & SWT 5
S Swing & Clean und build Problem AWT, Swing, JavaFX & SWT 12
S JLabel setText() Problem AWT, Swing, JavaFX & SWT 6
I 2D-Grafik Problem beim Ändern der Farbe eine 2d Objekts AWT, Swing, JavaFX & SWT 3
G Swing Splitpane Problem AWT, Swing, JavaFX & SWT 1
F Problem mit der FXML Rectangle Shape AWT, Swing, JavaFX & SWT 2
N JavaFX Stranges Problem mit der Autoscroll-Eigenschaft von Textareas AWT, Swing, JavaFX & SWT 0
E Java FX FXML Problem mit html Scriptausführung AWT, Swing, JavaFX & SWT 2
J JavaFX Intersect Problem mit Shapes AWT, Swing, JavaFX & SWT 10
R JavaFX MediaPlayer AVI-Problem AWT, Swing, JavaFX & SWT 1
M Swing Problem mit ListCellRenderer AWT, Swing, JavaFX & SWT 7
D Problem mit JTable AWT, Swing, JavaFX & SWT 1
F GUI Auflösung ändern - Koordianten und Proportions Problem AWT, Swing, JavaFX & SWT 21
J Problem mit Button darstellung AWT, Swing, JavaFX & SWT 23
M Problem mit Layoutmanagern... Hilfe wäre sehr nett. AWT, Swing, JavaFX & SWT 2
S 2D-Grafik Problem mit Variablen AWT, Swing, JavaFX & SWT 4
7 JavaFX Problem beim Zeichnen eines Dreiecks in einem GUI AWT, Swing, JavaFX & SWT 6
M Swing AttributiveCellTableModel addRow() Problem AWT, Swing, JavaFX & SWT 1
J Swing Problem mit Graphics Methode AWT, Swing, JavaFX & SWT 4
N JavaFX Problem mit table multiple selection AWT, Swing, JavaFX & SWT 5
K CheckBox Problem AWT, Swing, JavaFX & SWT 5
Grevak DisplayMode Problem seit Windows 10 AWT, Swing, JavaFX & SWT 2
S Swing Eigene JComboBox Problem! AWT, Swing, JavaFX & SWT 1
B Swing Problem mit Bildpfad AWT, Swing, JavaFX & SWT 4
N Swing Problem beim Scrollen mit JScrollPane AWT, Swing, JavaFX & SWT 6
V Graphics g - drawOval problem mit background AWT, Swing, JavaFX & SWT 1
C AWT Problem mit Protokol Fenster AWT, Swing, JavaFX & SWT 0
M Swing pack() Problem mit Taskleiste AWT, Swing, JavaFX & SWT 4
N Swing Choice- Problem! AWT, Swing, JavaFX & SWT 8
Q "AWT-EventQueue-0" Exception Problem AWT, Swing, JavaFX & SWT 4
D jButton Problem, ein Rieser Button bedeckt das ganze frame AWT, Swing, JavaFX & SWT 1
A Problem: repaint() - Schleife AWT, Swing, JavaFX & SWT 3
J Anfänger GUI Problem bei der Ausführung eines sehr einfachen Programms AWT, Swing, JavaFX & SWT 2
P AWT Problem mit Platzierung (GridBagLayout) AWT, Swing, JavaFX & SWT 2
N Swing JTree Problem beim erstellen der Knoten AWT, Swing, JavaFX & SWT 0
N Swing CardLayout: Problem beim Wechsel zwischen den JPanels AWT, Swing, JavaFX & SWT 3
A Mini-Menu-Schriften. Ein Problem bei hohen DPI Zahlen AWT, Swing, JavaFX & SWT 2
Z Canvas in Frame einfügen. Problem mit 4-Gewinnt AWT, Swing, JavaFX & SWT 1
C Thread-/ Simulations- Problem AWT, Swing, JavaFX & SWT 18
G Swing Setvisible problem AWT, Swing, JavaFX & SWT 1
J JTabbedPane: close Button Problem AWT, Swing, JavaFX & SWT 2
Tom299 JavaFX -> fxmlLoader -> getResourceAsStream Problem AWT, Swing, JavaFX & SWT 1
T Problem: ComboBox und addItem AWT, Swing, JavaFX & SWT 5
M JTextArea wird nicht aktualisiert (ActionListener-Problem) AWT, Swing, JavaFX & SWT 1
T LayoutManager LookAndFeel-Problem AWT, Swing, JavaFX & SWT 4
F Problem mit Implementierung von Kollisionsabfrage AWT, Swing, JavaFX & SWT 5
vodkaz (javafx) Image Problem AWT, Swing, JavaFX & SWT 2
T Problem beim Zeichnen von Rechteck AWT, Swing, JavaFX & SWT 3
B JavaFX Problem bei Kamera / Group, gesamte Scene bewegt sich mit AWT, Swing, JavaFX & SWT 0
L Swing Vier Gewinnt Problem AWT, Swing, JavaFX & SWT 2
Z GUI-Problem, finde meinen Fehler nicht! AWT, Swing, JavaFX & SWT 11
B JavaFX KeyEvent und Canvas draw Problem AWT, Swing, JavaFX & SWT 9
R Swing Problem: IOException bei ActionListener AWT, Swing, JavaFX & SWT 1
GianaSisters JFrame mit JInternalFrames, Keylistener-Problem AWT, Swing, JavaFX & SWT 9
Q JList Update Problem AWT, Swing, JavaFX & SWT 1
A Problem mit drawImage AWT, Swing, JavaFX & SWT 1

Ähnliche Java Themen

Neue Themen


Oben