Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Bearer Cloud Example

Files:

The Bearer Cloud example shows how to use the Bearer Management API to monitor the connectivity state of the local device.

Screenshot of the Bearer Cloud example

Bearer Management provides the QNetworkConfigurationManager class which can be used to monitor changes in the available network configurations and the QNetworkSession class which is used to open and close a session bringing a network interface up or down if necessary.

This example displays all known network configurations in a cloud orbiting the local device. There are four orbits representing the four possible states that the network configuration can be in. The closer the orbit the more useful the network configuration is in its current state. The inner orbit is populated with network configurations that are in the Active state. The second orbit is populated with network configurations that are in the Discovered state. The third orbit is populated with network configurations that are in the Defined state. Finally the outer orbit is populated by configurations that are in the Undefined state.

Hovering the mouse over a network configuration will display information about the network configuration in a tool tip.

Double clicking on an Active or Discovered network configuration will close or open a network session, respectively.

Lastly you can reorganize the cloud without changing the state of the network configurations by dragging them around.

This example consists of two main classes, the BearerCloud and Cloud classes. The Cloud class represents a single network session and associated network configuration. The BearerCloud class implements a Graphics View scene and manages the life-cycle of Cloud objects in response to notification signals from QNetworkConfigurationManager.

Setting the scene

When constructing the scene we first calculate some random offsets using the global qsand() and qrand() functions. We will use these offsets to scatter the initial position of new Cloud objects.

Next we place a text item in the center of the scene to represent the local device and surround it with four concentric circles to help visualize the orbits.

Finally we connect up the network configuration notification signals and queue the initial population of the scene during the next iteration of the event loop.

 BearerCloud::BearerCloud(QObject *parent)
 :   QGraphicsScene(parent), timerId(0)
 {
     setSceneRect(-300, -300, 600, 600);

     qsrand(QDateTime::currentDateTime().toTime_t());

     offset[QNetworkConfiguration::Active] = 2 * M_PI * qrand() / RAND_MAX;
     offset[QNetworkConfiguration::Discovered] = offset[QNetworkConfiguration::Active] + M_PI / 6;
     offset[QNetworkConfiguration::Defined] = offset[QNetworkConfiguration::Discovered] - M_PI / 6;
     offset[QNetworkConfiguration::Undefined] = offset[QNetworkConfiguration::Undefined] + M_PI / 6;

     thisDevice = new QGraphicsTextItem(QHostInfo::localHostName());
     thisDevice->setData(0, QLatin1String("This Device"));
     thisDevice->setPos(thisDevice->boundingRect().width() / -2,
                        thisDevice->boundingRect().height() / -2);
     addItem(thisDevice);

     qreal radius = Cloud::getRadiusForState(QNetworkConfiguration::Active);
     QGraphicsEllipseItem *orbit = new QGraphicsEllipseItem(-radius, -radius, 2*radius, 2*radius);
     orbit->setPen(QColor(Qt::green));
     addItem(orbit);
     radius = Cloud::getRadiusForState(QNetworkConfiguration::Discovered);
     orbit = new QGraphicsEllipseItem(-radius, -radius, 2*radius, 2*radius);
     orbit->setPen(QColor(Qt::blue));
     addItem(orbit);
     radius = Cloud::getRadiusForState(QNetworkConfiguration::Defined);
     orbit = new QGraphicsEllipseItem(-radius, -radius, 2*radius, 2*radius);
     orbit->setPen(QColor(Qt::darkGray));
     addItem(orbit);
     radius = Cloud::getRadiusForState(QNetworkConfiguration::Undefined);
     orbit = new QGraphicsEllipseItem(-radius, -radius, 2*radius, 2*radius);
     orbit->setPen(QColor(Qt::lightGray));
     addItem(orbit);

     connect(&manager, SIGNAL(configurationAdded(QNetworkConfiguration)),
             this, SLOT(configurationAdded(QNetworkConfiguration)));
     connect(&manager, SIGNAL(configurationRemoved(QNetworkConfiguration)),
             this, SLOT(configurationRemoved(QNetworkConfiguration)));
     connect(&manager, SIGNAL(configurationChanged(QNetworkConfiguration)),
             this, SLOT(configurationChanged(QNetworkConfiguration)));

     QTimer::singleShot(0, this, SLOT(updateConfigurations()));
 }

Populating the scene with the initial list of known network configuration is easy. Iterate over the list returned by QNetworkConfigurationManager::allConfigurations(), calling our configurationAdded() slot on each one.

We finishing off by calling cloudMoved() to ensure that animations are started.

 void BearerCloud::updateConfigurations()
 {
     QList<QNetworkConfiguration> allConfigurations = manager.allConfigurations();

     while (!allConfigurations.isEmpty())
         configurationAdded(allConfigurations.takeFirst());

     cloudMoved();
 }

The configurationAdded() slot gets called when a new network configuration is added to the system.

It stores the identifier of the network configuration in the configStates map, which is used to keep a count of the number of network configurations in each state. This in turn is used to calculate the initial position of new Cloud objects.

Next we create a new Cloud object for this network configuration. Set its initial position and store it in the configurations hash.

The last step is to add it to the scene by calling QGraphicsScene::addItem().

 void BearerCloud::configurationAdded(const QNetworkConfiguration &config)
 {
     const QNetworkConfiguration::StateFlags state = config.state();

     configStates.insert(state, config.identifier());

     const qreal radius = Cloud::getRadiusForState(state);
     const int count = configStates.count(state);
     const qreal angle = 2 * M_PI / count;

     Cloud *item = new Cloud(config);
     configurations.insert(config.identifier(), item);

     item->setPos(radius * cos((count-1) * angle + offset[state]),
                  radius * sin((count-1) * angle + offset[state]));

     addItem(item);

     cloudMoved();
 }

The configurationRemoved() slot gets called when a network configuration is removed from the system.

First we remove all references to the network configuration from the configStates and configurations member variables.

Next we initiate animation by setting a final scale value on the Cloud object associated with the removed network configuration.

Finally we flag the Cloud object to delete itself after it has finished animating.

 void BearerCloud::configurationRemoved(const QNetworkConfiguration &config)
 {
     foreach (const QNetworkConfiguration::StateFlags &state, configStates.uniqueKeys())
         configStates.remove(state, config.identifier());

     Cloud *item = configurations.take(config.identifier());

     item->setFinalScale(0.0);
     item->setDeleteAfterAnimation(true);

     cloudMoved();
 }

The Cloud object will take care of most of the work required when a network configuration changes. All we do in the configurationChanged() slot is update the configStates member variable.

 void BearerCloud::configurationChanged(const QNetworkConfiguration &config)
 {
     foreach (const QNetworkConfiguration::StateFlags &state, configStates.uniqueKeys())
         configStates.remove(state, config.identifier());

     configStates.insert(config.state(), config.identifier());

     cloudMoved();
 }

Responding to changes

Each network session and associated network configuration known to the system is represented in the scene as a Cloud object.

In the Cloud constructor we first initialize member variables. Then we create a new QNetworkSession object bound to the network configuration. Next we connect the QNetworkSession signals which we use to monitor it for state changes.

Next we set some QGraphicsItem properties. The QGraphicsItem::ItemIsMovable flag enables mouse interaction with the Cloud object.

The Cloud object consists of an icon and a text caption, these are constructed here. We will assign values to them later, as these will change as the sessions state changes.

Next we set the initial animation state and call our newConfigurationActivated() slot to finish setting up the Cloud object based on the state of network session.

 Cloud::Cloud(const QNetworkConfiguration &config, QGraphicsItem *parent)
 :   QGraphicsItem(parent), configuration(config), deleteAfterAnimation(false)
 {
     session = new QNetworkSession(configuration, this);
     connect(session, SIGNAL(newConfigurationActivated()),
             this, SLOT(newConfigurationActivated()));
     connect(session, SIGNAL(stateChanged(QNetworkSession::State)),
             this, SLOT(stateChanged(QNetworkSession::State)));

     setFlag(ItemIsMovable);
 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
     setFlag(ItemSendsGeometryChanges);
 #endif
     setZValue(1);

     icon = new QGraphicsSvgItem(this);
     text = new QGraphicsTextItem(this);

     currentScale = 0;
     finalScale = 1;
     setTransform(QTransform::fromScale(currentScale, currentScale), false);
     setOpacity(0);

     newConfigurationActivated();
 }

The newConfigurationActivated() slot is called when a session has successfully roamed from one access point to another.

The first thing we do is set the icon, inserting it into a shared SVG renderer cache if it is not already available. Next we set the text caption to the name of the network configuration.

We then set the position of the icon and text caption so that they are centered horizontally.

Finally we call our stateChanged() slot.

 void Cloud::newConfigurationActivated()
 {
     QNetworkConfiguration::BearerType bearerType = configuration.bearerType();
     if (!svgCache.contains(bearerType)) {
         QSvgRenderer *renderer = 0;
         switch (bearerType) {
         case QNetworkConfiguration::BearerWLAN:
             renderer = new QSvgRenderer(QLatin1String(":wlan.svg"));
             break;
         case QNetworkConfiguration::BearerEthernet:
             renderer = new QSvgRenderer(QLatin1String(":lan.svg"));
             break;
         case QNetworkConfiguration::Bearer2G:
             renderer = new QSvgRenderer(QLatin1String(":cell.svg"));
             break;
         case QNetworkConfiguration::BearerBluetooth:
             renderer = new QSvgRenderer(QLatin1String(":bluetooth.svg"));
             break;
         case QNetworkConfiguration::BearerCDMA2000:
         case QNetworkConfiguration::BearerWCDMA:
         case QNetworkConfiguration::BearerHSPA:
             renderer = new QSvgRenderer(QLatin1String(":umts.svg"));
             break;
         default:
             renderer = new QSvgRenderer(QLatin1String(":unknown.svg"));
         }

         if (renderer)
             svgCache.insert(bearerType, renderer);
     }

     icon->setSharedRenderer(svgCache[bearerType]);

     if (configuration.name().isEmpty()) {
         text->setPlainText(tr("HIDDEN NETWORK"));
     } else {
         if (configuration.type() == QNetworkConfiguration::ServiceNetwork)
             text->setHtml("<b>" + configuration.name() + "</b>");
         else
             text->setPlainText(configuration.name());
     }

     const qreal height = icon->boundingRect().height() + text->boundingRect().height();

     icon->setPos(icon->boundingRect().width() / -2, height / -2);

     text->setPos(text->boundingRect().width() / -2,
                  height / 2 - text->boundingRect().height());

     stateChanged(session->state());
 }

The stateChanged() slot is called when the session state changes.

In this slot we set lower the opacity of Cloud objects with network sessions that cannot be opened, and set a detailed tool tip describing the sessions state.

 void Cloud::stateChanged(QNetworkSession::State state)
 {
     if (configuration.name().isEmpty())
         finalOpacity = qreal(0.1);
     else if (session->state() == QNetworkSession::NotAvailable)
         finalOpacity = 0.5;
     else
         finalOpacity = 1.0;

 #if !defined(Q_WS_MAEMO_5) && !defined(Q_WS_MAEMO_6) && \
     !defined(Q_OS_SYMBIAN) && !defined(Q_OS_WINCE)
     QString tooltip;

     if (configuration.name().isEmpty())
         tooltip += tr("<b>HIDDEN NETWORK</b><br>");
     else
         tooltip += tr("<b>%1</b><br>").arg(configuration.name());

 #ifndef QT_NO_NETWORKINTERFACE
     const QNetworkInterface interface = session->interface();
     if (interface.isValid())
         tooltip += tr("<br>Interface: %1").arg(interface.humanReadableName());
     tooltip += tr("<br>Id: %1").arg(configuration.identifier());
 #endif

     const QString bearerTypeName = configuration.bearerTypeName();
     if (!bearerTypeName.isEmpty())
         tooltip += tr("<br>Bearer: %1").arg(bearerTypeName);

     QString s = tr("<br>State: %1 (%2)");
     switch (state) {
     case QNetworkSession::Invalid:
         s = s.arg(tr("Invalid"));
         break;
     case QNetworkSession::NotAvailable:
         s = s.arg(tr("Not Available"));
         break;
     case QNetworkSession::Connecting:
         s = s.arg(tr("Connecting"));
         break;
     case QNetworkSession::Connected:
         s = s.arg(tr("Connected"));
         break;
     case QNetworkSession::Closing:
         s = s.arg(tr("Closing"));
         break;
     case QNetworkSession::Disconnected:
         s = s.arg(tr("Disconnected"));
         break;
     case QNetworkSession::Roaming:
         s = s.arg(tr("Roaming"));
         break;
     default:
         s = s.arg(tr("Unknown"));
     }

     if (session->isOpen())
         s = s.arg(tr("Open"));
     else
         s = s.arg(tr("Closed"));

     tooltip += s;

     tooltip += tr("<br><br>Active time: %1 seconds").arg(session->activeTime());
     tooltip += tr("<br>Received data: %1 bytes").arg(session->bytesReceived());
     tooltip += tr("<br>Sent data: %1 bytes").arg(session->bytesWritten());

     setToolTip(tooltip);
 #else
     Q_UNUSED(state);
 #endif
 }

In our reimplementation of the QGraphicsItem::mouseDoubleClickEvent() function we call QNetworkSession::open() or QNetworkSession::close() to open or close the session in response to a double left click.

 void Cloud::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton) {
         if (session->isOpen())
             session->close();
         else
             session->open();

         event->accept();
     }
 }

As we support the user dragging Cloud objects around we need to restart animations when the position of the Cloud object changes. This is accomplished by reimplementing the QGraphicsItem::itemChanged() function and calling the cloudMoved() function of the BearerCloud object.

 QVariant Cloud::itemChange(GraphicsItemChange change, const QVariant &value)
 {
     switch (change) {
     case ItemPositionHasChanged:
         if (BearerCloud *bearercloud = qobject_cast<BearerCloud *>(scene()))
             bearercloud->cloudMoved();
     default:
         ;
     };

     return QGraphicsItem::itemChange(change, value);
 }

The remainder of the code for the Cloud object implements the animations. The calculateForces() function calculates the new position of the Cloud object based on the position of all the other Cloud objects in the scene. The new position is set when the advance() function is called to update the Cloud object for the current animation frame.

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 94
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  4. Pourquoi les programmeurs sont-ils moins payés que les gestionnaires de programmes ? Manquent-ils de pouvoir de négociation ? 42
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 9
  7. Qt Commercial : Digia organise un webinar gratuit le 27 mars sur la conception d'interfaces utilisateur et d'applications avec le framework 0
Page suivante

Le blog Digia au hasard

Logo

Créer des applications avec un style Metro avec Qt, exemples en QML et C++, un article de Digia Qt traduit par Thibaut Cuvelier

Le blog Digia est l'endroit privilégié pour la communication sur l'édition commerciale de Qt, où des réponses publiques sont apportées aux questions les plus posées au support. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web