Ergebnis 1 bis 8 von 8

Java Timer soll langsamer ticken

  1. #1 Zitieren
    Veteran
    Registriert seit
    Jun 2012
    Beiträge
    630
    Ich habe 4 Bilder, die nacheinander gezeigt werden sollen, sodass sie eine Animation ergeben.

    Ich habe erst die vier Bilder geladen und ich habe einen Timer erzeugt.
    Jetzt wird die Variable MoveFrame immer hochgezählt von 0 bis 3 ( = 4 stück und je eins von den Bildern gezeigt )


    "zitat:

    Timer moveTimer = new Timer(1000, this);
    int MoveFrame = 0;
    Image imgmove1;
    Image imgmove2;
    Image imgmove3;
    Image imgmove4;


    MoveFrame++;
    if (MoveFrame > 3) {
    MoveFrame = 0;
    }

    if (MoveFrame == 0) {
    g.drawImage(imgmove1,X_Bild, (Y_Bild),null);
    }
    if (MoveFrame == 1) {
    g.drawImage(imgmove2,X_Bild, (Y_Bild),null);
    }
    if (MoveFrame == 2) {
    g.drawImage(imgmove3,X_Bild, (Y_Bild),null);
    }
    if (MoveFrame == 3) {
    g.drawImage(imgmove4,X_Bild, (Y_Bild),null);
    }
    }
    moveTimer.start();
    zitatEnde"

    Die Bilder werden zwar wie gewünscht gezeigt und sehen aus wie eine Bewegung, aber alles läuft in weniger als einer Sekunde ab, sodass die Animation super schnell und völlig hyperaktiv aussieht.

    Wie mache ich es, dass zwischen den Bildern je 1 Sekunde gewartet wird? (ohne sowas wie "thread.sleep" oder so, was das ganze Programm freezed.)



    EDIT:
    und nochwas ähnliches. Ich kann generell anfangs mit einem Timer für das ganze Programm (ein Spiel, das mit graphics g gezeichnet wird) festlegen, wie oft in einer Millisekunde neu gezeichnet wird.

    Trotzdem habe ich eine super hohe Framerate und wenn ich versuche es mit Fraps aufzunehmen schießt die Framerate in die Höhe und alles läuft plötzlich superschnell ab oder aber wird super zähflüssig und langsam.

    Weiß jemand warum, und was man machen kann dagegen, dass sich die Framerate ändert bei Videoaufnahmen vom Programm?
    Gothicforum ist offline Geändert von Gothicforum (31.03.2019 um 15:31 Uhr)

  2. #2 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Oh, ein Ratespiel.
    (da Codefragmente aus dem Zusammenhang gerissen und wild zusammengewürfelt)

    Vielleicht wird deine Warteschlange mit Events überflutet, möglicherweise durch immer neue Timer, die periodisch weiterfeuern, was bei verspäteten Events eben Ausführung ohne Wartezeit und daher maximale fps bewirkt. Natürlich geht es etwas langsamer, wenn dabei auch noch gemessen wird.

    Damit mir der Spaß nicht vergeht: Bitte lasse mich wissen, ob ich richtig liege und falls nicht, warum.
    jabu ist offline

  3. #3 Zitieren
    Veteran
    Registriert seit
    Jun 2012
    Beiträge
    630
    Zitat Zitat von jabu Beitrag anzeigen
    immer neue Timer, die periodisch weiterfeuern, was bei verspäteten Events eben Ausführung ohne Wartezeit und daher maximale fps bewirkt
    Das hier verstehe ich nicht.

    Zitat Zitat von jabu Beitrag anzeigen
    (da Codefragmente aus dem Zusammenhang gerissen und wild zusammengewürfelt)
    Ich kann ja mal ohne viel Code fragen.
    Angenommen, ich habe einen Timer (der dann für die Animation genutzt werden soll);
    die Syntax bei einem Timer besagt, dass die 10 die Refresh-Rate ist, oder?

    timer1 = new Timer(10,this);
    timer1.start();

    Wenn ich eine 50 eingebe, wird das Spiel/ die Animation weniger schnell neu gezeichnet und wenn ich eine 1 eingebe,
    dann läuft die Animation superschnell.
    So sollte es grundsätzlich funktionieren, oder?
    Also je größer ich die Zahl mache, umso langsamer wird die Animation?


    EDIT:
    Ich glaube, der Fehler ist die Verbindung zwischen dem Timer und was er ausführen soll.

    Ich habe, im Bsp oben, einen "MoveTimer" und jetzt will ich, dass er alle 5 Sekunden ,"MoveFrame++" auslöst.
    Wie ist denn die Syntax korrekt, um sowas (TimerTask?) zu kreieren?
    Gothicforum ist offline Geändert von Gothicforum (03.04.2019 um 13:52 Uhr)

  4. #4 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Ich ziehe dieses vor, damit meine Antwort weniger zerfasert:
    Zitat Zitat von Gothicforum Beitrag anzeigen
    Ich kann ja mal ohne viel Code fragen.
    Es geht doch nicht um die Menge, sondern um die fehlende Struktur. Der Programmfluss ist so leider nicht nachvollziehbar, sodass er geraten werden muss.

    So könnte ich z.B. raten, dass dieses durchweg Felder (und keine lokalen Variablen) sind:
    Code:
    Timer moveTimer = new Timer(1000, this);
    int MoveFrame = 0;
    Image imgmove1;
    Image imgmove2;
    Image imgmove3;
    Image imgmove4;

    Dein Code sagt leider nicht, wann bzw. unter welcher Bedingung MoveFrame inkrementiert wird. Und er sagt nicht, wann der Timer gestartet wird. Er sagt noch nicht mal, welcher Timer das ist, weswegen ich mal anhand der Parameter rate, dass es sich um einen javax.swing.Timer handeln soll.

    Gut, damit lässt sich schon etwas machen, falls ich richtig geraten habe. Dass der Code beim Parameter this kompiliert, deutet darauf hin, dass ich deinen Code ungefähr so ergänzen darf (Klassenname frei gewählt):
    Code:
    class Animator implements ActionListener
    {
        Timer moveTimer = new Timer(1000, this);
        int MoveFrame = 0;
        Image imgmove1;
        Image imgmove2;
        Image imgmove3;
        Image imgmove4;
        // . . .
    }
    Bis hierhin^ sehe ich noch keinen genügend verdächtigen Versagensgrund.

    Hierzu könnte ich mir denken...
    Code:
    MoveFrame++;
    if (MoveFrame > 3) {
        MoveFrame = 0;
    }
        
    if (MoveFrame == 0) {
        g.drawImage(imgmove1 ,X_Bild, Y_Bild, null);
    }
    if (MoveFrame == 1) {
        g.drawImage(imgmove2,X_Bild, Y_Bild, null);
    }
    if (MoveFrame == 2) {
        g.drawImage(imgmove3, X_Bild, Y_Bild, null);
    }
    if (MoveFrame == 3) {
        g.drawImage(imgmove4, X_Bild, Y_Bild, null);
    }
    ... dass es innerhalb von einem überschreibenden paintComponent steht. Da hätten wir schon mal einen Hinweis, dass das nicht gut wäre. Warum? Weil MoveFrame bei jedem Neuzeichnen erhöht wird, z.B. auch bei Resizes. Da man das nicht will, rate ich mal, dass der obere Abschnitt (vor der Leerzeile) woanders steht, nämlich innerhalb der überschreibenden Methode actionPerformed des Objektes, welches der Timer per this mitgeteilt bekommt. Richtig? Falls nicht, könnte hier vielleicht eine Ursache liegen.

    Puh, dafür musste ich jetzt schon meine Detektiv-Lupe bemühen. Wer weiß, ob ich unter anderen Umständen (z.B. mit dem falschen Bein aufgestanden) auf den ganzen Kram gekommen wäre.

    Falls MoveFrame doch bei jedem Neuzeichnen erhöht wird, wäre das schon ein möglicher Fehler. Aber das kann hier leider nur geraten werden, weil eben alles fehlt, was man bräuchte, um das zu erkennen.

    Spätestens hier müsste meine Lupe einer Glaskugel weichen:
    Code:
    }  // huch???
    moveTimer.start();  // wo wird das aufgerufen?

    Wo ist denn der Code, der das Neuzeichnen (z.B. JFrame.repaint) auslöst? Den hätte ich nämlich innerhalb von ActionListener.actionPerformed erwartet. Das Wichtigste fehlt hier also.

    Man beachte, dass der ganze Kram auf dem Event Dispatch Thread (EDT) ausgeführt werden muss. Den Stoff, also alles unter Nebenläufigkeit ("Concurrency in Swing"), sollte man, damit man keinen Mist fabriziert, wenigstens grob kennengelernt haben.

    Das hier verstehe ich nicht.
    Wenn man die Warteschlange mit Timer-Events flutet, die nicht so schnell abgearbeitet werden können, wie sie normalerweise dran kämen, dann ist dort die verbleibende Wartezeit Null, was maximale Geschwindigkeit bedeutet. Normalerweise müsste man das mit der Brechstange provozieren, aber Zufälle haben es so an sich, dass es auch so passieren kann (also als ein Aspekt einer Variante, den man raten kann, vorsichtshalber erwähnt).

    Angenommen, ich habe einen Timer (der dann für die Animation genutzt werden soll);
    die Syntax bei einem Timer besagt, dass die 10 die Refresh-Rate ist, oder?

    timer1 = new Timer(10,this);
    timer1.start();
    Unter "Refresh-Rate" versteht man in etwa "Aktualisierungen je Zeiteinheit". Bei dem Parameter handelt es sich, im Gegensatz dazu, um den Kehrwert und zwar in Millisekunden je Aktualisierung. Mit 10 ms wärest du hier so flott unterwegs, dass du bereits damit rechnen musst, dass andere Einflüsse gegenüber dem Timer überwiegen:
    So ist z.B. nicht garantiert, dass die Abarbeitung in der Zeit fertig ist. Auch das Interrupt-Intervall könnte mit seiner relativen Grobheit die Zeiten verfälschen. Meistens dürfte man das aber gar nicht merken.

    Wenn ich eine 50 eingebe, wird das Spiel/ die Animation weniger schnell neu gezeichnet und wenn ich eine 1 eingebe,
    dann läuft die Animation superschnell.
    So sollte es grundsätzlich funktionieren, oder?
    Also je größer ich die Zahl mache, umso langsamer wird die Animation?
    Ja, so sollte das sein. Bei geschickter Programmierung (EDT sollte keine langwierigen Berechnungen ausführen) und relativ wenig Berechnungen und nicht allzu kurzen Zeiten kann der Wert gut angenähert werden. Ansonsten kann er sich mehr erhöhen, als einem lieb ist. Bei einer einfachen "Diashow" und Vielfachen von ungefähr 100 ms als Bildwechselintervall sollte das aber noch nicht spürbar sein.

    EDIT:
    Ich glaube, der Fehler ist die Verbindung zwischen dem Timer und was er ausführen soll.
    Das könnte wohl gut hinkommen, fragt sich nur, was gemacht wurde.
    Vorschlag:
    1. In actionPerformed des Objektes, dem der Timer angehört, den Bildwechsel vollziehen und
    2. dort einmal ganz zum Schluss repaint ausführen und
    3. unter paintComponent nichts an der Animation manipulieren, weil das auch sonst aufgerufen wird, wenn es nötig ist (Animation würde ungewollt voranstolpern).

    Ich habe, im Bsp oben, einen "MoveTimer" und jetzt will ich, dass er alle 5 Sekunden ,"MoveFrame++" auslöst.
    Wie ist denn die Syntax korrekt, um sowas (TimerTask?) zu kreieren?
    Instanziieren (nicht zwingend mit this als ActionListener):
    Timer timer = new Timer(5000, this);

    Intervall ändern:
    timer.setDelay(delay);

    Anfangsverzögerung einstellen:
    timer.setInitialDelay(initialDelay);

    Starten:
    timer.start();

    Stoppen:
    timer.stop();

    Der Parameter, welcher this erhält, verweist selbstredend auf das aktuelle Objekt, z.B. gemäß einer solchen Klasse (kann alles zusammen als eine Möglichkeit für ein grobes Konzept genommen werden):
    Code:
    class Animator implements ActionListener { 
    
        private Timer timer = null;
    
        public Animator (int delay, int initialDelay) {
        	timer = new Timer(delay, this);
            timer.setInitialDelay(initialDelay);
        }
         
        @Override
        public void actionPerformed(ActionEvent evt) {
        	stepFwd();
        	frame.repaint(); // frame: oberste Ebene des GUIs
        }
        
        private void stepFwd() {
        	// Bildwechsel-Code einfügen
        }
           
        void start() {
            timer.start();
        }
        
        void stop() {
            timer.stop();
        }   
    }
    
    class Panel extends JPanel {    
        //...
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(Globals.curImage, 110, 110, null);
        }
    }
    
    void CreateAndShowGui() {          
        // GUI erstellen und erstmals anzeigen lassen
    }
    	
    public static void main(String[] args) throws Exception {
        // sicherstellen, dass auf dem EDT ausgeführt:
        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                Animator animator = new Animator(5000, 100);
                CreateAndShowGui();
                animator.start();  // oder woanders
            }
        });
    }
    Es fehlen natürlich Klassenzugehörigkeiten (insbes. mit Auswirkungen auf Besitz und Persistenz), einige Spezifizierer, da diese, z.B. je nach Klassendesign, unterschiedlich ausfallen können und das Erstellen des GUIs (z.B. das besagte Panel einem JFrame hinzufügen). Ich wollte kein komplettes Programm "spoilern", damit die Sache nicht ihren Reiz/Sinn/Nutzen verliert.

    Das musste schnell gehen, weswegen mit Fehlern zu rechnen ist. In der Hoffnung, dass es hilft.
    jabu ist offline Geändert von jabu (07.04.2019 um 13:29 Uhr) Grund: Leerzeile eingefügt

  5. #5 Zitieren
    Veteran
    Registriert seit
    Jun 2012
    Beiträge
    630
    An den Timern doktor ich noch rum.

    Aber noch eine andere Frage, da ich nicht für jede Frage einen Thread öffnen mag:

    Kann ich Graphics g sagen, dass ein Element über ein anderes gezeichnet werden soll, IF condition true?

    also sagen wir ich male ein grünes Dreieck und einen blauen Kreis.
    Wenn das Dreieck im Bild höher ist (kleinere Y-Koordinate), dann soll es als erstes gezeichnet werden und der Kreis teilweise darüber,
    wenn das Dreieck im Bild tiefer ist (größere Y-Koordinate), dann soll es nach dem Kreis gezeichnet werden, sodass es jenen teilweise verdeckt.
    Gothicforum ist offline

  6. #6 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Zitat Zitat von Gothicforum Beitrag anzeigen
    An den Timern doktor ich noch rum.
    Ja, zunächst sieht das etwas kompliziert aus, da man sie so nutzen muss, wie es das Framework vorsieht, was eine Einstiegshürde ist, da man erst mal ergründen muss, wie es tickt. Die Doku zum Event Dispatch Thread sollte dafür ein geeigneter Einstiegspunkt sein.
    Kann ich Graphics g sagen, dass ein Element über ein anderes gezeichnet werden soll, IF condition true?
    Das geschieht automatisch, wenn du das verdeckende Element (natürlich auf deine Bedingung hin) später zeichnen lässt.
    also sagen wir ich male ein grünes Dreieck und einen blauen Kreis.
    Wenn das Dreieck im Bild höher ist (kleinere Y-Koordinate), dann soll es als erstes gezeichnet werden und der Kreis teilweise darüber,
    wenn das Dreieck im Bild tiefer ist (größere Y-Koordinate), dann soll es nach dem Kreis gezeichnet werden, sodass es jenen teilweise verdeckt.
    Dazu genügt es (vorausgesetzt, alles andere stimmt), die Reihenfolge gemäß deiner Bedingungen zu steuern.

    Nebenbei: Für Transparenz, wo gewünscht, kannst du den Alphakanal benutzen, also z.B. Schema RGBA anstatt RGB. Bei Color geht das einfach mit einem weiteren Parameter für den Alphakanal, also new Color(r, g, b, a).
    jabu ist offline

  7. #7 Zitieren
    Veteran
    Registriert seit
    Jun 2012
    Beiträge
    630
    Zitat Zitat von jabu Beitrag anzeigen
    Das geschieht automatisch, wenn du das verdeckende Element (natürlich auf deine Bedingung hin) später zeichnen lässt.

    Dazu genügt es (vorausgesetzt, alles andere stimmt), die Reihenfolge gemäß deiner Bedingungen zu steuern.
    Was ist, wenn es z.b. drei oder vier rectangles gibt, die sich bewegen, hoch und runter, links und rechts,
    also ich kann es nicht `hard-coden`, welches zuerst gezeichnet wird.
    Wie kann ich das coden, dass immer dasjenige, das am weitesten unten ist (größte Y-Koordinate) als letztes gezeichnet werden soll?

    Bei nur zwei Stück hatte ich es so
    if (Y1 > Y2){ dann mal erst das eine dann das andere}
    if (Y1 < Y2){ dann erst das andere dann das eine}

    aber wenn ich jetzt drei, vier habe und die ihre Position wechseln (UND die darüber hinaus auch noch Bewegungsanimationen, also wechselnde Bilder bekommen), wird das ein bisschen viel Code, der immer und immer wieder geprüft wird von graphics g.
    Gothicforum ist offline

  8. #8 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Zitat Zitat von Gothicforum Beitrag anzeigen
    Was ist, wenn es z.b. drei oder vier rectangles gibt, die sich bewegen, hoch und runter, links und rechts,
    also ich kann es nicht `hard-coden`, welches zuerst gezeichnet wird.
    Wie kann ich das coden, dass immer dasjenige, das am weitesten unten ist (größte Y-Koordinate) als letztes gezeichnet werden soll?
    Das ließe sich bewerkstelligen, indem du die Objekte (falls du keine hast, mach dir eine Klasse, s.u.) gemäß ihrer Y-Koordinate sortierst. Du mögest dich also mit Sortieralgorithmen beschäftigen.

    Ein einfacher Sortieralgorithmus, der als Bubblesort bezeichnet wird, besteht aus zwei ineinander geschachtelten Schleifen, hier simpel demonstriert (lauffähig (wobei die int-Werte natürlich auch Objekten angehören könnten, auf denen man mit Gettern und Settern arbeitet)):
    Code:
    class Sortieren {
        static final int[] reihenfolge_01 = { -20, 1, 2, 3, 4, 4, -4, 5, 20, 10, -11, 12, 13, 0, 14, 15, 16, -17, 90, 90 };
        static final int[] reihenfolge_02 = { -19, -19, -11, 9, -17, -5, -9, -12, 10, -3, 7, 4, 5, -5, 4, 4, 3, 2, 1, 13 };
    
        static void sort(int[] a) {
            for (int end = a.length - 1; end > 0; end--) {
                for (int i = 0; i < end; i++) {
                    if (a[i] < a[i + 1]) {
                        int tmp = a[i];
                        a[i] = a[i + 1];
                        a[i + 1] = tmp;
                    }
                }
            }
        }
    
        static void out(int[] a) {
            for (int i : a) System.out.format("%4d", i);
            System.out.println();
        }
    
        public static void main(String[] args) {
            int[] sammlung;
            sammlung = reihenfolge_01;
            sort(sammlung);
            out(sammlung);
            sammlung = reihenfolge_02;
            sort(sammlung);
            out(sammlung);
        }
    }
    Ausgabe:
    Code:
      90  90  20  16  15  14  13  12  10   5   4   4   3   2   1   0  -4 -11 -17 -20
      13  10   9   7   5   4   4   4   3   2   1  -3  -5  -5  -9 -11 -12 -17 -19 -19
    Bei kleinen Zahlenmengen ist Bubblesort relativ schnell, bei großen relativ langsam (wegen O(n2)). Doch schnellere Algorithmen sind komplexer, wodurch ein Zusatzaufwand entsteht, der mit abgearbeitet werden muss, weswegen einfache Algorithmen wie dieser lange die Nase vorn haben (und bei großen Mengen irgendwann unbrauchbar werden). Bevor du dir komplexere anguckst (was du irgendwann tun solltest, z.B. Heapsort), solltest du Bubblesort verstanden haben. Natürlich lässt der sich nicht nur auf ein starres Array aus int-Werten anwenden, sondern z.B. auch auf ein ArrayList<T>.

    Diese Containerklassen bieten selbst eine Sortiermethode an, aber dazu müsstest du Comparable<T> implementieren und die Methode compareTo überschreiben, was man schon als eine fortgeschrittene Thematik bezeichnen könnte. Wer dazu zu faul ist, kann ab Java 8 ersatzweise mit Comparator.comparing (und einer Lambda-Funktion als Parameter, die sich bequem von einem Methodennamen ableiten lässt) bei standardmäßigen Sortierkriterien, wie sie meistens genügen, eine Menge Schreibarbeit einsparen und den Code damit übersichtlicher halten. Das könnte dann, auf deinen Fall gemünzt (nur Konsolenausgabe, um das Konzept zu verdeutlichen), etwa so aussehen (lauffähig):
    Code:
    import java.awt.Color;
    import java.util.ArrayList;
    import java.util.Comparator;
    
    abstract class Primitive
    {
        protected Primitive (Color color, boolean visible, int posX, int posY) {
            this.color = color;
            this.visible = visible;
            this.posX = posX;
            this.posY = posY;        
        }
        public Color getColor() { return this.color; };
        public boolean getVisible() { return this.visible; }
        public int getPosX() { return this.posX; }
        public int getPosY() { return this.posY; }    
        public void setColor(Color color) { this.color = color; }
        public void setVisible(boolean visible) { this.visible = visible; }
        public void setPosX(int posX) { this.posX = posX; }
        public void setPosY(int posY) { this.posY = posY; }    
        private Color color;
        private boolean visible;
        private int posX;
        private int posY;    
    }
    
    class Rectangle extends Primitive
    {
        public Rectangle (Color color, boolean visible, int posX, int posY, int width, int height) {
            super(color, visible, posX, posY);
            this.width = width;
            this.height = height;
        }    
        public int getWidth() { return this.width; }
        public int getHeight() { return this.height; }
        public void setWidth(int width) { this.width = width; }
        public void setHeight(int height) { this.height = height; }
        private int width;
        private int height;
    }
    
    class Circle extends Primitive
    {
        public Circle (Color color, boolean visible, int posX, int posY, int diameter) {
            super(color, visible, posX, posY);
            this.diameter = diameter;
        }    
        public int getDiameter() { return this.diameter; }
        public void setDiameter(int diameter) { this.diameter = diameter; }
        private int diameter;
    }
    
    final class Colors
    {
        final static Color color_01 = new Color(32, 64, 128);
        final static Color color_02 = new Color(64, 128, 32);
        final static Color color_03 = new Color(128, 32, 64);    
        final static Color color_04 = new Color(32, 128, 64);
        final static Color color_05 = new Color(128, 64, 32);
        final static Color color_06 = new Color(64, 32, 128);
    }
    
    public class ListSort
    {    
        public static void printAllPosY(ArrayList<Primitive> list) {
            for (Primitive primitive : list) {
                if (primitive.getVisible()) {
                    if (primitive instanceof Circle) {
                        Circle circ = (Circle)primitive;
                        System.out.format("PosY: %d - I'm a circle. ", circ.getPosY());
                        System.out.format("My diameter is: %d%n", circ.getDiameter());
                    } else if (primitive instanceof Rectangle) {
                        Rectangle rect = (Rectangle)primitive;
                        System.out.format("PosY: %d - I'm a rectangle. ", rect.getPosY());
                        System.out.format("My width and height are: %dx%d%n", rect.getWidth(), rect.getHeight());
                    } else {
                        System.out.format("PosY: %d - I'm an unknown primitive!%n", primitive.getPosY()); 
                    }
                } else {
                    System.out.format("You don't see me!%n");
                }
            }
            System.out.println();
        }
    
        public static void main(String[] args) throws Exception {
    
            ArrayList<Primitive> list = new ArrayList<Primitive>();
            list.add(new Rectangle(Colors.color_01, true, 100, 444, 50, 80));
            list.add(new Rectangle(Colors.color_02, true, 100, 999, 50, 80));
            list.add(new Rectangle(Colors.color_03, false, 100, 777, 50, 80));
            list.add(new Rectangle(Colors.color_04, true, 100, 666, 50, 80));
            list.add(new Circle(Colors.color_05, true, 100, 888, 77));
            list.add(new Circle(Colors.color_06, true, 100, 222, 77));       
    
            System.out.format("Vor der Sortierung:%n");
            printAllPosY(list);
    
            list.sort(Comparator.comparing(Primitive::getPosY));
            System.out.format("Nach aufsteigender Sortierung:%n");
            printAllPosY(list);
    
            list.sort(Comparator.comparing(Primitive::getPosY).reversed());
            System.out.format("Nach absteigender Sortierung:%n");
            printAllPosY(list);
    
        }
    
    }
    Ausgabe:
    Code:
    Vor der Sortierung:
    PosY: 444 - I'm a rectangle. My width and height are: 50x80
    PosY: 999 - I'm a rectangle. My width and height are: 50x80
    You don't see me!
    PosY: 666 - I'm a rectangle. My width and height are: 50x80
    PosY: 888 - I'm a circle. My diameter is: 77
    PosY: 222 - I'm a circle. My diameter is: 77
    
    Nach aufsteigender Sortierung:
    PosY: 222 - I'm a circle. My diameter is: 77
    PosY: 444 - I'm a rectangle. My width and height are: 50x80
    PosY: 666 - I'm a rectangle. My width and height are: 50x80
    You don't see me!
    PosY: 888 - I'm a circle. My diameter is: 77
    PosY: 999 - I'm a rectangle. My width and height are: 50x80
    
    Nach absteigender Sortierung:
    PosY: 999 - I'm a rectangle. My width and height are: 50x80
    PosY: 888 - I'm a circle. My diameter is: 77
    You don't see me!
    PosY: 666 - I'm a rectangle. My width and height are: 50x80
    PosY: 444 - I'm a rectangle. My width and height are: 50x80
    PosY: 222 - I'm a circle. My diameter is: 77
    Es gibt also eine flexible Liste, zu der sich beliebig viele Elemente eines selbst definierten Typs hinzufügen lassen, wobei auch der Typ flexibel ist, solange er die abstrakte Klasse Primitive erweitert. Natürlich könntest du alternativ selber, z.B. per Bubblesort (s.o.), sortieren.

    [...] wird das ein bisschen viel Code, der immer und immer wieder geprüft wird von graphics g.
    Packe den Animationscode besser nicht in die Präsentationsebene. Erinnerst du dich an meinen vorletzten Beitrag, von wegen
    Code:
    class Animator implements ActionListener
    usw. ? Dort ist das, wie gesagt, besser aufgehoben. Außerdem lässt sich der Krempel dann auch steuern (actionPerformed erhält einen Event, den du auswerten kannst). Vielleicht guckst du dir das mal an. Das Schema beantwortet solche Fragen.

    Solange die Ausführungszeit deines Animators kurz ist, klappt das innerhalb der Methode actionPerformed, also auf den Timer-Event hin, normalerweise gut. Bei langen Ausführungszeiten, wie sie sich bei komplexen Szenen oder viel Kopierarbeit ergeben können, könnten sich u.U. die Unterschiede in den Ausführungszeiten störend bemerkbar machen. Dann sollte es besser sein, die Berechnungen nach der Präsentation durchführen zu lassen, damit die Präsentation auf den Event hin sofort und in konstanter Zeit erfolgen kann. Bei dem Kleinkram hier fallen solche Unterschiede natürlich nicht auf, da sie absolut sehr gering sind. Da fallen schon eher die groben Timer-Interrupt-Intervalle (von typ. 1...15,625 ms, was die tatsächliche Auflösung definiert) auf, in deren "Rauschen" solche kleinen Unterschiede untergehen.
    jabu ist offline Geändert von jabu (07.05.2019 um 01:05 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •