Button wird mit setOpaque(false) und setContentAreafilled(false) nicht angezeigt

Liebe Community,

Ich arbeite gerade an einem Java Menü. Wenn man auf den ersten Button klickt, soll dieser verschwinden und darauf ein anderer Button erscheinen. Die Buttons sind Grafiken und sollen teilweise transparent sein. Ich verwende dafür setOpaque(false); und setContentAreaFilled(false);. Der erste Button wird richtig angezeigt, aber der nachfolgende nicht. Kann mir irgendjemand weiter helfen? Ich hab auf Google und dergleichen nichts gefunden. :frowning:

import javax.swing.*;

public class Main implements ActionListener{
	private JButton button1;
	private JButton button2;
	private JFrame f;
	public Main(){
		
		f= new JFrame("Menü");
		f.setSize(1280,720);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
		f.setLayout(null);
		
		button1 = new JButton(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button1.png")));
		button1.setBounds(36,240,280,80);
		button1.setOpaque(false);
		button1.setContentAreaFilled(false);
		button1.setBorderPainted(false);
		button1.addMouseListener(new MouseAdapter(){
			public void mouseEntered(MouseEvent m){
			button1.setIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button1+Border.png")));
			button1.repaint();
			}
			public void mouseExited(MouseEvent m){
			button1.setIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button1.png")));
			button1.repaint();
			}
		});
		button1.addActionListener(this);
		f.add(button1);
	}
	
	public static void main(String[] args){ 
		new Main();
	}
	public void actionPerformed(ActionEvent e) {
		if (e.getSource()==button1){
			button1.setVisible(false);
			button1.setEnabled(false);

			button2 = new JButton(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button2.png")));
			button2.setBounds(36,240,280,80);
			button2.setBorderPainted(false);
			button2.addMouseListener(new MouseAdapter(){
				public void mouseEntered(MouseEvent m){
				button2.setIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button2+Border.png")));
				button2.repaint();
				}
				public void mouseExited(MouseEvent m){
				button2.setIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Button2.png")));
				button2.repaint();
				}
			});
			f.add(button2);
	}
}

Zuerst mal ist NULL-Layout pfui!!!

und dann soll man Sachen, die man mehrmals machen will nicht mehrfach hinschreiben, sondern in Methoden oder Objekte auslagern, welche man wieder verwendet:
wo möglich so:
[spoiler]```
public class ButtonTest implements ActionListener {
private JButton button2;
private final JFrame f;
private final JButton button1;

public ButtonTest() {

    f = new JFrame("Menü");
    f.setSize(1280, 720);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
    f.setLayout(new FlowLayout());
    button1 = createButton("B1");
    f.add(button1);
}

JButton createButton(final String buttonName) {
    final JButton button1;
    button1 = new JButton(buttonName);
    button1.setBounds(36, 240, 280, 80);
    button1.setOpaque(false);
    button1.setContentAreaFilled(false);
    button1.setBorderPainted(false);
    button1.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseEntered(MouseEvent m) {
            button1.setText(buttonName
                    + " MouseIn");
            ;
            button1.repaint();
        }

        @Override
        public void mouseExited(MouseEvent m) {
            button1.setText(buttonName
                    + " mouseOut");
            ;
            button1.repaint();
        }
    });
    button1.addActionListener(this);
    return button1;
}

public static void main(String[] args) {
    new ButtonTest();
}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == button1) {
        button1.setVisible(false);
        button1.setEnabled(false);

        button2 = createButton("B2");
        f.add(button2);
    }
}

}```[/spoiler]

Darüber hinaus sollte man nicht die Klasse selbst Listener-Interfaces implementieren lassen.
Und wenn jeder Button sein eignes Objekt einer anonymen Listener-Klasse bekommt braucht man darin nicht mal ein If

**[edit]**Und Rahmen setzen man auch nicht als Bild sonder so:[SPOILER]```// button1.setBorderPainted(false);
button1.setBorder(BorderFactory.createLineBorder(Color.RED, 5));
button1.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent m) {
((JButton) m.getSource()).setBorderPainted(true);
}

        @Override
        public void mouseExited(MouseEvent m) {
            ((JButton) m.getSource()).setBorderPainted(false);
        }
    });

bye
TT

Buttons kannst du mit setVisible(false) verschwinden lassen.

Ergänzend zu den bisherigen Anmerkungen:

  1. Es macht keinen Sinn die selben Bilder mehrfach oder immer wieder einzulesen.
  2. Den Schmarrn mit dem MouseListener für einen Rollover Effekt kann man sich sparen, da der JButton so etwas bereits implementiert hat.
button.setRolloverIcon(rolloverIcon);```

Danke schon Mal für die bisherigen Antworten :slight_smile:
Aber wieso taucht der zweite Button nicht auf?
Ich bin noch Anfänger und hab noch viel zu lernen.

LG Jawas

Ein Problem dürfte sein, dass Du den zweiten Button zur Laufzeit neu erstellst und dem Frame hinzufügst. Sowas erfordert eine Validierung der GUI.

Aber benötigst Du wirklich zwei Buttons? Der zweite soll ja scheinbar an der selben Stelle wie der erste angezeigt werden. Daher würde ein Button völlig ausreichen - man muss nur die Icons austauschen und entsprechend anders beim Klick reagieren. Wobei so etwas (einen Button durch einen anderen ersetzen) eigentlich eher unüblich ist und mir spontan keine Anwendung einfällt die so etwas praktiziert.

[quote=Jawas]Aber wieso taucht der zweite Button nicht auf?[/quote]Wie @_Michael schreibt wird der erst zur Laufzeit erzeugt, Du siehst ihn also erst, wenn Du auf den ersten drauf klickst. Zumindest passiert das in dem Code-Besipiel von mir. Wie sich das null-Layout verhält weiss ich nicht
und es ist mir auch egal.
[spoiler]Entweder lernst Du mit Layout-Managern umzugehen oder Du musst auf meine Hilfe verzichten…[/spoiler]

bye
TT

Füge beide Buttons von anfang an deiner GUI hinzu. Setze einen Button visible(False). Beim Klick auf den anderen setzt du ihn visible(true).

Timothy_Truckle hat moniert, dass du ohne LayoutManager deine GUI erzeugen willst. Recht hat er!
Am Anfang mag das einfach erscheinen, aber je komplexer die GUI wird um so schwerer behält man den Durchblick und um so schlechter ist sie zu warten bzw. umzugestalten. Im schlimmsten Fall musst du immer wieder viele Koordinaten von anderen Komponenten anfassen, nur um eine Komponente zu ändern. Einfach nur unflexibel.
Und ganz schlimm kann es dich erwischen, wenn dein Programm auf anderen Betriebssystemen laufen soll. Es ist dann sehr wahrscheinlich, dass deine GUI regelrecht unbrauchbar wird.

Im Wiki findest du Einsteiger-Tutorials von einigen meist benutzen LayoutManagern. Schau da ruhig mal rein.

Okay,

Ich werde mich mal mit den Layout-Managern beschäftigen. Ich werde dann später einen neuen Code posten, wenn ich fertig bin ^^
Ich meld mich dann wieder.

LG Jawas

So, Ich hab jetzt für die zwei Buttons/Menüs(!) das CardLayout verwendet. Der zweite Button taucht jetzt wie gewollt auf! Leider wird der zweite Button (bzw. das zweite Label) um 7x19 pixel versetzt. Im Code hab ich das zwar mit der Hand korrigiert, aber gibt es dafür irgendeinen Befehl, damit das nicht passiert?

Gibt es einen LayoutManager, bei dem man Positionen von JLabels, JButtons festlegen kann und der dann diese in einem gleichbleibenden Verhältnis vergrößert bzw. verkleinert wenn man das Fenster mit der Maus vergrößert oder verkleinert?

LG Jawas

import java.awt.event.*;

import javax.swing.*;

import Game.game;

public class Main implements ActionListener{
	
	private JButton button1;
	private JButton button2;
	private JLabel background;
	private JLabel menu1;
	private JLabel menu2;
	private JLabel menu;
	private JFrame f;
	CardLayout cl = new CardLayout();

	public Main(){
        f = new JFrame("Menü");
	f.setSize(1280,720);
	f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	f.setVisible(true);
		
		menu1=new JLabel();
		
		button1 = new JButton();
		button1.setIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/StartButton.png")));
		button1.setBounds(36,240,280,80);
		button1.setOpaque(false);
		button1.setContentAreaFilled(false);
		button1.setBorderPainted(false);
		button1.setRolloverIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/StartButton+Border.png")));
		button1.addActionListener(this);
		menu1.add(button1);
		
		menu2 = new JLabel();
		
		button2 = new JButton(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Mod1.png")));
		button2.setBounds(28,221,280,80);
		button2.setOpaque(false);
		button2.setContentAreaFilled(false);
		button2.setBorderPainted(false);
		button2.setRolloverIcon(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/Mod1+Border.png")));	
		button2.setVisible(true);
		menu2.add(button2);
		
		menu = new JLabel();
		menu.setLayout(cl);
		menu.add(menu1, "1");
		menu.add(menu2, "2");
		cl.show(menu, "1");
		f.add(menu);
		
		background = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("Game/Pictures/SchereSteinPapier++Menü.jpg")));
		background.setSize(1280, 720);
		background.setLayout(null);
		f.add(background);
		f.repaint();
	}
	public static void main(String[] args){ 
		new Main();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
			
			cl.show(menu, "2");
		}
	}

Einer der Vorteile von Java ist, dass man einige Räder nicht nochmal erfinden muss. Wenn Du also ein Menü realiseren willst solltest Du auch die von Java dafür vorgesehenen Klassen nutzen.

http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html
oder
http://docs.oracle.com/javafx/2/ui_controls/menu_controls.htm

Ansonsten poste Deinen Code bitte so, dass er sich ohne weitere Anpassungen ausführen lässt.

Nun zu Deinem Code:
JLabel ist keine Container-Klasse das Dein Layout damit nicht funktioniert ist ziehmlich naheliegend.

Mir ist nicht ganz klar, warum Du die Border unbedingt über ein Bild setzen willst anstatt über die entspechende Methode. Das größere Bild ändert die “peferedSize” der Componente und führt zu Verschiebungen im Layout.

Genau so wenig verstehe ich warum Du immer noch zwei mal den (fast) gleichen Code hinschreibts anstatt die Buttons in einer parametrisierten Mehtode zu konfigurieren. Vermutlich rührt genau daher Deine “Verschiebung”.

Du setzt die Position der Button immer noch mit willkürlichen Pixelpositionen. Aus das könnte Teil Deines Problem sein. Lass das einfach und überlasse dem Layout sowas.

setVisible() wir immer erst aufgerufen wenn das Layout fertig konfiguriert ist, nie als erstes im Konstruktor. Meist ist ein pack() diekt davor eine gute Idee.

[quote=Jawas]Gibt es einen LayoutManager, bei dem man Positionen von JLabels, JButtons festlegen kann und der dann diese in einem gleichbleibenden Verhältnis vergrößert bzw. verkleinert wenn man das Fenster mit der Maus vergrößert oder verkleinert?[/quote]Klar, Die Auswahl ist ross: Ich persönlich bevorzuge [JAPI]BorderLayout[/JAPI] und [JAPI]GridLayout[/JAPI] in Kombination für einfache Fälle. Manche schwören für komplexere Strukturen auf [JAPI]GridBagLayout[/JAPI], aber ich bin ehr ein Freund von [JAPI]GroupLayout[/JAPI] oderJGoodies FormLayout.

bye
TT

Öhh, doch.
Die Vererbungshierarchie von [japi]JLabel[/japi] sieht so aus:

java.lang.Object
java.awt.Component
[INDENT]java.awt.Container [/INDENT]
[INDENT][INDENT]javax.swing.JComponent [/INDENT][/INDENT]
[INDENT][INDENT][INDENT]javax.swing.JLabel[/INDENT][/INDENT][/INDENT]

[quote=L-ectron-X]Öhh, doch[/quote]Trotzdem fühlt sich das, was unser junger Freund damit macht komisch an…

bye
TT

Also,

Die Buttons sind nicht wirklich willkürlich gesetzt. Das liegt daran, dass das Hintergrundbild sozusagen dafür gemacht wurde. Wenn du möchtest, kann ich es ja mal anhängen :wink: Genau so ist das mit den Bordern der Buttons, die hab ich mir mit Photoshop zusammengebastelt :).

Ich werd mich dann mal weiter durchlesen und danke, dass du mir hilfst. ^^

LG Jawas

Der Meinung bin ich auch.
@Jawas : Guck mal in Inhaltsverzeichnis da findest du, wie man Menüs in JFrames einhängt etc.

[quote=Jawas]Das liegt daran, dass das Hintergrundbild sozusagen dafür gemacht wurde.[/quote]Damit hast Du effektiv dynamische Gößenänderungen durch Ziehen des Fensters ausgehebelt. Hintergrundbild und Componenten synchon zu skalieren halte ich zwar nicht für unmöglich, aber extrem aufwändig. Aber selbst wenn Du Größenänderungen des Fensters verhinderst: Java-Componenten können (und sollen) ihre Größe entspechend ihrem Inhalt anpassen. Wenn sich also beisplielsweise der Text in einem Lable ändert und länger wird musst Du Dein Hintergrundbild neu mahlen, oder Du fixierst die Größe der Label und lebst damit, dass der Text abgeschnitten wird…

Übrigens kann Dir das auch dann passieren, wenn der Benutzer in seiner Oberfläche größere Schriften eingestellt hat…

bye
TT