Zeichnen auf JPanel und in JFrame einfügen

vannelle

Mitglied
Hallo,

ich möchte auf einem JPanel etwas Zeichnen, und dieses JPanel soll dann zusammen mit einem weiteren JPanel auf einem JFrame dargestellt werden. Alles zusammen soll durch den GridBagLayout Manager verwaltet werden.

Der relevante Code:
Java:
public Nonomat() {

maincontent = new JFrame("Fenstertitel");
GridBagLayout gbl = new GridBagLayout();
GridBagLayout gblm = new GridBagLayout();
maincontent.setLayout(gblm);

[...]

gamecontent = new JPanel();
gamecontent.add(new Raster()); //<-- Hier soll auf das Panel gezeichnet werden
gamecontent.setOpaque(true);
gamecontent.setVisible(true);
gamecontent.setSize(377,377);
			
menu = new JPanel();
menu.setLayout(gbl);
menu.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
menu.setOpaque(true);

[...]

addMain(maincontent,gblm,((JPanel)menu),0,0,0,0,0,0);
addMain(maincontent,gblm,((JPanel)gamecontent),150,140,100,100,1.0,0); 
//Werte sind nur durch rumprobieren entstanden, haben keine Aussage, da es ja nicht funktioniert.

/*Das JPanel gamecontent dass das gezeichnete Raster enthalten soll, wird nicht angezeigt.
Wenn ich das Layout des maincontent allerdings von gbl auf default setzt, dann wird entweder
das Menü oder das Raster angezeigt, je nach Reihenfolge, was so aussehen würde:
maincontent.add(newRaster());
*/
		
maincontent.setJMenuBar(menuBar);
maincontent.setLocation(100, 100);
maincontent.setPreferredSize(new Dimension(627,500));
maincontent.setVisible(true);
maincontent.pack();
}

	static void addComponent(Container menu, GridBagLayout gbl, Component c,int x, int y, int
 width, int height, double weightx, double weighty) {
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.gridx = x;
		gbc.gridy = y;
		gbc.gridwidth = width;
		gbc.gridheight = height;
		gbc.weightx = weightx;
		gbc.weighty = weighty;
		gbl.setConstraints(c, gbc);
		menu.add(c);
	}
	static void addMain(Container maincontent, GridBagLayout gblm, Component c,int x, int y, int
 width, int height, double weightx, double weighty) {
		GridBagConstraints gbcm = new GridBagConstraints();
		gbcm.fill = GridBagConstraints.VERTICAL;
		gbcm.anchor = GridBagConstraints.FIRST_LINE_START;
		gbcm.gridx = x;
		gbcm.gridy = y;
		gbcm.gridwidth = width;
		gbcm.gridheight = height;
		gbcm.weightx = weightx;
		gbcm.weighty = weighty;
		gblm.setConstraints(c, gbcm);
		maincontent.add(c);
	}

Zum Verständniss was gezeichnet wird:
Java:
import java.awt.*;
import java.awt.event.*;

import javax.swing.JPanel;

public class Raster extends Canvas {
	
    public static final int IDEAL_WIDTH = 377;
    public static final int IDEAL_HEIGHT = 377;
    
    
    public void paint(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(230,60, IDEAL_WIDTH, IDEAL_HEIGHT);
        
        // Array das dargestellt wird
        Color values[][] = new Color[18][18];
        for (int i = 0; i < 10; i++){
            for(int j = 0; j < 9; j++)
                values[i][j] = Color.WHITE;
        }
        values[1][1] = Color.RED;
        values[5][2] = Color.BLUE;
        
        // Ankerpunkt für das Raster
        int x_start = 230;
        int y_start = 60;
        // Raster zeichnen
        for (int i = 0; i < 18; i++) {        
            for (int j = 0; j < 18; j++) {
                g.setColor(values[i][j]);
                g.fillRect(x_start + i * 20, y_start + j * 20, 20, 20);
                y_start += 1;
            }
            y_start = 60;
            x_start += 1;
        }
    }
}
Das soll sozusagen ein Raster werden.

Mein Problem ist dass ich beide JPanels nicht angezeigt bekomme, oder einfach irgend einen Fehler
habe dass der erst garnicht auf das JPanel gamecontent zeichnet, sondern nur direkt auf den JFrame.
Das JPanel menu wird problemlos und korrekt angezeigt.


Vielen Dank im vorraus
Vannelle
 
Zuletzt bearbeitet:
Ich glaube das Problem liegt beim Layout. Wieso kommt die Zelle 150|140 ?
Und wieso zeichnest du überhaupt erst auf ein Canvas und fügst dieses dann dem JPanel hinzu? Da kannst du doch genauso gut gleich aufs JPanel malen.
 
meinst du mit Zelle hier die 150|140 ?
Code:
addMain(maincontent,gblm,((JPanel)gamecontent),150,140,100,100,1.0,0);

Falls ja, steht drunter dass das keine Bedeutung hat, und immo nur so drin steht weil es eh noch nicht angezeigt wird.

Warum ich nicht direkt aufs JPanel zeichne hat den Grund das ein Bekannter meinte dass das nich funktionieren würde, und ich solle mir das Canvas ansehen ...

Wenn ich direkt auf ein JPanel zeichnen will, würde das dann so aussehen?
Java:
import java.awt.*;
import java.awt.event.*;
 
import javax.swing.JPanel;
 
public class Raster extends Canvas {
    
    public static final int IDEAL_WIDTH = 377;
    public static final int IDEAL_HEIGHT = 377;
    
    
    public void paint(Graphics g) {
        
       
    }
}

und dann im maincontent:
Code:
addMain(maincontent,gblm,((JPanel)Raster),150,140,100,100,1.0,0);

So hab ich das aus diversen Beispielen verstanden 😛
 
Naja, Raster muss dann natürlich von JPanel erben und du musst paintComponent und nicht paint überschreiben (lies dir gegebenenfalls mal das "Zeichnen in Swing Tutorial" hier im Forum durch).

"gamecontent.setSize(...)" hat übrigens rein gar keinen Effekt, wenn du später pack() aufrufst, da dann die Größe aller Komponenten anhand ihrer preferredSize festgelegt wird. Vieleicht reicht es schon, statt setSize einfach setPreferredSize aufzurufen.
 
Das ganze sieht jetzt so aus:

Java:
public Nonomat() {

		maincontent = new JFrame("Nonomat2000");
		GridBagLayout gbl = new GridBagLayout();
		GridBagLayout gblm = new GridBagLayout();
		maincontent.setLayout(gblm);
		
		JMenuBar menuBar = new JMenuBar();
		JMenu helpMenu = new JMenu("Hilfe");
		explain = new JMenuItem("Spielbeschreibung");
		impressum = new JMenuItem("Impressum");
		helpMenu.add(explain);
		helpMenu.add(impressum);
		menuBar.add(Box.createHorizontalGlue());
		menuBar.add(helpMenu);
		impressum.addActionListener(this);
		explain.addActionListener(this);
		
			gamecontent = new JPanel();
			gamecontent.add(new Raster());
			gamecontent.setOpaque(true);
			gamecontent.setVisible(true);
			gamecontent.setPreferredSize(new Dimension(377,377));
			
			menu = new JPanel();
			menu.setLayout(gbl);
			menu.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
			menu.setOpaque(true);
			
				ImageIcon game = new ImageIcon("images/replay1.png");
		        JButton newGame = new JButton("Neu anfangen",game);
		        newGame.setHorizontalAlignment(SwingConstants.LEFT);
		        newGame.setActionCommand("newGameClick");
		        newGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)newGame),0,0,1,1,1.0,0);
		
				ImageIcon open = new ImageIcon("images/open1.png");
		        JButton openGame = new JButton("Spiel laden",open);
		        openGame.setHorizontalAlignment(SwingConstants.LEFT);
		        openGame.setActionCommand("openGameClick");
		        openGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)openGame),0,10,1,1,1.0,0);
		
				ImageIcon save = new ImageIcon("images/save1.png");
		        JButton saveGame = new JButton("Spiel speichern",save);
		        saveGame.setHorizontalAlignment(SwingConstants.LEFT);
		        saveGame.setActionCommand("saveGameClick");
		        saveGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)saveGame),0,20,1,1,1.0,0);
		
				ImageIcon control = new ImageIcon("images/control1.png");
		        JButton controlGame = new JButton("Lösung kontrollieren",control);
		        controlGame.setHorizontalAlignment(SwingConstants.LEFT);
		        controlGame.setActionCommand("controlGameClick");
		        controlGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)controlGame),0,30,1,1,1.0,0);
		
				ImageIcon show = new ImageIcon("images/show1.png");
		        JButton showGame = new JButton("Lösung anzeigen",show);
		        showGame.setHorizontalAlignment(SwingConstants.LEFT);
		        showGame.setActionCommand("showGameClick");
		        showGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)showGame),0,40,1,1,1.0,0);
		
				ImageIcon zoomin = new ImageIcon("images/zoomin1.png");
		        JButton zoomIn = new JButton("Ansicht vergrößern",zoomin);
		        zoomIn.setHorizontalAlignment(SwingConstants.LEFT);
		        zoomIn.setActionCommand("zoomInClick");
		        zoomIn.addActionListener(this);
		        addComponent(menu,gbl,((JButton)zoomIn),0,50,1,1,1.0,0);
		
				ImageIcon zoomout = new ImageIcon("images/zoomout1.png");
		        JButton zoomOut = new JButton("Ansicht verkleinern",zoomout);
		        zoomOut.setHorizontalAlignment(SwingConstants.LEFT);
		        zoomOut.setActionCommand("zoomOutClick");
		        zoomOut.addActionListener(this);
		        addComponent(menu,gbl,((JButton)zoomOut),0,60,1,1,1.0,0);
		       
				ImageIcon exit = new ImageIcon("images/exit1.png");
		        JButton exitGame = new JButton("Beenden",exit);
		        exitGame.setHorizontalAlignment(SwingConstants.LEFT);
		        exitGame.setActionCommand("exitGameClick");
		        exitGame.addActionListener(this);
		        addComponent(menu,gbl,((JButton)exitGame),0,70,0,0,1.0,0);
		        
        addMain(maincontent,gblm,((JPanel)menu),0,0,0,0,0,0);
        addMain(maincontent,gblm,(new Raster()),150,140,100,100,1.0,0);
		maincontent.setJMenuBar(menuBar);
		maincontent.setLocation(100, 100);
		maincontent.setPreferredSize(new Dimension(627,500));
		maincontent.setVisible(true);
		maincontent.pack();
	}
	public class Raster extends JPanel {
		
	    public static final int IDEAL_WIDTH = 377;
	    public static final int IDEAL_HEIGHT = 377;
	    JPanel Raster = new JPanel();
	    
	    public void paintComponent (Graphics g) {
	        g.setColor(Color.BLACK);
	        g.fillRect(230,60, IDEAL_WIDTH, IDEAL_HEIGHT);
	        
	        // Array das dargestellt wird
	        Color values[][] = new Color[18][18];
	        for (int i = 0; i < 10; i++){
	            for(int j = 0; j < 9; j++)
	                values[i][j] = Color.WHITE;
	        }
	        values[1][1] = Color.RED;
	        values[5][2] = Color.BLUE;
	        
	        // Ankerpunkt für das Raster
	        int x_start = 230;
	        int y_start = 60;
	        // Raster zeichnen
	        for (int i = 0; i < 18; i++) {        
	            for (int j = 0; j < 18; j++) {
	                g.setColor(values[i][j]);
	                g.fillRect(x_start + i * 20, y_start + j * 20, 20, 20);
	                y_start += 1;
	            }
	            y_start = 60;
	            x_start += 1;
	        }
	    }
	}

Falls ich grundsätzlich richtig liege, würd ich mich über eine Berichtigung freuen, und derweil les ich mir mal das Tutorial durch 🙂
 
Naja, dann reicht auch
Java:
gamecontent = new Ratser();
und setOpaque(true) kannst du dir sparen.

Funtkioniert's denn jetzt?
 
Jap, es funktioniert ... also das Raster wird gezeichnet^^
Java:
gamecontent = new Raster();
gamecontent.setOpaque(true);
	//gamecontent.setBorder(BorderFactory.createLineBorder(Color.black));
gamecontent.setVisible(true);
gamecontent.setPreferredSize(new Dimension(377,377)); 

addMain(maincontent,gblm,((JPanel)menu),0,0,0,0,0,0);
addMain(maincontent,gblm,((JPanel)gamecontent),180,0,0,0,0,0);

Allerdings sollte der ja durch die
Code:
((JPanel)gamecontent),180,0,0,0,0,0)
bei das Raster bei 180px auf der xAchse anzeigen ... aber Pustekuchen.
Der Klatscht die 2 JPanels einfach übereinander ...

bildschirmfoto20100128ud.png


und das soll ja so nicht sein ...
bei dem Bild ist übrigens das
Code:
maincontent.setPreferredSize(new Dimension(655,520));
auskomplementiert, da das nur den JFrame größer macht, die zwei JPanels aber trotzdem wie auf dem Bild angezeigt werden, nur dann zentriert ...
 
Ich hab mir den Code jetzt nicht so genau angeschaut aber eines ist mir sofort aufgefallen: Du musst in der Methode paintComponent(Graphics g) immer am Anfang der Methode super.paintComponent(g) aufrufen. Dort werden Aufräumarbeiten erledigt. Sonst werden die einzelnen Panels immer übereinander gelegt.

Struktur der paintComponent(...)-Methode:
[Java]
public void paintComponent(Graphics g){
super.paintComponent(g);

// ...
// Hier kommt der Rest des Codes
// ...
}
[/Java]
 
Keinen Canvas verwenden (AWT) sondern einfach von JComponent erben und paintComponent() uberschreiben. Super-Aufruf natürlich nicht vergessen, wie mein Vorredner schreibt.

Ebenius
 
Also die Raster-Klasse mit der Paint-Methode sieht jetzt so aus:

Java:
	public class Raster extends JComponent {
		
	    public static final int IDEAL_WIDTH = 377;
	    public static final int IDEAL_HEIGHT = 377;
	    JPanel Raster = new JPanel();
	    
	    public void paintComponent (Graphics g) {
	    	super.paintComponent(g);
	        g.setColor(Color.BLACK);
	        g.fillRect(0,0, IDEAL_WIDTH, IDEAL_HEIGHT);
	        
	        // Array das dargestellt wird
	        Color values[][] = new Color[18][18];
	        for (int i = 0; i < 10; i++){
	            for(int j = 0; j < 9; j++)
	                values[i][j] = Color.WHITE;
	        }
	        values[1][1] = Color.RED;
	        values[5][2] = Color.BLUE;

	        
	        // Ankerpunkt für das Raster
	        int x_start = 0;
	        int y_start = 0;
	        // Raster zeichnen
	        for (int i = 0; i < 18; i++) {        
	            for (int j = 0; j < 18; j++) {
	                g.setColor(values[i][j]);
	                g.fillRect(x_start + i * 20, y_start + j * 20, 20, 20);
	                y_start += 1;
	            }
	            y_start = 0;
	            x_start += 1;
	        }
	    }
	}

Da ist doch jetzt eigentlich alles umgesetzt was fehlerhaft war, oder irre ich mich?
Wenn Raster allerdings nicht von JPanel erbt sondern von JComponent, dann bekomm ich eine Exeption beim erzeugen von
Code:
private JComponent gamecontent;
Code:
gamecontent = new Raster();

Java:
Exception in thread "main" java.lang.ClassCastException: Nonomat$Raster cannot be cast to javax.swing.JPanel
	at Nonomat.<init>(Nonomat.java:116)
	at Nonomat.main(Nonomat.java:24)

Wenn Raster direkt von JPanel erbt wird es einwandfrei erstellt, nur das Layout im maincontent stimmt nicht.
 
Natürlich ist es gut und richtig Raster von JPanel erben zu lassen (JPanel erbt von JComponent). Wenn Raster von JComponent erbt, musst du "gamecontent" auch als solche deklarieren.
In etwa...
Java:
JComponent gamecontent; //nicht "JPanel gamecontent;"

// ...
// ...
// ...

gamecontent = new Raster();
Wie du's machst ist im Grunde egal - mit JPanel geht's auch.

Du solltest dir aber auf jeden Fall nochmals genauer anschauen, wie GridBagLayout funktioniert (ist nicht ganz trivial).
GridBagLayout teilt die Componente in Reihen und Spalten, in denen dann die Unterkomponten angeordnet werden, wobei eine Kopmonente mehrere Zellen beanspruchen kann und auch eine Zelle nicht zwingend füllen muss.
Auf jeden Fall gibt der GridBagConstraints-Wert gridx nicht die letztendliche Position der Komponente in Pixel an, sondern die Zelle, in der die linke obere Ecke der Komponente liegen soll.
Deshalb hatte ich mich auch über die hohen Werte gewundert, die du dort angibst, ohne dass die dazwischenliegenden Zellen belegt wären.

Lies dir am besten das hir mal durch.
 
Sollte dir das GridbagLayout zu "fummelig" sein, kann ich dir das TableLayout ans Herz legen, einfach mal kurz Google bemühen. Meiner Meinung nach wesentlich einfacher und schneller zu verstehen.
 
Vielen Dank Seppel für den Link, der hat mir ziemlich weitergeholfen.

Hab das Layout jetzt auch hinbekommen ... und wie das so ist wenn man wissenstechnisch am Anfang steht, bin ich schon auf ein nächstes Problem gestoßen.
Das JPanel gamecontent ist in der Größe variabel, und soll Scrollbar sein.
Allerdings bekomme ich einfach keine funktionierende Scrollbar hin ...

Hab mich schon auf diversen Seiten darüber infomiert (Galileo etc), aber bekomm aber einfach keine Lösung hin ... generell sollte es doch so funktionieren:

Java:
gamecontent.setPreferredSize(new Dimension(500,500));
JScrollPane scrollPane = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS ); 
scrollPane.setViewportView( gamecontent );
scrollPane.setPreferredSize(new Dimension(400,400));
getContentPane().add(scrollPane, BorderLayout.CENTER);

Aus Galileo-Computering schließe ich, dass JPanel wohl die Schnittstelle Scrollable nicht implementiert?!

Und leider fehlen auch Beispiele um die Funktion des Viewport zu verstehen ...


Ich hoffe das das Problem hier in dem Thread einfach weiter behandelt werden kann ... oder besser
neuen Thread mit passenderer Überschrift? Will nicht das Forum mit meinen Problem-Threads zuspammen 🙂
 
ich weis nicht wo das Problem lag, aber es hat sich irgendwie mit diesem Code beheben lassen:

Java:
scroll = new JScrollPane(gamecontent); //JPanel liegt in JScrollPane
maincontent.add(scroll,c); //JScrollpane wird zu JFrame hinzugefügt

Ich hatte das allerdings schonmal so, aber irgendwo war da wohl ein Würmchen versteckt 🙂
So funktionierts auf jeden Fall bei mir.
 
Was ist bei dir c?
Ohne die Definitionen für das Erscheinen der Scrollbars anzugeben, sollten diese doch garnicht erscheinen oder?

Ich habe bei mir das Gitterfeld (Klasse mit den Gitterpaint()-Methoden) direkt in das ScrollPane gelegt, und dieses Scrollpane direkt in den Container, also eigentlich so wie du. Nur scrollen tut's einfach nicht :/
 
Code:
GridBagConstraints c = new GridBagConstraints();

Das c ist nur für mein Layout mit dem GridBagLayout Manager relevant.

Mich hat ehrlich gesagt auch gewundert, dass es komplet ohne Sichtbarkeitsdefinitionen der ScrollBars funktioniert ... aber wenn der gamecontent zu groß wird, fügt er die AS_NEEDED ein, obwohl ich das selbst nirgends definiert habe ... vll ist das DEFAULT
 

Neue Themen


Zurück
Oben