# Geteiltes Fenster in Bedienoberfläche und OpenGL-Ausgabebereich



## ChillSn (14. Jul 2009)

Hallo Liebe Community,

ich bin neu im Gebiet der Java-Programmierung. Ich programmiere seit mehreren Jahren leidenschaftlich gerne PHP und alles was dazugehört (HTML, JavaScript , XML, Ajax). Ich habe Grundkenntnisse in Delphi, C++ und mittlerweile auch ein bisschen Java. Ich stamme ganz klar aus der prozeduralen Ecke und hatte mit Objektorientierung bisher nicht allzu viel am Hut.

Ich versuche nun, in Java eine Oberfläche zu basteln, in der ich auf der einen Seite Formularelemente (Buttons, Listen, Panels, Labels etc.) darstellen kann und auf der anderen Seite einen OpenGL-Ausgabebereich (habe mit JOGL angefangen) habe. 

Das ganze soll wohlgemerkt in einem einzigen Fenster kombiniert werden. Ist das grundsätzlich möglich oder habe ich einen völlig verkehrten Ansatz?!

Das ganze soll ungefähr so wie im Anhang aussehen.

Btw:

Ich bekomme es ohne Probleme hin, ein reines JOGL-Fenster zusammenzubauen *oder* eine AWT-Oberfläche zu erstellen. Wenn ich aber beides kombinieren will, so fehlt mir ganz klar der richtige Ansatz dafür.

Ich freue mich auf eure Antworten!

Viele Grüße,
ChillSn


----------



## mmz (14. Jul 2009)

Is nur gerade schnell zusammengebaut und das Layout passt auch nid ganz, aber so sollte es doch funktionieren. Der Cube is das Ausgabefenster.


```
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class CanvasTest extends JFrame {

    public CanvasTest() {
        setSize(new Dimension(600, 400));
        setLayout(new BorderLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
        Canvas3D canvas = new Canvas3D(config);
        JPanel left = new JPanel();
        left.add(new JLabel("Hallo"));
        JButton exit = new JButton("Beenden");
        left.add(exit);
        JPanel south = new JPanel();
        JTextArea ta = new JTextArea(10, 20);
        ta.setText("Ich bin eine Textarea");
        south.add(ta);
        add("West", left);
        add("Center", canvas);
        add("South", south);
        BranchGroup contents = new BranchGroup();
        contents.addChild(new ColorCube(0.3));
        SimpleUniverse universe = new SimpleUniverse(canvas);
        universe.getViewingPlatform().setNominalViewingTransform();
        universe.addBranchGraph(contents);
    }

    public static void main(String[] args) {
        new CanvasTest().setVisible(true);
    }
}
```

Edith: Achso JOGL, na ja da sollte es auch so was wie ein Canvas3d geben auf das gezeichnet wird. Halt einfach ersetzen dann. Wenns das nicht gibt, dann sry :bahnhof:

Edith 2 : Also auch mit JOGL geht das


```
import com.sun.opengl.util.Animator;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;



/**
 * SimpleJOGL.java <BR>
 * author: Brian Paul (converted to Java by Ron Cemer and Sven Goethel) <P>
 *
 * This version is equal to Brian Paul's version 1.2 1999/10/21
 */
public class SimpleJOGL implements GLEventListener {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Simple JOGL Application");
        frame.setLayout(new BorderLayout());
        JPanel left = new JPanel();
        left.add(new JButton("Test"));
        GLCanvas canvas = new GLCanvas();
        canvas.setSize(new Dimension(500, 480));
        canvas.addGLEventListener(new SimpleJOGL());
        frame.add("East", canvas);
        frame.add("West",left);
        frame.setSize(640, 480);
        Animator animator = new Animator(canvas);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        // Center frame
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        animator.start();
    }

    public void init(GLAutoDrawable drawable) {
        // Use debug pipeline
        // drawable.setGL(new DebugGL(drawable.getGL()));

        GL gl = drawable.getGL();
        System.err.println("INIT GL IS: " + gl.getClass().getName());

        // Enable VSync
        gl.setSwapInterval(1);

        // Setup the drawing area and shading mode
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see what happens.
    }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        if (height <= 0) { // avoid a divide by zero error!

            height = 1;
        }
        final float h = (float) width / (float) height;
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 1.0, 20.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void display(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        // Clear the drawing area
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Reset the current matrix to the "identity"
        gl.glLoadIdentity();

        // Move the "drawing cursor" around
        gl.glTranslatef(-1.5f, 0.0f, -6.0f);

        // Draw A Quad
        gl.glBegin(GL.GL_QUADS);
            gl.glColor3f(0.5f, 0.5f, 1.0f);    // Set the current drawing color to light blue
            gl.glVertex3f(-1.0f, 1.0f, 0.0f);  // Top Left
            gl.glVertex3f(1.0f, 1.0f, 0.0f);   // Top Right
            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // Bottom Right
            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
        // Done Drawing The Quad
        gl.glEnd();

        // Flush all drawing operations to the graphics card
        gl.glFlush();
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
    }
}
```

Nicht wundern, die Klasse ist generiert, hab nur ein paar kleine Änderungen gemacht.


----------



## ChillSn (16. Jul 2009)

Hallo mmz,

also erstmal vielen Dank für deine schnelle Antwort - das ist genau das, was ich benötige  *freu*

Ich habe nur sehr lange gebraucht, bis ich das Skript zum laufen gebracht hatte. Dies lag vor allem daran, dass ich nach wie vor unendlich lange brauche, die JOGL-Libraries einzubinden (ohne Eclipse hab ich es partout nicht hinbekommen).

Ich habe eine aktuelle JOGL-Version (https://jogl.dev.java.net/#NIGHTLY) für meinen x86er P4 gezogen und jars in das lib und dlls in das native gepackt (beides Unterordner in meinem Projektverzeichnis). Bin genau nach Anleitung vorgegangen wie auf jogl und eclipse - Java @ tutorials.de: Forum, Tutorial, Anleitung, Schulung & Hilfe beschrieben. 
Mit einer älteren JOGL-Version klappt das auch einwandfrei (mit der lief dann auch dein Skript), nur nicht mit der neueren.
Die neuere hat auch viel mehr jars und dlls im Archiv. Das kommt mir schon irgendwie spanisch vor, denn bei der alten waren es nur 4 dlls und 2 jars.

Nun bin ich zwar erstmal glücklich, dass das Skript soweit funktioniert, würde aber gerne auf die neueste JOGL-Library umschwenken, um nicht mit veralteten oder deprecated Funktionen rumhantieren zu müssen.

Hast du/ihr evtl. eine Idee, was ich beim einbinden der aktuellen JOGL-Librarys verkehrt mache?

Vielen dank schonmal im vorraus!!!

Greets,
der ChillSn


----------



## mmz (16. Jul 2009)

Ich arbeite unter linux, aber die .so dateien sollten das gleiche sein wie die dlls unter windows. Für netbeans gäbe es ein bundle (plugins für jogl) falls Dus dir mal anschauen möchtest. https://netbeans-opengl-pack.dev.java.net/

Hmm, die jars sind eigentlich egal wo die liegen, müssen nur wie beschrieben im path mit angegeben werden.
Versuch mal die dlls in den Ordner .../jdk1.6.0_14/jre/lib/i386/ zu kopieren ob es dann funktioniert. Dann musst den  Pfad zu den dlls zumindest vorerst nicht im path angeben. Wenn das immer noch nicht funktioniert, dann muss ich mich auch noch mal schlau machen. Wie gesagt Linux und netbeans...


----------



## ChillSn (28. Jul 2009)

Hallo mmz,

also ich habe es jetzt hinbekommen - es lag daran, dass dass .Jar bereits extrahiert worden war und demnach ein Haufen andere Dateien ausspuckte. Wie auch immer, die Dll's und Jar's sind jetzt ein eclipse eingebunden und funtionieren wie gewünscht.
Ich habe das Layout (siehe Eingangspost) auch so umsetzen können. Ich habe dazu das GridBagLayout verwendet (komplex, aber einmal vertanden super :applaus und bin auch sonst komplett auf Swing-Komponenten umgestiegen (AWT und Swing sollte man ja nicht mischen).

So, nun stecke ich in einem anderen Dilemma. Ich habe gelesen, dass alle Swing-Komponenten DoubleBuffered sind. Trotz dieser Eigenschaft "flackert" der Screen, sobald ich eine Aktion ausführe - also z.B. eine Auswahl im Menü treffe, einen Button Klicke, oder etwas im OpenGL-Ausgabebereich bewegt wird. Es sieht so aus, als würde der ganze JFrame bei jeder Aktion neu gezeichnet werden (was natürlich nicht gewünscht ist), obwohl ich nirgendwo eine repaint() oder paint() - Methode aufrufe. 

Hast du spontan eine Idee, woran das liegen kann? 
Wenn du den "Quälcode" benötigst, poste ich den gerne heute Abend.

Viele Grüße,
der ChillSn


----------



## mmz (28. Jul 2009)

Hi,

Hmm, Quelltext wäre nicht schlecht. Hatte das auch schon ab und an mal und die Lösung lag dann meist irgendwo im src wo man es nicht vermutet hätte...
Muss ja nicht der komplette Quelltext sein. Ein kleines Beispiel, das ich kompilieren kann und wo das Problem auftritt reicht schon.


----------



## ChillSn (28. Jul 2009)

Klar, kein Problem:


```
package editor;

import com.sun.opengl.util.Animator;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.opengl.*;

public class OGL_editor extends JFrame implements GLEventListener,KeyListener,MouseListener, 
MouseWheelListener, MouseMotionListener, ActionListener  
{
 
	public int angle;	
	public JFrame frame;
	public JMenuBar meinMenu;	
	public Animator animator;
	public GridBagLayout gbl;
	public GraphicsDevice myDevice;
	
	private JPanel pnl_object_choice;
	private JPanel pnl_object_properties;
	private JTextArea txt;
	private GLCanvas canvas;	
	private JScrollPane scrollingArea;

	
	public OGL_editor(){
		
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		angle=0; //nur test für OpenGl-Bewegung
		    
		//frame erzeugen und Listener Registrieren
		frame=new JFrame("Mein TEST");	
		frame.addKeyListener(this);
		frame.setBounds(0,0,800,600);	     
	     
		//Menü erzeugen			
		create_menu();
		//Panels erzeugen
		create_panel();
		create_panel_properties();
		
	  	//canvas erzeugen
	  	create_canvas();
	        animator = new Animator(canvas); 
	        animator.start();
	  
	  	//LAYOUT ausrichten
	  	Layout();
		
	  	//Falls FS möglich ist, dann FS		
		myDevice= GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 
		
		txt.append("Fullscreen-Support: "+myDevice.isFullScreenSupported());
		
		if(myDevice.isFullScreenSupported()){ 
		
			frame.setResizable(false);			
			
			//Fehler tritt nur auf, wenn folgende 2 Zeilen einkommentiert sind			
			myDevice.setFullScreenWindow(frame);
			myDevice.setDisplayMode(new DisplayMode(1024,768,32,0)); 
			
		}
		
		frame.setVisible(true);
	}
	
	public static void main(String[] args) {
		
		OGL_editor fenster = new OGL_editor();	    
      }
	
	
	private void Layout(){		
		
		GridBagLayout gbl = new GridBagLayout();
		
	  	frame.setLayout(gbl);		
		GridBagConstraints c = new GridBagConstraints();

	  	c.fill = GridBagConstraints.BOTH;
	  	c.weightx=1;//Container im Frame Maximieren
	  	c.weighty=1;//Container im Frame Maximieren	  	
	  	c.gridx = 0;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;

	  	frame.add(pnl_object_choice, c);

	  	c.gridx = 1;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;
	  	frame.add(pnl_object_properties, c);

	  	c.gridx = 2;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;

	  	frame.add(canvas, c);

	  	txt = new JTextArea(1,10);	  	
	  	txt.setEditable(false);

	  	scrollingArea = new JScrollPane(txt);
	  	
	  	c.fill = GridBagConstraints.BOTH;
	  	c.gridx = 2;
	  	c.gridy = 1;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;

	  	frame.add(scrollingArea, c);
	} 
	
	
	
	private GLCanvas create_canvas(){		
	  	
		canvas = new GLCanvas(); 
		canvas.addGLEventListener(this);
	     
		return canvas;
	}

	private void create_menu(){
	
		meinMenu=new JMenuBar();
		
	        //Menutest
	        JMenu datei =new JMenu("Datei");
	        meinMenu.add(datei);

	        JMenuItem oeffnen= new JMenuItem("Öffnen");
	        JMenuItem schliessen= new JMenuItem("Schließen");
	        schliessen.addActionListener(this);
	        
	        datei.add(oeffnen);
	        datei.add(schliessen); 
	        
	        frame.setJMenuBar(meinMenu);
		   		
	}
	
	private JPanel create_panel(){
		
		    pnl_object_choice = new JPanel();
		    pnl_object_choice.add(new JLabel("Objektauswahl"));
		    pnl_object_choice.setBackground(new Color(255,255,0));
	    
		    return pnl_object_choice;
	}
	
	private JPanel create_panel_properties(){
		
		    pnl_object_properties = new JPanel();
		    pnl_object_properties.add(new JLabel("Objekteigenschaften"));
		    pnl_object_properties.setBackground(new Color(255,0,0));
		    
		    return pnl_object_properties;
	}
	

        
    

    public void init(GLAutoDrawable drawable) {
	    	
	    GL gl = drawable.getGL();
	    gl.glEnable(GL.GL_NORMALIZE);
		
	    drawable.addMouseListener(this);	//Setzt für dieses Objekt Listener für MouseEvents
	    drawable.addMouseMotionListener(this);//Setzt für dieses Objekt Listener für MouseMove
	    drawable.addMouseWheelListener(this);//Setzt für dieses Objekt Listener für MouseWheel
    
	    drawable.addKeyListener(this);
        
    }
    
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
	    
	    GL gl = drawable.getGL();	    
	    float h = (float)height / (float)width;
	           
	    gl.glMatrixMode(GL.GL_PROJECTION);

	    gl.glLoadIdentity();
	    
	    gl.glScaled(0.5,0.5,0.5); //bestimmt die Sklalierung
	    
	    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Standard hintergrundfarbe
	    
	    //procedure glFrustum(left, right, bottom, top, zNear, zFar : glDouble);
	    gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
	    gl.glMatrixMode(GL.GL_MODELVIEW);
	    gl.glLoadIdentity();
	    gl.glTranslatef(0,0,-20);
     }
    


    
 
    public void display(GLAutoDrawable drawable) {
  
	  GL gl = drawable.getGL();
       
        // Clear the drawing area
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Reset the current matrix to the "identity"
        gl.glLoadIdentity();
 
        // Move the "drawing cursor" around
        gl.glTranslatef(-1.5f, 0.0f, -6.0f);
 
        gl.glRotatef(angle, 1, 0,0);
	   
        // Draw A Quad
        gl.glBegin(GL.GL_QUADS);
            gl.glColor3f(0.5f, 0.5f, 1.0f);    // Set the current drawing color to light blue
            gl.glVertex3f(-1.0f, 1.0f, 0.0f);  // Top Left
            gl.glVertex3f(1.0f, 1.0f, 0.0f);   // Top Right
            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // Bottom Right
            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
        // Done Drawing The Quad
        gl.glEnd();        
        
        // Flush all drawing operations to the graphics card
        gl.glFlush(); 
   
    }
 
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
    }

    public void actionPerformed(ActionEvent ae){
	   
	    JMenuItem mi =(JMenuItem)ae.getSource();
	    String menupunkt=mi.getText();
	    
	    if(menupunkt=="Schließen")
		    System.exit(0);
	    
	    txt.append(mi.getText());
	    
    } 
    

@Override
public void keyPressed(KeyEvent e)
{
	// TODO Auto-generated method stub
	txt.append("\nKeyCode: "+e.getKeyCode());
	angle+=10;

	if(e.getKeyCode()==27){		
		System.exit(0);
	}
	
}



public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseWheelMoved(MouseWheelEvent e){}
public void mouseDragged(MouseEvent e){}
public void mouseMoved(MouseEvent e){}


public void windowClosing (WindowEvent event)
{ 
	System.exit(0);
}

}
```

Habe eben bemerkt, das der Fehler nur im Vollbildmodus auftritt und dir die 2 Zeilen im Konstruktor mit kommentiert (Zeile 62+63). Kommentier sie mal aus und du wirst sehen, dass es im "Fenstermodus" funktioniert. Allerdings check ich nicht ganz, worin der Unterschied zwischen beidem liegt ???:L 

Im Allgemeinen habe ich sowieso das Gefühl, da ne ziemliche Codewurst fabriziert zu haben! Also wenn dir irgendwo was auffallen sollte, so lass es mich wissen.


Ich hoffe du bekommst es compiliert 

VG ChillSn


----------



## mmz (29. Jul 2009)

Hi,

Du benutzt GLCanvas welches AWT ist, dieses ist nicht double buffered. Mach daraus einfach überall nen GLJPanel ( Swing ), dann funktioniert das Ganze auch.

Ansonsten, na ja ich würde den Renderer, also die Implementierung von GLEventListener in ne eigene Klasse packen. Ist übersichtlicher. adden dann einfach per 
	
	
	
	





```
canvas.addGLEventListener(new GLRenderer());
```
 z.B.

Ich habe mir auch angewöhnt, wenn es kleinere Projekte sind, die ActionListener so zu implementieren :

```
jButton1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                // was passieren soll
            }
});
```

Bei größeren Sachen dann natürlich den Umständen entsprechend anders.
Und OOP lernt man mit der Zeit und Erfahrung, das hier zu beschreiben wäre ein wenig overhead...

Hoffe das hilft Dir weiter


----------



## ChillSn (31. Jul 2009)

Grüße,

also erstmal vielen Dank für den Tip -> es lag wirklich daran. Habe GLCanvas mit GLJPanel ersetzt und der Flackereffekt war weg  

Dann habe ich mir (wie von dir empfohlen) ne neue Klasse Namens GLRenderer aufgesetzt.
Nach einigem rumtüfteln hat dies auch geklappt. Wie du siehst, habe ich jetzt mit Get und Set Methoden gearbeitet. Für die meisten Set-Methoden habe ich als Sichtbarkeit private gewählt, da diese nur aus der Hauptklasse initialisiert werden sollten. Ich hoffe, das das so prinzipiell richtig ist.

Jetzt habe ich aber leider ein neues Problem: der KeyListener wird nicht mehr aktiv (habe den mit in die GLRenderer-Klasse aufgenommen, da ich später über die Tastatur die Perspektive verändern möchte), wohingegen der MouseListener funktioniert.

Ich poste einfach mal (nun sinds ja 2 Klassen) den Code.

Die Hauptklasse OGL_editor:

```
package editor;

import com.sun.opengl.util.Animator;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.opengl.*;



public class OGL_editor extends JFrame implements  ActionListener 
{
 
	public JFrame frame;
	public JMenuBar meinMenu;	
	public Animator animator;
	public GridBagLayout gbl;
	public GraphicsDevice myDevice;
	
	private static JPanel pnl_object_choice;
	private static JPanel pnl_object_properties;
	private static JTextArea txt;
	private static int angle;
	private static GLJPanel canvas;
	
	private JScrollPane scrollingArea;


	
	public OGL_editor(){
		
		//wird zum Schließen benötigt
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		setAngle(0); //nur test für OpenGl-Bewegung
		    
		//frame erzeugen
		frame=new JFrame("Mein TEST");	
		frame.setBounds(0,0,800,600);	   
		
	     
		//Menü erzeugen			
		create_menu();
		//Panels erzeugen
		setPnl_object_choice();		
		setPnl_object_properties();
		
	  	//canvas erzeugen
	  	setCanvas();
	     animator = new Animator(getCanvas()); 
	     animator.start();
	  
	  	//LAYOUT ausrichten
	  	Layout();

		
	  	//Falls FS möglich ist, dann FS		
		myDevice= GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 
		
		getTxt().append("Fullscreen-Support: "+myDevice.isFullScreenSupported());		
		
		if(myDevice.isFullScreenSupported()){ 
		
			frame.setResizable(false);			
			//Fehler tritt nicht mehr auf, da canvas 
			// nun vom Typ GLJPanel (Swing->doublebuffered)			
			myDevice.setFullScreenWindow(frame);
			myDevice.setDisplayMode(new DisplayMode(1024,768,32,0)); 	
			
		}
		
		frame.setVisible(true);
		
	}
	
	public static void main(String[] args) {		
		OGL_editor fenster = new OGL_editor();	 	    
      }
	
	
	private void Layout(){
		
		
		GridBagLayout gbl = new GridBagLayout();		
	  	frame.setLayout(gbl);		
		GridBagConstraints c = new GridBagConstraints();
		
	  	c.fill = GridBagConstraints.BOTH;
	  	c.weightx=1;//Container im Frame Maximieren
	  	c.weighty=1;//Container im Frame Maximieren	  	
	  	c.gridx = 0;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;

	  	frame.add(getPnl_object_choice(), c);

	  	c.gridx = 1;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;
	  	frame.add(getPnl_object_properties(), c);

	  	c.gridx = 2;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;

	  	frame.add(getCanvas(), c);

	  	//Textarea
	  	setTxt();	  	

	  	scrollingArea = new JScrollPane(getTxt());
	  	
	  	c.fill = GridBagConstraints.BOTH;
	  	c.gridx = 2;
	  	c.gridy = 1;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;

	  	frame.add(scrollingArea, c);
		
	} 
	




	private void create_menu(){
	
		   meinMenu=new JMenuBar();
		
	        //Menutest
	        JMenu datei =new JMenu("Datei");
	        meinMenu.add(datei);

	        JMenuItem oeffnen= new JMenuItem("Öffnen");
	        JMenuItem schliessen= new JMenuItem("Schließen");
	        schliessen.addActionListener(this);
	        
	        datei.add(oeffnen);
	        datei.add(schliessen); 
	        
	        frame.setJMenuBar(meinMenu);
		   		
	}



    public void actionPerformed(ActionEvent ae){
	   
	    JMenuItem mi =(JMenuItem)ae.getSource();
	    String menupunkt=mi.getText();
	    
	    if(menupunkt=="Schließen")
		    System.exit(0);
	    
	    getTxt().append(mi.getText());
	    
    } 


public void windowClosing (WindowEvent event)
{ 
	System.exit(0);
}

private static void setTxt()
{
	txt = new JTextArea();
	txt.setEditable(false);
}

public static JTextArea getTxt()
{
	return txt;
}

public static int getAngle()
{
	return angle;
}

public static void setAngle(int wert)
{
	angle = wert;
}

public static GLJPanel getCanvas()
{
	return canvas;
}

private static void setCanvas()
{
	canvas = new GLJPanel(); 
	canvas.addGLEventListener(new GLRenderer());
}

public static JPanel getPnl_object_properties()
{
	return pnl_object_properties;
}

private static void setPnl_object_properties()
{
	pnl_object_properties = new JPanel();
	pnl_object_properties.add(new JLabel("Objekteigenschaften"));
	pnl_object_properties.setBackground(new Color(255,0,0));
	
}

public static JPanel getPnl_object_choice()
{
	return pnl_object_choice;
}

private static void setPnl_object_choice()
{
	pnl_object_choice = new JPanel();
	pnl_object_choice.add(new JLabel("Objektauswahl"));
	pnl_object_choice.setBackground(new Color(255,255,0));

}

}
```

.. und die ausgelagerte GLRenderer:


```
package editor;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;

public class GLRenderer implements GLEventListener,MouseListener, MouseWheelListener, MouseMotionListener, KeyListener{


	    public void display(GLAutoDrawable drawable) {
	       

		    GL gl = drawable.getGL();
	        
	        // Clear the drawing area
	        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	        // Reset the current matrix to the "identity"
	        gl.glLoadIdentity();
	 
	        // Move the "drawing cursor" around
	        gl.glTranslatef(-1.5f, 0.0f, -6.0f);
	 
	        gl.glRotatef(OGL_editor.getAngle(), 1, 0,0);
		   
	        // Draw A Quad
	        gl.glBegin(GL.GL_QUADS);
	            gl.glColor3f(0.5f, 0.5f, 1.0f);    // Set the current drawing color to light blue
	            gl.glVertex3f(-1.0f, 1.0f, 0.0f);  // Top Left
	            gl.glVertex3f(1.0f, 1.0f, 0.0f);   // Top Right
	            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // Bottom Right
	            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
	        // Done Drawing The Quad
	        gl.glEnd();        
	        
	        // Flush all drawing operations to the graphics card
	        gl.glFlush(); 
	        
	        
	    }

	    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
	    }

	public void init(GLAutoDrawable drawable)
	{
		    GL gl = drawable.getGL();
		    gl.glEnable(GL.GL_NORMALIZE);
			
		    drawable.addMouseListener(this);	//Setzt für dieses Objekt Listener für MouseEvents
		    drawable.addMouseMotionListener(this);//Setzt für dieses Objekt Listener für MouseMove
		    drawable.addMouseWheelListener(this);//Setzt für dieses Objekt Listener für MouseWheel		    
		    
		    
		    //Hmm, warum registriert MouseListener Ereignisse, aber KeyListener nicht?!
		    drawable.addKeyListener(this);//Setzt für dieses Objekt Listener für Tastatur
		    
	}

	    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		    
		    GL gl = drawable.getGL();	    
		    float h = (float)height / (float)width;
		           
		    gl.glMatrixMode(GL.GL_PROJECTION);

		    gl.glLoadIdentity();
		    
		    gl.glScaled(0.5,0.5,0.5); //bestimmt die Sklalierung
		    
		    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Standard hintergrundfarbe
		    
		    //procedure glFrustum(left, right, bottom, top, zNear, zFar : glDouble);
		    gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
		    gl.glMatrixMode(GL.GL_MODELVIEW);
		    gl.glLoadIdentity();
		    gl.glTranslatef(0,0,-20);
	        
	    }


	public void mouseClicked(MouseEvent e){}
	public void mouseEntered(MouseEvent e){}
	public void mouseExited(MouseEvent e){}

	public void mousePressed(MouseEvent e)
	{
		// TODO Auto-generated method stub
		OGL_editor.getTxt().append("\nMAUSKLICK");
		OGL_editor.setAngle(OGL_editor.getAngle()+10);
	}


	public void mouseReleased(MouseEvent e){}
	public void mouseWheelMoved(MouseWheelEvent e){}
	public void mouseDragged(MouseEvent e){}
	public void mouseMoved(MouseEvent e){}

	public void keyPressed(KeyEvent e)
	{
		System.out.println("HALLO");
		// TODO Auto-generated method stub
		OGL_editor.getTxt().append("\nKeyCode: "+e.getKeyCode());
		OGL_editor.setAngle(OGL_editor.getAngle()+10);

		if(e.getKeyCode()==27){		
			System.exit(0);
		}
		
	}

	public void keyReleased(KeyEvent e){}
	public void keyTyped(KeyEvent e){}

}
```

Es wäre echt lieb, wenn du nochmal schauen könntest, warum der KeyListener nicht reagieren will. Und nochmals, vielen Dank für die Geduld!!!

Viele Grüße,
der ChillSn


----------



## mmz (31. Jul 2009)

Weiß nicht obs die einzige Lösung ist, oder die schönste, aber funktioniert immerhin 

```
drawable.addKeyListener(this);
        OGL_editor.getCanvas().requestFocus();
```
Da das Panel den Focus nicht bekommt, auch beim Mausklick nicht, musst den per Hand setzten, dann kann es auch auf KeyEvents reagieren.

Ein paar Sachen noch :
- Stringvergleiche mit equals() machen. Z.B bei der Abfrage beim Beenden lieber 
	
	
	
	





```
if(menupunkt.equals("Schließen"))
```
schreiben.
- Überleg noch mal ob Du das ganze *static* auch wirklich brauchst. Ich denke nämlich nicht. Eine Möglichkeit wäre z.B. dem Konstruktor den JFrame einfach zu übergeben und dann per getter und setter auf die benötigten Komponenten zugreifen. Dann brauchst kein static und die Methoden können auch einfach nur private sein. Static wirklich nur benutzen wenns auch sein muss. In der FAQ steht glaub ich auch nen Thema wie man das Zugreifen auf die GUI verschieden realisieren kann.
- Schöner wäre es denk ich auch wenn Du die Maus- und Keyboardbehandlung wiederum in eigene Klassen aufteilst. So hast Du die Funktionalitäten so weit es geht getrennt.
- Du erbst von JFrame, d.h die Klasse ist quasi ein JFrame. Deswegen müsstest Du eigentlich keinen eigenen JFrame frame erzeugen sondern kannst direkt (oder mit this) die Methoden von JFrame nutzen.​
Ansonsten ist das mit den gettern und settern und dem private deklarieren von globalen Variablen schon richtig so.


----------



## ChillSn (2. Aug 2009)

Moino,

vielen lieben Dank für die vielen nützlichen Tips!!! Ich glaube so langsam sehe ich Licht am Anfang der OOP 
Ich habe allerdings noch so das unbehagliche Gefühl, dass die Übergabe bei den Konstruktoren evtl. auch einfacher gehen könnte.

Also Ich:
1) habe jetzt alle static-Sachen entfernt
2) habe alle Methoden(außer Konstruktoren  ) und Variablen auf Private gesetzt
3) habe aus Klasse GLRenderer die Listener extrahiert und in ne eigene Klasse gestopft

Du hast Recht, das erhöht die Übersichtlichkeit wirklich enorm - vor allem, dass man die Funktionalität besser trennen kann gefällt mir sehr gut!!!

Ich poste der Vollständigkeit halber mal noch den kompletten Code der nunmehr drei Klassen:

Hauptprogramm:


```
package editor;

import com.sun.opengl.util.Animator;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.opengl.*;

public class OGL_editor extends JFrame implements  ActionListener 
{

	private GraphicsDevice myDevice;
	private JMenuBar meinMenu;	
	private JPanel pnl_object_choice;
	private JPanel pnl_object_properties;
	private JTextArea txt;
	private GLJPanel canvas;
	private Animator animator;
	private JScrollPane scrollingArea;
	
	private int angle;
	

	public static void main(String[] args) {		

		new OGL_editor();		
		
      }
	
	public OGL_editor(){
		
		//wird zum Schließen benötigt
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setTitle("TEST123");		

		//LAYOUT erstellen
		Layout(this);
	  	
	  	//Falls FS möglich ist, dann FS		
		myDevice= GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 
		
		getTxt().append("Fullscreen-Support: "+myDevice.isFullScreenSupported());		
		
		if(myDevice.isFullScreenSupported()){ 
		
			setResizable(false);			
			//Fehler tritt nicht mehr auf, da canvas 
			// nun vom Typ GLJPanel (Swing->doublebuffered)			
			myDevice.setFullScreenWindow(this);
			myDevice.setDisplayMode(new DisplayMode(1024,768,32,0)); 	
			
		}
		else
		{
			//Größe festlegen			
			setBounds(0,0,800,600);	 			
		}
		
		//Frame anzeigen
		setVisible(true);
		
		setAngle(0); //nur test für OpenGl-Bewegung
		
	}
	

	
	
	private void Layout(JFrame frame){
		

		
		//Menü erzeugen			
		create_menu(this);
		
		GridBagLayout gbl = new GridBagLayout();		
		frame.setLayout(gbl);		
		GridBagConstraints c = new GridBagConstraints();
		
		setPnl_object_choice();		
		setPnl_object_properties();
				
		//Linkes Panel		
	  	c.fill = GridBagConstraints.BOTH;
	  	c.weightx=1;//Container im Frame Maximieren
	  	c.weighty=1;//Container im Frame Maximieren	  	
	  	c.gridx = 0;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;
	  	frame.add(getPnl_object_choice(), c);

	  	//Mittleres Panel	
	  	c.gridx = 1;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 2;
	  	frame.add(getPnl_object_properties(), c);

	  	//OpenGL GLJPanel	
		setCanvas();
	  	c.gridx = 2;
	  	c.gridy = 0;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;
	  	frame.add(getCanvas(), c);

	  	//Textarea mit ScrollPane
	  	setTxt();	
	  	scrollingArea = new JScrollPane(getTxt());
	  	
	  	c.fill = GridBagConstraints.BOTH;
	  	c.gridx = 2;
	  	c.gridy = 1;
	  	c.gridwidth = 1;
	  	c.gridheight = 1;
	  	frame.add(scrollingArea, c);
		
	} 
	




	private void create_menu(JFrame frame){
	
		   meinMenu=new JMenuBar();
		
	        //Menutest
	        JMenu datei =new JMenu("Datei");
	        meinMenu.add(datei);

	        JMenuItem oeffnen= new JMenuItem("Öffnen");
	        JMenuItem schliessen= new JMenuItem("Schließen");
	        schliessen.addActionListener(this);
	        
	        datei.add(oeffnen);
	        datei.add(schliessen); 
	        
	        this.setJMenuBar(meinMenu);
		   		
	}



    public void actionPerformed(ActionEvent ae){
	   
	    JMenuItem mi =(JMenuItem)ae.getSource();
	    String menupunkt=mi.getText();
	    
	    if(menupunkt.equals("Schließen"))
		    System.exit(0);
	    
	    getTxt().append(mi.getText());
	    
    } 


public void windowClosing (WindowEvent event)
{ 
	System.exit(0);
}

private void setTxt()
{
	this.txt = new JTextArea();
	this.txt.setEditable(false);
}

public JTextArea getTxt()
{
	return txt;
}

public int getAngle()
{
	return angle;
}

public void setAngle(int wert)
{
	this.angle = wert;
}

public GLJPanel getCanvas()
{
	return canvas;
}

private void setCanvas()
{
	this.canvas = new GLJPanel(); 
	this.canvas.addGLEventListener(new GLRenderer(this));
	this.animator = new Animator(getCanvas()); 
	this.animator.start();

}

private JPanel getPnl_object_properties()
{
	return pnl_object_properties;
}

private void setPnl_object_properties()
{
	this.pnl_object_properties = new JPanel();
	this.pnl_object_properties.add(new JLabel("Objekteigenschaften"));
	this.pnl_object_properties.setBackground(new Color(255,0,0));

}

private JPanel getPnl_object_choice()
{
	return pnl_object_choice;
}

private void setPnl_object_choice()
{
	this.pnl_object_choice=new JPanel();
	this.pnl_object_choice.add(new JLabel("Objektauswahl"));
	this.pnl_object_choice.setBackground(new Color(255,255,0));
	

}

}
```

Die GLRenderer-Klasse:


```
package editor;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;


public class GLRenderer implements GLEventListener{

	private OGL_editor fenster;
	private Ereignisse ereignisse;
	
	    public GLRenderer(OGL_editor ogl_editor) {
		// TODO Auto-generated constructor stub
		    fenster=ogl_editor;
		    ereignisse=new Ereignisse(fenster);
	}

	public void display(GLAutoDrawable drawable) {
	      
		   // System.exit(0);	
		   GL gl = drawable.getGL();
		   
	        // Clear the drawing area
	        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	        // Reset the current matrix to the "identity"
	        gl.glLoadIdentity();
	 
	        // Move the "drawing cursor" around
	        gl.glTranslatef(-1.5f, 0.0f, -6.0f);	        
	        
	        gl.glRotatef(fenster.getAngle(), 1, 0,0);
		   
	        // Draw A Quad
	        gl.glBegin(GL.GL_QUADS);
	            gl.glColor3f(0.5f, 0.5f, 1.0f);    // Set the current drawing color to light blue
	            gl.glVertex3f(-1.0f, 1.0f, 0.0f);  // Top Left
	            gl.glVertex3f(1.0f, 1.0f, 0.0f);   // Top Right
	            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // Bottom Right
	            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
	        // Done Drawing The Quad
	        gl.glEnd();        
	        
	        // Flush all drawing operations to the graphics card
	        gl.glFlush(); 
	        
	        
	    }

	@Override
	    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
	    }

	@Override
	public void init(GLAutoDrawable drawable)
	{

		    GL gl = drawable.getGL();
		    gl.glEnable(GL.GL_NORMALIZE);

		    drawable.addMouseListener(ereignisse);	//Setzt für dieses Objekt Listener für MouseEvents
		    drawable.addMouseMotionListener(ereignisse);//Setzt für dieses Objekt Listener für MouseMove
		    drawable.addMouseWheelListener(ereignisse);//Setzt für dieses Objekt Listener für MouseWheel		    
		    
		    //Hmm, warum registriert MouseListener Ereignisse, aber KeyListener nicht?!
		    //weil der Focus gefehlt hat...
		    drawable.addKeyListener(ereignisse);//Setzt für dieses Objekt Listener für Tastatur
		    fenster.getCanvas().requestFocus();
		    
	}

	@Override
	    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		    
		    GL gl = drawable.getGL();	    
		    float h = (float)height / (float)width;
		           
		    gl.glMatrixMode(GL.GL_PROJECTION);

		    gl.glLoadIdentity();
		    
		    gl.glScaled(0.5,0.5,0.5); //bestimmt die Sklalierung
		    
		    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Standard hintergrundfarbe
		    
		    //procedure glFrustum(left, right, bottom, top, zNear, zFar : glDouble);
		    gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
		    gl.glMatrixMode(GL.GL_MODELVIEW);
		    gl.glLoadIdentity();
		    gl.glTranslatef(0,0,-20);
	        
	    }

}
```

und die Ereigniss-Klasse:


```
package editor;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

public class Ereignisse implements MouseListener, MouseWheelListener, MouseMotionListener, KeyListener{
	
	private OGL_editor fenster;
	
	public Ereignisse(OGL_editor bla){
		
		fenster=bla;
		
	}
	
	public void mouseClicked(MouseEvent e){}
	public void mouseEntered(MouseEvent e){}	
	public void mouseExited(MouseEvent e){}
	
	public void mousePressed(MouseEvent e)
	{
		// TODO Auto-generated method stub
		fenster.getTxt().append("\nMAUSKLICK");
		fenster.setAngle(fenster.getAngle()+10);
		
	}
	
	public void mouseReleased(MouseEvent e){}	
	public void mouseWheelMoved(MouseWheelEvent e){}	
	public void mouseDragged(MouseEvent e){}	
	public void mouseMoved(MouseEvent e){}
	
	public void keyPressed(KeyEvent e)
	{
		fenster.getTxt().append("\nKeyCode: "+e.getKeyCode());
		fenster.setAngle(fenster.getAngle()+10);

		if(e.getKeyCode()==27){		
			System.exit(0);
		}
		
	}
	
	public void keyReleased(KeyEvent e){}	
	public void keyTyped(KeyEvent e){}

}
```

Im Moment habe ich erst mal nur eine nicht kritische Frage:

Der Frame ist ja im FS-Modus auf resizable(false) gesetzt. Wenn ich ihn jetzt aber minimiere und wieder Maximiere, verschiebt sich der ganze Inhalt um ein Paar dutzend Pixel nach unten. Was kann ich dagegen tun!? (Du arbeitest ja unter Linux, so dass du das womöglich gar nicht reproduzieren kannst  )

Du kannst dir aber gar nicht vorstellen, wie happy ich gerade bin :toll: Ohne deine Hilfe wäre das nix geworden!

Ganz liebe Grüße,

der ChillSn


----------



## mmz (4. Aug 2009)

Hi,

freut mich wenn ich helfen konnte...

Also, ich nutze hier KDE 4, da ist das alles ein wenig anders als bei Windows. Wenn ich dein Programm ausführe bekomme ich auch keinen wirklichen FS mehr, sondern das Programm wird mit meiner Auflösung gestartet (1600x1200). Ausserdem bekomme ich eine Exception :

```
Exception in thread "main" java.lang.IllegalArgumentException: Invalid display mode
        at sun.awt.X11GraphicsDevice.setDisplayMode(X11GraphicsDevice.java:362)
        at org.yourorghere.OGL_editor.<init>(OGL_editor.java:51)
        at org.yourorghere.OGL_editor.main(OGL_editor.java:27)
```
Das Problem kann ich also wirklich nicht nach vollziehen, da ich gar nicht in den FS komme... Ohnen FS passiert die Verschiebung bei mir nicht.

Wenn ich die Zeit finde, dann kann ich das ganze noch mal inner VM mit Windows testen.Obs da auch passiert weiß ich nid. Vllt was beim reshape. Das wäre meine erste Vermutung. Lass Dir mal die Werte für Höhe, Breite und die Location ausgeben und vergleiche die mal mit deiner Auflösung.

Edith: Ok, wenn unter Linux setResizable(false); aufgerufen wird, dann wird hinter den ich sag mal "Desktop" gezeichnet ( Dashboard bleibt im Vordergrund ), deswegen auch kein FS. Mal sehen ob ichs etz reproduzieren kann.


----------

