Image bewegt sich nicht nach Klicken auf Button

darkcloud

Mitglied
Hallo,

zunächst einmal sind das meine Klassen

Java:
import javax.swing.JFrame;


import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class MyFrame extends JFrame implements ActionListener {
 

UpperPanel uPanel;
LowerPanel lPanel;
SidePanel sPanel;

    public MyFrame(){
        
        setTitle("Frame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(630, 650);
        setResizable(true);
        setLocationRelativeTo(null);
        

        // neues Layout Manager Objekt und constraints Objekt erstellen, Layout dem Frame hinzufügen
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        setLayout(layout);

    


        // neue Panelobjekte erstellen
        uPanel = new UpperPanel();
        lPanel = new LowerPanel();
        sPanel = new SidePanel();

        uPanel.getButtonLeft().addActionListener(this);
        uPanel.getButtonRight().addActionListener(this);
        sPanel.getButtonUp().addActionListener(this);
        sPanel.getButtonDown().addActionListener(this);
    

        

        // Add UpperPanel to the layout
        constraints.gridx = 0;              // fängt oben links an mit diesen Einstellungen
        constraints.gridy = 0;
        constraints.gridwidth = 2;          // gridwith von diesem und SidePanel addiert sich insgesamt zu 3
        constraints.gridheight = 1;         // da gridheight von SidePanel 2 ist weiß Programm das Upper und Lower Panel 2 unterschiedliche Grids auf der 2/3 Seite sind
        constraints.weightx = 0.67;         // nimmt 2/3 horizontal des Objekts (hier frame-Objekt) ein auf dem es platziert ist
        constraints.weighty = 0.1;          // nimmt 1/10 vertikal des Objekts ein auf dem es paltziert ist
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(uPanel, constraints);
        add(uPanel);

        // Add LowerPanel to the layout
        constraints.gridx = 0;
        constraints.gridy = 1;
        constraints.gridwidth = 2;
        constraints.gridheight = 1;
        constraints.weightx = 0.67;
        constraints.weighty = 0.9;
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(lPanel, constraints);
        add(lPanel);

        // Add SidePanel to the layout

        constraints.gridx = 2;
        constraints.gridy = 0;
        constraints.gridwidth = 1;
        constraints.gridheight = 2;
        constraints.weightx = 0.33;
        constraints.weighty = 1;
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(sPanel, constraints);
        add(sPanel);


        

    setVisible(true);

    

}

    

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == uPanel.getButtonLeft()){
            int currentX = lPanel.getImageLabel().getX();
                lPanel.getImageLabel().setLocation(currentX - 10, lPanel.getImageLabel().getY());
              
              
        }
        
        else if (e.getSource() == uPanel.getButtonRight()){
            int currentX = lPanel.getImageLabel().getX();
                lPanel.getImageLabel().setLocation(currentX + 10, lPanel.getImageLabel().getY());
                System.out.println("Rechts");
              
        }
        
        else if (e.getSource() == sPanel.getButtonUp()){
            int currentY = lPanel.getImageLabel().getY();
            lPanel.getImageLabel().setLocation(lPanel.getImageLabel().getX(), currentY + 10);
            System.out.println("Oben");
          
        }
        
        else if (e.getSource() == sPanel.getButtonDown()){
            int currentY = lPanel.getImageLabel().getY();
            lPanel.getImageLabel().setLocation(lPanel.getImageLabel().getX(), currentY - 10);
            System.out.println("Unten");
            
        
    }

            
            lPanel.repaint();
            lPanel.revalidate();

    }   

}

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class LowerPanel extends JPanel {
    

    JLabel imageLabel;

    public LowerPanel(){
        setBackground(Color.BLUE);

        ImageIcon originalIcon = new ImageIcon("IMG-20220508-WA0017.jpg");  // zuerst Bild in ImageIcon-Objekt einfügen
        Image image = originalIcon.getImage().getScaledInstance(150, 150, Image.SCALE_SMOOTH); 
        ImageIcon scaledIcon = new ImageIcon(image); // ImageObjekt zurück in ein ImageIcon-Objekt umwandeln damit es von JLabel Objekt getragen werden kann
        imageLabel = new JLabel(scaledIcon);
      
        add(imageLabel);
        
    }

    // override-methode wird automatisch von jedem Objekt dieser Klasse ausgeführt ohne konkrete Implementierung
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // einige grundlegende Zeichnungsoperationen ausgeführt, die erforderlich sind, um das Komponenten-Rendering korrekt durchzuführen.
        
        // Positionieren des JLabels in der Mitte des Panels
        int x = (getWidth() - imageLabel.getPreferredSize().width) / 2; // (LowerPanel-Objekt-imageLabel-Obekt) / 2
        int y = (getHeight() - imageLabel.getPreferredSize().height) / 2;
      
        imageLabel.setLocation(x, y);
        
}


    public JLabel getImageLabel(){
        return imageLabel;
    }

}

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.JButton;
import javax.swing.JPanel;

public class SidePanel extends JPanel {
    
    JButton buttonUp;
    JButton buttonDown;

    
    public SidePanel(){

        setBackground(Color.GREEN);       
        setLayout(new BorderLayout());  // JButton Komponente wird kein Standard LM zugewiesen, sodas wir BLM erstellen und zuweisen müssen


        buttonUp = new JButton();
        buttonDown = new JButton();

       buttonUp.setText("oben");
       buttonDown.setText("unten");
       add(buttonUp, BorderLayout.NORTH);
       add(buttonDown, BorderLayout.SOUTH);
}


public JButton getButtonUp(){
    return buttonUp;
}

public JButton getButtonDown(){
    return buttonDown;

}

}

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.JButton;
import javax.swing.JPanel;

public class UpperPanel extends JPanel {
    
    JButton buttonLeft;
    JButton buttonRight;


    public UpperPanel (){
        setBackground(Color.RED);
        setLayout(new BorderLayout());  // JButton Komponente wird kein Standard LM zugewiesen, sodas wir BLM erstellen und zuweisen müssen


        buttonLeft = new JButton();
        buttonRight = new JButton();

       buttonLeft.setText("links");
       buttonRight.setText("rechts");
       add(buttonRight, BorderLayout.EAST);
       add(buttonLeft, BorderLayout.WEST);

    }

    public JButton getButtonLeft(){
        return buttonLeft;
    }

    public JButton getButtonRight(){
        return buttonRight;
}

}

Ich würde die Klassenunterteilung gerne beibehalten. Mein Problem ist, dass sobald ich auf die jeweiligen Buttons klicke, mir der Text "oben" "unten" etc. zwar korrekt ausgegeben wird, der Button also somit erkannt wird, jedoch verschiebt sich das Bild nicht. Die repaint-Methode habe ich im Nachhinein noch implementiert. Ob sie jetzt da ist oder nicht hat keinen Unterschied gemacht, ich habe sie jedoch dringelassen damit ihr seht, was ich bereits ausprobiert habe.

Viele Grüße
 

KonradN

Super-Moderator
Mitarbeiter
Wenn ich das richtig sehe, dann nutzt Du ein Panel, das seine Elemente selbst anordnet. Damit kannst Du die Positionen nicht selbst setzen.

Also wentweder Du nutzt ein Layout, bei dem Du die Position vorgibst (dann kannst du die Positionen setzen) oder Du setzt auf Layouts, die die Positionen vorgeben (Das erspart Dir das Setzen des Positionen aber du kannst die Positionen dann auch nicht frei setzen).

Und ich wäre auch vorsichtig - Du hast eine Instanz von den GridBagConstraints. Diese Instanz einmal zu setzen, dann anzupassen und dann erneut an anderer Stelle zu nutzen mag funktionieren, falls GridBagLayout da intern eine Kopie erstellen sollte. Aber das ist zumindest nicht vermerkt (oder ich habe es auf den ersten Blick nicht gesehen), so dass ich da zumindest vorsichtig wäre (Zumal man diese Constraints auch auslesen kann ...)
 

Neumi5694

Top Contributor
Nur zur Info: Das mit GridbadContraints passt so. Die Werte werden beim Hinzufügen der Komponente tatsächlich kopiert.
Schöner ist es anders, aber es funktioniert.

Was so nicht passt, sind die Weights.
Java:
constraints.weightx = 0.67;         // nimmt 2/3 horizontal des Objekts (hier frame-Objekt) ein auf dem es platziert ist
Das stimmt nicht grundsätzlich. Ist die Komponente die einzige in der Zeile, dann ist dieser weight-Wert 100%. Es muss noch eine zweite Komponente mit 0.33 geben, damit das klappt (ignorieren wir mal die Texte im Inneren, die ebenfalls einen Einfluss haben).
Edit: In diesem Fall ist das zwar gegeben, aber die Beschreibung ist so nicht vollständig. Man könnte auch 2 und 1 verwenden mit dem selben Ergebnis.
Um fix immer zwei Drittel zu kriegen, müsste man die interne Berechnung ausschalten, denk ich, vielleicht die ColumnWidths überschreiben.
 
Zuletzt bearbeitet:

darkcloud

Mitglied
Das Problem hat sich mittlerweile geklärt. Der Fehler lag darin die Position des Images in der paintComponent-Methode zu definieren. Stattdessen habe ich dies im Konstruktor der LowerPanel-Klasse gemacht und die paintComponent-Methode so gelassen wie sie ursprünglich war. Hat nun funktioniert
 

Neumi5694

Top Contributor
Ja, innerhalb von Paint-Methoden darf wirklich nur gezeichnet werden. Ändert man hier das Layout, wird Paint ja nochmals aufgerufen. Das hat schon zu ein paar hübschen Endlosschleifen geführt.
 

darkcloud

Mitglied
Danke, ich habe allerdings nun ein weiteres Problem. Ich möchte nun das

1. wenn ich das Bild bspw. nach rechts bewegt habe und ich nun auf das Bild klicke, dass das Bild für 3 Sekunden verschwindet. Anschließend soll es an der Stelle auftauchen, wo es verschwunden ist. Das Verschwinden klappt bereits, aber das Bild taucht jedesmal wieder an der Initialposition auf, sprich in der Mitte.

Lösungsansatz: Ich habe bei der mouseClicked-Methode die Position des Bildes zwischengespeichert. Sobald der Timer abgelaufen ist, sollte das Bild eigentlich an der gleichen Stelle wieder ausgegeben werden (ich übergebe dem imageLabel die imagePosition). Doch dies will irgendwie nicht klappen. Ich habe mir testweise die Positionen in der Konsole beim Start und nach dem Bewegen ausgeben lassen. Die Methode registriert auf jeden Fall eine Änderung in den Koordinaten, aber das Bild wird trotzdem nicht dort ausgegeben, wo es verschwunden ist.

2. das Bild soll nur dann verschwinden, wenn ich auf das imageLabel klicke. Klicke ich nun aber auf das balue Panel, verschwindet das Bild ebenfalls.

Lösungsansatz. Ich habe in meinem Konstruktor bewusst nur dem ImageLabel den MouseListener übergeben. Aber es funktioniert sowohl beim klicken auf das Image als auch beim Klicken auf das Panel. Was muss ich da tun?

Mein aktueller Code:

Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import javax.swing.Timer;

public class LowerPanel extends JPanel {
   

    JLabel imageLabel;
    private Timer timer;
    private Point imagePosition;
   

    public LowerPanel(){
        setBackground(Color.BLUE);

        ImageIcon originalIcon = new ImageIcon("IMG-20220508-WA0017.jpg");  // zuerst Bild in ImageIcon-Objekt einfügen
        Image image = originalIcon.getImage().getScaledInstance(150, 150, Image.SCALE_SMOOTH);
        ImageIcon scaledIcon = new ImageIcon(image); // ImageObjekt zurück in ein ImageIcon-Objekt umwandeln damit es von JLabel Objekt getragen werden kann
        imageLabel = new JLabel(scaledIcon);

        setLayout(new BorderLayout());

       
       
        add(imageLabel, BorderLayout.CENTER); // Labelposition im Panel mit Image muss im Konstruktor definiert werden, würde man in paintComponent-Methode machen würde Bild nicht bewegen
       
       

         // Erstelle einen Maus-Adapter, um auf Klicks auf das Bild zu reagieren
         imageLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                imageLabel.setVisible(false);
                imagePosition = imageLabel.getLocation();
               
                timer.start();
               
            }
        });

        // Erstelle einen Timer, der nach 3 Sekunden das Bild wieder anzeigen soll
       
         timer = new Timer(3000, e -> {
            imageLabel.setLocation(imagePosition);
            imageLabel.setVisible(true);
           
        });

        // stelle ein, dass der Timer nur einmal ausgeführt wird
        timer.setRepeats(false);
    }



    public JLabel getImageLabel(){
        return imageLabel;
    }

}


import javax.swing.JFrame;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
import java.awt.event.*;



public class MyFrame extends JFrame implements ActionListener  {
 
// als Instanzvariable implementieren, da man sonst nicht mit getter-Methode in override auf die Objekte der jeweiligen Panels zugreifen könnte
UpperPanel uPanel;
LowerPanel lPanel;
SidePanel sPanel;
Timer timer;
Point imagePosition;

    public MyFrame(){
       
        setTitle("Frame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(630, 650);
        setResizable(true);
        setLocationRelativeTo(null);
       

        // neues Layout Manager Objekt und constraints Objekt erstellen, Layout dem Frame hinzufügen
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        setLayout(layout);

   


        // neue Panelobjekte erstellen
        uPanel = new UpperPanel();
        lPanel = new LowerPanel();
        sPanel = new SidePanel();

        // Zugriff auf Buttons der Panels mit getter-Methode und ActionListener Objekt hinzufügen
        uPanel.getButtonLeft().addActionListener(this);
        uPanel.getButtonRight().addActionListener(this);
        sPanel.getButtonUp().addActionListener(this);
        sPanel.getButtonDown().addActionListener(this);
   

       

        // Add UpperPanel to the layout
        constraints.gridx = 0;              // fängt oben links an mit diesen Einstellungen
        constraints.gridy = 0;
        constraints.gridwidth = 2;          // gridwith von diesem und SidePanel addiert sich insgesamt zu 3
        constraints.gridheight = 1;         // da gridheight von SidePanel 2 ist weiß Programm das Upper und Lower Panel 2 unterschiedliche Grids auf der 2/3 Seite sind
        constraints.weightx = 0.67;         // nimmt 2/3 horizontal des Objekts (hier frame-Objekt) ein auf dem es platziert ist
        constraints.weighty = 0.1;          // nimmt 1/10 vertikal des Objekts ein auf dem es paltziert ist
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(uPanel, constraints);
        add(uPanel);

        // Add LowerPanel to the layout
        constraints.gridx = 0;
        constraints.gridy = 1;
        constraints.gridwidth = 2;
        constraints.gridheight = 1;
        constraints.weightx = 0.67;
        constraints.weighty = 0.9;
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(lPanel, constraints);
        add(lPanel);

        // Add SidePanel to the layout

        constraints.gridx = 2;
        constraints.gridy = 0;
        constraints.gridwidth = 1;
        constraints.gridheight = 2;
        constraints.weightx = 0.33;
        constraints.weighty = 1;
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(sPanel, constraints);
        add(sPanel);


       

    setVisible(true);


    }

   

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == uPanel.getButtonLeft()){
            int currentX = lPanel.getImageLabel().getX();
            lPanel.getImageLabel().setLocation(currentX - 10, lPanel.getImageLabel().getY());
        }
       
        else if (e.getSource() == uPanel.getButtonRight()){
            int currentX = lPanel.getImageLabel().getX();
              lPanel.getImageLabel().setLocation(currentX + 10, lPanel.getImageLabel().getY());
                       
        }
       
        else if (e.getSource() == sPanel.getButtonUp()){
            int currentY = lPanel.getImageLabel().getY();
            lPanel.getImageLabel().setLocation(lPanel.getImageLabel().getX(), currentY - 10);        
        }
       
        else if (e.getSource() == sPanel.getButtonDown()){
            int currentY = lPanel.getImageLabel().getY();
            lPanel.getImageLabel().setLocation(lPanel.getImageLabel().getX(), currentY + 10);
    }

           
           
           

    }  

}
 

Neumi5694

Top Contributor
Da du Borderlayout verwendest, wird dein ImageLabel auf die gesamte Größe gestreckt. Es mag zwar transparent sein, aber es füllt trotzdem die gesamte Fläche aus.
Setz dein Imagelabel mal nicht auf transparent und gib ihm irgend eine gut sichtbare Farbe, damit du genau siehst, wo es sich befindet.


imageLabel.setLocation ... Das bringt dir bei einem Borderlayout nicht viel, um genau zu sein gar nichts. iI einem BorderLayout gibt's keine Location, die man irgendwie beeinflussen könnte.

Hier mal ein etwas anderer Ansatz.
Überschreibe die paintComponent Methode deines Labels. Das Label selbst kriegt überhaupt kein Icon, dieses zeichnest du in der paintComponent-Methode manuell mit drawImage an einer selbst spezifischen Position. Die Position des Labels wird niemals angepasst, dieses füllt immer die gesamte Fläche aus. Angepasst wird nur die Position, an welcher die Paintmethode das Icon zeichnen soll.



ps: Damit dein Clicklistener nur reagiert, wenn auf das Bild geklickt wurde, dann wertest du einfach die Mausposition im Listener aus, die dort relativ zum Label ankommt. Also x >= offset.x und x <= offset.x + image.width, genauso in y.

Noch was ... man könnte auch die Position des Icons innerhalb des Labels festlegen. Wäre vielleicht eine Alternative zu der selbstgeschriebenen paint-Methode. Aber dann könnte es sein, dass dir Border und Insets einen Strich durch die Rechnung machen, wenn es zur Auswertung der Position kommt. Einfach mal ausprobieren.

Ich würde außerdem empfehlen, UI-Logik und Ablauflogik zu trennen, aber das ist vor allem persönlicher Geschmack. Im Listener steht denn nur so was wie:
Java:
if(wasLeftMouseButton() && checkLocation(x, y) && isImageShown()) {
  hideImageAndStartTimer();
}
Das ist allerdings nur persönlicher Geschmack, erhöht meiner Meinung nach Lesbarkeit und Wartbarkeit.
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Ein Ansatz könnte ggf. auch sein, dass man erst ein JPanel einfügt. Das hat dann im Border Layout die ganze Größe. In dem JPanel kann man dann das JLabel so plazieren wie man will - und kann es auch bewegen und so.

Das war ja bereits der Punkt, den ich angemerkt hatte. Ich finde es halt etwas bedenklich, Komponenten zu nutzen, die eben Child Elemente positionieren nur um dann die Positionierung doch manuell machen zu wollen. Damit hat man zwei Konzepte, die sch ggf. gegenseitig beeinflussen können.
 

mihe7

Top Contributor
Ein Ansatz könnte ggf. auch sein, dass man erst ein JPanel einfügt. Das hat dann im Border Layout die ganze Größe. In dem JPanel kann man dann das JLabel so plazieren wie man will - und kann es auch bewegen und so.
Richtig.

Java:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;

public class Test {
    public void run() {
        JLabel label = new JLabel("<html>XXX<br>XXX</html>");        
        JPanel panel = new JPanel(null);
        panel.add(label);
        label.setBounds(0, 0, label.getPreferredSize().width, label.getPreferredSize().height);
        panel.setPreferredSize(new Dimension(800, 600));

        JSpinner xSpinner = new JSpinner(new SpinnerNumberModel(label.getX(), 0, panel.getPreferredSize().width, 10));
        JSpinner ySpinner = new JSpinner(new SpinnerNumberModel(label.getY(), 0, panel.getPreferredSize().height, 10));
        xSpinner.addChangeListener(event -> label.setLocation((int) xSpinner.getValue(), (int) ySpinner.getValue()));
        ySpinner.addChangeListener(event -> label.setLocation((int) xSpinner.getValue(), (int) ySpinner.getValue()));

        JPanel input = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
        input.add(createLabeled("X: ", xSpinner));
        input.add(createLabeled("Y: ", ySpinner));

        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.add(input, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    private JComponent createLabeled(String label, JComponent component) {
        JPanel panel = new JPanel();
        panel.add(new JLabel(label));
        panel.add(component);
        return panel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

darkcloud

Mitglied
Ein Ansatz könnte ggf. auch sein, dass man erst ein JPanel einfügt. Das hat dann im Border Layout die ganze Größe. In dem JPanel kann man dann das JLabel so plazieren wie man will - und kann es auch bewegen und so.
Was ist denn genau mit JPanel einfügen gemeint? Ich habe ja bereits die Klasse LowerPanel, welches im Frame eingefügt ist. Oder meinst du ich soll nochmal ein Panel in im LowerPanel einfügen? Und wie geht es dann weiter?

Da du Borderlayout verwendest, wird dein ImageLabel auf die gesamte Größe gestreckt. Es mag zwar transparent sein, aber es füllt trotzdem die gesamte Fläche aus.
Setz dein Imagelabel mal nicht auf transparent und gib ihm irgend eine gut sichtbare Farbe, damit du genau siehst, wo es sich befindet.


imageLabel.setLocation ... Das bringt dir bei einem Borderlayout nicht viel, um genau zu sein gar nichts. iI einem BorderLayout gibt's keine Location, die man irgendwie beeinflussen könnte.
Auch hier verstehe ich leider nicht genau was gemeint ist. Soweit ich das verstanden habe, unterteilt doch mein BLM in meinem Fall das LowerPanel-Objekt in 5 Bereiche und mit der Methode add füge ich das Label dem Panel zu und zentriere es in der Mitte. Und aufgrund des BLM ist keine Speicherung von Locations möglich? Ich habe nämlich mal den BLM entfernt und mit folgenden Formeln versucht mein Bild zu zentrieren:

Java:
        // Image einfügen
        ImageIcon originalIcon = new ImageIcon("IMG-20220508-WA0017.jpg");  // zuerst Bild in ImageIcon-Objekt einfügen
        Image image = originalIcon.getImage().getScaledInstance(150, 150, Image.SCALE_SMOOTH); 
        ImageIcon scaledIcon = new ImageIcon(image); // ImageObjekt zurück in ein ImageIcon-Objekt umwandeln damit es von JLabel Objekt getragen werden kann
        imageLabel = new JLabel(scaledIcon);
    

        // Image positionieren
        
        int labelWidth = imageLabel.getSize().width;
        int labelHeight = imageLabel.getSize().height;
        int x = (getWidth() - labelWidth) / 2;
        int y = (getHeight() - labelHeight) / 2;
        imageLabel.setBounds(x, y, labelWidth, labelHeight);
        
      
        
        add(imageLabel);

Kein BLM benutzt, aber das abspeichern der Locations funktioniert immernoch nicht, auch ohne einen LM. Problem hierbei war auch dass das Bild nicht im Zentrum des LowerPanels angezeigt wird sondern am oberen Rand in der Mitte. Ich habe auch nicht ganz verstanden, was mit dem nicht transparent (also setOpaque(true)) gemeint war. Lediglich die blaue Hintergrundfarbe wurde ausgeblendet.
Hier mal ein etwas anderer Ansatz.
Überschreibe die paintComponent Methode deines Labels. Das Label selbst kriegt überhaupt kein Icon, dieses zeichnest du in der paintComponent-Methode manuell mit drawImage an einer selbst spezifischen Position. Die Position des Labels wird niemals angepasst, dieses füllt immer die gesamte Fläche aus. Angepasst wird nur die Position, an welcher die Paintmethode das Icon zeichnen soll.
Wie kann ich den die paintComponent-Methode des Labels überschreiben. Ich hatte dies ja zuvor mit meinem Panel gemacht und da gab es die Probleme,. Müsste ich eine neue Klasse erstellen. Des Weiteren würde ich ungern manuell Größen eingeben (bis auf das des Frameobjekts). Dies ist nämlich die Vorgabe in der Aufgabenstellung.



Tut mir Leid, wenn ich nicht alles direkt verstehe, ich habe erst vor kurzem angefangen so wirklich zu coden.

Vielen Dank schonmal!
 

mihe7

Top Contributor
Was ist denn genau mit JPanel einfügen gemeint?
Wenn Du Dir den Code in #9 ansiehst, dann wird dort in Zeile 15 ein JPanel erzeugt, das ohne LayoutManager arbeitet. Alles, was Du in dieses JPanel einfügst, kannst Du frei positionieren bzw. musst Du sowohl Position als auch Größe der enthaltenen Komponenten selbst festlegen. In Zeile 31 wird dieses JPanel zum "content pane" des JFrame hinzugefügt. Dieser Container verwendet standardmäßig das BorderLayout. Weil in Zeile 31 kein Constraint beim add angegeben ist, wird das JPnael im Zentrum platziert.

Soweit ich das verstanden habe, unterteilt doch mein BLM in meinem Fall das LowerPanel-Objekt in 5 Bereiche und mit der Methode add füge ich das Label dem Panel zu und zentriere es in der Mitte. Und aufgrund des BLM ist keine Speicherung von Locations möglich?

Mal von hinten angefangen: Die Aufgabe des LayoutManagers ist es, den zur Verfügung stehenden Platz auf die Komponenten zur verteilen, die der Container (z. B. JPanel) enthält. Der LayoutManager legt also Position und Größe der Komponenten fest. Daher ist es ein Aufruf von setLocation auf einer Komponente, die sich in einem Container mit LayoutManager befindet, ziemlich sinnlos. Sobald der LayoutManager zuschlägt, wird die Location wieder geändert.

BorderLayout ist ein LayoutManager, der die zur Verfügung stehende Fläche in fünf Bereiche einteilt: das Zentrum, das von den vier Haupt-Himmelsrichtungen umgeben ist. Jeder dieser fünf Bereiche kann genau eine Komponente aufnehmen. Die Komponenten im Norden und Süden erhalten ihre bevorzugte Höhe, ihre Breite wird an die Breite des content pane angepasst. Analaog dazu erhalten die Komponenten im Osten und Westen ihre bevorzugte Breite und ihre Höhe wird an die Höhe des content pane angepasst. Im Zentrum entsteht so ein Bereich, der sowohl in der Breite als auch in der Höhe variiert. Die Komponente in Zentrum wird dem entsprechend in ihrer Größe angepasst.

Die Komponente im Zentrum wird also nicht zentriert, sondern erhält einfach den ganzen Platz, der nach Abzug der vier umgebenden Bereiche übrig bleibt.
 

mihe7

Top Contributor
OMG, die Deutschfehler sind ja schrecklich. Tippfehler wie JPnael -> JPanel will ich gar nicht erst aufführen, aber zwei Teile gehen ja gar nicht, hier mal die Korrekturen:
Alles, was Du in dieses JPanel einfügst, kannst Du frei positionieren; Du musst sowohl Position als auch Größe der enthaltenen Komponenten selbst festlegen.
Die Aufgabe des LayoutManagers ist es, den zur Verfügung stehenden Platz auf die Komponenten zu verteilen, die der Container (z. B. JPanel) enthält. [...] Daher ist ein Aufruf von setLocation auf einer Komponente, die sich in einem Container mit LayoutManager befindet, ziemlich sinnlos.

Noch eine Anmerkung zu den Ausführungen zur Anpassung von Breite und Höhe der "content pane" im Absatz, der mit "BorderLayout ist ein LayoutManager" beginnt: das bezieht sich die content pane des JFrame, wenn dieses ein BorderLayout verwendet. Tatsächlich stand der Absatz ursprünglich unter dem ersten, so dass der Zusammenhang klar war.
 

darkcloud

Mitglied
Ok danke schonmal für die Antwort. Ich habe jetzt verstanden, dass ich mit dem BLM nicht zum Ziel komme. Ich denke die JSpinner Klasse und das JPanel mit dem Input ist in diesem Fall irrelevant für mich, da es mir vermutlich nur zeigen soll, wie sich ein Label im Panel bewegt.

Ich habe nun versucht deinen Implementierung auf meinen Code zu übertragen. Zuerst erstellst du ja ein JLabel. Das gleiche mache ich auch, nur ich speichere noch mein ImageIcon drin. Als nächstes erzeugst du ein JPanel und setzt den LM auf null. Das gleiche mache ich auch (s.Z. 24). Nun sollte ich mein Label ja frei platzieren können. Dies versuche ich in Z.36-39. Die Idee dahinter: Wenn man bspw. davon ausgeht, dass das Panel 600x600 und das Label 150x150 hat, berechne ich für x und y jeweils 225(x225). Mit setBounds() übergebe ich dem Label die gewünschte Position (labelWidht und labelHeight brauche ich glaube ich nicht erklären). Am Ende übergebe ich das Labelobjekt dem Panel.

Was mich schonmal freut ist, dass die imagePosition Variable nun endlich dass macht was es soll. Nachdem das Image nach 3 Sekunden wieder auftaucht, "spawnt" es dann der Stelle, an welcher es verschwunden ist. Des Weiteren habe ich nicht mehr das Problem, dass das Bild auch dann verschwindet, wenn ich aufs Panel klicke. Es verschwindet jetzt nur noch dann, bei einem Klick auf das Bild.

Interessant dass beide Porbleme mit dem BorderLayout zusammenhingen: Wenn ich dass jetzt richtig verstehe, lag das einfach daran, dass das imageLabel quasi (ohne es zu sehen) das ganze Panel eingenommen hat, sodass ein Klick auf die blaue Hintergrundfläche auch gleichzeitig ein Klick auf das JLabel Objekt war? Und die imagePosition Variable konnte ihren Zweck nicht erfüllen, weil der BLM keinen Unterschied macht, ob es jetzt ein bisschen nach rechts oder links verschoben wird, weil es quasi immer in der Mitte ist?

Das einzige Problem aktuell ist noch die Initialposition des JLabel-Objekts. Wie oben bereits geschrieben, funktioniert die Positionierung in Z.36-Z.39 nicht. Versteht er eventuell nicht, wie groß das Panel sein muss? Ich habe jenes ja in meiner MyFrame Klasse mittels GridBagLayout bestimmt (ich poste es nochmal). Der Aktuelle Code:

Java:
import java.awt.Color;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import javax.swing.Timer;

public class LowerPanel extends JPanel {
   

    JLabel imageLabel;
    private Timer timer;
    private Point imagePosition;
   

    public LowerPanel(){
        setBackground(Color.BLUE);
        setLayout(null);
       

        // Image einfügen
        ImageIcon originalIcon = new ImageIcon("IMG-20220508-WA0017.jpg");  // zuerst Bild in ImageIcon-Objekt einfügen
        Image image = originalIcon.getImage().getScaledInstance(150, 150, Image.SCALE_SMOOTH);
        ImageIcon scaledIcon = new ImageIcon(image); // ImageObjekt zurück in ein ImageIcon-Objekt umwandeln damit es von JLabel Objekt getragen werden kann
        imageLabel = new JLabel(scaledIcon);
   
       

        // Image positionieren
        int labelWidth = imageLabel.getPreferredSize().width;
        int labelHeight = imageLabel.getPreferredSize().height;
        int x = (getWidth() - labelWidth) / 2;
        int y = (getHeight() - labelHeight) / 2;
        imageLabel.setBounds(x, y, labelWidth, labelHeight);
       
     
        add(imageLabel);// Labelposition im Panel mit Image muss im Konstruktor definiert werden, würde man in paintComponent-Methode machen würde Bild nicht bewegen
       
       
       

         // Erstelle einen Maus-Adapter, um auf Klicks auf das Bild zu reagieren
         imageLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                imageLabel.setVisible(false);
                imagePosition = imageLabel.getLocation();
               
                timer.start();
               
            }
        });

        // Erstelle einen Timer, der nach 3 Sekunden das Bild wieder anzeigen soll
       
         timer = new Timer(3000, e -> {
            imageLabel.setLocation(imagePosition);
            imageLabel.setVisible(true);
           
        });

        // stelle ein, dass der Timer nur einmal ausgeführt wird
        timer.setRepeats(false);
    }



    public JLabel getImageLabel(){
        return imageLabel;
    }

}


// Teil aus der MyFrame-Klasse

 // Add LowerPanel to the layout
        constraints.gridx = 0;
        constraints.gridy = 1;
        constraints.gridwidth = 2;
        constraints.gridheight = 1;
        constraints.weightx = 0.67;
        constraints.weighty = 0.9;
        constraints.fill = GridBagConstraints.BOTH;
        layout.setConstraints(lPanel, constraints);
        add(lPanel);


Nochmals Danke!
 

mihe7

Top Contributor
getWidth() dürfte 0 liefern, weil das JPanel zu diesem Zeitpunkt noch keine Größe hat (die wird ja erst durch den LayoutManager bestimmt).
 

darkcloud

Mitglied
Java:
import java.awt.Color;
import java.awt.Image;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import javax.swing.Timer;

public class LowerPanel extends JPanel {
    

    JLabel imageLabel;
    private Timer timer;

    
    

    public LowerPanel(){
        setBackground(Color.BLUE);
        setLayout(null); // um frei positionieren zu können
        

        // Image einfügen
        ImageIcon originalIcon = new ImageIcon("IMG-20220508-WA0017.jpg");  // zuerst Bild in ImageIcon-Objekt einfügen
        Image image = originalIcon.getImage().getScaledInstance(150, 150, Image.SCALE_SMOOTH); 
        ImageIcon scaledIcon = new ImageIcon(image); // ImageObjekt zurück in ein ImageIcon-Objekt umwandeln damit es von JLabel Objekt getragen werden kann
        imageLabel = new JLabel(scaledIcon);
    
        

        
        
      
        add(imageLabel);// Labelposition im Panel mit Image muss im Konstruktor definiert werden, würde man in paintComponent-Methode machen würde Bild nicht bewegen
        
        // benötigen ComponentListener damit LowerPanel Konstruktor weiß wie groß das LowerPanel, welches im MyFrame-Konstruktor definiert wurde, ist.
        addComponentListener(new ComponentAdapter() {   //mit Adapter lässt sich nur eine der ComponentListener Methoden implementieren statt alle
            public void componentResized(ComponentEvent e) {
                int labelWidth = imageLabel.getPreferredSize().width;
                int labelHeight = imageLabel.getPreferredSize().height;
                int x = (getWidth() - labelWidth) / 2;
                int y = (getHeight() - labelHeight) / 2;
                imageLabel.setBounds(x, y, labelWidth, labelHeight);
            }
        });
        

         // Erstelle einen Maus-Adapter, um auf Klicks auf das Bild zu reagieren
         imageLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                imageLabel.setVisible(false);
                timer.start();
                
            }
        });

        // Erstelle einen Timer, der nach 3 Sekunden das Bild wieder anzeigen soll
        
         timer = new Timer(3000, e -> {
            imageLabel.setVisible(true);
            
        });

        // stelle ein, dass der Timer nur einmal ausgeführt wird
        timer.setRepeats(false);
    }

 


    public JLabel getImageLabel(){ // für actionListener in MyFrame Klasse
        return imageLabel;
    }

}

Ich habe nun einen ComponentListener hinzugefügt. Dadurch (habe ich mir sagen lassen) versteht der LowerPanel-Konstruktor wie groß seine width und height ist, welche ja im MyFrame-Konstruktor definiert wird.

getWidth() dürfte 0 liefern, weil das JPanel zu diesem Zeitpunkt noch keine Größe hat (die wird ja erst durch den LayoutManager bestimmt).
Damit dürfte ich doch dieses Problem gelöst haben oder?

Es funktioniert jetzt auch alles wie es soll, allerdings ist mir aufgefallen, dass die imagePosition Variabel, die ich vorher benutzt hatte, gar nicht benötigt wird. Ich frage mich gerade, wie das Programm versteht, dass das Bild genau wieder da auftauchen soll, wo es verschwunden ist, ohne das ich die Position spezifisch abgespeichert habe? Ich vermute mal, dass die dies auch mit der componentResized-Methode geschieht?
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Mozart53 JLabel nur meinen Text verschieben ohne Image Allgemeine Java-Themen 3
Y Wie bekomme ich durch getImage an das Image heran? Allgemeine Java-Themen 1
J jsch direktes streamen in ein image Allgemeine Java-Themen 11
A 2D-Grafik Einfachster Ansatz, um sich wiederholende Figur in einem 2D-Image zu erkennen Allgemeine Java-Themen 1
T 2D-Grafik Chart als Image erstellen Allgemeine Java-Themen 3
G Image in Shape wandeln Allgemeine Java-Themen 1
T Swing Image rotieren Allgemeine Java-Themen 1
I nach Image Load in ListView, kann Ordner nicht mehr gelöscht werden Allgemeine Java-Themen 1
C pfad vom Image ausgeben lassen Allgemeine Java-Themen 5
Bananabert Swing jtree : image als user object Allgemeine Java-Themen 2
M Image auslesen Allgemeine Java-Themen 2
G Pixelanzahl aus Raw Image Datei Allgemeine Java-Themen 1
H OCR und Image Processing Allgemeine Java-Themen 4
M Image für PDF nicht verfügbar - Runnable .jar Allgemeine Java-Themen 3
S BLOB Image in JSP anzeigen Allgemeine Java-Themen 5
BRoll Image RGB Werte auslesen und vergleichen Allgemeine Java-Themen 8
K Image zu BufferedImage konvertieren Allgemeine Java-Themen 9
K Image beim catchen ist immer null Allgemeine Java-Themen 9
X Image Processing libary für JavaSE und Android Allgemeine Java-Themen 2
Crashbreaker RCP-View Image öffnen und darstellen Allgemeine Java-Themen 7
S IMAGE ARRAY laden Allgemeine Java-Themen 6
B Image oder GridControl? Allgemeine Java-Themen 8
B Image Thinning Allgemeine Java-Themen 3
A Input/Output Buffered Image zu Byte Array und zurück konvertieren Allgemeine Java-Themen 4
F Datentypen Floppy-Image-Dateisystem Allgemeine Java-Themen 5
F Image - Ausschnitt bekommen Allgemeine Java-Themen 3
J Teil eines Image/ImageIcon zeichnen Allgemeine Java-Themen 2
N Unable to convolve src image Allgemeine Java-Themen 7
H image in jtextarea/JLabel einbinden... Allgemeine Java-Themen 4
Aigu Bilderkennung / Image Analysis Allgemeine Java-Themen 2
M Nochmal I-Frame zu Image Allgemeine Java-Themen 4
M JPEG Image komprimieren Allgemeine Java-Themen 2
M Probleme mit Image Extraction aus PDF Allgemeine Java-Themen 2
V Image laden - URL über ClassLoader ermitteln Allgemeine Java-Themen 2
G sun.awt.image.OffScreenImage Serializable machen Allgemeine Java-Themen 5
T Image in gif umwandeln Allgemeine Java-Themen 14
G itext größe von image Allgemeine Java-Themen 2
T JPanel to Image? Allgemeine Java-Themen 6
K Image Resizer Allgemeine Java-Themen 4
D Image runterscalieren, aber schlechte Quali? Allgemeine Java-Themen 3
L Buffered Image teilweise zeichnen Allgemeine Java-Themen 6
P Image erzeugen Allgemeine Java-Themen 7
B Image libraries Allgemeine Java-Themen 3
MQue Image über Komponente Allgemeine Java-Themen 3
P Image auf JPanel auf JFrame Allgemeine Java-Themen 3
P Image auf einem Panel mit null-Layout Allgemeine Java-Themen 8
E Image unterscheiden Allgemeine Java-Themen 16
E Image auf einem JLabel darstellen Allgemeine Java-Themen 3
F BufferedImage -> Image Allgemeine Java-Themen 4
E Wie bekomme ich mein Image in das Fenster Allgemeine Java-Themen 2
T Muster/Zeichen/Texterkennung auf einem Image Allgemeine Java-Themen 9
L Linien, Recktecke und Elipsen zeichnen ohne Image Allgemeine Java-Themen 2
T Disk Image Library (iso,mdf,nrg,bin) Allgemeine Java-Themen 6
S KeyListener! Image Problem! Allgemeine Java-Themen 2
S Image als Background Allgemeine Java-Themen 5
B Image(png) versenden Allgemeine Java-Themen 3
N Image -> cropImage Allgemeine Java-Themen 3
T Image mithilfe von DirectColorModel und Pixel erstellen Allgemeine Java-Themen 3
G Image in der Größe ändern Allgemeine Java-Themen 2
C probleme mit image Allgemeine Java-Themen 4
C Pixelfarbe aus einem image auslesen Allgemeine Java-Themen 6
M Image Skalieren Allgemeine Java-Themen 23
D ByteArray für Image-Icon laden. Allgemeine Java-Themen 4
T iso datei (Image) mit Java einlesen und Inhalt entpacken Allgemeine Java-Themen 3
O Image mit transparenten farben wie bei *.GIF ? Allgemeine Java-Themen 3
B Image#getScaledInstance & Graphics2D#drawImage ClassCast Allgemeine Java-Themen 3
H Speicher freigeben klappt nicht bei Image Objekten, warum? Allgemeine Java-Themen 8
H Skalieren von Image -> java.lang.OutOfMemoryError - WARUM Allgemeine Java-Themen 18
T Auf ein Image geklickt Allgemeine Java-Themen 13
J ISO image erzeugen Allgemeine Java-Themen 3
J Wie mache ich den Hintergrund einer Image durchsichtig? Allgemeine Java-Themen 7
G Aus JPanel Image Hohlen Allgemeine Java-Themen 3
D BufferedReader in image umwandeln Allgemeine Java-Themen 3
S Image Datei serializieren Allgemeine Java-Themen 3
G JFrame nimmt mein Image nicht Allgemeine Java-Themen 2
F Image als GIF oder JPEG abspeichern Allgemeine Java-Themen 2
N Lwjgl 3d Objekt wird schmaler, wenn es sich dreht Allgemeine Java-Themen 0
S Java Programm lässt sich vom USB-Stick starten, aber nicht von HDD Allgemeine Java-Themen 16
A Eclipse hängt sich auf Allgemeine Java-Themen 7
Viper13125 Eclipse Hängt sich auf, wenn ich SimpelDateFormat drin lasse Allgemeine Java-Themen 2
L Java überprüfen lassen, ob sich ein gegebener Pfad / das Programm an sich auf einer CD oder Festplatte befindet Allgemeine Java-Themen 14
Tiago1234 Warum hängt sich mein Programm auf? Allgemeine Java-Themen 22
C Parsen einer sich updatenden Html mithilfe von jsoup Allgemeine Java-Themen 4
Kiki01 Häufigster Buchstabe lässt sich nicht ermitteln Allgemeine Java-Themen 30
Tobero Wie berechnet man ob zwei Linien sich schneiden? Allgemeine Java-Themen 2
T Projekt baut nicht mehr/lässt sich nicht mehr ausführen Allgemeine Java-Themen 6
Tobero Wie bekomme ich in welchem Quadrat sich eine Position in einem Grid befindet Allgemeine Java-Themen 11
O Jar lässt sich auf bestimmten Pc nicht starten Allgemeine Java-Themen 18
D Anfänger versucht sich an Xtext Allgemeine Java-Themen 0
F Sich automatisch aufrufende Java-Methoden Allgemeine Java-Themen 2
kodela Inhalt eines Arrays ändert sich mysteriös Allgemeine Java-Themen 2
P JavaFX Anwendung beendet sich selbst nur als Jar Allgemeine Java-Themen 40
Drachenbauer Wie finde ich den Aufrufer zu einer Methode, die sich nicht in meinem Projekt befindet? Allgemeine Java-Themen 2
M String lässt sich nicht Zusammenfügen Allgemeine Java-Themen 10
I Lohnt sich heutzutage der Aufwand einer Portierung für MacOS Allgemeine Java-Themen 8
G Jar lässt sich mit macOS nicht starten Allgemeine Java-Themen 9
H Erste Schritte Ausführbare Dateien lassen sich nicht starten Allgemeine Java-Themen 5
L Excel Datei löscht sich selbst im Programm - Java Allgemeine Java-Themen 3
K OOP Daten addieren sich bei GUI-Eingabe Allgemeine Java-Themen 10
K ursprüngliche ArrayList ändert sich bei Übergabe in Methode Allgemeine Java-Themen 18

Ähnliche Java Themen

Neue Themen


Oben