Dibujar una imagen diferente para dos objetos de la misma clase

Tengo dos objetos, whitepawn y blackpawn, que son de tipo Piece. Todo acerca de estos dos objetos es igual excepto por la imagen utilizada. Actualmente este es el código que utilizo para dibujar el peón blanco,

void Pawn::paintEvent(QPaintEvent *)
{
    pixmap.load(":/whitepawn.png");

    QPainter paint(this);
    paint.drawPixmap(x, y, pixmap);
}

¿Hay alguna manera de usar una imagen diferente para blackpawn creando una nueva clase y anulando la función paintEvent de la nueva clase?

Editar: el título antiguo era para una pregunta diferente, ignóralo si lo viste.

preguntado el 28 de agosto de 11 a las 02:08

2 Respuestas

Seguro que puedes

class Pawn {
    public:
    virtual char const* imageFileName() = 0;
};

Lo siento, fui escasa en la explicación la última vez e hice que pareciera que no había clases adicionales, realmente debería haber:

class WhitePawn : public Pawn {
    public:
    virtual char const* imageFileName();
};

Luego anula (+ declaración):

char const* WhitePawn::imageFileName() { return "./whitepawn.png"; }

char const* BlackPawn::imageFilename() { return "./blackpawn.png"; }

y llama imageFilename() desde paintEvent():

void Pawn::paintEvent(QPaintEvent *)
{
    pixmap.load(imageFilename());

    QPainter paint(this);
    paint.drawPixmap(x, y, pixmap);
}

Pero personalmente me gusta la idea de Kerrek de convertirlo en una variable. Incluso podrías hacer eso sin hacer clases adicionales:

class Pawn {
    public:
    Pawn(char const *filename) : filename(filename) { }

    private:
    char const *filname;
};

Pawn whitePawn("./whitepawn.png");

Respondido 28 ago 11, 06:08

Muy bien, ¡mucho mejor que mi anulación de toda la función! En realidad, incluso podría convertir el nombre de archivo en una variable miembro ... Kerrek SB

Oh, pensé que solo las clases podían anular las funciones de las clases heredadas. ¡No sabía que se podían anular funciones para objetos específicos! Gracias, eso me ayuda mucho. - gsingh2011

@ gsingh2011 ¡Oh, no, lo malinterpreté! Pensé que BlackPawn y WhitePawn eran clases. No, desafortunadamente no funcionará solo para objetos. - Owen

Pero como dice Kerrek, podría convertirlo en una variable. - Owen

@Owen Oh, está bien. Me emocioné :( De todos modos, el método de Kerrek también es bueno. Y la mala interpretación fue mi culpa, quise decir que ambos "objetos" heredados de la clase "Pieza", no "Peón". - gsingh2011

Las funciones virtuales son la solución estándar aquí:

class Pawn
{
  virtual void paintEvent(QPaintEvent *) { }
  // ...
};

class WhitePawn : public Pawn
{
  virtual voidpaintEvent(QPaintEvent *)
  {
    pixmap.load(":/whitepawn.png");
    QPainter paint(this);
    paint.drawPixmap(x, y, pixmap);
  }
};

// similar for class BlackPawn

Ahora puedes llamar Pawn * p = new BlackPawn; p->paintEvent(e); y obtenga la función correcta. (El término aquí es "anular", no "sobrecargar", que es algo diferente).


Editar: al ver la excelente respuesta de Owen, otra idea que requiere cambiar los constructores es hacer que el nombre del archivo sea una variable miembro:

class Pawn
{
  public: Pawn(const std::string & filename = "") : m_filename(filename) { }
  void paintEvent(QPaintEvent *)
  {
    if (m_filename == "") return;

    pixmap.load(m_filename);
    QPainter paint(this);
    paint.drawPixmap(x, y, pixmap);
  }
  // ...
  private: std::string m_filename;
};

class BlackPawn : public Pawn
{
  public: BlackPawn() : Pawn(":/blackpawn.png") { }
};

Respondido 28 ago 11, 06:08

Sí, mi plan de respaldo fue su primer método, pero no quería hacer una clase separada para cada peón ya que son muy similares. Y tu segunda solución también es muy buena, pero de nuevo, estoy evitando clases adicionales. Editar: Resulta que Owen cometió un error, así que voy con tu segundo método. - gsingh2011

@gsingh: Bueno, no hay clases adicionales aquí, ya que dijiste que ya tienes las dos clases derivadas, pero cambiar la clase base es ciertamente más intrusivo que la idea de Owen con una función virtual que devuelve el valor de la cadena. - Kerrek SB

¡Ah, yo también entendí mal y pensé que ya tenías clases derivadas! OK, si tu no quiere clases derivadas, puede simplemente mantener la clase base de mi segundo ejemplo y poner el nombre del archivo en el constructor. - Kerrek SB

@Kerrer: En realidad, fue un error tipográfico de mi parte, mira el comentario en la publicación de Owen. Perdón. - gsingh2011

@gsingh: Ya veo. ¡Entonces no digas "heredar" en tu publicación! :-) - Kerrek SB

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.