[英]Qt Create a QML Slider Sensitive to Touch Events
我正在为触摸屏创建一个游戏,该游戏需要2-4个玩家才能访问一对滑块控件。 问题在于QML滑块控件会在鼠标事件发生时对触摸做出响应并抓住焦点。 这样一来,一次只有一个玩家可以访问单个控件。 我需要多个滑块来同时响应触摸事件。 我的问题是怎么做?
借助各种堆栈溢出帖子的帮助,到目前为止,我已经能够创建自己的答案了,而且似乎还行得通。 我在“答案”部分详细介绍了以下答案,以免其他像我这样的新手遇到麻烦。
我找不到解决问题的纯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
}
}
}
在类似Surface Pro的触摸屏上,我可以用两个手指同时控制每个滑块。 由于Windows支持多达10个同时触摸,这意味着我可以毫无问题地拥有2-4个播放器。 我们将会看到。
有一个纯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文件没有任何价值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.