[<< Contents] [<< Prev] [Next >>]
Here we are going to enhance our application to allow the user to move and delete previously placed radio stations. The user will be able to select a station by pointing at it with the mouse cursor and pressing the left button, while holding the button down move the station by moving the mouse, and releasing the station by releasing the mouse button. To allow the user to delete a station we will provide a context menu when the user presses the right button while pointing at a station.
To implement this functionality we will enhance our Scene class by implementing the inherited QGraphicsScene mouseMoveEvent, mouseReleaseEvent and contextMenuEvent virtual methods.
Add forward declarations for the classes QGraphicsSceneContextMenuEvent and Station.
class QGraphicsSceneContextMenuEvent; class Station; |
After the mousePressEvent declaration add the following lines to declare the mouseMoveEvent, mouseReleaseEvent and contextMenuEvent methods plus some private variables. The private variables will be used to track which station is being moved and where from.
void mouseMoveEvent( QGraphicsSceneMouseEvent* ); // receive mouse move events void mouseReleaseEvent( QGraphicsSceneMouseEvent* ); // receive mouse release events void contextMenuEvent( QGraphicsSceneContextMenuEvent* ); // receive context menu events private: Station* m_movingStation; // station being moved (otherwise zero ) qreal m_movingFromX; // station being moved original x coord qreal m_movingFromY; // station being moved original y coord |
Include the QGraphicsSceneContextMenuEvent, QMenu and QAction class header files.
#include <QGraphicsSceneContextMenuEvent> #include <QMenu> #include <QAction> |
Inside the constructor initialise the m_movingStation private variable to indicate no station currently being moved.
// initialise variables m_movingStation = 0; |
In the mousePressEvent method replace the lines after checking which button was pressed up to emitting the message with the new lines below. By using the inherited itemAt method this will check if the user is pointing at a station. If the user is pointing at a station the code records the starting position and returns, otherwise adds a new station to the scene.
// if existing station clicked, move it, otherwise create new
qreal x = event->scenePos().x();
qreal y = event->scenePos().y();
m_movingStation = dynamic_cast<Station*>( itemAt( x, y ) );
if ( m_movingStation )
{
m_movingFromX = m_movingStation->x();
m_movingFromY = m_movingStation->y();
return;
}
// create new Station at point where user clicked scene
addItem( new Station( x, y ) );
|
Add the code for the new method mouseMoveEvent. This code will be call everytime the mouse moves over the scene and if a station is being moved will move that station to the new mouse pointer position.
/********************************** mouseMoveEvent ***********************************/
void Scene::mouseMoveEvent( QGraphicsSceneMouseEvent* event )
{
// when moving a station, move it to new mouse position
qreal x = event->scenePos().x();
qreal y = event->scenePos().y();
if ( m_movingStation ) m_movingStation->setPos( x, y );
}
|
Add the code for the new method mouseReleaseEvent. When the user releases the button, we need to set the m_movingStation variable back to zero and emit a message.
/********************************* mouseReleaseEvent *********************************/
void Scene::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
{
// if moving a station, release it when mouse button released
if ( m_movingStation )
{
qreal x = event->scenePos().x();
qreal y = event->scenePos().y();
m_movingStation = 0;
emit message( QString("Station moved from %1,%2 to %3,%4")
.arg(m_movingFromX).arg(m_movingFromY).arg(x).arg(y) );
}
}
|
Add the code for the new method contextMenuEvent. When the user presses the right mouse button over the scene this routine is called. We only want to display a context menu if currently not moving a station and user is pointing at a station. We then create a menu with just one option to delete the station. If the user selects this option we remove the station from the scene, delete the station from memory and emit a useful message.
/********************************* contextMenuEvent **********************************/
void Scene::contextMenuEvent( QGraphicsSceneContextMenuEvent* event )
{
// we only want to display a menu if not currently moving a station
if ( m_movingStation ) return;
// we only want to display a menu if station where user clicked scene
qreal x = event->scenePos().x();
qreal y = event->scenePos().y();
Station* station = dynamic_cast<Station*>( itemAt( x, y ) );
if ( station == 0 ) return;
// display context menu and action accordingly
QMenu menu;
QAction* deleteAction = menu.addAction("Delete Station");
if ( menu.exec( event->screenPos() ) == deleteAction )
{
removeItem( station );
delete station;
emit message( QString("Station deleted at %1,%2").arg(x).arg(y) );
}
}
|
The new code will automatically re-compile when you attempt to run the application. Play with the application adding, moving and deleting stations.
[<< Contents] [<< Prev] [Next >>]