# Wie Breite und Höhe eines Panels festlegen?



## ernst (27. Mai 2010)

Hallo allerseits,
Mit dem Visual-Editor von Netscape habe ich eine einfache grafische Oberfläche erzeugt.
Ich dachte, dass man mit
this.setSize(400, 400);
ein quadratisches Fenster bekommt.
Dies ist leider nicht so. Okay, das akkzeptiere ich so.

Wie man in dem Demoprogramm unten sieht, habe ich die 2. Winkelhalbierende gezeichnet, um zu zeigen,
daß der Panel (grünes Quadrat) auch nicht quadratisch ist.
Meine Frage:
Mit welchem Befehl kann ich den Panel quadratisch machen, so dass die 2. Winkelhalbierende eine Diagonale meines Panel ist?

mfg
Ernst

[Java]
// 
package pack1;

public class ZeichnungJFrame extends javax.swing.JFrame {
  private ZeichnungJPanel spielJPanel;
    /** Creates new form ZeichnungJFrame */
    public ZeichnungJFrame() {
        initComponents();
        this.setSize(400, 400);
        spielJPanel = new ZeichnungJPanel();
        jPanel1.add(spielJPanel, "Center");

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jPanel1.setBackground(new java.awt.Color(255, 255, 204));
        jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        jPanel1.setLayout(new java.awt.BorderLayout());

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ZeichnungJFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JPanel jPanel1;
    // End of variables declaration

}

[/Java]


[Java]
package pack1;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
//import java.awt.image.BufferedImage;


public class ZeichnungJPanel extends javax.swing.JPanel implements MouseListener, MouseMotionListener {
    // --- Beginn Einfügen Barner ---
    ZeichnungJFrame zeichnungJFrame;
    private Image bild;
    private Tangente tangente;
    // Parameter t der Geraden
    private double parameterDeltaX;
    private double parameterxFestpunkt;
    private Graphics graphicsNormalparabel;
    private Image bildNormalparabel;
    private int anzahlMausImPunkt;
//  private BufferedImage bild;
//    private BufferedImage bufferedBild;



    public ZeichnungJPanel(ZeichnungJFrame pZeichnungJFrame) {
        initComponents();
        zeichnungJFrame = pZeichnungJFrame;
        // Welt-Koordinatensystem festlegen
        //Transformation.setWeltMinMax(-5, -0.5, 5, 25);
        Transformation.setWeltMinMax(-5, -0.1, 5, 16);
        tangente = new Tangente(this);
        addMouseMotionListener(this);
        addMouseListener(this);
        parameterDeltaX=3;
        parameterxFestpunkt=1;
        anzahlMausImPunkt=0;
    }

	/**
	 * Gibt Tangente zurück.<br>
	 * @return (o) Tangente
	 */
    public Tangente getTangente(){
        return tangente;
    }

	/**
	 * legt Festpunkt auf Parabel fest, der mit dem Schieberegler
     * festgelegt wurde.<br>
	 * @param pParameterxFestpunkt (i) Festpunkt
	 */
    public void setParameterXFestpunkt(double pParameterxFestpunkt){
        parameterxFestpunkt = pParameterxFestpunkt;
    }

	/**
	 * Gibt Festpunkt auf Parabel zurück, der mit dem Schieberegler
     * festgelegt wurde.<br>
	 * @return (o) Festpunkt
	 */
    public double getParameterXFestpunkt(){
        return parameterxFestpunkt;
    }

	/**
	 * Legt Laufpunkt auf Parabel fest.<br>
	 * @param pDeltaX (i) deltaX des Steigungsdreiecks
	 */
    public void setParameterDeltaX(double pDeltaX){
        parameterDeltaX = pDeltaX;
    }

	/**
	 * Gibt das deltaX des Steigungsdreiecks zurück,
     * das mit dem Schieberegler festgelegt wurde.<br>
	 * @return (o) deltaX des Steigungsdreiecks
	 */
    public double getParameterDeltaX(){
        return parameterDeltaX;
    }

	/**
	 * Updaten der Daten der Tangente, also des Festpunkts und des
     * Laufpunkts.<br>
	 */
    public void allesUpdaten() {
        //System.out.println("this.getWidth()="+this.getWidth()+"this.getHeight="+this.getHeight());
        tangente.berechnePos();
    }

	/**
	 * Malt in die Zeichenfläche die Parabel,Tangente, Sekante, usw.
     * und in das Fenster die neuen Stellungen der Schieberegler,
     * neue Inhalte der Textfelder, usw. <br>
	 */
    public void maleKomplettesFenster(){
        maleZeichnungJPanelOffscreen();
        zeichnungJFrame.maleRestZeichnungJFrame();
        repaint();
    }

	/**
	 * Malt offscreen in die Zeichenfläche die Parabel,Tangente,
     * Sekante, usw. <br>
	 */
    public void maleZeichnungJPanelOffscreen(){
        int sx, sy;
        Graphics graphics=null;

        sx = this.getSize().width;
        sy = this.getSize().height;

        //System.out.println("__ sx="+sx+" sy="+sy);

        /*
        Ein Bild zu erstellen ist aufwändig: es muss Speicher allokiert
        und gecleart werden. Deshalb sollte das nur einmal gemacht werden.
        */
        /* Da sx und sy erst nach der Anweisung
        zeichnungJFrame.setVisible(true);
        einen Wert != 0 haben, aber die folgenden Anweisungen schon vorher
        durchgeführt werden, muss sx und sy abgefragt werden
        */
        if(bild==null || bild.getWidth(this)!=sx || bild.getHeight(this)!=sy){
            if(sx!=0 && sy!=0){
                bild = createImage(sx, sy);
                Transformation.setScreenBreite(sx);
                Transformation.setScreenHoehe(sy);
            }
        }

        if(sx!=0 && sy!=0){
            graphics = bild.getGraphics();
            // mit den 2 Anweisungen wird der Hintergrund ausgegeben
            // unbedingt nötig
            graphics.setColor(getBackground());
            graphics.fillRect(0,0,sx,sy);

            tangente.zeichneNormalparabel(graphics, Color.black);
            tangente.zeichneSekante(graphics, Color.green);
            //tangente.zeichneTangente(graphics, Color.cyan);
            tangente.zeichneTangente(graphics, Color.orange);
            tangente.zeichneAchsenkreuz(graphics, Color.black);
            /*
            Wenn dies jetzt erst gemacht wird, wird Sekante, usw
            nicht mehr angezeigt. Warum ?
            */
            // tangente.zeichneNormalparabel(graphics, Color.black);
        }

    }


	/**
	 * Malt auf die Leinwand, die auf die Anzeige auf dem
     * Bildschirm gelegt wird. <br>
     * neue Inhalte der Textfelder, usw. <br>
	 */
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
    	g.drawImage(bild,0,0,null);
    }    // --- Ende Einfügen Barner ---

	public void mouseClicked(MouseEvent arg0) {
    }

	public void mousePressed(MouseEvent arg0) {
	}

	public void mouseEntered(MouseEvent arg0) {
	}

	public void mouseExited(MouseEvent arg0) {
	}

	public void mouseMoved(MouseEvent arg0) {
	}

	/**
	 * Wenn sich der Mauszeiger innerhalb des Laufpunkts befindet und
     * die gedrückte Maus gezogen wird, wird auch der Laufpunkt
     * verschoben <br>
	 * @param ev (i) Mouseevent
	 */
    public void mouseDragged(MouseEvent ev) {
        boolean b=true;
        Point2DDouble p2D;
		Point javaklick = new Point();
        javaklick = ev.getPoint();
        // Der Mauszeiger befindet sich innerhalb des Laufpunkts
        if(anzahlMausImPunkt==0){
            b = tangente.istInnerhalb(javaklick, tangente.getLaufPunkt());
            if(b==true)
                anzahlMausImPunkt=1;
        }

        if(anzahlMausImPunkt==1){
            System.out.println("javaklick.x="+javaklick.x+"javaklick.y"+javaklick.y);
            // Zeichne den Punkt an die Mauskoordinaten
            p2D = Transformation.transformScreenTo2DWelt(javaklick.x, javaklick.y);
            setParameterDeltaX(p2D.x-tangente.getFestPunkt().x);
            allesUpdaten();
            //System.out.println("der 4. Aufruf");
            maleKomplettesFenster();
        }
	}

	/**
	 * Wenn die gedrückte Maustaste wieder losgelassen wird,
     * wird diese Methode ausgeführt.<br>
	 * @param ev (i) Mouseevent
	 */
	public void mouseReleased(MouseEvent ev) {
        boolean b;
		Point javaklick = new Point();
        Point2DDouble p2D;

        javaklick = ev.getPoint();
        //System.out.println("javaklick.x="+javaklick.x+"javaklick.y"+javaklick.y);
        if(anzahlMausImPunkt==1){
            anzahlMausImPunkt=0;
        }
        //System.out.println("mouseReleased wurde aufgerufen");
	}


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        setBackground(new java.awt.Color(255, 255, 255));
        setLayout(new java.awt.BorderLayout());
    }// </editor-fold>                        


    // Variables declaration - do not modify                     
    // End of variables declaration                   

}

[/Java]


----------



## Marco13 (27. Mai 2010)

Ist schon arg viel code, aber nicht compilierbar (wie Tangente und Transformation fehlen ... ich hab' die zwar noch von damals hier rumliegen, aber die werden sich wohl geändert haben )

Ganz allgemein gibt man die größe einer Component als die "preferredSize" an, und überläßt den Rest den LayoutManagern. Und wenn man denen nicht dazwischenfunkt, und es keine "unmöglichen" Anforderungen gibt (wie etwa ein 100 pixel hohes Panel und ein 200 Pixel hohe Panel nebeneinander in einem JFrame anzuzeigen, und beide gleich hoch zu machen) dann schaffen die das auch.

Im speziellen, der Versuch das auf das einfachste Beispiel zu reduzieren:

```
import javax.swing.*;
import java.awt.*;


class FrameTest
{
    public static void main(String args[])
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());


        JPanel p = new JPanel()
        {
            public void paintComponent(Graphics g)
            {
                super.paintComponent(g);
                g.drawLine(0,0,500,500);
            }
        };
        p.setPreferredSize(new Dimension(400,400));
        f.getContentPane().add(p, BorderLayout.CENTER);

        f.getContentPane().add(new JButton("Bla"), BorderLayout.EAST);
        f.getContentPane().add(new JButton("Ble"), BorderLayout.SOUTH);
        f.getContentPane().add(new JButton("Bli"), BorderLayout.NORTH);
        f.getContentPane().add(new JButton("Blo"), BorderLayout.WEST);

        f.pack();
        f.setVisible(true);
    }
}
```

Wenn man 
panel.setPreferredSize(new Dimension(400,400));
macht, und dann auf dem Frame "pack()" aufruft, versucht er, alles so anzuordnen, dass die "preferred sizes" erfüllt sind. Und in diesem Fall gelingt ihm das (trotz der "störenden" Buttons) : Das Panel ist genau 400x400 groß.


----------



## ernst (28. Mai 2010)

Marco13 hat gesagt.:


> Ist schon arg viel code, aber nicht compilierbar (wie Tangente und Transformation fehlen ... ich hab' die zwar noch von damals hier rumliegen, aber die werden sich wohl geändert haben )


Das verstehe ich nicht ganz. Warum ist der Code nicht compilerbar?
Bei mir läuft er. Warum fehlen Tangente und Transformation ? Die habe ich doch gar nicht gepostet.
Oder habe ich was falsches gemacht?



Marco13 hat gesagt.:


> Im speziellen, der Versuch das auf das einfachste Beispiel zu reduzieren:
> 
> ```
> import javax.swing.*;
> ...


----------



## Marco13 (28. Mai 2010)

ernst hat gesagt.:


> Das verstehe ich nicht ganz. Warum ist der Code nicht compilerbar?



Weil in der Klasse ZeichnungJPanel die Klasse Transformation verwendet wird, und wer die nicht hat, kann die Klasse nicht Compilieren.



> Warum fehlen Tangente und Transformation ? Die habe ich doch gar nicht gepostet.



Sie fehlen... weil du sie nicht gepostet hast 

Ist ja nicht schlimm, nur kann man es dann halt nicht selbst testen. 

Dieser von einem GUI-Builder erzeugte Code ist eben eigentlich nicht dafür gedacht, von einem Menschen noch bearbeitet zu werden ... der ist eben schwer nachzuvollziehen, und nicht mehr so "anschaulich"  (und zugegeben, ich habe das GroupLayout noch nicht verwendet - wenn man Code per Hand schreibt verwendet man eher andere Layouts). 

Aber das hier

```
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                .addContainerGap())
        );
```
Sieht für mich aus, als ob da einfach nur das jPanel1 in die ContentPane gelegt wird (mit einer bestimmten Größe und bestimmten Randabständen).

Das
_spielJPanel ----> jPanel1 ----> zeichnungJFrame _
stimmt also wohl (wobei das ---> für "ist enthalten in" steht)




> Mit der Methode (in ZeichnungJPanel):
> ...
> wird damit also nur das Kindeskind, also der Panel spielJPanel gezeichnet.
> Ist das richtig?


Jein: Gezeichnet wird natürlich alles. Aber dadurch dass man diese Methode überschrieben hat, kann man genau sagen, WAS dort gezeichnet wird (normalerweise zeichnet ein Panel "nichts", nur seine enthaltenen Components und seinen Rand...)


Über Spezifika beim Zusammenspiel vom Netbeans Editor und Animationen kann ich leider nichts sagen, den Editor habe ich noch nicht verwendet... Vermutlich wäre es nicht viel Aufwand, das GUI per Hand zu schreiben, aber ich weiß ja nicht, was da noch alles dazukommen soll...


----------



## ernst (28. Mai 2010)

Marco13 hat gesagt.:


> Weil in der Klasse ZeichnungJPanel die Klasse Transformation verwendet wird, und wer die nicht hat, kann die Klasse nicht Compilieren.
> 
> Sie fehlen... weil du sie nicht gepostet hast
> 
> Ist ja nicht schlimm, nur kann man es dann halt nicht selbst testen.


Du hast recht.
Du brauchst die Zeilen nur zu löschen. Dann müsste es funktionieren.




			
				Marco13;
Das
[i hat gesagt.:
			
		

> spielJPanel ----> jPanel1 ----> zeichnungJFrame [/i]
> stimmt also wohl (wobei das ---> für "ist enthalten in" steht)
> 
> Jein: Gezeichnet wird natürlich alles. Aber dadurch dass man diese Methode überschrieben hat, kann man genau sagen, WAS dort gezeichnet wird (normalerweise zeichnet ein Panel "nichts", nur seine enthaltenen Components und seinen Rand...)


okay, aber jPanel1 wird nicht gezeichnet, oder wo steht der entsprechende Befehl dazu?

mfg
Ernst


----------



## Marco13 (28. Mai 2010)

OK, hab' mal alles rausgelöscht, was nicht compilieren wollte... wenn man die beiden Zeilen

.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)

ändert in

.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)


und die main dann so schreibt:

```
public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                ZeichnungJFrame z = new ZeichnungJFrame();
                z.pack();
                z.setVisible(true);
            }
        });
    }
[/Java]
ist das Panel am anfang genau 400x400 pixel groß. Das bringt natürlich nichts, wenn das alles vom Netbeans-Editor neu erzeugt wird, aber ... diese Größenangaben die da vorher standen (380 x 278) kann man ja auch irgendwo in diesem Editor einstellen...


Zum Zeichnen: Wie gesagt, das Zeichnen passiert automatisch. Jede JComponent (also jeder JButton, jeder JSlider, jedes JPanel) hat die Methode "paintComponent". In dieser Methode wird die Component gezeichnet. Beim Button der Rand und die Schrift, beim Slider dier Schiebebalken, und beim JPanel "nichts", außer den weiteren Components, die in dem JPanel enthalten sein können (und ggf. dem Rahmen des JPanels)

Etwas vereinfacht: Java erkennt, wenn ein bestimmter Bereich des JFrames (oder der ganze Frame) neu gezeichnet werden muss. Dann wird die "paint"-Methode des JFrames aufgerufen. Die paint-Methode des JFrames ruft die paintComponent-Methode aller Components auf, die in dem JFrame enthalten sind. Also auch die paintComponent-Methode von deinem 'jPanel1'. Diese paintComponent-Methode macht nichts, außer die paintComponent-Methode vom ZeichnungsPanel aufzurufen. Und DIE hast du dann überschrieben, und darin sagst du:
[code=Java]
    public void paintComponent(Graphics g) 
    {
        // Zeichne alles, was du "normalerweise" zeichnen würdest,
        // wenn ich diese Methode nicht überschrieben hätte...
        super.paintComponent(g); 

        // ... und danach male zusätzlich noch dieses Bild hier
        g.drawImage(bild,0,0,null);
    }
```

Dieses ganze Neuzeichnen passiert weitgehend automatisch. Man kann zwar "repaint" aufrufen, und damit sagen, dass "so bald wie möglich" neu gezeichnet werden soll, aber den _eigentlichen_ Aufruf der paintComponent-Methoden macht dann Java automatisch. Und indem man z.B. bei einem JPanel die paintComponent-Methode überschreibt, kann man ihm sagen, WAS es denn dort zeichnen soll.


EDIT: Schau dir vielleicht auch mal Painting in AWT and Swing an.


----------

