Cast eines Objektes in eine Hashmap

  • Themenstarter Themenstarter Nice Slider
  • Beginndatum Beginndatum
N

Nice Slider

Gast
Hoi!

Möchte gerade ein Objekt "Card" während eines ActionListenerEvents in eine Hashmap casten, was bei mir zu folgender Fehlermeldung führt:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JButton cannot be cast to mtg.Card

Projektname: mtg
Klassenname: Card

Die hashmap ist ein Private-Member:
Java:
private HashMap<String,Card> MainDeck;

Warum funktioniert dieser Cast nicht? Seltsamerweise funktioniert er sehr wohl wenn ich statt der Hashmap einen Vektor verwende....

Hier mal der relevante Code:

Java:
private class HandlerClass implements ActionListener {    
        @Override
        public void actionPerformed(ActionEvent event) {
            int answer = JOptionPane.showConfirmDialog(null, String.format("Do you want to add the Card \"%s\" to your Main Deck?", event.getActionCommand()));

            if (answer == 0) // Yes
            {
               JOptionPane.showMessageDialog(null, String.format("You pressed \"Yes\"! \n \"%s\" will be added to your Deck!", event.getActionCommand()));
               toMainObj.setMainDeck(event.getActionCommand(),(Card) event.getSource());   // add Card by cast Card in()
            }            
            if (answer == 1) // No
            {
                JOptionPane.showMessageDialog(null, String.format("You pressed \"No!\" \n \"%s\" will not be added to your Deck!", event.getActionCommand()));
            }
        }
    }
 
Man sollte eventuell noch hinzufügen dass "toMainObj" dazu dient auf das Objekt zugreifen zu können, welches die Hashmap enthält...dieses objekt enthält dann die setMainDeck-Funktion!

Java:
    public void setMainDeck(String str, Card c){
        MainDeck.put(str, c);
    }
 
Möchte gerade ein Objekt "Card" während eines ActionListenerEvents in eine Hashmap casten, was bei mir zu folgender Fehlermeldung führt:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JButton cannot be cast to mtg.Card
Kann sein, dass Du das möchtest ;-) aber Du versucht gerade ein JButton in ein Card Objekt zu casten.
Die Quelle eines ActionEvents ist i.d.R. ein JButton, JComboBox... ausser Du hast ein eigenes Objekt definiert welches ebenfalls ActionEvents feuern kann.
 
Die Quelle deines Events (getSource()) ist ein JButton, und ein Card-Objekt ist offensichtlich kein JButton. Deswegen kannst du das nicht casten. Du musst das Card-Objektauf eine andere weise identifizieren.
 
> Seltsamerweise funktioniert er sehr wohl wenn ich statt der Hashmap einen Vektor verwende....

fragwürdig erscheindende Behauptungen sieht man ziemlich häufig ohne Code, wobei ein vollständiges Programm noch überzeugender wäre,

die Zeile 3 des zweiten Postings kann auch auskomentiert werden, es ist völlig egal was diese Methode macht,
soweit kommt es gar nicht, der Fehler findet schon in der actionPerformed() statt, eben beim Cast

HashMap im Titel ist weit überbewertet, ist bedeutungslos
 
hmm die Buttons sind aber doch solche "Cards"... hätt ich eventuell auch erwähnen müssen? bekomme ich dann denn über die getSource-Methode nicht die Card??


Java:
// Code für EINE Karte
Icon ico = new ImageIcon(ConvertToImage(BI));
Card OneCard = new Card("Card", null, ico);
OneCard.addActionListener(new HandlerClass());
 
Java:
 if (answer == 0) // Yes
...
if (answer == 1) // No
Besser:
Java:
if(answer==JOptionPane.YES_OPTION)
Java:
if(answer==JOptionPane.NO_OPTION)
wobei man hier beim zweiten auch noch ein
Code:
else if
nutzen könnte, da ja nur eine der Bedingungen erfüllt sein kann.
 
> Seltsamerweise funktioniert er sehr wohl wenn ich statt der Hashmap einen Vektor verwende....

fragwürdig erscheindende Behauptungen sieht man ziemlich häufig ohne Code, wobei ein vollständiges Programm noch überzeugender wäre,

die Zeile 3 des zweiten Postings kann auch auskomentiert werden, es ist völlig egal was diese Methode macht,
soweit kommt es gar nicht, der Fehler findet schon in der actionPerformed() statt, eben beim Cast

HashMap im Titel ist weit überbewertet, ist bedeutungslos

Wenn du ernsthaft vor hast es zu lesen post ich dir gerne das ganze Programm ist nur leider schon sehr lang inzwischen 😉
 
nein ist abgeleitet von JPanel...ist das ein Problem? wie erhält man denn im Actionlistener über das event das Panel?

Hier mal der ganze Coder einer Card:

Java:
package mtg;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.Icon;

//-----------------------------------------
// CardClass
//-----------------------------------------
public class Card extends javax.swing.JPanel implements MouseListener {
    private static final long serialVersionUID = 3670910111612350552L;

    //  private Icon cardPicture;
    private String name;
    private Icon rollOver;
    private Icon normalPic;
    private ArrayList<ActionListener> listener = null;

    /**
     * Creates new form Card
     */
    public Card() {
        initListener();
        normalPic = new DefaultIcon();
        rollOver = new DefaultIcon();
        initComponents();
        setPicture();
    }

    public Card(String name, Icon rollOver, Icon normalPic) {
        initListener();
        this.normalPic = normalPic;
        this.rollOver = rollOver;
        this.name = name;
        initComponents();
        cardName.setText(name);
        setPicture();
        this.rollOverButton.setActionCommand(name);
    }

    private void setPicture() {
        rollOverButton.setRolloverEnabled(true);
        rollOverButton.setIcon(normalPic);
        rollOverButton.setRolloverIcon(rollOver);

    }
    private void initListener(){
        listener = new ArrayList<ActionListener>();
	addMouseListener(this);
    }

    public String getCardName() {
        return cardName.getText();
    }

    public Icon getNormalPic() {
        return normalPic;
    }

    public Icon getRollOver() {
        return rollOver;
    }

    /**
     * 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() {

        cardName = new javax.swing.JLabel();
        rollOverButton = new javax.swing.JButton();

        rollOverButton.setMaximumSize(new java.awt.Dimension(200, 279));
        rollOverButton.setMinimumSize(new java.awt.Dimension(200, 279));
        rollOverButton.setPreferredSize(new java.awt.Dimension(200, 279));
        rollOverButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                none(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(cardName, javax.swing.GroupLayout.PREFERRED_SIZE, 185, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addComponent(rollOverButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(rollOverButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cardName, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
    }// </editor-fold>                        

    private void none(java.awt.event.ActionEvent evt) {                      
        // TODO add your handling code here:
    }                     

    // Variables declaration - do not modify                     
    private javax.swing.JLabel cardName;
    private javax.swing.JButton rollOverButton;
    // End of variables declaration                   

    @Override
    public void mouseClicked(MouseEvent evt) {
        fireUpdate(new ActionEvent(this, 0, name));
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    protected void fireUpdate(ActionEvent evt) {
        for (ActionListener al : listener) {
            al.actionPerformed(evt);
        }
    }

    public void addActionListener(ActionListener al) {
        listener.add(al);
        this.rollOverButton.addActionListener(al);
    }

    public void removeActionListener(ActionListener al) {
        listener.remove(al);
    }
}
 
tja, die Lage ist offensichtlich, der Listener ist am rollOverButton,
warum sollte die Source das Panel/ die Card liefern?

eine einfache Bestimmung der Card vom rollOverButton gibt es auch nicht, da musst du irgendwas ergänzen,
von JButton doch erben zu CardButton, der seine Card kennt (Attribut), aber unschön,
eher gleich statt ActionListener eine neue erbende Klasse, die auch die Card als Attribut bekommt,

nicht groß originell anders, aber ein winziger leichgewichtiger Listener ist schneller vererbt und benutzt
als ein dickes Swing-Element mit hunderten internen Variablen


etwas direkte Arbeit wäre, irgendwo in einer eine Map von Button auf Panel zu verweisen, diese Verknüpfung also speziell abzuspeichern,
oder alle verfügbaren Panel anschauen und die dorigen Buttons mit dem aktuellen vergleichen
 
nein ist abgeleitet von JPanel...ist das ein Problem?
naja, beim Source Objekt handelt es sich ja um den JButton, selbst wenn ein Cast erfolgreich wäre hätte man ja das falsche Objekt.
wie erhält man denn im Actionlistener über das event das Panel?
Man könnte sich durch die Komponentenhierarchie "hochhangeln" - was m.M. aber eine eher unsaubere quick&dirty Lösung wäre.
Besser wäre es etwas mehr Aufwand in eine saubere Konzeption zu stecken. keine Ahnung was eine Card genau darstellen soll, aber hier könnte man mit einem eigenen Listener oder dem Oberver Pattern arbeiten.
 
Mal ne andere Idee:
Die Card ist im Listener
und jeder Button hat einen
eigenen Listener.
Nur so ne Idee...
edit:
Der Button kann immer der
gleiche bleiben und immer den
Listener Wechseln, wenn eine
Card gelegt wird.(Ich geh davon
aus , dass du ein Kartenspiel
machst, daher legen)
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben