[<< Contents] [<< Prev] [Next >>]
Here we enable the user to load simulation data from XML format files saved previously. We add a new File menu action "Open ...", use QFileDialog functionality to let the user select the file to be read, and use QXmlStreamReader functionality to read the XML file contents.
We need to add a public slot to receive the signal when user selects the new menu action.
bool fileOpen(); // load simulation file returning true if successful |
Include the header file for the QXmlStreamReader functionality.
#include <QXmlStreamReader> |
In the constructor just above were we previously created the save action, create and add the new open action to the File menu.
QAction* openAction = fileMenu->addAction( "&Open ...", this, SLOT(fileOpen()) ); |
Set the keyboard shortcut.
openAction->setShortcut( QKeySequence::Open ); |
Now add the code for the new public slot. In this slot we ask the user for the filename and location of the file, check we can read the file, and then process the file using QXmlStreamReader functionality. The simulation data is loaded into a new scene that is swapped with the old scene if no errors are encountered. First we look for the "qsimulate" element and then call a new scene method to read the remainder. The slot returns true if a XML file was successfully read, otherwise it returns false.
/************************************* fileOpen **************************************/
bool MainWindow::fileOpen()
{
// get user to select filename and location
QString filename = QFileDialog::getOpenFileName();
if ( filename.isEmpty() ) return false;
// open the file and check we can read from it
QFile file( filename );
if ( !file.open( QIODevice::ReadOnly ) )
{
showMessage( QString("Failed to open '%1'").arg(filename) );
return false;
}
// open an xml stream reader and load simulation data
QXmlStreamReader stream( &file );
Scene* newScene = new Scene( m_undoStack );
while ( !stream.atEnd() )
{
stream.readNext();
if ( stream.isStartElement() )
{
if ( stream.name() == "qsimulate" )
newScene->readStream( &stream );
else
stream.raiseError( QString("Unrecognised element '%1'").arg(stream.name().toString()) );
}
}
// check if error occured
if ( stream.hasError() )
{
file.close();
showMessage( QString("Failed to load '%1' (%2)").arg(filename).arg(stream.errorString()) );
delete newScene;
return false;
}
// close file, display new scene, delete old scene, and display useful message
file.close();
m_undoStack->clear();
QGraphicsView* view = dynamic_cast<QGraphicsView*>( centralWidget() );
view->setScene( newScene );
delete m_scene;
m_scene = newScene;
showMessage( QString("Loaded '%1'").arg(filename) );
return true;
}
|
Add a forward declaration for the QXmlStreamReader class.
class QXmlStreamReader; |
Add the declaration for the new public scene method that reads the simulation data from a QXmlStreamReader.
void readStream( QXmlStreamReader* ); // read scene data from xml stream |
Include the header file for QXmlStreamReader.
#include <QXmlStreamReader> |
Add the code for our new scene method. This method creates a new scene station for each "station" element found in the XML stream and sets its x & y coordinates according to any XML attributes found.
/************************************ readStream *************************************/
void Scene::readStream( QXmlStreamReader* stream )
{
// read station data from xml stream
while ( !stream->atEnd() )
{
stream->readNext();
if ( stream->isStartElement() && stream->name() == "station" )
{
qreal x = 0.0, y = 0.0;
foreach( QXmlStreamAttribute attribute, stream->attributes() )
{
if ( attribute.name() == "x" ) x = attribute.value().toString().toDouble();
if ( attribute.name() == "y" ) y = attribute.value().toString().toDouble();
}
addItem( new Station( x, y ) );
}
}
}
|
The new code will automatically re-compile when you attempt to run the application. Play with the application and load some of the files you saved earlier.
[<< Contents] [<< Prev] [Next >>]