Subclasificación de QGraphicsView y configuración de drawBackground

Estoy tratando de hacer una función similar a impoly (de matlab) en Qt. En este momento, tengo una subclase de QGraphicsView y configuré la función virtual "drawBackground" como:

void roiwindow::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->save();
painter->drawImage(rect, *refimage);
painter->restore();
}

Esto funciona muy bien y es básicamente exactamente lo que quiero en cuanto a la capa de fondo. Ahora, estoy tratando de agregar círculos que eventualmente actuarán como nodos para el polígono. Hice esto usando:

QGraphicsView *view = new QGraphicsView(this);
view->show();
QGraphicsEllipseItem *e1;
e1 = this->addEllipse(20, 20, 30, 30, QColor(0, 0, 0), Qt::white);
e1->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsMovable);

Esto es algo de lo que quiero. Pero existe el problema de que cuando hago clic y arrastro las elipses, el fondo de la elipse es una versión reducida de *refimage... Esto deja una especie de raya en la pantalla, pero desaparece cuando hago clic en otra ventana o minimizar la ventana. ¿QGraphicsItem también llama a drawBackground? Si es así, parece llamarlo solo cuando se arrastra el elemento. ¿Alguna sugerencia sobre cómo puedo codificar esto mejor? Gracias.

preguntado el 22 de mayo de 12 a las 21:05

Acabo de agregar una instrucción printf y se llama a la función drawbackground cuando se arrastra el elemento ... -

Dónde refimage ¿viene de? -

2 Respuestas

Las rayas se producen porque probablemente tenga QGraphicsView configurado en el valor predeterminado modo de actualización de ventana gráfica, cual es QGraphicsView::MinimalViewportUpdate. En este caso, necesita QGraphicsView::FullViewportUpdate. La razón es que cuando mueve elementos, el fondo detrás de ellos debe volver a dibujarse, pero cuando tiene MinimalViewportUpdate establecido, solo se volverán a dibujar los elementos (a menos que haya una actualización completa de la ventana gráfica, por ejemplo, al minimizar/maximizar la ventana).

contestado el 22 de mayo de 12 a las 21:05

Esto sería posible pero probablemente lento, ya que en cada actualización se escalaría y dibujaría toda la imagen. - lemes

@leemes Si hay muchos elementos en la escena, no necesariamente será más lento. Si hay pocos elementos en la escena, la diferencia de velocidad probablemente sea insignificante, si no completamente imperceptible. - Antonio

Imagine una escena de tamaño 1k x 1k píxeles con muchos elementos. Ahora mueve un elemento de tamaño 20 x 20 píxeles por 5 píxeles => redibujar 1 millón de píxeles frente a 100 píxeles de la imagen de fondo escalada es un factor de 10000 más el redibujado de los otros elementos. Para movimientos suaves del elemento arrastrado, este puede ser problemático Pero creo que depende del caso... - lemes

@leemes El OP está tratando de recrear impoly de MATLAB, en el que no solo hay nodos, sino también enlaces de conexión. En mi experiencia, los enlaces tienden a tener grandes rectas delimitadoras (porque generalmente son diagonales) a menos que te metas con la región delimitadora, lo cual es costoso. Así que creo que es poco probable que la escena contenga solo elementos pequeños. - Antonio

Esto resolvió el problema que estaba teniendo y me permitió mantener una imagen de fondo escalada. Voy a jugar con él solo para asegurarme de que no haya problemas de rendimiento. Gracias por la respuesta. - justinblaber

QGraphicsView::drawBackground se llama siempre que algo de la vista de gráficos debe volver a dibujarse. Esta algo podría ser más pequeño que la vista completa para un mejor rendimiento.

Ejemplo: cuando tiene un elemento rectangular, digamos 50 x 50 píxeles, dentro de una escena/vista más grande y mueve este rectángulo 20 píxeles a la derecha, solo la región cubierta por la posición anterior + nueva del elemento (70 x 50 píxeles) se vuelve a dibujar (ya que esta es la región que cambia).

En su reimplementación de drawBackground, tu dices:

painter->drawImage(rect, *refimage);

que en realidad dibuja la imagen en y en el tamaño de la región a actualizar, no el tamaño total de la vista.

Para dibujar la imagen cada vez en la misma posición y en el mismo tamaño, puede usar una posición constante (por ejemplo, el origen) y no cambiar el tamaño de la imagen:

painter->drawImage(0, 0, *refimage);

o podría usar toda la región de la escena:

painter->drawImage(sceneRect(), *refimage);

sin que importe sceneRect() se define como el mismo rect que usa su escena para toda la escena. Este rect se actualiza automáticamente cuando agrega contenido nuevo que estaría fuera del rect. También puede forzar una rectificación de escena configurándola manualmente en un valor, por ejemplo:

scene()->setSceneRect(0, 0, 800, 800);

Ver documentación: QGraphicsView::sceneRect y QGraphicsScene::sceneRect

contestado el 22 de mayo de 12 a las 22:05

Gracias por la respuesta. Lo probé y funciona muy bien. El único problema es que el fondo no se ajusta al tamaño de la ventana. Me gustaría que el tamaño de la ventana sea redimensionable, pero si esto genera problemas en el futuro, podría volver a esta solución. Gracias por la respuesta. - justinblaber

¿Desea que su fondo sea estático e independiente del desplazamiento, es decir, siempre dibujado en la misma posición de la pantalla (y en el tamaño de la vista visible) en lugar de en la posición de la escena (y en el tamaño de la escena)? Si es así, esta no es la solución correcta. - lemes

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