Java JPanel trotz eindeutiger Positionierung per GridBagLayout zweimal gezeichnet?!

while(break)

Newbie
Registriert
Aug. 2013
Beiträge
4
Hallo Forumgemeinde,

Ich hab ein Problem mit nem GridBagLayout und hoffe, dass jemand hier einen Tipp für mich hat.
Das Bild anbei zeigt das Problem. Eigentlich sollte nur ein so ein roter Turm gezeigt werden, das ActionPanel wird aber ein zweites Mal, etwas versetzt gezeichnet.. Und auch das JTextField bei 0, 0 ist Unsinn.

Fände es toll, wenn jemand eine Ahnung hat, wo das Problem liegen könnte.

Hier der Code:

Frame:

Code:
public class MainFrame extends JFrame implements KeyListener
{
	TetrisController controller;
	
	ActionPanel aPanel;
	InfoPanel iPanel;
	
	public MainFrame(TetrisController controller)
	{		
		this.controller = controller;
		initMainFrame();
	}
	
	public void initMainFrame()
	{

		this.setTitle("Tetris");
		
        try
        {
           UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
      	   SwingUtilities.updateComponentTreeUI(this);
        }catch(Exception e)
        {
           System.err.println("Could not load LookAndFeel");
        }
        
        this.setMinimumSize(new Dimension(650, 800));
        this.setResizable(false);

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 
        this.setLocation((int) dim.getWidth()/2-this.getWidth()/2, (int) (dim.getHeight()/2-this.getHeight()/2));
        

        GridBagLayout glayout = new GridBagLayout();
        this.setLayout(glayout);
        
        GridBagConstraints gbc = new GridBagConstraints();
        
        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = 0;
        gbc.gridy = 0;
//        gbc.ipadx = 400;
//        gbc.ipady = 800;
        
        aPanel = new ActionPanel(controller);
        this.add(aPanel, gbc);
      
        gbc.anchor = GridBagConstraints.NORTH;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.weightx = 0;
        gbc.weighty = 0;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = 1;
        gbc.gridy = 0;

        iPanel = new InfoPanel();
        iPanel.setBackground(Color.DARK_GRAY);       
        this.add(iPanel, gbc);       
        
        gbc.ipadx = 200;//-iPanel.getWidth();
       
        this.addKeyListener(this);
        
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        this.pack();
        this.revalidate();
        this.repaint();
        this.setVisible(true);
	}
	
	public Dimension getPreferredSize()
	{
		return new Dimension(650, 800);
	}

	public ActionPanel getaPanel() 
	{
		return aPanel;
	}

	public InfoPanel getiPanel() 
	{
		return iPanel;
	}

	@Override
	public void keyPressed(KeyEvent arg0) 
	{
		aPanel.keyPressed(arg0);
	}

	@Override
	public void keyReleased(KeyEvent arg0)
	{}

	@Override
	public void keyTyped(KeyEvent arg0)
	{}	
}

Panel:

Code:
public class ActionPanel extends JPanel implements KeyListener
{
	Dimension dim = new Dimension(400, 800);
	
	TetrisController controller;
	
	int aktuellePositionX;
	int aktuellePositionY;
	
	int borderXleft = 0;
	int borderXright = dim.width;
	int borderYbottom;
	
	boolean commandDirectionRight = false;
	boolean commandDirectionLeft = false;
	
	ElementeGitter egitter;
	
	public ActionPanel(TetrisController controller)
	{
		this.controller = controller;
		this.setBackground(Color.red);
		this.addKeyListener(this);	

		this.setPreferredSize(dim);
		
        egitter = new ElementeGitter(dim.width/40, dim.height/40);
	}
	
	public void paint (Graphics g)
	{
		for (int yy = 0; yy < (dim.height / 40); yy++)
		{
			for (int xx = 0; xx <  (dim.width / 40); xx++)
			{
				if (egitter.getElemente()[xx][yy] != null)
				{
					g.setColor(egitter.getElemente()[xx][yy].c);
					g.fill3DRect(xx*40, yy*40, egitter.getElemente()[xx][yy].getSize().width, egitter.getElemente()[xx][yy].getSize().height, true);
				}
			}
		}
		
		/**
		 * löscht Verlauf von oben nach unten ohne Richtungswechsel
		 * */
		if (aktuellePositionY/40 >= 0)
		{
			if (egitter.getElemente()[aktuellePositionX/40][aktuellePositionY/40] == null)
			{
				g.clearRect(aktuellePositionX, aktuellePositionY-40, 40, 40);
			}
		}
		/**
		 * löscht Verlauf von links nach rechts
		 * */
		if (commandDirectionRight)
		{
			if (egitter.getElemente()[aktuellePositionX/40-1][aktuellePositionY/40] == null)
			{
				g.clearRect(aktuellePositionX-40, aktuellePositionY-1, 40, 41);
				commandDirectionRight = false;
			}
		}
		/**
		 * löscht Verlauf von rechts nach links
		 * */
		else if (commandDirectionLeft)
		{
			if (egitter.getElemente()[aktuellePositionX/40+1][aktuellePositionY/40] == null)
			{
				g.clearRect(aktuellePositionX+40, aktuellePositionY-1, 40, 41);
				commandDirectionLeft = false;
			}
		}

		System.out.println("ACTIONPANEL - aktuelle Postion: " + aktuellePositionX + " " + aktuellePositionY);
		g.fill3DRect(aktuellePositionX, aktuellePositionY, 40, 40, true);

//		int xPoly[] = {0, 250, 325, 375, 450, 275, 400};
//        int yPoly[] = {0, 100, 125, 225, 250, 375, 800};
//        Polygon poly = new Polygon(xPoly, yPoly, xPoly.length);
//        g.drawPolygon(poly);
	}

	public Dimension getPreferredSize()
	{
		return dim;
	}
	
	public void setX(int x) 
	{
		this.aktuellePositionX = x;
	}

	public int getX() 
	{
		return aktuellePositionX;
	}

	public int getY() 
	{
		return aktuellePositionY;
	}

	public void setY(int y) 
	{
		this.aktuellePositionY = y;
	}

	@Override
	public void keyPressed(KeyEvent arg0) 
	{
		if (arg0.getKeyCode() == 37 && aktuellePositionX > 0 && aktuellePositionX < dim.width)
		{
			System.out.println("left pressed");
			commandDirectionLeft = true;
			commandDirectionRight = false;
			if (this.egitter.getElemente()[aktuellePositionX/40-1][aktuellePositionY/40+1] == null)
			{
				this.setX(aktuellePositionX-40);
			}
		}
		else if (arg0.getKeyCode() == 39)
		{
			int elementBreite = 40;
			System.out.println("right pressed");
			commandDirectionRight = true;
			commandDirectionLeft = false;
			if (aktuellePositionX < dim.width-40)
			{
				if (this.egitter.getElemente()[aktuellePositionX/40+1][aktuellePositionY/40+1] == null)
				{
					this.setX(aktuellePositionX+40);
				}
			}
		}
		else if (arg0.getKeyCode() == 40)
		{
			System.out.println("down pressed");
			controller.getEngine().incCtr(40);
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) 
	{
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) 
	{
		// TODO Auto-generated method stub
		
	}

	public ElementeGitter getEgitter() 
	{
		return egitter;
	}

	public void addToGitter(Element e, int x, int y) 
	{
		egitter.addToGitter(e, x, y);
	}
}

Beste Grüße
while(break)
 

Anhänge

  • tetris_frame.png
    tetris_frame.png
    51,7 KB · Aufrufe: 483
MigLayout ist kein Teil des JDK da macht sich alles nur komplizierter, für einfachere Fälle kannst du es immer wieder mit Null-Layout versuchen, einfach null als layout übergeben und mit setBounds(x1, y1, x2, y2) bestimmen wo es hingezeichnet werden soll. GridBagLayout ist schon recht komplex, daher dauert die Fehlersuche dort immer recht lang.
 
pmkrefeld schrieb:
... st kein Teil des JDK da macht sich alles nur komplizierter
Das Totschlag-Argument gegen alle Bibliotheken... also wer es nicht schafft, eine JAR in Form einer Bibliothek seinem Projekt hinzuzufügen, dürfte auch kaum die Komplexität von GridBagLayout beherrschen ...
 
1668mib schrieb:
Man kann auch bewusst schlechten Stil empfehlen ...

Oder unbewusst. Das sind die schlimmsten :D

@while(break): Wenn Du ein lauffähiges Beispiel postest, schaue ich es mir an.
 
1668mib schrieb:
Man kann auch bewusst schlechten Stil empfehlen ...

Man ja kann aus einer Mücke einen Elefanten machen, was nutzt es einem wenn man für ein kleines Projekt die hälfte der Zeit fürs Layout verplempert, hat nicht viel mit Programmierstil zu tun, MigLayout/GridBagLayout ist einfach Overkill. Und wenn die Daten vernünftig von der Darstellung getrennt sind, kann man im nachhinein immer noch die Darstellende Komponente erstetzen wenn noch Zeit/Lust vorhanden ist.
 
Deshalb ja MigLayout... damit er nicht die Zeit fürs Layout verplempert...
 
Danke für die Tipps.

Von Null-Layout halte ich wenig und will ich nicht verwenden. (nichts für ungut ;))

MigLayout will ich mir auf alle Fälle ansehen, bibs adden ist sicher nicht das Problem, aber ganz ehrlich .. mich ärgert das mit dem GBL im Augenblick ziemlich und drum würde ich es gerne zum Laufen bringen.

Ich hänge das eclipse-projekt dran, wäre echt nett, wenn du mal drüberschaun könntest soares.
(nur die view, der Rest ist noch nicht weit gedeiht)

Anhang anzeigen Tetris.7z
 
1668mib schrieb:
Deshalb ja MigLayout... damit er nicht die Zeit fürs Layout verplempert...

Naja, wenn man MigLayout nicht kennt, dann bedarf es erst einmal einiger Einarbeitungszeit. Das lohnt sich langfristig auf jeden Fall - ich rate auch immer zu MigLayout - aber wenn man kurzfristig ein Problem zu lösen hat, ist es vielleicht doch nicht der richtige Ansatz. Wobei NullLayout fast nie der richtige Ansatz ist.

Ich habe mittlerweile das Programm zur Ausführung gebracht. Bei mir schaut es allerdings etwas anders aus, als auf dem Eingangs-Screenshot:

tetris.png

Nur ein "Turm", kein zusätzliches Textfield. Ist das so ok? Hast Du den Code mittlerweile geändert?
 
@soares: hast du etwas geändert? bei mir treten nach wie vor Überlagerungen der Panels auf und der Würfel verschwindet rechts und auf halber Höhe im Nichts. Aber ja, so sollte es eigentlich aussehen.

Experementiere im Augenblick auch mit MiG Layout herum, würde aber immer noch eine GBL-Lösung vorziehen.
 
Nein, ich habe nichts geändert. Mit dem Layout sollte es aber ohnehin nichts zu tun haben.

Ich würde im MainFrame aber nicht auf GridBag setzen. Warum so kompliziert? Du hast doch nur zwei Widgets nebeneinander anzuordnen. BorderLayout wäre hier viel einfacher. Du musst dann nur die bevorzugten Größen ActionPanel und InfoPanel (korrekt) angeben.

Das Programm terminiert nicht, wenn man das Programmfenster schließt. Bist Du sicher, dass alle alten Instanzen geschlossen sind? Nicht, dass im Hintergrund noch etwas läuft, was Ressourcen frisst und Dir die Anzeige durcheinander bringt.

Lass das Programm mal laufen, ohne die Engine und den Repainter zu starten.
 
das WindowClosing-Event stoppt jetzt auch die Threads.
Wenn man Engine und Repainter nicht startet stimmt das Layout.. da Repainter nur repainted liegt der Fehler wohl in der Engine-Klasse.

Habe jetzt MiG-Layout durchprobiert und dann noch mal BorderLayout.. beides mit unschönen Ergebnissen. Werde die Threads mal komplett rausnehmen und ein bisschen basteln..

mich würde aber immer noch interessieren, warum es bei dir richtig angezeigt wird?!

Beste Grüße
 
while(break) schrieb:
Wenn man Engine und Repainter nicht startet stimmt das Layout.. da Repainter nur repainted liegt der Fehler wohl in der Engine-Klasse.

Im ActionPanel zeichnest Du ja selbst, dessen Inhalt hat somit nichts mit dem Layout zu tun. Vielleicht wird zuerst an der falschen Stelle gezeichnet und später nicht mehr aktualisiert. Würde allerdings nicht erklären, warum auch ein zusätzliches Textfeld auftaucht.

while(break) schrieb:
Habe jetzt MiG-Layout durchprobiert und dann noch mal BorderLayout.. beides mit unschönen Ergebnissen. Werde die Threads mal komplett rausnehmen und ein bisschen basteln.

Was war hier problematisch? Wenn ich das Layout in MainFrame auf BorderLayout ändere, erhalte ich das gewünschte Ergebnis. PreferredSize muss dann halt wie gesagt bei ActionPanel bzw. InfoPanel stimmen.

while(break) schrieb:
mich würde aber immer noch interessieren, warum es bei dir richtig angezeigt wird?!

Java - write once, test anywhere :D

Meine Fenster haben keinen Rahmen. Wenn Du das Fenster auf eine fixe Größe setzt, steht bei mir mithin mehr Platz für den Content zur Verfügung. Vielleicht reichen diese wenigen Pixel schon, um Deine Positionsberechnung durcheinander zu bringen.

Aber das Textfeld passt nicht zu dieser These... Zeige das Infopanel mal überhaupt nicht an. Dann müsste auf jeden Fall genug Platz vorhanden sein und das ActionPanel wird korrekt angezeigt?
 
Generell sollte die paint() Methode nie überschrieben werden. Statt dessen lieber paintComponent überschreiben:
Code:
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
	
		// hier zeichnen ..
	}
Wenn du das so abänderst, wird der rote Hintergrund gezeichnet.
 
Das Problem hinsichtlich der an den falschen Stellen gezeichneten Elemente liegt darin begründet, dass Du in ActionPanel getX und getY überschreibst! Diese Methoden müssen umbenannt werden. Dann sollte es klappen. Mit dem LayoutManager hat es wie schon vermutet, nichts zu tun.

Übrigens:
Das Look&Feel sollte man vor dem Aufruf der GUI setzen.
Die GUI sollte man im EDT erstellen.
 
Als Programmierer sollte man sich mit dem Thema GUIs nur oberflächlich befassen, das erledigen im Betrieb die Designer oder die kleineren Sachen das Tool "WindowBuilder" oder ähnliches.

Im Informatik Studium geben die Profs auch einen feuchten Furz auf Desgin, während bei den Medieninformatikern solcher Kram im Fokus steht und die Code Qualität unwichtiger ist.
 
Zuletzt bearbeitet von einem Moderator:
Zurück
Oben