AWT Buttons verschwinden, wenn Fenster Vollbild gesetzt wird

chaostheory

Bekanntes Mitglied
Hallo,
ich schreibe momentan ein 2D-Spiel, für das ich ein Menü mit Hilfe von Buttons realisieren möchte.
Weil ich damit nur Probleme hatte, habe ich mir aus dem Internet ein sehr kurzes Test-Programm besorgt:
Java:
public static void main(String[] args) {
		int width = 1920;
		int height = 1080;
		
		GraphicsEnvironment graphEnv =
		  GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice graphDevice = graphEnv.getDefaultScreenDevice();
		GraphicsConfiguration graphicConf =
		  graphDevice.getDefaultConfiguration();
		
		JFrame jFrame = new JFrame(graphicConf);
		JButton button = new JButton("Jingle Bells");
		button.setBounds(100, 100, 100, 100);
		jFrame.add(button);
		jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jFrame.setTitle("double buffer demo");
		jFrame.setResizable(false);
		jFrame.setFocusTraversalKeysEnabled(false);
		
		Canvas canvas = new Canvas();
		canvas.setSize(width, height);
		canvas.setIgnoreRepaint(true);
		
		jFrame.getContentPane().add(canvas);
		jFrame.pack();
		jFrame.show();
		
		GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(jFrame);
		
		
		canvas.createBufferStrategy(2); // must be after we are visible!
		BufferStrategy bufferStrategy = canvas.getBufferStrategy();
		
		while(true) {
			Graphics g = bufferStrategy.getDrawGraphics();
			g.setColor(Color.BLACK);
			g.fillRect(0,0,width,height);
			g.setColor(Color.RED);
			g.drawLine((int)(Math.random()*width),(int)(Math.random()*height),
			             (int)(Math.random()*width),(int)(Math.random()*height));
			bufferStrategy.show();
			g.dispose();
		}
	}

Das Problem:
Normalerweise funktioniert alles wunderbar, der Button wird gezeichnet und alles ist in Ordnung. Setze ich den Frame jedoch in Zeile 28 in den Vollbild-Modus, wird der Button nicht mehr angezeigt.
Streiche ich die eine Zeile geht es wieder. Tritt sowohl bei Buttons, als auch bei JButtons auf.

Minimiere ich das Fenster hängt es ca. eine Sekunde, für diese kurze Zeit sehe ich den Button. Auch wenn ich bei Windows 7 die Maus auf das Symbol in der Taskleiste halte, sehe ich in der Vorschau den Button. Allerdings erscheint auch NUR der Button.
Scheint also ein Update-Problem zu sein !?
Weder button.update(Graphics), noch button.repaint() haben geholfen...
 
Es könnte sich hierbei um ein typisches Problem handeln, welches auftritt, wenn man Swing-Komponenten mit AWT-Komponenten mischt.
Ersetze mal das [JAPI]Canvas[/JAPI] (AWT) mit einem [JAPI]JPanel[/JAPI] (Swing).
Hilft das?
 
Es könnte sich hierbei um ein typisches Problem handeln, welches auftritt, wenn man Swing-Komponenten mit AWT-Komponenten mischt.
Ersetze mal das [JAPI]Canvas[/JAPI] (AWT) mit einem [JAPI]JPanel[/JAPI] (Swing).
Hilft das?

Mein Programm ist etwas anders aufgebaut, ich habe Graphics usw. alles aus java.awt genutzt, nur der JFrame ist aus javax.swing. Den habe ich jetzt mit dem Frame aus java.awt ersetzt, sodass ich nur noch java.awt benutze, der Fehler ist jedoch immer noch da.
 
Wenn du schon deine Komponenten exakt positionieren willst, dann solltest du auch das Layout des Frames auf null setzen:
Code:
frame.setLayout(null);
 
nur der JFrame ist aus javax.swing.
Und was bist mit deinem Button? Der ist auch aus Swing.
Ich muss da noch mal meine obige Aussage etwas präzisieren: Es sollte die Mischung von reinen GUI-Komponenten vermieden werden. Wenn du Klassen, wie Graphics, Color, Point, Image, etc. aus AWT benutzt und in deinen Klassen mit Swing-GUI-Komponenten kombinierst, sind keine Probleme zu erwarten.
Du solltest deine Programme auf jeden Fall in Swing umsetzen. Die darin enthaltenen GUI-Komponenten sind moderner und mächtiger, als die Komponenten aus dem AWT.

Das "NullLayout" ist häufig eine ganz schlechte Wahl. Es ist unflexibel, schlecht zu warten oder zu erweitern und erzeugt auf anderen Systemen meist ein anderes Ausssehen. Es kann bspw. etwas verschoben sein, oder nicht alle Komponenten sind vollständig sichtbar.
Daher solltest du dich unbedingt mit LayoutManagern befassen. Keine moderne, leistungsfähige GUI, die in Java programmiert wurde, kommt heute ohne LayoutManager aus.
In der FAQ findest du einen einfachen Einstieg zu den meist genutzten LayoutManagern und erfährst mehr über ihre Strategie der Komponentenanordnung.

Um schließlich deinem Problem auf die Spur zu kommen brauchen wir sicher noch etwas mehr Code.
Hast du irgendwo eine paint()-Methode überschrieben?
 
Das da oben war nur ein anderes Programm aus dem Internet, das ich zum Testen benutzt habe.
Momentan benutze ich alles aus awt, außer dem JFrame. Das Problem ist, dass alle JComponents von der awt-graphics überschrieben werden, also der Hintergrund wird über die JButtons gezeichnet und sie werden unsichtbat, das passiert nicht bei den awt-Buttons, deswegen benutze ich die momentan.
Zu dem Layout-Manager: Ich will meine Sachen unbedingt selbst absolut anordnen und nicht automatisch sortieren lassen. Brauche ich dann überhaupt einen Layout-Manager?
 
Das Problem ist, dass alle JComponents von der awt-graphics überschrieben werden, also der Hintergrund wird über die JButtons gezeichnet und sie werden unsichtbat, das passiert nicht bei den awt-Buttons, deswegen benutze ich die momentan.
Liegt vermutlich am verwendeten Canvas. Warum zeigst du Code aus dem Internet, wenn du ganz anderen verwendest. So lässt sich doch kein Zusammenhang herstellen! 😱

Ich will meine Sachen unbedingt selbst absolut anordnen und nicht automatisch sortieren lassen. Brauche ich dann überhaupt einen Layout-Manager?
Glaubst du, ich labere hier nur so aus Spaß? :bahnhof: In 99% der Fälle ist ein LayoutManager sinnvoll.
 
Zuerst wird der Bildschirm gezeichnet:
Java:
public void createFrame() {
		frame = new JFrame("Bubble Trouble", graphicsDevice.getDefaultConfiguration());
		frame.setUndecorated(true);
		frame.setIgnoreRepaint(true);
		frame.setResizable(false);
		frame.setLayout(null);
		maximizeFrame(getFirstCompatibleMode(displayModes));
		frame.setVisible(true);
		
		main.getComponentHandler().initComponents(frame);
		
		//Enable double-buffering
		frame.createBufferStrategy(2);
	}
Dann werden die Komponenten hinzugefügt:
Java:
private Button mainMenuButton;
	private Button continueButton;
	private Button newGameButton;
	private Button endButton;
	
	private Rectangle buttonPosition1;
	private Rectangle buttonPosition2;
	private Rectangle buttonPosition3;
	private Rectangle buttonPosition4;
	private Rectangle buttonPosition5;

public void initComponents(JFrame frame) {
		this.frame = frame;
		
		int width = frame.getWidth();
		int height = frame.getHeight();		
		int buttonWidth = width / 3;
		int buttonHeight = height / 10;
		int buttonX = width / 2 - buttonWidth / 2;
		int buttonY = height / 10;
		int space = 40;
		
		buttonPosition1 = new Rectangle(buttonX, buttonY * 2 + space, buttonWidth, buttonHeight);
		buttonPosition2 = new Rectangle(buttonX, buttonY * 3 + space * 2, buttonWidth, buttonHeight);
		buttonPosition3 = new Rectangle(buttonX, buttonY * 4 + space * 3, buttonWidth, buttonHeight);
		buttonPosition4 = new Rectangle(buttonX, buttonY * 5 + space * 4, buttonWidth, buttonHeight);
		buttonPosition5 = new Rectangle(buttonX, buttonY * 6 + space * 5, buttonWidth, buttonHeight);
		
		mainMenuButton = new Button("Hauptmenü");
		continueButton = new Button("Spiel fortsetzen");
		newGameButton = new Button("Neues Spiel");
		endButton = new Button("Spiel beenden");
		
		continueButton.setBounds(buttonPosition1);
		newGameButton.setBounds(buttonPosition2);
		mainMenuButton.setBounds(buttonPosition3);
		endButton.setBounds(buttonPosition4);
		
		continueButton.setEnabled(false);
		mainMenuButton.setVisible(false);
		
		mainMenuButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				main.setStatus(GameStatus.MENU_MAIN);
			}			
		});
		continueButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				main.setStatus(GameStatus.GAME);
			}			
		});
		newGameButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				main.getGameManager().startNewGame();
				main.setStatus(GameStatus.GAME);
			}			
		});		
		endButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				main.setStatus(GameStatus.END);
			}			
		});
		
		frame.add(continueButton);
		frame.add(newGameButton);
		frame.add(mainMenuButton);
		frame.add(endButton);
	}
Und zuletzt wird das Spiel gezeichnet:
Java:
public void drawGame(Graphics2D graphics) {
		//Set background, image resized to screen dimensions with smooth scaling
		graphics.drawImage(imageHandler.getBackgroundGame(), 0, 0, null);
	
		for(Sprite sprite : spriteList) {
			graphics.drawImage(sprite.getImage(), (int) Math.round(sprite.getX()), (int) Math.round(sprite.getY()), null);
		}
	}
 
Hmm, leider nichts Kompilier- oder Ausführbares.
Was mir zu allererst aufgefallen ist: die setVisible()-Methode sollte auf jeden Fall in der letzten Zeile der createFrame()-Methode stehen.

Ändert sich damit etwas?
 
In die allerletzte Zeile kanns nicht, der Buffer brauch ja einen visible Frame 😉
Geändert hat sich leider nichts 🙁 Ich sehe kurz die Buttons, aber wenn der Hintergrund geladen ist, sind die wieder verdeckt und nicht zu benutzen...
 
Hatte ich vergessen zu sagen: Swing-Komponenten sind bereits gepuffert, du brauchst kein Double Buffering.
Gezeichnet wird in der paintComponent()-Methode einer JComponent oder eines JPanels.
Das solltest du umbauen.
 
Also soll ich bei jedem Zeichen-Durchgang auch alle JComponents neu zeichnen?

Und noch mal ne Frage zu den Layout-Managern: Ich möchte in einer Spalte Buttons untereinander anorden. Das funktioniert mit dem GridLayout ganz wunderbar. Allerdings sind die Buttons so groß, dass sie bis zum Bildschirmrand gehen. Wie kann ich festlegen, dass immer Rand gelassen werden soll?
 
Also soll ich bei jedem Zeichen-Durchgang auch alle JComponents neu zeichnen?
Nein, die werden einmal im Konstruktor instanziiert und auf die Oberfläche gesetzt (
Code:
add(...)
).

Wie kann ich festlegen, dass immer Rand gelassen werden soll?
Du kannst um dein JPanel bspw. einen leeren Rahmen legen.
Bsp.:
Java:
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 
Moin,

ohne den Code oben im Detail nachvollzogen zu haben und ohne die Notwendigkeit von AWT Komponenten dort infrage stellen zu wollen, so ist unabhängig davon imho die gleichzeitige Verwendung von Swing und AWT kein Problem mehr.

http://java.sun.com/developer/technicalArticles/GUI/mixing_components/index.html hat gesagt.:
Historically, in the Java language, mixing heavyweight and lightweight components in the same container has been problematic. However, as of the JDK 6 Update 12 and JDK 7 build 19 releases, mixing heavyweight and lightweight components is easy to accomplish.

Aus eigener Erfahrung funktioniert das mit Java 7 und auch den Java 6 Versionen der letzten Jahre ganz hervorragend (in 6U12 gab es noch ein paar Bugs, die später beseitigt wurden).


Das oben beschriebene Problem könnte mit diesem Bug in Verbindung stehen. Dieser Bug tritt auf sobald AWT im fullscreen exclusive mode verwendet wird, und zwar sowohl in gemischten AWT/Swing als auch im reinen AWT. Die reine Verwendung von Swing oder -Dsun.java2d.d3d=false könnten das Problem umgehen (bei mir erscheint dann der JButton aus dem obrigen Beispiel).

Viele Grüße,
Fancy
 
so ist unabhängig davon imho die gleichzeitige Verwendung von Swing und AWT kein Problem mehr.

Die reine Verwendung von Swing oder -Dsun.java2d.d3d=false könnten das Problem umgehen.
Ich hab mal deinen Beitrag auf das Wesentliche reduziert. Widerspricht sich da nicht etwas? 😉
Die Mischung von Swing- mit AWT-Komponenten macht in kaum einem Fall wirklich Sinn. Deshalb sollte man meiner Meinung nach auf Swing setzen.

Da denke ich eher, dass du mit dem Fullscreen-Bug einen berechtigen Hinweis gebracht hast.
 
Widerspricht sich da nicht etwas? 😉

Imho widerspricht sich das nicht. 😉

Der fullscreen exclusive mode bug tritt ja auch bei reinem AWT auf und ist damit erstmal unabhängig von der möglichen Swing/AWT Problematik.

Ansonsten hast Du natürlich recht, in fast allen Fällen ist reines Swing die bessere Wahl. Der oben angedeutete Fall mit fullscreen exclusive mode und active rendering könnte da ihmo jedoch auch eine der Ausnahme sein.

Viele Grüße,
Fancy
 
Vor allem tritt der Fehler, dass JComponents von der awt Graphics überschrieben werden, auch im nicht Vollbild-Modus auf...

Wie viel Arbeit wäre es denn, jetzt noch mal alles von awt auf Swing umzustellen? Welche Klassen muss ich bei Swing benutzen?
 
Vor allem tritt der Fehler, dass JComponents von der awt Graphics überschrieben werden, auch im nicht Vollbild-Modus auf...

Sollte bei validem Code und aktueller JRE nicht passieren...

Wie viel Arbeit wäre es denn, jetzt noch mal alles von awt auf Swing umzustellen? Welche Klassen muss ich bei Swing benutzen?

Vielleicht der Vollständigkeit halber: Kennst Du das Tutorial von Quaxli. Imho beschreibt er darin passives rendering unter Swing recht ausführlich und verständlich.

Viele Grüße,
Fancy
 
Ich benutze die aktuellste Java 6 Version, Update 30. Das Tutorial kannte ich schon und dort wird auch der JFrame aus Swing und Graphics aus AWT verwendet...
 
Ja, das ist auch okay so. Wenn von Problemen bei der gleichzeitigen Anwendung von AWT und Swing geschrieben wird, dann bezeiht sich das nicht unbedingt auf die Pakete, in denen einzelne Klassen liegen, sondern auf die "direkt sichtbaren" Komponenten.

AWT Komponenten sind heavyweight (Frame, Canvas, Button, …). Swing Komponenten sind lightweight (JFrame, JPanel, JButton,...). Das "direkt sichtbare" Swing Komponenten auf (nicht "direkt sichtbare") AWT Elemente zurückgreifen ist dabei unvermeidbar (Wie eben z.B. java.awt.Graphics).

Wenn Du es so machst, wie Quaxli, dann sollte das funktionieren.

Mit AWT muss das aber auch gehen: Mixing Heavyweight and Lightweight Components am Ende des Artikels ist ein roter Button "Launch", geht das Beispiel bei Dir?

Viele Grüße,
Fancy
 
So wollte ich die Komponenten auch nicht mixen, wenn die JButtons funktionieren würden, würde ich diese auch ausschließlich nutzen.
Das Beispiel hat funktioniert...
 
Dann bau doch einfach schnell ein KSKB und poste das hier. Dann kann man das passend zeigen.

Viele Grüße,
Fancy
 
Hier verschwindet der JButton und wenn man mit der Maus auf den Bildschirm geht, ist er wieder sichtbar, verschwindet aber nach wenigen Sekungen wieder.
Lässt man die Wartepause weg und lässt die Schleife dauerhaft neu zeichen, wie es ja im Spiel passiert, ist der Button dauerhaft unsichtbar.

Java:
public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(200, 200);
		frame.setVisible(true);
		
		JButton button = new JButton("Click me!");
		
		frame.add(button);

		while(true) {
			Graphics g = frame.getGraphics();
                        g.setColor(Color.YELLOW);			
			g.fillRect(0, 0, 200, 200);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {}
		}		
	}
 
Zuletzt bearbeitet:
Das scheint wohl eine Art von Alltagsproblem zu sein:
Niemals getGraphics() auf eine Instanz von einer Window oder Component erbenten Klasse aufrufen!

Schau dir doch mal die entsprechenden Tutorials dazu an: Zeichnen in Swing Tutorial und KEIN Swing-Tutorial

Danach sollte es dir klar sein.


P.S. Hier sieht man wieder mal, was so alles passieren kann wenn man doch getGraphics() aufruft und damit versuch irgendwas zu zeichnen!
 
In den beiden habe ich jetzt nur was für Components gesehen.
Ich schreibe also ne Unterklasse vom JFrame, überschreibe dessen Methode paint(Graphics g) und rufe in der Spiel-Schleife dann immer die repaint()-Methode auf?

//edit: Habs mal umgeschrieben, aber der Button ist immer noch unsichtbar.
Java:
public class Test extends JFrame{
	
	public Test() {
		super();
	}
	
	@Override    
	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(Color.YELLOW);			
		g.fillRect(0, 0, 200, 200);		
	}
	
	public static void main(String[] args) {
		Test frame = new Test();
		frame.setSize(200, 200);
		frame.setVisible(true);
		
		JButton button = new JButton("Click me!");
		
		frame.add(button);
		
		while(true) {
			frame.repaint();
		}	
	}
}
 
Zuletzt bearbeitet:
Ich schreibe also ne Unterklasse vom JFrame, überschreibe dessen Methode paint(Graphics g) und rufe in der Spiel-Schleife dann immer die repaint()-Methode auf?

Fast, nicht ganz. Du schreibst eine Unterklasse, die von JPanel erbts, überschreibst dort die paintComponent(Graphics g)-Methode (mit den super.paintComponent(g) - Aufruf) und rufst in der Spiel-Schleife dann immer die repaint()-Methode dieser Klasse auf.

[EDIT]
Zudem schreibt man, wenn überhaupt, eine Endlosschleife wie bei dir
Code:
while(true)
nur in einem Thread, da ansonsten die gesamte GUI blockiert wird.
[/EDIT]
 
Zuletzt bearbeitet:
So funktioniert es jetzt, auch wenn das GUI noch durch die Schleife blockiert ist.
Java:
public class Test extends JPanel{
	
	public Test() {
		super();
	}
	
	@Override    
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setColor(Color.YELLOW);			
		g.fillRect(0, 0, 200, 200);		
	}
	
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		Test test = new Test();                
		test.setPreferredSize(new Dimension(200, 100));		
		JButton button = new JButton("Click me!");		
		test.add(button);
        frame.getContentPane().add(test);
		frame.setSize(200, 200);
		frame.pack();
		frame.setVisible(true);
		
		while(true) {
			test.repaint();
		}	
	}
}
 
Das geht ja jetzt auch in die Richtung, wie es in Quaxlis Tutorial erklärt wird. Das nennt sich passives rendering. Die anderen Beispiele in diesem Thread (z.B.) gehen mehr in Richtung actives rendering. Allerdings fehlt da noch etwas Code, damit Swing Komponenten korrekt dargestellt werden:


Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;


public class ZZ {

    public static void main(final String[] args) {

        RepaintManager.setCurrentManager(new RepaintManager() {


            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {

            }


            @Override
            public void addInvalidComponent(final JComponent invalidComponent) {

            }


            @Override
            public void markCompletelyDirty(final JComponent aComponent) {

            }


            @Override
            public void paintDirtyRegions() {

            }

        });

        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        frame.setIgnoreRepaint(true);
        frame.setVisible(true);
        ((JComponent) frame.getContentPane()).setOpaque(false);

        final JPanel panel = new JPanel();
        final JButton button = new JButton("Click me!");
        panel.add(button);
        panel.setMaximumSize(new Dimension(100, 100));
        panel.setOpaque(false);
        frame.add(panel);

        frame.createBufferStrategy(2);
        final BufferStrategy bs = frame.getBufferStrategy();

        boolean color = true;

        while (true) {

            Graphics2D g = null;
            try {

                g = (Graphics2D) bs.getDrawGraphics();

                if (color)
                    g.setColor(Color.RED);
                else
                    g.setColor(Color.YELLOW);

                g.fillRect(0, 0, 200, 200);

                color = !color;

                g.translate(frame.getInsets().left, frame.getInsets().top);
                frame.getLayeredPane().paintComponents(g);

            } finally {

                g.dispose();

            }

            if (!bs.contentsLost())
                bs.show();

            Toolkit.getDefaultToolkit().sync();

            Thread.yield();

        }
    }

}


Viele Grüße,
Fancy
 
Passive vs. Active Rendering


Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;


public class ZZ {

    public static void main(final String[] args) {

        RepaintManager.setCurrentManager(new RepaintManager() {


            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {

            }


            @Override
            public void addInvalidComponent(final JComponent invalidComponent) {

            }


            @Override
            public void markCompletelyDirty(final JComponent aComponent) {

            }


            @Override
            public void paintDirtyRegions() {

            }

        });

        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        frame.setIgnoreRepaint(true);
        frame.setVisible(true);
        ((JComponent) frame.getContentPane()).setOpaque(false);

        final JPanel panel = new JPanel();
        final JButton button = new JButton("Click me!");
        panel.add(button);
        panel.setMaximumSize(new Dimension(100, 100));
        panel.setOpaque(false);
        frame.getContentPane().add(panel);

        frame.createBufferStrategy(2);
        final BufferStrategy bs = frame.getBufferStrategy();

        boolean color = true;

        while (true) {

            Graphics2D g = null;
            try {

                g = (Graphics2D) bs.getDrawGraphics();

                g.setColor(frame.getBackground());
                g.fillRect(0, 0, frame.getWidth(), frame.getHeight());

                if (color)
                    g.setColor(Color.RED);
                else
                    g.setColor(Color.YELLOW);

                g.fillRect(0, 0, 200, 200);

                color = !color;

                g.translate(frame.getInsets().left, frame.getInsets().top);
                frame.getLayeredPane().paintComponents(g);

                if (!bs.contentsLost())
                    bs.show();

            } catch (final IllegalStateException e) {

            } finally {

                if (g != null)
                    g.dispose();

            }

            Toolkit.getDefaultToolkit().sync();

            Thread.yield();

        }
    }

}

Viele Grüße,
Fancy
 
Ich habe dein Programm so wie es war ausgefügrt und alles hat wunderbar funktioniert.
Wenn ich das aber so in mein Hauptspiel einsetze, sehe ich die Buttons schon wieder nicht.

Frame wird erstellt:
Java:
public void createFrame() {
		RepaintManager.setCurrentManager(new RepaintManager() { 
            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {} 
             @Override
            public void addInvalidComponent(final JComponent invalidComponent) {}
            @Override
            public void markCompletelyDirty(final JComponent aComponent) {}
            @Override
            public void paintDirtyRegions() {} 
        });
		frame = new JFrame("Bubble Trouble", graphicsDevice.getDefaultConfiguration());
		frame.setUndecorated(true);
		frame.setIgnoreRepaint(true);
		frame.setResizable(false);
		frame.setFocusable(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		maximizeFrame(getFirstCompatibleMode(displayModes));
        
		frame.setVisible(true);

        ((JComponent) frame.getContentPane()).setOpaque(false);
        final JPanel panel = new JPanel();
        final JButton button = new JButton("Click me!");
        panel.add(button);
        panel.setMaximumSize(new Dimension(1800, 900));
        panel.setOpaque(false);
        
        panel.addKeyListener(main.getKeyHandler());
		panel.addMouseListener(main.getMouseListener());
		
		main.getComponentHandler().initComponents(panel);
        
        frame.getContentPane().add(panel);
		
		//Enable double-buffering
		frame.createBufferStrategy(2);
	}
Die draw-Methode wird von einem eigenen Thread aufgerufen:
Java:
public void draw() {
		JFrame frame = screenHandler.getFrame();
		Graphics2D graphics = screenHandler.getGraphics();
		
		switch(main.getStatus()) {
			case MENU_MAIN:		drawMainMenu(graphics); break;
			case MENU_GAME:		drawGameMenu(graphics); break;
			case GAME:			drawGame(graphics); break;
			case LEVELCHANGE:	drawLevelChange(graphics); break;
			case SCORE:			drawScore(graphics); break;
		} 
		graphics.translate(frame.getInsets().left, frame.getInsets().top);
        frame.getLayeredPane().paintComponents(graphics);
        
      //Display updaten, sodass die neue Grafik angezeigt wird
      	screenHandler.updateDisplay();
      	
		graphics.dispose();
		Toolkit.getDefaultToolkit().sync();
        Thread.yield();
	}

public void drawMainMenu(Graphics2D graphics) {
		graphics.setFont(new Font("Arial", Font.PLAIN, 40));
		graphics.setColor(Color.BLUE);
		graphics.fillRect(0, 0, screenHandler.getWidth(), screenHandler.getHeight());
		graphics.setColor(Color.RED);
		graphics.drawString("Press Enter to start the game.", 100, 100);
		graphics.drawString("Press Esc to stop the game.", 200, 200);
	}
Die Komponenten werden erstellt:
Java:
public void initComponents(JPanel panel) {
		layout = new GridLayout(4, 3, 200, 100);
		
		//frame.setLayout(layout);
		panel.setLayout(null);
		
		int width = panel.getWidth();
		int height = panel.getHeight();		
		int buttonWidth = width / 3;
		int buttonHeight = height / 10;
		int buttonX = width / 2 - buttonWidth / 2;
		int buttonY = height / 10;
		int space = 40;
		
		buttonPosition1 = new Rectangle(buttonX, buttonY * 2 + space, buttonWidth, buttonHeight);
		buttonPosition2 = new Rectangle(buttonX, buttonY * 3 + space * 2, buttonWidth, buttonHeight);
		buttonPosition3 = new Rectangle(buttonX, buttonY * 4 + space * 3, buttonWidth, buttonHeight);
		buttonPosition4 = new Rectangle(buttonX, buttonY * 5 + space * 4, buttonWidth, buttonHeight);
		buttonPosition5 = new Rectangle(buttonX, buttonY * 6 + space * 5, buttonWidth, buttonHeight);
		
		mainMenuButton = new Button("Hauptmenü");
		continueButton = new Button("Spiel fortsetzen");
		newGameButton = new Button("Neues Spiel");
		endButton = new Button("Spiel beenden");
		
		devPre_passwordField = new TextField();
		
		//Ohne Layout-Manager
		continueButton.setBounds(buttonPosition1);
		newGameButton.setBounds(buttonPosition2);
		mainMenuButton.setBounds(buttonPosition3);
		endButton.setBounds(buttonPosition4);
		devPre_passwordField.setBounds(0, 0, 100, 25);
		
		mainMenuButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				main.setStatus(GameStatus.MENU_MAIN);
			}			
		});
		continueButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				main.setStatus(GameStatus.GAME);
			}			
		});
		newGameButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				main.getGameManager().startNewGame();
				main.setStatus(GameStatus.GAME);
			}			
		});		
		endButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				main.setStatus(GameStatus.END);
			}			
		});
		devPre_passwordField.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent event) {
				TextComponent component = (TextComponent) event.getComponent();
				if(event.getKeyCode() == KeyEvent.VK_ESCAPE) {					
					main.setStatus(GameStatus.GAME);
					component.setText("");
					component.transferFocus();
					//FOKUS MUSS IRGENDWIE WECH!!!!
				}
				if(event.getKeyCode() == KeyEvent.VK_ENTER && component.getText().equals("cheater")) main.setStatus(GameStatus.DEV_MAIN);}
			@Override
			public void keyReleased(KeyEvent event) {}
			@Override
			public void keyTyped(KeyEvent event) {}
		});
		
		/*layout.addLayoutComponent("continueButton", continueButton);
		layout.addLayoutComponent("newGameButton", newGameButton);
		layout.addLayoutComponent("mainMenuButton", mainMenuButton);
		layout.addLayoutComponent("endButton", endButton);*/
		
		hideAll();
		showMainMenu();
		
		panel.add(continueButton);
		panel.add(newGameButton);
		panel.add(mainMenuButton);
		panel.add(endButton);
		panel.add(devPre_passwordField);
	}
 
Mir fehlt da zu viel Code, um was dazu sagen zu können. (Z.B. maximizeFrame und screenHandler)

Das Beispiel von oben mal als FSEM Variante (vielleicht findest Du dann ja einen Unterschied):

Java:
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;


public class ZZ {

    public static void main(final String[] args) {

        RepaintManager.setCurrentManager(new RepaintManager() {


            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {

            }


            @Override
            public void addInvalidComponent(final JComponent invalidComponent) {

            }


            @Override
            public void markCompletelyDirty(final JComponent aComponent) {

            }


            @Override
            public void paintDirtyRegions() {

            }

        });

        final GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        final DisplayMode mode = device.getDisplayMode();

        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setIgnoreRepaint(true);
        ((JComponent) frame.getContentPane()).setOpaque(false);

        final JPanel panel = new JPanel();
        final JButton button = new JButton("Click me!");
        panel.add(button);
        panel.setOpaque(false);
        frame.getContentPane().add(panel);

        frame.setUndecorated(true);
        frame.setResizable(false);
        frame.setSize(mode.getWidth(), mode.getHeight());
        frame.pack();
        frame.setVisible(true);

        device.setFullScreenWindow(frame);
        device.setDisplayMode(mode);

        frame.createBufferStrategy(2);
        final BufferStrategy bs = frame.getBufferStrategy();

        boolean color = true;

        while (true) {

            Graphics2D g = null;
            try {

                g = (Graphics2D) bs.getDrawGraphics();

                g.setColor(frame.getBackground());
                g.fillRect(0, 0, frame.getWidth(), frame.getHeight());

                if (color)
                    g.setColor(Color.RED);
                else
                    g.setColor(Color.YELLOW);

                g.fillRect(0, 0, mode.getWidth() / 2, mode.getHeight());

                color = !color;

                g.translate(frame.getInsets().left, frame.getInsets().top);
                frame.getLayeredPane().paintComponents(g);

                if (!bs.contentsLost())
                    bs.show();

            } catch (final IllegalStateException e) {

            } finally {

                if (g != null)
                    g.dispose();

            }

            Toolkit.getDefaultToolkit().sync();

            Thread.yield();

        }
    }

}

(Ansonsten bin ich jetzt auch offline und erst morgen Abend wieder da).

Viele Grüße,
Fancy
 
Die Anzeige funktioniert jetzt so, wie sie soll, nur der KeyListener empfängt keine Eingaben mehr.
Ich habe ihn mit KeyBindings ersetzt, doch auch dort gibt es ein Problem:
Ich benutze immer WHEN_IN_FOCUSED_WINDOW, damit alle Eingaben ankommen, egal welches Objekt im Frame gerade den Fokus hat.
Lege ich die Bindings aber so auf das JPanel, verliert es bei einem Knopfdruck den Fokus und nichts kommt an.
Lege ich es auf einen Button funktioniert es, solange dieser sichtbar ist. Verstecke ich ihn mit setVisible(false), kommt wieder nichts an.
Ich habe aber kein einziges Objekt, dass die gesamte Zeit auf dem Frame bleibt. Was kann man da machen?

[EDIT]Funktioniert jetzt. Danke an alle Helfer! :applaus:[/EDIT]
 
Es gibt doch ein neues Problem.
Alle Komponenten werden ständig überzeichnet, also im Grunde das alte Problem.
Meine bisher benutze Zeile
Java:
frame.getLayeredPane().paintComponents(graphics);
zeichnet zwar die Komponente, verursacht aber Fehler bei Textkomponenten, dann hängt sich das Programm auf.
 
Java:
public class JPasswordFieldTest {
	
	static JFrame frame;
	static JPanel panel;
	static JPasswordField passwordField;
	
	
	public static void main(String[] args) {
		createFrame();
		
		panel.add(passwordField);
		
		while(true) {
			draw();
		}
	}
	
	public static void createFrame() {
		RepaintManager.setCurrentManager(new RepaintManager() {
            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {}
            @Override
            public void addInvalidComponent(final JComponent invalidComponent) {}
            @Override
            public void markCompletelyDirty(final JComponent aComponent) {}
            @Override
            public void paintDirtyRegions() {} 
        });
 
        frame = new JFrame("Bubble Trouble");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        passwordField  = new JPasswordField(10);
        frame.setSize(1200, 800);
		frame.setResizable(false);
		frame.setUndecorated(true);
        frame.setIgnoreRepaint(true);
        frame.setVisible(true);
        ((JComponent) frame.getContentPane()).setOpaque(false);
 
        panel = new JPanel();
        panel.setOpaque(false);
		
        frame.getContentPane().add(panel);
 
        frame.createBufferStrategy(2);
	}
	
	public static void draw() {
		Graphics graphics = null;
		BufferStrategy bufferStrategy = frame.getBufferStrategy();
        try {

            graphics = (Graphics) bufferStrategy.getDrawGraphics();

            graphics.drawLine(20, 20, 400, 400);

            graphics.translate(frame.getInsets().left, frame.getInsets().top);
            //HIER IST DER FEHLER!!!
            frame.getLayeredPane().paintComponents(graphics);

            if (!bufferStrategy.contentsLost())
                bufferStrategy.show();

        } catch (IllegalStateException e) {} 
        finally {
            if (graphics != null) graphics.dispose();
        }

        Toolkit.getDefaultToolkit().sync();

        Thread.yield();
	}

}
 
Ja, das ist vermutlich eine race condition zwischen dem EDT und dem rendering Thread. Es gibt vermutlich auch mehrere Lösungen dazu. Spontan würde ich das [c]frame.getLayeredPane().paintComponents(g);[/c] einfach auf den EDT legen. Aufpassen muss man dann allerdings, das man das nicht bei jedem Frame macht, sondern nur wenn sich der Swing Inhalt wirklich geändert hat (sonnst wäre das active rendering nicht mehr wirklich sinnvoll).

Spontan sähe das dann etwa so aus:

Java:
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.RepaintManager;

public class JPasswordFieldTest2 {

    private static volatile boolean dirty = true;

    static {

        RepaintManager.setCurrentManager(new RepaintManager() {

            @Override
            public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {

                dirty = true;

            }


            @Override
            public void addInvalidComponent(final JComponent invalidComponent) {

                dirty = true;

            }


            @Override
            public void markCompletelyDirty(final JComponent aComponent) {

                dirty = true;

            }


            @Override
            public void paintDirtyRegions() {

            }

        });

    }


    private final JFrame            frame;
    private final BufferedImage     bi;
    private final BufferStrategy    bs;


    public static void main(final String[] args) {

        final JPasswordFieldTest2 main = new JPasswordFieldTest2();

        while (true)
            main.draw();

    }


    public JPasswordFieldTest2() {

        final GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        final DisplayMode mode = device.getDisplayMode();

        frame = new JFrame("Bubble Trouble");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setIgnoreRepaint(true);
        frame.setUndecorated(true);
        frame.setResizable(false);
        frame.setSize(mode.getWidth(), mode.getHeight());
        ((JComponent) frame.getContentPane()).setOpaque(false);

        final JPasswordField passwordField = new JPasswordField(10);
        final JPanel panel = new JPanel();
        panel.setOpaque(false);
        panel.add(passwordField);

        frame.getContentPane().add(panel);
        frame.pack();
        frame.setVisible(true);

        device.setFullScreenWindow(frame);
        device.setDisplayMode(mode);

        frame.createBufferStrategy(2);
        bs = frame.getBufferStrategy();

        bi = new BufferedImage(mode.getWidth(), mode.getHeight(), BufferedImage.TYPE_INT_ARGB);

    }


    private void draw() {

        Graphics2D g = null;
        try {

            g = (Graphics2D) bs.getDrawGraphics();

            drawOwn(g);

            if (dirty)
                drawSwing();

            synchronized (bi) {

                g.drawImage(bi, 0, 0, null);

            }

            if (!bs.contentsLost())
                bs.show();

        } catch (final IllegalStateException e) {

            e.printStackTrace();

        } finally {

            if (g != null)
                g.dispose();

        }

        Toolkit.getDefaultToolkit().sync();

        Thread.yield();

    }


    private void drawOwn(final Graphics2D g) {

        g.setColor(frame.getBackground());
        g.fillRect(0, 0, frame.getWidth(), frame.getHeight());

        g.setColor(Color.black);
        g.drawLine(20, 20, 400, 400);

    }


    private void drawSwing() {

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {

                dirty = false;

                synchronized (bi) {

                    final Graphics g = bi.getGraphics();

                    g.translate(frame.getInsets().left, frame.getInsets().top);
                    frame.getLayeredPane().paintComponents(g);

                    g.dispose();

                }

            }
        });

    }

}

Viele Grüße,
Fancy
 
Dein Beispiel funktioniert bei mir so wie es soll. Kannst du noch mal kurz zusammenfassen, was genau du alles geändert hast?
Und ich habe noch drei Fragen: Was hat das BufferedImage da zu suchen?
Gibt die boolesche Variable dirty einfach nur die Notwendigkeit eines repaints an?
Was ist das für ein Konstrukt:
Java:
synchronized (bi) {
 
                g.drawImage(bi, 0, 0, null);
 
            }
Habe ich noch nie bisher gesehen. Ist das so etwas wie eine innere Methode? Oder einfach nur ein Block, der mit dem synchronized-Attribut ausgeführt werden soll?
 

Zurück
Oben