2017-01-01 50 views
1

タッチスクリーン用のゲームを作成していますが、2〜4人のプレーヤーがそれぞれ一対のスライダーコントロールにアクセスする必要があります。問題は、QMLスライダコントロールがマウスイベントとしてタッチに応答し、フォーカスを捕捉することです。 1人のプレイヤーだけが一度に1つのコントロールにアクセスできます。タッチイベントに同時に応答するには、複数のスライダが必要です。私の質問はそれをどうやって行うのか?Qtタッチイベントに敏感なQMLスライダーを作成する

さまざまなスタックオーバーフローポストの助けを借りて、今までのところ私自身の答えを作成することができました。私はトラブルのような他の初心者を保存するために、回答のセクションで以下の答えを詳述します。

+0

FYI、Qtクイックコントロール2は、Qt 5.9でマルチタッチのサポートを受け、春になってリリースされました。 – jpnurmi

+0

それはすばらしいだろう。 –

+1

価値があるのは、それは完全に有効な質問です。私はなぜその質問がいくつかの理由で下落したのか理解していない。振り返ってみると、Qtクイックコントロール2に適切なタッチサポートを追加することが優先順位を上げていたはずですが、どうにかして無限のtodoリストに他のものの下に埋もれてしまいました... – jpnurmi

答えて

1

問題を解決するための純粋なQML方法が見つかりませんでしたが、私はC++の使用を最小限に抑えたかったのです。 C++を使用して、オブジェクトTouchSliderを作成し、それをqmlシーンに追加します。 TouchSliderオブジェクトは、位置引数に従って垂直スライダーの値を更新する単純な関数を持っています。 QMLコードでは、通常のスライダーの上にMultiPointTouchAreaを追加し、C++関数を呼び出してタッチイベントに応答します。

ここには、SliderPairというプロジェクト用のすべてのファイルがあります。

SliderPair.pro:

QT += qml quick widgets 
QT += quickcontrols2 
QT += core 
CONFIG += c++11 
SOURCES += main.cpp \ 
    touchslider.cpp 
RESOURCES += \ 
    qml.qrc 

# Additional import path used to resolve QML modules in Qt Creator's code model 
QML_IMPORT_PATH += qml 

# Default rules for deployment. 
qnx: target.path = /tmp/$${TARGET}/bin 
else: unix:!android: target.path = /opt/$${TARGET}/bin 
!isEmpty(target.path): INSTALLS += target 

HEADERS += \ 
    touchslider.h 

DISTFILES += 

main.cppに:

#include <QApplication> 
#include <QQmlApplicationEngine> 
// add following includes for exposing new class TouchSlider to QML 
#include <QQmlEngine> 
#include <QQmlContext> 
#include "touchslider.h" 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    //Create an object of type TouchSlider 
    //When a scoped pointer goes out of scope the object is deleted from memory. Good housekeeping: 
    QScopedPointer<TouchSlider> touchslider (new TouchSlider); 

    QQmlApplicationEngine engine; 
    engine.addImportPath(QStringLiteral("qml")); 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

    //QML can now refer to the TouchSlider object using the handle "touchslider": 
    engine.rootContext()->setContextProperty("touchslider",touchslider.data()); 

    return app.exec(); 
} 

touchslider.h:

#ifndef TOUCHSLIDER_H 
#define TOUCHSLIDER_H 

#include <QObject> 
#include <QDebug> 
#include <QtQuickControls2> 

class TouchSlider : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit TouchSlider(QObject *parent = 0); 

    //call Q_INVOKABLE macro to set up functions for QML 
    Q_INVOKABLE void testDebug();   //hello world from C++ 
    Q_INVOKABLE QString testStringReturn(); //hello world to javascript 
    Q_INVOKABLE void sliderSetValueFromTouch(QQuickItem *qs,int position);//use touch event to set slider value 
signals: 

public slots: 
}; 


#endif // TOUCHSLIDER_H 

touchslider.cpp:

#include "touchslider.h" 

TouchSlider::TouchSlider(QObject *parent) : QObject(parent) 
{ 

} 

void TouchSlider::testDebug() 
{ 
    qDebug() << "Hello from C++"; 
} 

QString TouchSlider::testStringReturn() 
{ 
    QString message = "Hi from C++"; 
    return message; 
} 

void TouchSlider::sliderSetValueFromTouch(QQuickItem *qs, int position) 
{ 
    // Assume qs a vertical slider 
    // Get its properties (its slider properties are accessible even though it is declared as QQuickItem) 
    // minimumValue and maximumValue are of type QVariant so we need to cast them as double 
    double minvalue = qs->property("minimumValue").value<double>(); 
    double maxvalue = qs->property("maximumValue").value<double>(); 
    // Since this is a vertical slider, by assumption, get the height 
    double height = qs->property("height").value<double>(); 

    // Compute the new value based on position coordinate 
    double newvalue = (height-position)/height * (maxvalue-minvalue); 
    if (newvalue<minvalue) newvalue = minvalue; 
    if (newvalue>maxvalue) newvalue = maxvalue; 
    //qDebug() << newvalue; 

    // Set the value of the slider 
    qs->setProperty("value",newvalue); 
} 

TouchSlider.qml:

import QtQuick 2.0 
import QtQuick 2.5 
import QtQuick.Controls 1.4 
import QtQuick.Layouts 1.2 

Item { 
    property string sliderTitle 

    property real sliderMin 
    property real sliderMax 
    property real sliderVal 


    ColumnLayout{ 
     Label { 
      text: qsTr(sliderTitle) 
      font.pointSize: 10 

     } 
     Slider { 
      id: touchSlider1 


      minimumValue: sliderMin 
      maximumValue: sliderMax 

      orientation: Qt.Vertical 
      value: sliderVal 
      onValueChanged: function(){ 
       sliderVal = Math.round(this.value); 
       labelSliderValue.text = qsTr(JSON.stringify(sliderVal)); 
      } 
     } 

     Label { 
      id: labelSliderValue 
      text: qsTr(JSON.stringify(sliderVal)) 
      font.pointSize: 10 
     } 
     MultiPointTouchArea{ 
      anchors.fill: touchSlider1 
      touchPoints: [ 
       TouchPoint { 
        id: point1 
        onPressedChanged: function(){ 
         if(pressed){ 
          //console.log("pressed"); 
          //console.log(touchslider.testStringReturn()); 
          touchslider.sliderSetValueFromTouch(touchSlider1,point1.y); 

         } 
        } 

       } 
      ] 
      onTouchUpdated: function(){ 
       touchslider.sliderSetValueFromTouch(touchSlider1,point1.y); 
      } 
     } 
    } 
} 

PlayerControls.qml:

import QtQuick 2.0 
import QtQuick.Controls 1.4 
import QtQuick.Layouts 1.2 


Item { 
    // These properties act as constants, useable outside this QML file 
    property string playerName 
    property real priceMin 
    property real priceMax 
    property real qualityMin 
    property real qualityMax 
    property real priceValue 
    property real qualityValue 
    property int sliderWidth 


    ColumnLayout{ 
     id: columnLayout1 
     width: 640 
     height: 480 
     Layout.minimumWidth: 640 
     Layout.fillWidth: true 
     anchors.fill: parent 
     spacing: 10.2 

     Label { 
      Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter 
      id: labelPlayer1 
      text: qsTr(playerName) 
      font.pointSize: 10 
     } 
     RowLayout{ 
      ColumnLayout{ 
       Label { 
        text: qsTr("") 
        font.pointSize: 10 
        width: 50 
       } 
      } 
      TouchSlider { 
       width: sliderWidth 

       sliderTitle: "Price" 
       sliderMin: priceMin 
       sliderMax: priceMax 
       sliderVal: priceValue 

      } 
      TouchSlider { 
       width: sliderWidth 

       sliderTitle: "Quality" 
       sliderMin: qualityMin 
       sliderMax: qualityMax 
       sliderVal: qualityValue 
      } 
     } 

    } 
} 

main.qml:

import QtQuick 2.7 
import QtQuick.Controls 2.0 
import QtQuick.Layouts 1.0 

ApplicationWindow { 
    visible: true 
    width: 640 
    height: 480 
    title: qsTr("SliderPair Test") 
    Item { 
     PlayerControls{ 
      playerName: "Player 1" 
      priceMin: 0 
      priceMax: 200 
      priceValue: 100 
      qualityMin: 0 
      qualityMax: 50 
      qualityValue: 25 
      sliderWidth: 200 
     } 
    } 

} 

結果は次のようになります。オン Pair of Sliders Responding to Separate Touch Points

私のSurface Proのようなタッチスクリーン各スライダを同時に2本の指で操作します。 Windowsは10までの同時タッチをサポートしているので、問題なく2〜4人のプレイヤーを持つことができるはずです。我々は見るであろう。

1

この問題に対する純粋なqmlソリューションがあります。私の最初の答え(このスレッドの他の場所)にあるTouchSlider C++オブジェクトは不要でした。ここでは、コードをTouchSlider qmlコードに変更して、touchslider(TouchSlider C++オブジェクト)への参照を排除しました。

TouchPoint.qml:

import QtQuick 2.0 
import QtQuick 2.5 
import QtQuick.Controls 1.4 
import QtQuick.Layouts 1.2 

Item { 
    property string sliderTitle 

    property real sliderMin 
    property real sliderMax 
    property real sliderVal 


    ColumnLayout{ 
     id: column1 
     Label { 
      text: qsTr(sliderTitle) 
      font.pointSize: 10 

     } 
     Slider { 
      id: touchSlider1 

      minimumValue: sliderMin 
      maximumValue: sliderMax 

      orientation: Qt.Vertical 
      value: sliderVal 
      onValueChanged: function(){ 
       sliderVal = Math.round(this.value); 
       labelSliderValue.text = qsTr(JSON.stringify(sliderVal)); 
      } 
     } 

     Label { 
      id: labelSliderValue 
      text: qsTr(JSON.stringify(sliderVal)) 
      font.pointSize: 10 
     } 
     function sliderSetValueFromTouch(position){ 
      // Assume qs a vertical slider 
      var minvalue = touchSlider1.minimumValue; 

      var maxvalue = touchSlider1.maximumValue; 
      // Since this is a vertical slider, by assumption, get the height 
      var height = touchSlider1.height; 

      // Compute the new value based on position coordinate 
      var newvalue = (height-position)/height * (maxvalue-minvalue); 
      if (newvalue<minvalue) newvalue = minvalue; 
      if (newvalue>maxvalue) newvalue = maxvalue; 
      //qDebug() << newvalue; 

      // Set the value of the slider 
      touchSlider1.value = newvalue; 
     } 

     MultiPointTouchArea{ 
      anchors.fill: touchSlider1 

      touchPoints: [ 
       TouchPoint { 
        id: point1 
        onPressedChanged: function(){ 
         if(pressed){ 
          //console.log("pressed"); 
          //console.log(touchslider.testStringReturn()); 
          //touchslider.sliderSetValueFromTouch(touchSlider1,point1.y); 
          column1.sliderSetValueFromTouch(point1.y); 
         } 
        } 

       } 
      ] 
      onTouchUpdated: function(){ 
       //touchslider.sliderSetValueFromTouch(touchSlider1,point1.y); 
       column1.sliderSetValueFromTouch(point1.y); 
      } 

     } 
    } 
} 

touchslider.hとtouchslider.cppファイルは値を追加しません。

関連する問題