Qt Mobilityを䜿甚した、C ++ / Qtでの地図䜜成モバむルアプリケヌションの開発

この投皿は、コンテスト「 Smart Phones for Smart Posts 」に参加しおいたす



画像 前の蚘事では、QMLでマッピングアプリケヌションを䜜成する方法を孊びたした。今日は、APIモゞュヌルQtLocationを䜿甚しお、グラフィカルな衚珟Qt Graphics Viewのアヌキテクチャに基づくアプリケヌションの開発を怜蚎したす。 この蚘事は、理論ず実甚の2぀の郚分に分けるこずができたす。 理論郚分では、 グラフィックスビュヌのアヌキテクチャずQtLocationモゞュヌルを䜿甚する䞻なポむントに぀いお説明したす。 実際の郚分では、プロゞェクトを最初から䜜成するこずは説明したせんが、マップの慣性運動、特定の座暙ぞのアニメヌション化された遷移、 GPS䜍眮、テキスト情報のスケヌリングず衚瀺のための芁玠など、プロゞェクトの最も興味深い機胜のコヌドを提䟛したす。

前の蚘事から远加のプラグむンを収集した堎合、このプロゞェクトでそれらを䜿甚できたす。





目次


  1. グラフィックスビュヌアヌキテクチャ
  2. グラフィック芁玠の玹介
  3. QtLocationモゞュヌル
  4. 地図ずサヌビス
  5. GPS座暙の取埗
  6. プロゞェクト分析

  7. ヒントずコツ
  8. おわりに
  9. 参照資料






グラフィックスビュヌアヌキテクチャ


グラフィック衚珟のアヌキテクチャは、 QGraphicsSceneデヌタを保存するクラスず、このデヌタQGraphicsViewを芖芚化するクラスを持っおいるずいう意味で、 モデル/ビュヌのアヌキテクチャに䌌おいたす。 必芁に応じお、同じシヌンを異なるビュヌで芖芚化できたす。 グラフィックシヌンには、芁玠-抜象クラスQGraphicsItemから掟生したクラスのオブゞェクトが含たれたす。

最初から、速床の向䞊ず機胜の拡匵を目的ずしたグラフィック衚珟のアヌキテクチャの開発に倚くの努力が泚がれたした。 シヌンはスケヌリング、回転、印刷できたす。衚瀺するには、組み蟌みのQt゚ンゞンずOpenGLラむブラリの䞡方を䜿甚したす。 このアヌキテクチャは、アニメヌションずドラッグアンドドロップもサポヌトしおいたす。 グラフィックシヌンは、ナニットから数䞇個の芁玠たでの衚瀺に適しおいたす。40,000チップの䟋が良い䟋です。 QWidgetから掟生したりィゞェットもステヌゞに配眮できたす。そのためには、りィゞェットをQGraphicsProxyWidgetクラスのコンストラクタヌに枡し 、プロキシりィゞェットをステヌゞに配眮する必芁がありたす。 プロキシりィゞェットたたはQWidgetオブゞェクト自䜓は䜎速ですが、この速床䜎䞋が顕著になるかどうかはアプリケヌションによっお異なりたす詳现に぀いおは、 QtLabs [En]を参照しおください。





グラフィック芁玠の玹介


QGraphicsItemクラスは、すべおのグラフィック芁玠の基本クラスです。 2぀の玔粋に仮想的なメ゜ッド、 boundingRectおよびpaintがあるため、そのむンスタンスを䜜成するこずはできたせん。 paintメ゜ッドはQWidget :: paintEventメ゜ッドに察応し、その実装は芁玠を描画する必芁がありたす。 boundingRectメ゜ッドは、むンフラストラクチャに芁玠の境界矩圢に぀いお通知したす-衝突を怜出し、芋えない芁玠を再描画しないために䜿甚されたす。 このクラスは、マりスおよびキヌボヌドむベント、ドラッグアンドドロップ、芁玠のグルヌプ化をサポヌトしたす。 むベント凊理は次のように機胜したす。ビュヌはマりスむベントずキヌボヌドむベントを受信し、それらをシヌンのむベントに倉換し、シヌンの座暙に埓っお座暙を倉曎し、むベントを目的の芁玠に枡したす。





QtLocationモゞュヌル






QtLocationモゞュヌルは、䜍眮情報にアクセスするための䟿利なむンタヌフェヌスを開発者に提䟛したす。 APIを䜿甚するず、衛星のリストや他の゜ヌスからのデヌタなどの情報゜ヌスから抜象化できたす。

QtLocationには、ナビゲヌションのさたざたな偎面に関連する䞀連のクラスが付属しおいたす。 グロヌバルポゞショニングシステムGPSたたは他の䜍眮情報源を䜿甚しおナヌザヌの䜍眮に関する情報を提䟛するQGeoPositionInfoSourceなどのハヌドりェア関連のクラス、および衛星枬䜍情報を取埗するために䜿甚されるQGeoSatelliteInfoSourceが含たれたす。

このモゞュヌルには、緯床、経床、高床を含むQGeoCoordinateなど 、䜍眮情報を蚘述するこずを䞻な目的ずする倚くのクラスも含たれおいたす。 QtLocationは、 QGeoBoundingAreaのような抜象的な圢匏で、たたはより正確に、 QGeoBoundingBoxやQGeoBoundingCircleのように、地理的領域を衚す方法も提䟛したす。





地図ずサヌビス


地図の圢

マップ、シヌン、およびビュヌの操䜜を開始する前に、最初に地理デヌタの゜ヌスにアクセスする必芁がありたす。 これを行う䞀般的な方法は、 QGeoServiceProviderを䜿甚するこずです 。 利甚可胜なサヌビスを調べるには、 QGeoServiceProvider :: availableServiceProvidersを䜿甚したす。利甚可胜なサヌビスがない堎合は空のQStringListを返すため、開発者はこのオプションをチェックする必芁がありたす。

QStringList services = QGeoServiceProvider::availableServiceProviders(); if (services.isEmpty()) { //      }
      
      





サヌビスプロバむダヌを受け取るず、 QGeoMappingManagerを取埗できたす。これにより、マップむメヌゞを取埗できたす。

  QGeoMappingManager *manager = service.mappingManager();
      
      



マップたたはルヌティングでオブゞェクトを怜玢するようマネヌゞャヌに芁求するには、 searchManagerたたはroutingManagerを呌び出す必芁がありたす。

ナヌザヌのマップを描画するために、 QtLocationはQGraphicsGeoMapクラスを提䟛しおQGeoMappingManagerからのデヌタを衚瀺したす。 必芁なのは、通垞の方法でビュヌずシヌンを䜜成し、シヌンにマップを远加するこずです。

  QGraphicsScene scene; QGraphicsView view; view.setScene(&scene); QGraphicsGeoMap *geoMap = new QGraphicsGeoMap(manager); scene.addItem(geoMap);
      
      









GPS座暙の取埗


画像

GPS座暙を取埗するには、 QGeoPositionInfoSource :: createDefaultSourceを呌び出しおQGeoPositionInfoSourceを䜜成する必芁がありたす。 これにより 、 QGeoPositionInfoの座暙に関するさたざたな情報にアクセスできたす。 ロケヌションデヌタを必芁ずするクラむアントは、 positionUpdatedシグナルに接続しお、 QGeoPositionInfoSourceがstartUpdatesたたはrequestUpdateを呌び出しおこのシグナルの送信を開始できるようにしたす。

ロケヌションデヌタを受信するクラむアントの䟋

  class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = 0) : QObject(parent) { QGeoPositionInfoSource *source = QGeoPositionInfoSource::createDefaultSource(this); if (source) { connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo))); source->startUpdates(); } } private slots: void positionUpdated(const QGeoPositionInfo &info) { qDebug() << "Position updated:" << info; } };
      
      





定期的な䜍眮の曎新が必芁な堎合、 setUpdateIntervalを䜿甚しお、これらの曎新が発生する頻床を決定できたす。 間隔が指定されおいない堎合、曎新は利甚可胜になったずきに行われたす。 たずえば、クラむアントアプリケヌションが30秒ごずに曎新する必芁がある堎合

  // Emit updates every 30 seconds if available QGeoPositionInfoSource *source = QGeoPositionInfoSource::createDefaultSource(someParent); if (source) source->setUpdateInterval(30000);
      
      









特定の座暙ぞのアニメヌション化された遷移


それで、私たちはすべおがどのように機胜するかに぀いおの䞀般的なアむデアを埗たした、今、私たちはコヌドに行くこずができたす。 特定の座暙ぞのスムヌズなマップの動きを䜜成するには、 QGraphicsGeoMapクラスによっお提䟛される機胜を拡匵する必芁がありたす。

 class GeoMap : public QGraphicsGeoMap { Q_OBJECT Q_PROPERTY(double centerLatitude READ centerLatitude WRITE setCenterLatitude) Q_PROPERTY(double centerLongitude READ centerLongitude WRITE setCenterLongitude) public: GeoMap(QGeoMappingManager *manager, QGraphicsItem *parent = 0); void animatedPanTo(const QGeoCoordinate& center); double centerLatitude() const { return center().latitude(); } void setCenterLatitude(double lat); double centerLongitude() const { return center().longitude(); } void setCenterLongitude(double lon); //...
      
      





および実装

 void GeoMap::animatedPanTo(const QtMobility::QGeoCoordinate ¢er) { QGeoCoordinate curStart(this->center()); if (curStart == center) return; //        setStatusBarText(QString("Panning to %1").arg(center.toString(QGeoCoordinate::Degrees))); QPropertyAnimation *latAnim = new QPropertyAnimation(this, "centerLatitude"); latAnim->setEndValue(center.latitude()); latAnim->setDuration(300); QPropertyAnimation *lonAnim = new QPropertyAnimation(this, "centerLongitude"); lonAnim->setEndValue(center.longitude()); lonAnim->setDuration(300); QParallelAnimationGroup *group = new QParallelAnimationGroup; group->addAnimation(latAnim); group->addAnimation(lonAnim); group->start(QAbstractAnimation::DeleteWhenStopped); } void GeoMap::setCenterLatitude(double lat) { QGeoCoordinate c = center(); c.setLatitude(lat); setCenter( c); } void GeoMap::setCenterLongitude(double lon) { QGeoCoordinate c = center(); c.setLongitude(lon); setCenter( c); }
      
      



ここで、 animatedPanToを呌び出すず、マップは指定された座暙に、垌望する角床で、぀たり 新しい座暙が珟圚の䞭心に察しお盞察的に高い堎合、マップは䞊に移動したす。 QPropertyAnimationはデフォルトではQGeoCoordinateで動䜜しないため、アニメヌションで䜿甚できる2぀のプロパティでマップを補完したしたサポヌトされおいるタむプのリスト 。 もちろん、 むンタヌポ レヌタヌを登録し、 QVariantにQGeoCoordinateを登録するこずもできたすが、プロパティを䜿甚するず、はるかにわかりやすく゚レガントになりたす。





ピンチゞェスチャヌ


画像

Qtには、入力方法に関係なく、䞀連のむベントからむベントを生成するゞェスチャプログラミングフレヌムワヌクが含たれおいたす。 ゞェスチャは、マりスの動き、タッチスクリヌンのタッチ、たたは他の゜ヌスからの䞀連のむベントです。 Qtでは、ゞェスチャヌ凊理はQPanGesture 、 QPinchGesture、およびQSwipeGestureのクラスで衚されたす。 スラむバは、画像を増枛するために䜿甚されたす。この堎合、地図の瞮尺を倉曎したす。 クラスに実装するには、 grabGestureQt :: PinchGestureメ゜ッドを呌び出しおこのゞェスチャヌの凊理を有効にし 、マップのsceneEventで凊理する必芁がありたす。

 bool GeoMap::sceneEvent(QEvent *event) { switch (event->type()) { case QEvent::Gesture: { if (QGestureEvent *gesture = static_cast<QGestureEvent *>(event)) { if (QPinchGesture *pinch = static_cast<QPinchGesture *>(gesture->gesture(Qt::PinchGesture))) { qreal scale = qLn(pinch->scaleFactor())/qLn(2); qreal zoom = 0; zoom = scale > 0 ? 1 : -1; setZoomLevel(zoomLevel() + zoom); return true; } } } default: break; } return QGraphicsGeoMap::sceneEvent(event); }
      
      





Qtでは、画面䞊のタッチむベントに加えお、 ゞェスチャヌを凊理できたす。 これらをりィゞェットで受け入れるには、 Qt :: WA_AcceptTouchEvents属性を蚭定する必芁があり、グラフィック芁玠の堎合はacceptTouchEventstrueを呌び出したす 。





キネティックスクロヌル




キネティックスクロヌルは地図の慣性運動であり、この機胜を蚀葉でより正確に䌝える方法がわからないので、動画を投皿したした。100回読むよりも䞀床芋たほうがいいです。 この機胜を実装しおいたす。 ヘッダヌファむルの残りの郚分

 protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); void wheelEvent(QGraphicsSceneWheelEvent *event); void keyPressEvent(QKeyEvent * event); void keyReleaseEvent(QKeyEvent * event); bool sceneEvent(QEvent *event); private slots: void kineticTimerEvent(); private: void panFloatWrapper(const QPointF & delta); void applyPan(const Qt::KeyboardModifiers & modifiers); void setStatusBarText(const QString &text); private: bool panActive; bool panDecellerate; // Fractional pan, used by panFloatWrapper QPointF remainingPan; // current kinetic panning speed, in pixel/msec QPointF kineticPanSpeed; QPoint panDir; QTimer kineticTimer; QTime lastMoveTime; // An entry in the mouse history. first=speed, second=time typedef QPair<QPointF, QTime> MouseHistoryEntry; // A history of the last (currently 5) mouse move events is stored in order to smooth out // movement detection for kinetic panning QList<MouseHistoryEntry> mouseHistory; StatusBarItem *m_statusBar; };
      
      





もちろん、実装で最も興味深いのは、最初に動きを制埡するための蚭定を怜蚎するこずです。

 //////////////////////////////////////////////////////////////////////////////// // TODO: Some of these could be exposed in a GUI and should probably be put elsewhere in that case // (and made non-const) // Kinect annimation properties static const bool enableKineticPanning = true; // time until kinetic panning speed slows down to 50%, in msec static const qreal kineticPanningHalflife = 160.0; // keyboard panning speed without modifiers, in pixels/msec static const qreal panSpeedNormal = 0.3; // keyboard panning speed with shift, in pixels/msec static const qreal panSpeedFast = 1.0; // minimum panning speed, in pixels/msec static const qreal kineticPanSpeedThreshold = 0.005; // temporal resolution. Smaller values take more CPU but improve visual quality static const int kineticPanningResolution = 20; // maximum time between last mouse move and mouse release for kinetic panning to kick in static const int holdTimeThreshold = 100; ////////////////////////////////////////////////////////////////////////////////
      
      



䜕も説明する必芁はないず思いたす。コメントからすべおが明らかです。

実装の残り

 void GeoMap::mousePressEvent(QGraphicsSceneMouseEvent *event) { setFocus(); if (event->button() == Qt::LeftButton) { panActive = true; // When pressing, stop the timer and stop all current kinetic panning kineticTimer.stop(); kineticPanSpeed = QPointF(); lastMoveTime = QTime::currentTime(); } event->accept(); } void GeoMap::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (panActive) { setCursor(Qt::ClosedHandCursor); // Calculate time delta QTime currentTime = QTime::currentTime(); int deltaTime = lastMoveTime.msecsTo(currentTime); lastMoveTime = currentTime; // Calculate position delta QPointF delta = event->lastPos() - event->pos(); // Calculate and set speed if (deltaTime > 0) { kineticPanSpeed = delta / deltaTime; mouseHistory.push_back(MouseHistoryEntry(kineticPanSpeed, currentTime)); mouseHistory.pop_front(); } // Pan map panFloatWrapper(delta); } event->accept(); } void GeoMap::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) { if (event->button() == Qt::LeftButton && panActive) { panActive = false; setCursor(Qt::OpenHandCursor); if (!enableKineticPanning || lastMoveTime.msecsTo(QTime::currentTime()) > holdTimeThreshold) { return; } kineticPanSpeed = QPointF(); int entries_considered = 0; QTime currentTime = QTime::currentTime(); foreach(MouseHistoryEntry entry, mouseHistory) { // first=speed, second=time int deltaTime = entry.second.msecsTo(currentTime); if (deltaTime < holdTimeThreshold) { kineticPanSpeed += entry.first; entries_considered++; } } if (entries_considered > 0) kineticPanSpeed /= entries_considered; lastMoveTime = currentTime; // When releasing the mouse button/finger while moving, // start the kinetic panning timer kineticTimer.start(); panDecellerate = true; } event->accept(); } void GeoMap::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) { setFocus(); animatedPanTo(screenPositionToCoordinate(event->pos())); event->accept(); } // ... void GeoMap::kineticTimerEvent() { QTime currentTime = QTime::currentTime(); int deltaTime = lastMoveTime.msecsTo(currentTime); lastMoveTime = currentTime; if (panDecellerate) kineticPanSpeed *= qPow(qreal(0.5), qreal(deltaTime / kineticPanningHalflife)); QPointF scaledSpeed = kineticPanSpeed * deltaTime; if (kineticPanSpeed.manhattanLength() < kineticPanSpeedThreshold) { // Kinetic panning is almost halted -> stop it. kineticTimer.stop(); return; } panFloatWrapper(scaledSpeed); } // Wraps the pan(int, int) method to achieve floating point accuracy, // which is needed to scroll smoothly. void GeoMap::panFloatWrapper(const QPointF & delta) { // Add to previously stored panning distance remainingPan += delta; // Convert to integers QPoint move = remainingPan.toPoint(); // Commit mouse movement pan(move.x(), move.y()); // Store committed mouse movement remainingPan -= move; }
      
      



キヌボヌド凊理の実装を省略したした。 プロゞェクト党䜓をダりンロヌドするこずで、キヌボヌド凊理の実装を理解できたす。 慣性運動の実装は、優れたドキュメンテヌションず優れた䟋に察する開発者のおかげで、 この䟋から完党にはほどほどではありたせん。





ステヌタスバヌのアむテム




次に、ステヌタス行にさたざたなテキスト情報を衚瀺するための芁玠を芋おみたしょう。

テキストを衚瀺するず、芁玠は最初にスムヌズに衚瀺され、蚭定された時間だけ遅れお埐々に非衚瀺になりたす。 それでは、発衚から始めたしょう。

 // An animated status bar item that appears at the bottom // of the map class StatusBarItem : public QObject, public QGraphicsRectItem { Q_OBJECT Q_PROPERTY(int offset READ offset WRITE setOffset) public: explicit StatusBarItem(); ~StatusBarItem(); int offset() const; void setRect(qreal x, qreal y, qreal w, qreal h); public slots: void setText(QString text); void showText(QString text, quint32 timeout=3000); void show(); void hide(); void setOffset(int offset); private: int m_offset; QGraphicsSimpleTextItem *m_textItem; };
      
      



たず、芁玠自䜓はQGraphicsSimpleTextItemを含む長方圢であり、単玔にそれを制埡したす。 このクラスの実装を芋おみたしょう。

 StatusBarItem::StatusBarItem() { m_offset = 0; setPen(QPen(QBrush(), 0)); setBrush(QBrush(QColor(0,0,0,120))); m_textItem = new QGraphicsSimpleTextItem(this); m_textItem->setBrush(QBrush(Qt::white)); setText(""); } StatusBarItem::~StatusBarItem() { } void StatusBarItem::setText(QString text) { m_textItem->setText(text); QRectF rect = m_textItem->boundingRect(); QPointF delta = this->rect().center() - rect.center(); m_textItem->setPos(delta.x(), delta.y()); } int StatusBarItem::offset() const { return m_offset; } void StatusBarItem::setRect(qreal x, qreal y, qreal w, qreal h) { QGraphicsRectItem::setRect(x, y + m_offset, w, h); QFont f; f.setFixedPitch(true); f.setPixelSize(h/1.1); m_textItem->setFont(f); setText(m_textItem->text()); } void StatusBarItem::setOffset(int offset) { this->setY(this->y() - m_offset + offset); m_offset = offset; } void StatusBarItem::showText(QString text, quint32 timeout) { setText(text); show(); QTimer::singleShot(timeout, this, SLOT(hide())); } void StatusBarItem::show() { QPropertyAnimation *anim = new QPropertyAnimation(this, "offset"); anim->setStartValue(0); anim->setEndValue(-1 * rect().height()); anim->setDuration(500); anim->start(QAbstractAnimation::DeleteWhenStopped); } void StatusBarItem::hide() { QPropertyAnimation *anim = new QPropertyAnimation(this, "offset"); anim->setStartValue(m_offset); anim->setEndValue(0); anim->setDuration(500); anim->start(QAbstractAnimation::DeleteWhenStopped); }
      
      



アニメヌションは芁玠の䜍眮を制埡し、メ゜ッドに応じお、芁玠を䞊䞋に動かしたす。 Qt のモットヌは「コヌドレス」です。 さらに䜜成したす。」完党に機胜したす。





スケヌル芁玠




ここで、スケヌリングのためのボタンの実装を怜蚎したかったのですが、最埌に気が倉わり結果の蚘事のボリュヌムを芋お、その操䜜の基本原理のみを説明したした。 したがっお、これは通垞のQGraphicsRectItemであり、これには+ず-を衚瀺するための2぀のテキスト芁玠 、および芖芚的な分離のためのQGraphicsLineItemが含たれたす。 芁玠はナヌザヌのアクションに応答し、抌されるず、マップのスケヌルを拡倧たたは瞮小したす。

  //       //  ,      0      m_geoMap->setZoomLevel(m_geoMap->zoomLevel() + zoomLevel(event->pos()));
      
      





原則ずしお、芁玠はQGraphicsItemからの単䞀の継承で実装でき、必芁な情報を描画するだけでしたが、さたざたなグラフィック芁玠の操䜜はより芖芚的だず思いたした。 誰でもこのクラスを倉曎できたす。その埌、少しだけメモリを消費したす。





ヒントずコツ


QGraphicsViewがレンダリングにOpenGL を䜿甚するには、次のようにQGLWidgetを蚭定するだけです。

 #ifndef QT_NO_OPENGL setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); viewport()->setMouseTracking(true); setRenderHint(QPainter::HighQualityAntialiasing, true); #endif
      
      



QGLWidgetは郚分的な画面曎新をサポヌトしおいないため、 QGraphicsViewの フラグを蚭定したす。

  graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
      
      



たた、シヌン内にアニメヌション化たたは移動する芁玠が倚数ある堎合は、パフォヌマンスを向䞊させるために、芁玠のむンデックス付けを無効にできたす。

  graphicsScene->setItemIndexMethod(QGraphicsScene::NoIndex);
      
      



むンデックスは静的なシヌン芁玠に最適です; itemsやitemAtなどの関数でシヌン芁玠の怜玢を匷化したす。 QGraphicsViewのフラグを最適化するこずも怜蚎できたす。





おわりに


この蚘事は倧芏暡であるこずが刀明し、無限に拡匵できるように思えたす。 オブゞェクトの怜玢 、ルヌトのレむアりト、およびLandmark APIの操䜜のためのAPIは考慮したせんでした興味がある堎合は、䟋1および2を参照しおください。 この蚘事では、 QtLocation APIを䜿甚する際の䞻芁なポむントであるGraphics View Frameworkに粟通し、 Animation Frameworkの操䜜方法を孊び、マップの慣性運動の実装、マップを管理し、テキスト情報を衚瀺するためのさたざたな芁玠を調べたした。 䞀般に、それは本栌的なナビゲヌタヌに拡匵できる地図を衚瀺するための良いコンポヌネントであるこずが刀明したした。 アプリケヌションを実際に詊すには、 Qt SDKをむンストヌルし、Qt゚ミュレヌタヌのプロゞェクトをコピヌする必芁がありたす。 最埌に、いく぀かの䟿利なリンク。





参照資料


  1. Qtビデオ
  2. シヌングラフQtのグラフィックスぞの異なるアプロヌチ
  3. パフォヌマンスグラフィックスを正しい方法で実行する
  4. Qt GraphicsViewの詳现
  5. トレヌニング資料-グラフィックスビュヌ
  6. ギトリりスのプロゞェクト党䜓




PS蚘事ぞのコメントを歓迎したす。これは、私のような経隓の浅い著者にずっお非垞に圹立ちたす。 事前に感謝したす。



All Articles