bitte um performance ratschläge

Status
Nicht offen für weitere Antworten.

hdi

Top Contributor
hallo,

nach 3 verschiedenen versuchen hab ich noch immer kein richtig schön flüssiges, vorallem stabil flüssiges, spiel hinbekommen (geht um n tetris).

ich hab hier grad n riesen aufsatz geschrieben wie ich das gemacht habe, aber wieder gelöscht. ich denke das würde euch eher langweilen und ohne viel code steigt man da eh nicht durch.

also frag ich gleich mal heraus, wie ihr den spielablauf von einem tetris-spiel gestalten würdet.

also: wieviele threads? (z.B. braucht man einen der alle 500ms einen stein nach unten rückt, aber einen anderen der in viel kürzeren abständen die tastatur überwacht)

am meisten geht es mir aber darum, wo ich die hauptberechnungen reinpacken soll.

direkt in den keylistener? und mit einem SwingWorker? Ich weis snciht, ich hab lediglich ein video gesehen vor nem tag wo jemand über swing geredet hat und darüber, komplexe vorgänge eines listeners in einen SwingWorker zu packen, weil sonst die repaint-methode zu lange warten muss.

ja also ich könnt wieder ewig labern ;)

wäre einfach sehr froh wenn mir einer einen logischen grundriss von tetris gibt, nur im hinblick auf threading.
welcher thread am besten was übernimmt, wie sie zusammenhängen und wo gezeichnet wird.

weil ich kriegs einfach nach 100 anläufen nicht richtig hin, und ich hab es auch satt code zu schreiben, bei dem ich schon während des schreibens die zähne zusammenbeiss so vonwegen "hoffentlich klappts".. das is ja nix, ich mag das endlich mal kapiert haben - tu schon seit über 3 wochen jeden tag 5 stunden mit swing rum :### aber bisher hab ich immer nur codefetzen von hier abgeschrieben oder halt durch rumprobieren gecodet.

also wär sehr dankbar, mich interessiert es einfach wie ihr profis so ein spiel angehen würdet! ich wette ich mach das absolut verkehrt weil es auch unnötig kompliziert und verschachtelt is.
 
G

Guest

Gast
hm also so einfach isses glaub ich nicht.
wie gesagt, man kann nicht einne mover-thread machen, denn es muss jede halbe sekunde der block eins nach unten ruschten (sleep 500), aber nach links und rechts bewegen und den Block drehen kann man natürlich mehr als nur 1 mal in der halben sekunde, das kann man viel schneller machen (sleep 20)

d.h. dafür alleine brauch ich schon zwei threads, oder?

und was meinst du mit dem AWT event dispatch der das zeichnet? was isn der AWT e.d. genau, das is ja nix was ich neu anlege oder? wie kann ich den zeichnen lassen?
 

Marco13

Top Contributor
Das Hin-und-Her-Bewegen wird ja sowieso über KeyEvents gemacht. Die Information wird dann einfach (direkt, oder indirekt) auf den Stein übertragen. (Du wirst ja jetzt wohl auch nicht alle 20 ms abfragen, ob irgendeine Taste gedrückt wurde?)
Wozu man da mehr als einen Spiel-Thread benötigen sollte (und den EDT) wüßt' ich jetzt auch nicht... ???:L
 
G

Guest

Gast
Du wirst ja jetzt wohl auch nicht alle 20 ms abfragen, ob irgendeine Taste gedrückt wurde?

ja gut äh, also ich sag mal, naja, natürlich isses ja so äh, und vorallem DESHALB, und ja genau (shice :oops:)

jaaa also irgendwie passieren die üänderungen auf der datenstruktur eines blocks gar nicht im keylistener, sondern eben in einem andren thread.
mein keylistener macht im moment nix anderes als eine variable zu setzen, in der die gedrückte taste gepsiechert wird.

jo, das is wohl nich so gut was^^ ich sollte also die berechnungen DIREKT in die methode keyPressed() reintun?
 

Wildcard

Top Contributor
Anonymous hat gesagt.:
jo, das is wohl nich so gut was^^ ich sollte also die berechnungen DIREKT in die methode keyPressed() reintun?
Bei den meisten Spielen wäre das nicht der Renner, zu Tetris passt es aber ganz gut, da die Geschwindigkeit tatsächlich von der Häufigkeit der Tastenanschläge abhängt.
 

Marco13

Top Contributor
Die Berechnungen sollten nicht unbedingt in die KeyPressed (genaugenommen hätte ich da sogar gewissen Bedenken bzgl. Synchronisation). Dass das keyPressed nur eine Variable setzt, wo drinsteht, welche Taste gedrückt wurde, KÖNNTE auch OK sein. Aber dann sollte das KeyPressed dafür sorgen, dass der Spiel-Thread aufgeweckt wird, und sich die Taste abholt. Also, wenn der Stein in 500ms-Schritten fallen soll, dann könnte da ja evtl. irgendwo ein
wait(timeTillNextStep);
stehen, wobei timeTillNextStep eben anfangs 500 ist. Wenn eine Taste gedrückt wird, wird aber der Thread ge-notify()-t, holt sich die gedrückte Taste ab, macht die bewegung, und wartet dann (mit wait) die restliche Zeit bis zum nächsten Schritt.
Das sind aber KEINE Empfehlungen! (ich weiß nicht, welche Methode "die beste" wäre). Nur Vorschläge, die du in Erwägung ziehen kannst.
 

André Uhres

Top Contributor
Marco13 hat gesagt.:
Die Berechnungen sollten nicht unbedingt in die KeyPressed (genaugenommen hätte ich da sogar gewissen Bedenken bzgl. Synchronisation)..
Man muss nur die Eventhandler synchronized machen (Key, Action und Timer Event) :wink:
 
G

Guest

Gast
eventhandler? und das heisst?
nicht die methoden zb. keyPressed() oder?

meinst du sowas:

keyPressed(KeyEvent e){
synchronized(e){
..
}
}

?
 

André Uhres

Top Contributor
Beispiel:
Code:
public class Game {
...
    private synchronized void handleTimerEvent() {
...
    }
    private synchronized void handleActionEvent() {
...
    }
    private synchronized void handleKeyEvent(KeyEvent e) {
...
    }
...
}
"handleKeyEvent" z.B. würdest du dann einfach in "keyPressed" aufrufen.
 
G

Guest

Gast
okay..

aber wird nich jedesmal ein neues event-objekt erstellt? heisst das jetzt echt dass eine gedrückte taste erst alle operationen durchführt, bevor eine andere anfangen kann?

und generell: diese sache mit time event und so, nur damit ich weiss woran ich bin:

wenn mein thread der diesen keyListener implementiert immer für 500ms schläft, heisst das dann, dass er in diesen pausen auch nicht auf tastendrücke reagieren wird? anders: MUSS ich dieses ge-notify()-ing (das solltest du übrigens copyrighten() ), machen, damit der spieler den stein schnell drehen und bewegen kann, während er langsam runterfällt?

danke
 

André Uhres

Top Contributor
Anonymous hat gesagt.:
..heisst das jetzt echt dass eine gedrückte taste erst alle operationen durchführt, bevor eine andere anfangen kann?
Das ist ja der Sinn der Synchronisation, nicht wahr?

Anonymous hat gesagt.:
..wenn mein thread der diesen keyListener implementiert immer für 500ms schläft, heisst das dann, dass er in diesen pausen auch nicht auf tastendrücke reagieren wird?
Der KeyListener läuft auf dem EDT und hat nix mit dem Game Thread zu tun.
Den sleep darf man natürlich nicht synchronisieren. In diesen Pausen wird dann weiterhin auf Tastendrücke reagiert.

Anonymous hat gesagt.:
anders: MUSS ich dieses ge-notify()-ing (das solltest du übrigens copyrighten() ), machen, damit der spieler den stein schnell drehen und bewegen kann, während er langsam runterfällt?
Musst du nicht, ist auch nicht meine Idee :D
 
G

Guest

Gast
hm okay leute also... leider ist das nicht so simpel wie ihr es hier darstellt. nicht umsonst hab ich das jetzt
schon 4 mal gemacht und komm immer wieder in die selben Probleme rein, deren Lösung ich noch immer nicht kenne.

mit nem move-thread und nem keylistener, der "eh den rest macht", geht das nicht. ODer ich kanns nicht. z.B.:

1. Der Spieler droppt nen Stein. der move-thread pennt gerade. Der neue stein hängt entweder 499 ms in der Luft (er wurde erstellt 1ms bevor der move-thread sich schlafen legte), ODER er bewegt sich sofort (der move-thread wacht just in dem moment auf, wo der neue stein erstellt wurde).
und nu? notify()? wait()? hä? synchronized? was? was hat das alles damit zu tun? ICh kann meinen Thread nich aufwecken, super.

2. wenn ne reihe voll ist soll sie aufblinken. dabei soll der move-thread natürlich NICHT nen stein nach unten bewgen! das gleiche problem wieder: was soll ich notifyen? Ich hab kein Objekt für die Situation , dass eine Reihe blinkt. Das Blinken einer Reihe ist eine Operation, kein Objekt. Aber normale Befehle gibt es in JAva nicht. Kein Objekt, kein Programm.

usw..

das Problem ist, wie ich schon sagte, dass alles voneinander abhängt! move-thread und jemand, der das zeichnet ist VIEL zu vereinfacht gesagt, so ist einfach das Tetris spiel nicht! Die 2 Punkte waren jetzt nur 2 von 10 Standard-Features eines einfachen Tetris.

Und meine Frage war ja eben, wie ich Threads kommunizieren lassen soll, wie ich das aufbau, usw.
Ich hab das Spiel nun zum 4.mal neu programmiert, und bleibe immer wieder stecken an solchen dingen wie oben erwähnt.

Riesen Probleme mit Threads halt... Ich bitte euch, nochmal genau über das Tetris-Spiel nachzudenken, und dann noch mal zu überlegen, wie ihr das machen würdet.

Ich will doch nur nen Grundriss eines UML-Diagramms, einfach wieveil Threads es gibt und was die machen.
und zwar so, dass z.B. die oberen 2 Punkte berückstigt werden.

Sorry, ich glaube einfach nicht, dass es so geht wie ihr hier sagt. Und ich werd langsam crazy dass ich so normale Spielsituationen nicht steuern kann,und es dauert nich mehr lang und ich klatsch java an die wand weil einem so krass die hände genbunden sind..

bitte... wie löst ihr sowas in java? ihr könnt das doch (und ich weiss sehr wohl dass JAva das AUCH kann). Aber ich nicht, nicht so wie ich's im Moment versuch. Da muss mehr sein, mehr Threads, mehr Objekte, keine Ahnung. Es geht einfach nich so leicht.

Bidde.. nochmal etwas länger nachdenken und mir weiterhelfen, ich flipp hier aus :bahnhof:

vielen, vielen dank

Und das hier ist jetzt nur für den fall, dass ich mich falsch ausdrück und ich lieber den Code sprechen lasse.
es soll hier aber NICHT eure aufbaue sein, den code durchzuwühlen. Nur auf freiwilliger Basis überfliegen, wenn ihr nicht so genau wisst wo überhaupt mein Problem liegt. Sonst ignorieren ;) Danke.


Code:
package newtetris;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;

public class ActionPanel extends JPanel implements Runnable, KeyListener{
    
    private Collection c; // das ist eine ArrayList mit Blöcken, die im Spiel sind
    
    public ActionPanel(){
        setPreferredSize(new Dimension(300,600));
        setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
        setBackground(Color.gray);

        c = new Collection(10*20);
        c.addElement(Param.now); // Param.now ist ein Tetris-Element, z.B. ein Würfel
        
        addKeyListener(this);
        setFocusable(true);

    }

    public void run() {
        
        while (true) {

            if (Param.running) { // man kann das spiel auch pausieren, dann ist das hier false,
                                          // aber man solls ja auch wieder aufnehmen können, daher steckt
                                          // das ganze in einer while(true)-schleife
                
                try {
                    Thread.sleep(Param.speed); // fall-geschwindigkeit der Blöcke, z.b: 500
                } catch (InterruptedException ex) {
                }

                if (! Param.now.isDumped()) { // das ist der fall wenn das element am Boden angelangt ist,
                                                            // oder mit einem anderen Objekt kollidierte.
                                                            // Hier kommt man also rein, wenn das NICHT der fall ist
                    if (c.mayFall()) {
                        Param.now.move(Param.DOWN);
                    } else {
                        Param.now.setDumped(); // block ist abgelegt worden
                        int multiply = c.checkForLines();  // prüft ob es volle Linien im Spiefeld gibt

                        Param.score += (multiply * 50) * Param.level * multiply;
                    }
                }
                if (Param.now.isDumped()) {  // block ist gerade abgelegt worden,
                    Param.now = Param.next;  // das ganze hier erstellt ein neues Tetris-Element
                    c.addElement(Param.now);
                    Param.next = new Quad();
                }
            }
            repaint();
        }
    }

// diese sachen hier machen so in etwa das selbe, bewegen also blöcke und prüfen ob ein block

    public void keyPressed(KeyEvent k) {
        switch(k.getKeyCode()){
            
            case KeyEvent.VK_LEFT:
                new SwingWorker() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        if(!Param.now.isDumped() && c.mayMoveLeft()){
                            Param.now.move(Param.LEFT);
                        }
                        repaint();
                        return Param.now;
                    }
                }.execute();
                break;

            case KeyEvent.VK_RIGHT:
                new SwingWorker() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        if(!Param.now.isDumped() && c.mayMoveRight()){
                            Param.now.move(Param.RIGHT);
                        }
                        repaint();
                        return Param.now;
                    }
                }.execute();
                break;
                
            case KeyEvent.VK_DOWN:
                new SwingWorker() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        int dropheight = 0;
                        while (!Param.now.isDumped() && c.mayFall()) {
                            Param.now.move(Param.DOWN);
                            dropheight++;
                        }

                        Param.now.setDumped();
                        Param.now = Param.next;
                        c.addElement(Param.now);
                        Param.next = new Quad();
                        
                        int multiply = c.checkForLines();
                        
                        Param.score += dropheight * Param.level +
                                   (multiply*50) * Param.level * multiply;
                        repaint();
                        systimeAtNewObj = System.currentTimeMillis();
                        return Param.now;
                    }
                }.execute();
                break;
                
            case KeyEvent.VK_UP:
                new SwingWorker() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        if(!Param.now.isDumped() && c.mayRotate()){
                            Param.now.rotate();
                        }
                        repaint();
                        return Param.now;
                    }
                }.execute();
                break;
        }
    }
    public void keyTyped(KeyEvent k) {}
    public void keyReleased(KeyEvent k) {}
    
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        c.paint(g);
        new PaintGridLines(g);
    }
}

tja, und genau diese sache: der listener und der move-thread, kann ich nicht vernünftig steuern, also voneinander abhängig machen, sie kommunizierne lassen etc.
 

schalentier

Gesperrter Benutzer
Vergiss die Threads. Du brauchst sie nicht. Mach einen Mainloop, in dem passiert folgendes:

Code:
long lastTime = System.currentMillis();
while( !stopped ) {
   long currentTime = System.currentMillis();
   long delta = currentTime - lastTime;
   lastTime = currentTime;

   processInput( delta );
   applyPhysic( delta );
   render( delta );

   sleep(1);
}

processInput( long) ermittelt die aktuelle Eingabe und bewegt darauf hin die Objekte. Wie das genau ablaeuft sei dir ueberlassen. Sinnvoll ist IMHO eine Queue, in die Events reingesteckt werden, z.b. vom Netzwerk oder eben vom User in deiner keyPressed(). Die processInput wuerde dann die Queue abarbeiten, bis sie leer ist und alles der Reihe nach umsetzen.

applyPhysic wendet die "Physik" auf die Spielwelt an. Bei dir waere das z.b. Kollision (Stein zu weit links/rechts) und das Bewegen nach unten. Dazu wuerde ich einen Counter hernehmen, der um "delta" reduziert wird. Ist der Counter kleiner 0, wird er wieder auf die aktuelle Geschwindigkeit gesetzt und der Stein bewegt sich eine Zeile nach unten.

In render wird dein Frame neu gezeichnet (repaint). Dort ueberschreibste die paintComponent()-Methode, die die ganze Welt zeichnet. Mit welchen Techniken du das tust, sei ebenfalls dir ueberlassen (Doublebuffer, etc).

Das sleep am Ende verhindert, dass dein Spiel mit 100% Prozessorauslastung laeuft.

Keep it simple!
 
G

Guest

Gast
hey, also erstmal vielen dank dafür!

ich habe nun mein programm komplett überarbeitet, hab das hier von dir leider erst jetzt gelesen. das heisst ich hab das jetzt nicht berücksichtigt.

okay im moment denke ich aber, es ist der beste anlauf bisher.

heisst: mein move-thread, der die blöcke stück für stück nach unten bewegt, läuft gut, und er kümmert sich komplett um das repainten, ganz alleine, und er kann auch volle lines aufleuchten lassen und dann entfernen. und erst danach kommt ein neuer block. es ruckelt nix, es kommt nich so hängern und alles wird genau in der reihenfolge gemacht, wie es soll.

soweit sogut also.

allerdings fehlt mir nun noch der user-input. und genau hier krieg ichs wieder mit der angst zu tun ;)
ich möchte nicht Wiiieeeeder, dass der ganze Code kaputt geht durch unüberlegtes coden..

ich möchte euch bitten, die situation, wie sie nun ist, anzusehen, und mir eine gute Lösung empfehlen, weil daran scheiter ich halt immer :/

die unwichtigen dinge hab ich weggelassen (so wie oben z.B. der grund, warum das ein thread ist), ihr seht hier lediglich den hauptcode, der für alles verantwortlich ist, mit kommentaren dazu. Happy hunting ;)

Code:
package newtetris;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;

public class ActionPanel extends JPanel implements Runnable, KeyListener {

    private Collection c;  // eine ArrayList, die alle _Steine_ enthält, die im Spiel sind.
                                  // ein Stein ist dabei nur ein Rechteck, heisst jeder SpielBLOCK besteht aus 4 Steinen.
    private InfoPanel ip; //unwichtig, was das macht

    public ActionPanel(InfoPanel ip, Collection c) {
        setPreferredSize(new Dimension(300, 600));
        setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
        setBackground(Color.gray);
        setFocusable(true);
        requestFocusInWindow();

        this.c = c;
        this.ip = ip;
        addKeyListener(this);
    }

    public void run() {

        while (true) {

            if (Param.running) { // spiel muss pausiert und gestartet werden können, daher auch die while(true) schleife

              // OKAY HIER BEGINNT DER ERWÄHNTE MOVE-THREAD:
                try {
                    Thread.sleep(Param.speed); // die geschwindigkeit, in der die blöcke fallen
                } catch (InterruptedException ex) {
                }

                if (!Param.now.isDumped()) { // "dumped" ist ein Block, wenn er am untersten Rand ankommt oder
                                                           // auf einen anderen Block trifft. Das folgende wird also bearbeitet, 
                                                           // wenn der Block NICHT dumped ist.
                                                            // Param.now ist der aktuelle Spielblock

                   // die namen der methoden sagen denke ich aus, was gemacht wird.
                   // was man wissen sollte: jede Methode, die auf die collection "c" angewandt wird, 
                   // arbeitet mit dem momentanen Stein. also c.mayFall() überprüft z.B., ob der momentane Stein
                   // fallen darf. 

                    if (c.mayFall()) {
                        Param.now.move(Param.DOWN);
                    } else {
                        Param.now.setDumped();
                        Param.now = Param.next;  // wurde vorher schon erstellt, der nächste Spielblock
                        c.addElement(Param.now); // fügt alle Steine des Blocks Param.now zur Collection hinzu
                        Param.next = Generator.create();  // macht n neuen Zufallsblock im Spiel

                       // Prüft nun, ob eine Zeile komplett ausgefüllt mit Blöcken ist. Wenn ja, werden die entsprechenden
                       // Zeilen aufblinken und dann entfernt (das macht checkForLines, ist jetz unwichtig wie genau)
                        Param.updateGame(0, flashLines(c.checkForLines()));

                        if (c.checkForGameOver()) {
                            Param.running = false;
                            Param.saveHighscore();
                        }
                        // das is nur für die anzeige der punkte usw.
                        ip.update();
                    }
                }
                repaint();
            }
        }
    }

     // oookay und DAS FEHLT JETZT NOCH! 
     // mit links und rechts kann man den stein bewegen, das trickreichste ist eher wenn man nach unten drückt:
     // dann soll der Stein "gedroppt" werden, also solange nach unten fallen (natürlich in cpu-zeit, für den spieler
     // nicht sichtbar), bis er dumped. Und hier ist auch das Problem:
     // Der Listener muss im Prinzip die selben Methoden der Collection aufrufen wie shco der move-Thread.
     // Und da passieren dann eben diese Dinge, dass es nicht mehr regelmässig ist, weil es ab hier parallel läuft.
     // Ich komm nicht dahinter, wie ich das gescheit steuern kann :/

    public void keyPressed(KeyEvent k) {
        switch (k.getKeyCode()) {

            case KeyEvent.VK_LEFT:
                         // ???
                break;

            case KeyEvent.VK_RIGHT:
                         // ???
                break;

            case KeyEvent.VK_DOWN:
                         // ???
                break;

            case KeyEvent.VK_UP:
                         // ???
                break;
        }
    }

    public void keyTyped(KeyEvent k) {
    }

    public void keyReleased(KeyEvent k) {
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        c.paint(g);
        new PaintGridLines(g); // is wurscht hier
    }

   // wird ja vom move-thread aufgerufen. falls es lines zu removen gibt, blinken sie und danach geht das spiel weiter
    public int flashLines(int[] a) {
        if (a.length > 0) {
            int flashTime = 2;
            while (--flashTime >= 0) {

                for (int i = 0; i < a.length; i++) {
                    c.lightUpLine(i);
                }
                repaint();

                try {
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                }

                for (int i = 0; i < a.length; i++) {
                    c.lightDownLine(i);
                }
                repaint();

                try {
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                }
            }

        }
        return a.length;
    }
}

ja wie gesagt, nur der move-thread alleine ist ja nicht schwer, weil ich als programmierer weiss, was er wann macht.
wenn jetzt der keylistener dazu kommt hab ich keine Kontrolle mehr über den Ablauf.
Das gibt Probleme, ich kann z.B. die Linien nicht mehr aufblinken lassen und erst DANN einen neuen stein machen,
weil der keyListener die Linien blinken lässt, und schläft (die sleep-aufrufe in der methode flashLines), jedoch der move-thread damit nix am hut hat und fleissig weiter macht..

Das sind die Sachen, die ich halt meinte. Wie steuer ich das, wie kontrolliert man MultiThreading ?

Vielen Dank, ich kanns nciht oft genug sagen.
 

byte

Top Contributor
schalentier hat gesagt.:
byto hat gesagt.:
Die Programmlogik im EDT laufen lassen? Ganz schlecht.

Nix EDT. Das laeuft im Mainthread, also in dem, der automatisch vom main(...) erzeugt wird. Im EDT wird nur gemalt.

Warum schreibst du dann:
Vergiss die Threads. Du brauchst sie nicht.
:?:

Auch in Deinem Code musst Du synchronisieren. Swing ist schließlich nicht thread-safe.

Im übrigen bezweifel ich, dass das Spiel flüssig laufen wird, wenn Eingabe, Berechnung und Painting sequentiell abgearbeitet werden.
 

André Uhres

Top Contributor
Anonymous hat gesagt.:
..leider ist das nicht so simpel wie ihr es hier darstellt..
Doch:
Code:
package demo;

/*
 * Game.java
 */
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Game extends JFrame {

    private JButton btControl;
    private Board board;
    private Figure figure;
    private GameThread thread;

    public Game() {
        super("Start and then type right/left arrows");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400, 700);
        setLocationRelativeTo(null);
        
        btControl = new JButton("Start");
        board = new Board();
        
        btControl.setFocusable(false);
        add(btControl, BorderLayout.PAGE_START);
        board.setFocusable(true);
        add(board);
        btControl.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent evt) {
                handleActionEvent(evt);
            }
        });
        board.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(final KeyEvent e) {
                handleKeyEvent(e);
            }
        });
    }

    private synchronized void handleActionEvent(final ActionEvent evt) {
        thread = new GameThread();
        thread.startGame();
    }

    private synchronized void handleTimerEvent() {
        if (figure == null) {
            figure = new Figure(board);
        } else {
            figure.moveDown();
        }
    }

    private synchronized void handleKeyEvent(final KeyEvent e) {
        if (figure == null) {
            return;
        }
        switch (e.getKeyCode()) {

            case KeyEvent.VK_LEFT:
                figure.moveLeft();
                break;

            case KeyEvent.VK_RIGHT:
                figure.moveRight();
                break;
        }
    }

    public static void main(final String args[]) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Game().setVisible(true);
            }
        });
    }

    private class GameThread extends Thread {

        private int sleeptime = 500;

        public void startGame() {
            if (!isAlive()) {
                this.start();
            }
        }

        @Override
        public void run() {
            while (thread == this) {
                handleTimerEvent();
                try {
                    Thread.sleep(sleeptime);
                } catch (InterruptedException e) {
                }

            }
        }
    }
}

class Figure {

    private int xPos = 100;
    private int yPos;
    private Board board;

    public Figure(final Board board) {
        this.board = board;
    }

    public void moveDown() {
        if (board != null) {
            yPos += 20;
            board.setPos(xPos, yPos);
        }
    }

    public void moveLeft() {
        if (board != null) {
            xPos -= 20;
            board.setPos(xPos, yPos);
        }
    }

    public void moveRight() {
        if (board != null) {
            xPos += 20;
            board.setPos(xPos, yPos);
        }
    }
}

class Board extends JPanel {

    private int x1,  y1;

    public void setPos(final int x, final int y) {
        x1 = x;
        y1 = y;
        repaint();
    }

    @Override
    protected void paintComponent(final Graphics g) {
        super.paintComponent(g);
        g.drawRect(x1, y1, 20, 20);
    }
}
 
G

Guest

Gast
Andrés,

ich schätze deine Bemühungen, aber ich denke du hast nicht ganz verstanden:
Deine run-methode, die den Block alle 500ms nach unten schiebt, macht nichts weiter als genau das.

das ist im Spiel aber nicht der Fall. siehe mein code. es muss einiges abgefragt werden, sowohl in dieser run-methode als auch bei jedem keyEvent. und genau dort liegt das Problem.

In deinem Spiel bewegt sich ein Block nach unten, wahlweise auch nach rechts oder links. Das war's.

In einem Tetris spiel aber bewegt sich ein Block nur solange nach unten, bis er auf etwas stösst, das gleich emuss bei den Richtungen überprüft werden, und es ist erst zur Laufzeit vom Spieler festgelegt, ob der move-thread den Block absetzt oder die nach-unten-taste, die der spieler drückt.

Dann muss ein neuer Block kommen, die Threads sind komplexer und man kann das nicht so stur machen.

Das is ja eben das Problem. Beide, der automatische move-thread, sowie auch der keyListener, müssen die selben methoden auf der collection (siehe mein code) aufrufen. Die Arbeitsweise des einen hängt von der des anderen ab.

That's the problem ;)

Und that's nicht zu lösen für mich, und mit deinem Code, wie er jetzt ist, kann man das auch nicht realisieren :(
 

Marco13

Top Contributor
Mensch :? ich hätte den Thread, nachdem ich das
..leider ist das nicht so simpel wie ihr es hier darstellt..
gelesen hatte, vielleicht mal zuende lesen sollen, bevor ich hier........
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.List;

class Tetris extends JFrame implements KeyListener
{
    public static void main(String args[])
    {
        new Tetris();
    }

    private TetrisPanel tetrisPanel = new TetrisPanel();
    private TetrisGame tetrisGame = new TetrisGame(tetrisPanel);

    public Tetris()
    {
        setSize(300,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(tetrisPanel);
        addKeyListener(this);
        setVisible(true);
        tetrisGame.startGame();
    }

    public void keyPressed(KeyEvent k) {
        switch(k.getKeyCode()){

            case KeyEvent.VK_LEFT:
                tetrisGame.moveLeft();
                break;

            case KeyEvent.VK_RIGHT:
                tetrisGame.moveRight();
                break;

            case KeyEvent.VK_DOWN:
                tetrisGame.moveDown();
                break;

            case KeyEvent.VK_UP:
                break;
        }
    }
    public void keyTyped(KeyEvent k) {}
    public void keyReleased(KeyEvent k) {}

}


class TetrisPanel extends JPanel
{
    private List<Block> blocks = new ArrayList<Block>();

    public void addBlock(Block block)
    {
        blocks.add(block);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        for (Block block : blocks) block.draw(g);
    }
}


class Block
{
    private int x = 120;
    private int y = 0;

    public void draw(Graphics g)
    {
        g.fillRect(x,y,10,10);
    }

    public void moveDown()
    {
        y += 10;
    }
    public void moveLeft()
    {
        x -= 10;
    }
    public void moveRight()
    {
        x += 10;
    }

    public boolean isDropped()
    {
        return y >= 250;
    }
}


class TetrisGame implements Runnable
{

    private List<Block> blocks = new ArrayList<Block>();
    private TetrisPanel tetrisPanel;
    private Block currentBlock;

    public TetrisGame(TetrisPanel tetrisPanel)
    {
        this.tetrisPanel = tetrisPanel;
    }

    public void startGame()
    {
        Thread t = new Thread(this);
        currentBlock = new Block();
        tetrisPanel.addBlock(currentBlock);
        t.start();
    }

    public void run()
    {
        while (true)
        {
            if (currentBlock.isDropped())
            {
                currentBlock = new Block();
                tetrisPanel.addBlock(currentBlock);
            }
            try
            {
                Thread.sleep(500);
            } catch (InterruptedException ex) {}

            currentBlock.moveDown();
            tetrisPanel.repaint();
        }
    }


    public void moveLeft()
    {
        currentBlock.moveLeft();
        tetrisPanel.repaint();
    }
    public void moveRight()
    {
        currentBlock.moveRight();
        tetrisPanel.repaint();
    }
    public void moveDown()
    {
        currentBlock.moveDown();
        tetrisPanel.repaint();
    }

}
....aber die Lösung von André Uhres ist in mancher Hinsicht sicher schöner....


EDIT: Und die Nachfrae hätte ich vielleicht auch noch abwarten sollen :roll:
 
G

Guest

Gast
oh leute danke ^^

aber wie gesagt.. es geht hier um das konkrete Problem, das ich habe. Eure Beispiele genügen halt nicht den Anforderungen, deswegen bringt mich das nicht weiter leider :/

ps: @marco13 ich kann dein Spiel nicht ausführen? Er sagt noClassDefFound: Game
weiss nicht obs an mir liegt? Aber finde das Problem nicht..
 

André Uhres

Top Contributor
Anonymous hat gesagt.:
.. es geht hier um das konkrete Problem, das ich habe. Eure Beispiele genügen halt nicht den Anforderungen, deswegen bringt mich das nicht weiter leider ..
Man muss das eben noch Schrittweise erweitern. Das Grundprinzip müsste aber jedenfalls richtig sein.
Ich hab das hier mal ein wenig erweitert:
TetrisDemo.jar (Quellcode im jar)
 
G

Guest

Gast
danke, danke.

aber bevor ihr hier viel zeit investiert gehe ich mal genz genau ins detail,
denn die implementierung einer kollisionsabrage etc hab ich ja alles schon, der code den ich gepostet
hab ist ja nur 1 von mehreren klassen.


es geht mir, wenn man bis zum ende denkt, eigentlich nur um eine sache, und das ist die taste nach unten, also das dropToBottom in deinem beispiel:

in diesem fall müsste ich nämlich 1:1 das tun, was der else-zweig des move-threads macht (bitte nochmal oben im code nachsehen!) denn es ist das selbe, ich beweg ihn halt bis er kollidiert, und nix anderes passiert im move-thread, nur halt dort nicht auf einen schlag.

das problem dabei ist z.B. das "aufleuchten" der lines. wenn ihr euch bitte den else-zweig des move-threads anseht (ich post ihn jetzt nochmal schnell):

Code:
// else heisst also: der stein is gedumped:
else {
                        Param.now.setDumped();
                        Param.now = Param.next;
                        c.addElement(Param.now);
                        Param.next = Generator.create();

                        Param.updateGame(0, flashLines(c.checkForLines()));

                        if (c.checkForGameOver()) {
                            Param.running = false;
                            Param.saveHighscore();
                        }
                        ip.update();
                    }

es wird in dem falle die methode checkForLines() aufgerufen. diese stellt fest, ob es komplett befüllte zeilen gibt, die ja bekanntlich im Tetris dann verschwinden müssen. flashLines() wird mit dem ergebnis dieser methode aufgerufen.
und die macht dann, falls flashLines "sagt", dass zeilen gelöscht werden müssen:

Code:
    public int flashLines(int[] a) {
        if (a.length > 0) {
            int flashTime = 2;
            while (--flashTime >= 0) {

                for (int i = 0; i < a.length; i++) {
                    c.lightUpLine(i);
                }
                repaint();

                try {
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                }

                for (int i = 0; i < a.length; i++) {
                    c.lightDownLine(i);
                }
                repaint();

                try {
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                }
            }

        }
         // ************ zeilen hier tatsächlich aus der collection löschen und darüberliegende zeilen 
        // ************ nachrutschen lassen:

        for (int i = 0; i < a.length; i++) {
            c.removeLine(a[i]);
            for (int j = 0; j < c.size(); j++) {
                if (c.get(j).getLine() < a[i]) {
                    c.get(j).fall();
                }
            }
        }
        return a.length;
    }

das heisst, sie lässt diese zeilen zweimal aufblinken., und löscht sie dann.

zurück zum problem: beim move-thread is das kein thema, da die sleep-anweisungen in der flashLines()-methode den thread anhalten, und er erst wieder in seinen normalen "stein-nach-unten-bewegen-cycle" kommt, wenn das alles passiert ist.

wenn nun aber der spieler die taste nach unten drückt, muss ja das selbe passieren.

prinzipiell könnte der keyListener wirklich nur den stein nach unten bewegen, und im nächsen durchlauf wird der move-thread festellen: e.isDumped() == TRUE und es würde alles nach plan verlaufen.

problem: das ganze soll sofort passieren, was es so aber nicht tut. denn der move-thread könnte z.B. gerade eben erst in seine sleep-methode eingetreten sein, wenn der spieler den stein droppt. dann gibt es ne verzögerung von knapp 500ms bis die lines aufblinken und alles. man kann auch glück haben und der move-thread hat gerade nen neuen cycle begonnen, das gehts sofort.
aber das is ja keine vernünftige lösung.

ich muss also den move-thread aus seinem schlaf reissen, wenn der keyListener nen stein droppt! ich hab inzwischen mitbekommen, dass anscheinend interrupt() dafür sorgen kann. ist zwar sehr seltsam, da in der API steht das unterbricht einen thread (heisst ja auch so) aber okay, das muss ich mal testen. ich muss mir nur irgendwie überlegen wie der keyListener den move-Thread kennt? er braucht ja seinen namen um ein interrupt() darauf aufzurufen oder?

ich hoffe, ihr versteht nun genau, woran ich scheitere. es geht nich ums spielprinzip, das hab ich wie gesagt schon 3 mal gemacht. ich hab auch ein laufendes tetris hier, aber es hat eben die o.g. probleme, und das gefällt mir nicht.

das meinte ich damit, als ich sagte, die threads sind abhängig voneinander! das muss flüssig laufen, egal welcher thread jetz was macht! Ich kann nicht stur den move-thread für 500ms schlagen legen...

any ideas?
 

hdi

Top Contributor
edit

okay now, damit ihr genau wisst was ich mein, hier mal ne abgespeckte, vereinfachte version vom game:

http://rapidshare.com/files/93417218/newtetris.jar.html

(die klasse mit der main-Methode heisst "Main" falls das Archiv irgendwie beschädigt ist und man es manuell aufrufen muss. Ich hab die Datei auch hier in mein Account hochgeladen, aber wie füge ich sie dann in diesne Text ein? Woher krieg ich den link?)

wenn ihr den stein droppt, werdet ihr merken, dass das flashen der linien (falls ne reihe voll ist) sowie das erstellen eines neuen blocks verzögert ist. DAS ist mein prob.
also ich muss aus dem keyListener, wenn diese pfeiltaste nach unten gedrückt wurde, den move-thread sofort aufwecken :)

wer mir sagt, wie ich das mache, hat denk ich das game zum goldstatus gemacht, dann werd ich nur noch bissi rumspielen aber es muss dann alles soweit passen :p
 

André Uhres

Top Contributor
Ich fasse nochmal zusammen.
Du brauchst nur zwei Threads: den Timerthread und den Eventthread.
Im Timerthread wird eine Figur gestartet, im 500ms Takt nach unten bewegt und das Nötige getan wenn sie angekommen ist.
Alles Andere geschieht im Eventthread.
Die geringe Reaktionsverzögerung beim manuellen Dropdown könnte man einfach so belassen.
Wer sich auf das Spiel konzentriert, dem fällt das wohl kaum auf.
Andernfalls schafft ein thread.interrupt() Abhilfe.
In meinem Beispiel hab ich den thread.interrupt() einfach mal eingebaut.

Bei den eigenen Dateien siehst du die URL gewöhnlich unten im Browser, wenn die Maus drüber ist.
Mit einem Rechstklick kann man z.B. im Firefox den Link auch kopieren.

Mit deiner jar komm ich übrigens nicht klar. Hab schon am Manifest rumgedoktert, aber ohne Erfolg.
 

Marco13

Top Contributor
Anonymous hat gesagt.:
das hab ich wie gesagt schon 3 mal gemacht. ich hab auch ein laufendes tetris hier, aber es hat eben die o.g. probleme, und das gefällt mir nicht.
Ohne dich nun (meht als angebracht) diskreditieren zu wollen: Wenn ich sowas sehe wie "Param.running", muss ich davon ausgehen, dass "Param" eine Klasse (mit einem ... fragwürdigen Namen) ist, und "running" eine "public static (nicht-final) boolean" :autsch: Genauso wie Param.now, Param.next usw. Und ob es nun schlimmer ist, eine "Collection" ungetypt zu verwenden, oder ihr so einen grandiosen namen wie "c" zu geben, weiß ich nicht.

Jedenfalls (und darum gibg's jetzt nur) sind DAS alles Gründe für mich, mir deinen Code garnicht erst anzusehen. (Sorry).

Zur letzten Frage: Du solltest wohl nicht mit "interrupt" arbeiten. Stattdessen könntest du da, wo jetzt
Thread.sleep(500);
steht, sowas schreiben wie
Code:
synchronized (someObject)
{
    someObject.wait(500);
}
und ihn an dieser stelle dann "aufwecken", indem du
Code:
synchronized (someObject)
{
    someObject.notify();
}
aufrufst. (Ja, dann stimmen die 500 nichtmehr, und man muss danach VIELLEICHT(!) noch so lange warten, wie notwendig, damit die 500 voll werden usw.... )
..leider ist das nicht so simpel wie ihr es hier darstellt..
... die meisten wissen dass, aber offenbar ist es noch un-simpler, als du es dir vorstellst :wink:
 

hdi

Top Contributor
@ marco13:

"Param" steht für Parameter, bei mir in der uni eine gängige Klassendefinition für bestimmte, feste Werte.
Wie genial das jetzt ist, ist denke ich nicht allzu wichtig.

Dass die Benutzung von tausend globalen statischen Variablen dilletantisch ist, weiss ich. Allerdings ist es für mich der beste weg, ich will nochmal drauf aufmerksam machen, dass der hier gezeigte code lediglich eine von ca. 15 Klassen vom Programm ist (allerdings nimmt auch jeder Tetris-Stein eine eigene Klasse ein, hört sich also schlimmer an als es ist)
U.a. ist da noch ein weiteres Panel auf dem Frame, dieses muss auch über den Status von allem informiert sein, deshalb die globalen Variablen. Ich weiss wie gesagt, dass es nicht gut ist, aber ich wüsste nicht wie sonst.
Mit fehlt einfach die praktische Übung, um zu sehen, was sinnvoll ist, und was nicht.

Wegen der Variablen "c" : Ich finde, jetz übertreibste aber n bisschen ;)
Die komplette Klasse besitzt EINE variable, und das ist ne Collection. Deshalb "c" für COllection, könnte auch "col", "coll" oder "collection" schreiben.
Aber über die 150 Zeilen Code kann ich mir die einzige Variable in der Klasse durchaus merken, und mein Code war vernünftig für euch kommentiert wie ich finde. Ich denke nicht, dass du den Code gelesen hättest, wenn die Variable anders heißen würde ;)

(was du mit ungetypter Collection meinst, weiss ich nicht. Das is eine eigene Klasse, und zwar nix weiter als eine ArrayList<Block>)

Naja, aber bevor ich hier noch blasphemischer werde: Ihr habt ja recht, aber Anfänger is halt Anfänger, und in Java finde ich ist das ziemlich schwer, vorallem wenn man sich Threading und Swing als erstes Thema auswählt.

@André:
Tatsache dein Game funktioniert sehr schön. Ich versuch das mal auf meinen Code zu adaptieren.
Doof dass du mein Programm nicht starten kannst, dann würdest du genau die Unterschiede sehen.
die "geringe" Verzögerung von der du nämlich sprichst, sind eben bis zu 500ms.

Und ab 60-100 ms lokalem ping nimmt man das spiel "unflüssig" wahr. eine halbe sekunde is natürlich mehr als nur n witz! das merkt man AUF JEDEN FALL ^^

Okay nun, ich versuche mal das ganze mit interrupt()... (ich denk bald ist die schwere Geburt vorbei. Bald, noch nich jetz^^)
 

schalentier

Gesperrter Benutzer
byto hat gesagt.:
Auch in Deinem Code musst Du synchronisieren. Swing ist schließlich nicht thread-safe.

Im übrigen bezweifel ich, dass das Spiel flüssig laufen wird, wenn Eingabe, Berechnung und Painting sequentiell abgearbeitet werden.

Nee, es gibt auch Active Rendering bei Java. Dabei gibts quasi keinen EDT, sondern man muss das Rendering manuell anstossen, bzw jeder Graphics2D-Befehl wird direkt umgesetzt. Dabei nutzt man sinnigerweise einen Backbuffer, in den alles gemalt wird und sobald das Frame fertig ist, wird der Backbuffer in einem Rutsch in das Canvas gezeichnet.

http://www.gamedev.net/reference/programming/features/javarender/

Das laeuft super fluessig und man muss sich nicht um Thread-Synchronisierung kuemmern. Im uebrigen macht man das schon immer so ^^
 

Marco13

Top Contributor
André Uhres hat gesagt.:
Und siehe da: thread.interrupt() funzt wie ein geölter Blitz!
Hm. Ob man "interrupt" wirklich als elementaren Teil der Spiel-Ablauf-Steuerung verwenden sollte...? ???:L Dass ein interrupt() eine Ausnahmensituation darstellt, sieht man IMHO nicht zuletzt daran, dass dort eine Exception geworfen wird... Aber ... ich werde mich da jetzt mal nicht weiter reindenken... :roll:
 
G

Guest

Gast
OK also ich hab das jetzt auch mit interrupt gemacht und es funktioniert wirklich sehr sehr gut!
Ich musste alles nur bisschen verändern weil mein Panel ja kein Thread war (extends JPanel schon) sondern das Runnable Interface implementiert hat. Aber scheinbar kann man das dann so nicht machen,
also interrupt oder this.interrupt checkt er nich.

Aber nun läuft's ja!

Vielen Dank für eure Bemühungen !

ps: bald wird das Spiel komplett fertig sein und ich find es macht richtig bock, ich werds dann mal hochladen und ihr könnt "unser" spiel zocken ;)
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Drag und drop aus einer JTable - bitte um Unterstützung AWT, Swing, JavaFX & SWT 2
A Swing Meine JButtons werden nicht angezeigt bitte helft mir AWT, Swing, JavaFX & SWT 2
J Bitte Erläuterung (skin/virtualflow) AWT, Swing, JavaFX & SWT 0
H JTextArea - farbige Zeilen .. bitte um Vorschläge zur Implementierung AWT, Swing, JavaFX & SWT 1
A Swing TicTacToe-Bitte um Hilfe AWT, Swing, JavaFX & SWT 32
T Bitte um Hilfe AWT, Swing, JavaFX & SWT 2
X Swing JButton's zum JScrollPane hinzufügen geht nicht. Bitte um Hilfe. AWT, Swing, JavaFX & SWT 9
R Swing JOptionPane Fehlermeldung- bitte um Hilfe! AWT, Swing, JavaFX & SWT 4
T action für Button übergeben - bitte um Segen AWT, Swing, JavaFX & SWT 1
C Swing XML - JAVA (GUI) Problem !! BITTE HELFEN !! AWT, Swing, JavaFX & SWT 6
R Bitte kein Menü bei F10 AWT, Swing, JavaFX & SWT 9
S Bitte um ein Beispiel von JXTreeTable AWT, Swing, JavaFX & SWT 12
J AWT Einmal FileDialog-Beispiel für Dumme bitte AWT, Swing, JavaFX & SWT 6
Jats Bitte um Hilfe bei JComboBox mit Array AWT, Swing, JavaFX & SWT 6
S Swing Bild (Gif) in Bitte warten JDialog AWT, Swing, JavaFX & SWT 6
A repaint() zu langsam, bitte um alternativen AWT, Swing, JavaFX & SWT 5
hdi GUI - Bitte optisches Feedback ;) AWT, Swing, JavaFX & SWT 26
O Verbesserungfrage zu einem MP3Player Slider - Ebenius kannst du helfen bitte ? AWT, Swing, JavaFX & SWT 10
V Bitte um Hilfe bei nem Taschenrechner AWT, Swing, JavaFX & SWT 8
R JDialog "Bitte warten..." durchsichtig AWT, Swing, JavaFX & SWT 5
O Bitte um Hilfe bei ComboBox in TableHeader AWT, Swing, JavaFX & SWT 9
A Bitte warten Dialog AWT, Swing, JavaFX & SWT 4
E bei gedrückte Taste --> Bitte nur ein Event auslösen AWT, Swing, JavaFX & SWT 4
P Anfänger Probleme mit JTable bitte um Rat! AWT, Swing, JavaFX & SWT 5
N ausrichtung Button - hilfe bitte AWT, Swing, JavaFX & SWT 2
G Mausklick event? BITTE HELFT MIR! :( AWT, Swing, JavaFX & SWT 8
I TrayIcon aber bitte nur einmal AWT, Swing, JavaFX & SWT 2
H <Synth> Alle die sich auskennen Bitte hier rein schaue AWT, Swing, JavaFX & SWT 2
G kann meine idee nicht verwirklichen, bitte helfen AWT, Swing, JavaFX & SWT 3
G eingegebene Werte einer JTable prüfen? Bitte helfen AWT, Swing, JavaFX & SWT 5
V Bitte um kurze erklärung AWT, Swing, JavaFX & SWT 2
S ScrollBar, bitte helft mir! AWT, Swing, JavaFX & SWT 9
S Bitte Sinusbefehl erklären AWT, Swing, JavaFX & SWT 5
C JTree bereitet große Probleme, kann uns bitte jemand helfen! AWT, Swing, JavaFX & SWT 6
J eventhandling / Problemmeldung Bitte schaut euch den Code an AWT, Swing, JavaFX & SWT 2
J JPanel in JScrollPane Hilfe bitte AWT, Swing, JavaFX & SWT 2
thE_29 Vor dem ersten Posten bitte lesen! AWT, Swing, JavaFX & SWT 0
M MouseEnter - Exit - Starthilfe bitte! AWT, Swing, JavaFX & SWT 3
A Kann mir mal bitte jemand die Ausrichtungen logisch erklären AWT, Swing, JavaFX & SWT 10
H Viele ActionListener (MouseListener) - Performance AWT, Swing, JavaFX & SWT 24
missy72 JavaFX Performance / ImageView in TableView über TimeLine AWT, Swing, JavaFX & SWT 1
L JavaFX ListCell Performance AWT, Swing, JavaFX & SWT 10
E Swing Miserable Performance beim Ändern der Hintergrundfarbe von JLabels AWT, Swing, JavaFX & SWT 3
W Swing Performance bei Griderstellung verbessern AWT, Swing, JavaFX & SWT 15
C Pixel-Rendering/Animation Performance in BufferedImage AWT, Swing, JavaFX & SWT 1
I JavaFX Graphics Performance AWT, Swing, JavaFX & SWT 2
S Swing Performance bei Verschachtelung problematisch AWT, Swing, JavaFX & SWT 0
R Performance Drag and Drop & Timer AWT, Swing, JavaFX & SWT 3
O AWT Performance und Bug behebung[brauche Hilfe] AWT, Swing, JavaFX & SWT 2
T Swing Allgemeines Problem mit der Performance bei DragAndDrop AWT, Swing, JavaFX & SWT 2
T Prüfen ob 2 JLabel übereinander liegen. Performance Problem. AWT, Swing, JavaFX & SWT 5
S Swing Lauftext Performance Probleme, in größerer Anwendung AWT, Swing, JavaFX & SWT 6
B Performance-Probleme AWT, Swing, JavaFX & SWT 17
D DefaultTableCellRenderer - Performance AWT, Swing, JavaFX & SWT 3
hdi Swing [Umfrage] Swing Performance AWT, Swing, JavaFX & SWT 27
B 2D-Grafik BufferedImage Performance AWT, Swing, JavaFX & SWT 3
C Performance-Problem beim Überschreiben von paintComponent() AWT, Swing, JavaFX & SWT 2
Hausmeister JTable mit Bildern - Performance AWT, Swing, JavaFX & SWT 5
J JTree Performance AWT, Swing, JavaFX & SWT 2
Developer_X Swing Graphics2D translate zerstört performance AWT, Swing, JavaFX & SWT 2
hdi Swing JTable: Mein CellRenderer ist ein Performance-Killer? AWT, Swing, JavaFX & SWT 7
J Performance bei mouseMoved(...) AWT, Swing, JavaFX & SWT 4
L JFreeChart - Performance bei PNG-Erstellung AWT, Swing, JavaFX & SWT 5
P seltsame Performance Probleme bei 2 Guis abhängig vom Aufruf AWT, Swing, JavaFX & SWT 8
G Performance beim Zeichnen erhöhen? AWT, Swing, JavaFX & SWT 21
G performance fragen zu AWT, Swing AWT, Swing, JavaFX & SWT 14
T (Java 6) Thumbnails in JFileChooser - Performance steigern? AWT, Swing, JavaFX & SWT 3
hdi schlechte performance bei simplem swing AWT, Swing, JavaFX & SWT 9
G Probleme mit Performance bei einer Tabelle AWT, Swing, JavaFX & SWT 16
M Performance SWT ??? AWT, Swing, JavaFX & SWT 8
D performance problem: paintcomponent, alphacomp, bufferedImag AWT, Swing, JavaFX & SWT 10
P SWT: StyledText Performance steigern? AWT, Swing, JavaFX & SWT 2
T Performance Problem bei BufferedImage AWT, Swing, JavaFX & SWT 3
P SWT Performance : "Text" - Ausgabe beschleunigen ? AWT, Swing, JavaFX & SWT 21
O performance g2d.drawImage() AWT, Swing, JavaFX & SWT 17
D Performance Probleme Jtable AWT, Swing, JavaFX & SWT 4
N Performance (BufferStrategy?) AWT, Swing, JavaFX & SWT 2
F Problem mit Transparenz, MouseEvents und Performance AWT, Swing, JavaFX & SWT 3
O LookAndFeel und Performance AWT, Swing, JavaFX & SWT 7
W Performance verbessern AWT, Swing, JavaFX & SWT 2
S TableCellRenderer, Performance AWT, Swing, JavaFX & SWT 9
S Performance-Problem: JTextArea als Logging-Window AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen

Neue Themen


Oben