implement custom SpinBox Delegeta for QML ListView

preperation for Config usage from c++
This commit is contained in:
Felix Hammer
2015-08-13 15:39:24 +02:00
parent a935bfd0b8
commit 93b9881e75
15 changed files with 669 additions and 177 deletions
+78 -23
View File
@@ -1,24 +1,31 @@
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import "../js/colors.js" as GlobalColors
Rectangle {
id: selector
z:1000
visible: false
anchors.fill: parent
color: "#88000000" //Background
color: "#88000000" //dark transparent background
property ListModel mySelectionModel: ListModel {}
property string myTitleString
property var returnSelection
property ListModel selectionModel: ListModel {}
property string titleString
property string valueFromParent
property string returnValue
property bool valueIsIndex
function show(title, map) {
//at first fill the model
myTitleString = title
// for (var i=0; i < map.count; i++) {
// mySelectionModel.append({"value": map.get(i).value});
// }
function show(title, list, vl, valueIndex) {
titleString = title;
valueFromParent = vl;
valueIsIndex = valueIndex;
//fill the model
selectionModel.clear();
for (var i=0; i < list.count; i++) {
selectionModel.append({"valueString": list.get(i).value});
}
visible = true;
}
@@ -26,13 +33,19 @@ Rectangle {
visible = false;
}
function selected() {
function selected(newString, index) {
if(valueIsIndex) {
returnValue = index.toString();
}
else {
returnValue = newString
}
visible = false;
}
MouseArea {
//set empty MouseArea to prevent the background to be clicked
anchors.fill: parent
onClicked: console.log("1001")
}
Rectangle {
@@ -43,23 +56,66 @@ Rectangle {
width: Math.round(parent.width*0.6)
x: Math.round(parent.width*0.5 - width*0.5)
y: Math.round(parent.height*0.5 - height*0.5)
radius: Math.round(parent.height*0.01)
ColumnLayout {
id: content
anchors.fill: parent
spacing: Math.round(selectionBox.height*0.06)
Text {
id: titleText
font.pixelSize: Math.round(selectionBox.height*0.10)
font.bold: true
text: myTitleString
text: titleString
anchors.left: parent.left
anchors.margins: 30
Layout.preferredHeight: titleText.contentHeight
anchors.top: parent.top
anchors.leftMargin: 30
anchors.topMargin: 10
Layout.preferredHeight: contentHeight
}
ScrollView {
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 30
anchors.leftMargin: 50
Layout.fillHeight: true
ListView {
anchors.fill: parent
model: mySelectionModel
delegate: Text {
text: modelData
spacing: Math.round(selectionBox.height*0.05)
model: selectionModel
delegate: RadioButton {
id: radioBtn
//check of value is index type and do the corresponding checked? test
checked: valueIsIndex ? (parseInt(valueFromParent) == index ? true : false) : (valueFromParent == valueString ? true : false)
onClicked: {
selector.selected(valueString, index)
}
style: RadioButtonStyle {
indicator: Rectangle {
implicitWidth: Math.round(selectionBox.height*0.05)
implicitHeight: Math.round(selectionBox.height*0.05)
radius: Math.round(selectionBox.height*0.03)
border.color: radioBtn.checked ? GlobalColors.accentColor : "grey"
border.width: Math.round(selectionBox.height*0.005)
Rectangle {
anchors.fill: parent
visible: control.checked
color: radioBtn.checked ? GlobalColors.accentColor : "grey"
radius: Math.round(selectionBox.height*0.03)
anchors.margins: Math.round(selectionBox.height*0.01)
}
}
label: Text {
anchors.left: parent.left
anchors.leftMargin: 10
font.pixelSize: Math.round(selectionBox.height*0.05)
text: valueString
MouseArea {
anchors.fill: parent
onClicked: radioBtn.clicked()
}
}
}
}
}
}
@@ -67,18 +123,17 @@ Rectangle {
id: cancelButton
font.pixelSize: Math.round(selectionBox.height*0.07)
font.bold: true
text: qsTr("Cancel")
text: qsTr("CANCEL")
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 50
Layout.preferredHeight: cancelButton.contentHeight
anchors.rightMargin: 30
anchors.bottomMargin: 20
Layout.preferredHeight: contentHeight
MouseArea {
id: cancelMouse
anchors.fill: parent
// preventStealing: true
onClicked: {
console.log("1002")
reject()
}
}
@@ -9,6 +9,8 @@ Item {
id: root
property int myListViewsHeight: 0
property int myListViewsWidth: 0
property var myListViewRoot
property var myListViewModel
property var componentMap: {
"ComboBox": myComboBox,
"SpinBox": mySpinBox
@@ -23,9 +25,17 @@ Item {
}
// ComboBox
Component {
id: myComboBox
Rectangle {
MyComboBoxSelector {
id: myComboBoxSelector
parent: myListViewRoot
}
id: myComboBoxContent
property int modelIndex: model.index
color: mouse.pressed ? "#11000000" : "white"
width: root.width
height: Math.round(comboBoxTitle.contentHeight*2.1 + comboBoxValue.contentHeight*1.0)
@@ -45,7 +55,8 @@ Item {
y: Math.round(parent.height*0.5 + contentHeight*0.15)
color: "grey"
font.pixelSize: myValue != "" ? Math.round(myListViewsHeight*0.05) : 0
text: myValue
//setup value from Index if necessary
text: myValueIsIndex ? myValuesList.get(parseInt(myValue)).value : myValue
}
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
@@ -58,23 +69,43 @@ Item {
id: mouse
anchors.fill: parent
onClicked: {
myComboBoxSelector.show(myTitle, myValuesList)
//call selector overlay and set inital values
myComboBoxSelector.show(myTitle, myValuesList, myValue, myValueIsIndex)
}
Connections {
target: myComboBoxSelector
onVisibleChanged: {
if(!myComboBoxSelector.visible) {
//call update the currentItem with selection from the comboBox selector
myListViewModel.setProperty(myComboBoxContent.modelIndex, "myValue", myComboBoxSelector.returnValue);
}
}
}
}
Component.onCompleted: {
//after building the delegate content set the final height to the root item
root.height = Qt.binding(function() { return height })
}
}
}
// Spinbox
Component {
id: mySpinBox
Rectangle {
MySpinBoxSelector {
id: mySpinBoxSelector
parent: myListViewRoot
}
id: mySpinBoxContent
property int modelIndex: model.index
color: mouse.pressed ? "#11000000" : "white"
width: root.width
height: Math.round(comboBoxTitle.contentHeight*2.1 + comboBoxValue.contentHeight*1.0)
height: Math.round(spinBoxTitle.contentHeight*2.1 + spinBoxValue.contentHeight*1.0)
Text {
id: comboBoxTitle
id: spinBoxTitle
anchors.left: parent.left
anchors.margins: 30
y: myValue != "" ? Math.round(parent.height*0.5 - contentHeight*0.9) : Math.round(parent.height*0.5 - contentHeight*0.5)
@@ -83,7 +114,7 @@ Item {
text: myTitle
}
Text {
id: comboBoxValue
id: spinBoxValue
anchors.left: parent.left
anchors.margins: 30
y: Math.round(parent.height*0.5 + contentHeight*0.15)
@@ -99,9 +130,25 @@ Item {
color: "lightgrey"
}
MouseArea {
id: mouse
anchors.fill: parent
onClicked: {
//call selector overlay and set inital values
mySpinBoxSelector.show(myTitle, myMinValue, myMaxValue, myValue, myPrefix)
}
Connections {
target: mySpinBoxSelector
onVisibleChanged: {
if(!mySpinBoxSelector.visible) {
//call update the currentItem with selection from the comboBox selector
myListViewModel.setProperty(mySpinBoxContent.modelIndex, "myValue", mySpinBoxSelector.returnValue);
}
}
}
}
Component.onCompleted: {
//after building the delegate content set the final height to the root item
root.height = Qt.binding(function() { return height })
}
}
@@ -0,0 +1,221 @@
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import "../js/colors.js" as GlobalColors
Rectangle {
id: selector
z:1000
visible: false
anchors.fill: parent
color: "#88000000" //dark transparent background
property string titleString
property string prefix
property int minValue
property int maxValue
property string returnValue
property int initialTextFieldValue
property int initialSliderValue
function show(title, min, max, value, pref) {
titleString = title;
initialTextFieldValue = parseInt(value);
initialSliderValue = parseInt(value)
minValue = min;
maxValue = max;
prefix = pref
visible = true;
}
function reject() {
visible = false;
}
function selected(newSelection) {
returnValue = newSelection;
visible = false;
}
MouseArea {
//set empty MouseArea to prevent the background to be clicked
anchors.fill: parent
}
Rectangle {
id: selectionBox
visible: true
color: "white"
height: Math.round(parent.height*0.9)
width: Math.round(parent.width*0.6)
x: Math.round(parent.width*0.5 - width*0.5)
y: Math.round(parent.height*0.5 - height*0.5)
radius: Math.round(parent.height*0.01)
ColumnLayout {
id: content
anchors.fill: parent
spacing: Math.round(selectionBox.height*0.06)
Text {
id: titleText
font.pixelSize: Math.round(selectionBox.height*0.10)
font.bold: true
text: titleString
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 30
anchors.topMargin: 10
Layout.preferredHeight: contentHeight
}
TextField{
id: textField
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 50
//make space for the prefix
property int prefixIndent: Math.round(selectionBox.height*0.04)
anchors.leftMargin: 50 + prefixIndent
// validator: IntValidator{bottom: minValue; top: maxValue;} TODO: test validator in later QtVersions > 5.5.0
focus: true
text: initialTextFieldValue
function correctValue() {
if(text > maxValue) text = maxValue
else if(text < minValue) text = minValue
else {
//remove leading "0000"
var temp = parseInt(text)
text = temp
}
}
onFocusChanged: correctValue()
onEditingFinished: correctValue()
style: TextFieldStyle {
textColor: "black"
font.pixelSize: Math.round(selectionBox.height*0.10)
background: Item { //bottom line with colored focus indicator
implicitHeight: Math.round(selectionBox.height*0.12)
implicitWidth: parent.width
Text { //prefix
color: "black"
font.pixelSize: Math.round(selectionBox.height*0.10)
text: prefix
anchors.left: parent.left
anchors.leftMargin: -textField.prefixIndent
anchors.bottom: parent.bottom
anchors.bottomMargin: Math.round(selectionBox.height*0.005)
}
Rectangle {
color: GlobalColors.accentColor
opacity: textField.activeFocus ? 0.8 : 0
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: -textField.prefixIndent
width: parent.width + textField.prefixIndent
height: Math.round(selectionBox.height*0.005)
}
Rectangle {
color: "black"
opacity: textField.activeFocus ? 0.6 : 0.4
anchors.bottom: parent.bottom
anchors.bottomMargin: Math.round(selectionBox.height*0.005)
anchors.left: parent.left
anchors.leftMargin: - textField.prefixIndent
width: parent.width + textField.prefixIndent
height: Math.round(selectionBox.height*0.005)
}
}
}
}
Slider {
id: slider
width: parent.width
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 50
anchors.leftMargin: 50
maximumValue: maxValue
minimumValue: minValue
value: initialSliderValue
stepSize: minimumValue * 10
on__HandlePosChanged: {
if (slider.value > minimumValue && slider.value < maximumValue)
textField.text = slider.value - minimumValue
else
textField.text = slider.value
}
style: SliderStyle {
handle: Rectangle {
width: Math.round(selectionBox.height*0.12)
height: width
radius: width
antialiasing: true
color: Qt.lighter(GlobalColors.accentColor, 1.2)
}
groove: Item {
implicitHeight: Math.round(selectionBox.height*0.04)
implicitWidth: slider.width
Rectangle {
height: Math.round(selectionBox.height*0.03)
width: slider.width
anchors.verticalCenter: parent.verticalCenter
color: "#666"
Rectangle {
antialiasing: true
radius: 1
color: GlobalColors.accentColor
height: parent.height
width: parent.width * control.value / control.maximumValue
}
}
}
}
}
RowLayout { //bottom button line
width: parent.width
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 30
anchors.bottomMargin: 20
spacing: okButton.contentWidth
Layout.preferredHeight: cancelButton.contentHeight
Text {
id: cancelButton
font.pixelSize: Math.round(selectionBox.height*0.07)
font.bold: true
text: qsTr("CANCEL")
Layout.preferredHeight: contentHeight
MouseArea {
id: cancelMouse
anchors.fill: parent
onClicked: {
reject()
}
}
}
Text {
id: okButton
font.pixelSize: Math.round(selectionBox.height*0.07)
font.bold: true
color: GlobalColors.accentColor
text: qsTr("OK")
Layout.preferredHeight: contentHeight
MouseArea {
id: okMouse
anchors.fill: parent
onClicked: {
textField.correctValue();
selected(textField.text);
}
}
}
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
#include "qmlconfigwrapper.h"
#include "configfile.h"
QmlConfigWrapper::QmlConfigWrapper(ConfigFile *c)
:QObject(), myConfig(c)
{
}
QmlConfigWrapper::~QmlConfigWrapper()
{
}
QmlConfigWrapper::QmlConfigWrapper(const QmlConfigWrapper&)
:QObject()
{
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef QMLCONFIGWRAPPER_H
#define QMLCONFIGWRAPPER_H
#include <QtCore>
class ConfigFile;
class QmlConfigWrapper: public QObject
{
Q_OBJECT
public:
QmlConfigWrapper(ConfigFile *c);
~QmlConfigWrapper();
QmlConfigWrapper(const QmlConfigWrapper&);
private:
ConfigFile *myConfig;
};
#endif // QMLCONFIGWRAPPER_H
+3
View File
@@ -0,0 +1,3 @@
//global color definition
var accentColor = "#FF9800";
+2 -1
View File
@@ -4,6 +4,7 @@ import QtQuick.Controls.Styles 1.2
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import "views/startview"
import "js/colors.js" as GlobalColors
ApplicationWindow {
id: appWindow
@@ -18,7 +19,7 @@ ApplicationWindow {
id: toolbar
opacity: 1
Behavior on opacity { NumberAnimation{} }
color: "#FF9800"
color: GlobalColors.accentColor
width: appWindow.width
height: appWindow.height*0.15
Behavior on height { NumberAnimation{} }
+3 -1
View File
@@ -1,7 +1,7 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>components/ListViewDelegateFactory.qml</file>
<file>components/MyListViewDelegateFactory.qml</file>
<file>images/arrow_back.svg</file>
<file>images/button-default.png</file>
<file>images/button-pressed.png</file>
@@ -13,5 +13,7 @@
<file>views/startview/StartView.qml</file>
<file>views/createlocalgameview/CreateLocalGameView.qml</file>
<file>components/MyComboBoxSelector.qml</file>
<file>js/colors.js</file>
<file>components/MySpinBoxSelector.qml</file>
</qresource>
</RCC>
-31
View File
@@ -1,31 +0,0 @@
#include <QtCore>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
//#include "startview/startview.h"
#include "qmlwrapper.h"
qmlWrapper::qmlWrapper()
:QObject()
{
qDebug("qmlWrapperKonstruktor");
myEngine.reset(new QQmlApplicationEngine);
myEngine->load(QUrl(QStringLiteral("qrc:/main.qml")));
// QTimer *timer = new QTimer(this);
// timer->setSingleShot(true);
// connect(timer, SIGNAL(timeout()), this, SLOT(showStartForm()));
// timer->start(1000);
}
qmlWrapper::~qmlWrapper()
{
myEngine->deleteLater();
}
qmlWrapper::qmlWrapper(const qmlWrapper&)
:QObject()
{
}
-22
View File
@@ -1,22 +0,0 @@
#ifndef QMLWRAPPER_H
#define QMLWRAPPER_H
#include <QtCore>
#include <boost/shared_ptr.hpp>
class QQmlApplicationEngine;
class qmlWrapper: public QObject
{
Q_OBJECT
public:
qmlWrapper();
~qmlWrapper();
qmlWrapper(const qmlWrapper&);
public slots:
private:
boost::shared_ptr<QQmlApplicationEngine> myEngine;
};
#endif // QMLWRAPPER_H
@@ -5,35 +5,43 @@ import QtQuick.Layouts 1.1
import "../../components"
Rectangle {
id: createLocalGameViewRoot
width: parent.width
height: parent.height
color: "#FAFAFA"
MyComboBoxSelector {
id: myComboBoxSelector
}
ScrollView {
width: parent.width
height: parent.height
ListView {
id:myListView
id: createLocalGameViewList
anchors.fill: parent
model: ListModel {
id: createLocalGameViewModel
ListElement {
myId: "comboBox_NumberOfPlayers"
myTitle: qsTr("Number of players")
myType: "ComboBox"
myValuesList: [
ListElement { value: "10" },
ListElement { value: "9" },
ListElement { value: "8" },
ListElement { value: "7" },
ListElement { value: "6" },
ListElement { value: "5" },
ListElement { value: "4" },
ListElement { value: "3" },
ListElement { value: "2" }
]
myValueIsIndex: false
myValue: "10"
// property var myValuesInt: [10, 9, 8, 7, 6, 5, 4, 3, 2]
}
ListElement {
myId: "spinBox_StartCash"
myTitle: qsTr("Start cash")
myType: "SpinBox"
myMaxValue: 10000000
myMaxValue: 1000000
myMinValue: 1000
myPrefix: "$"
myValue: "5000"
@@ -43,29 +51,58 @@ Rectangle {
myTitle: qsTr("Blinds")
myType: "ComboBox"
myValuesList: [
ListElement { value: qsTr("Use saved blinds settings") },
ListElement { value: qsTr("Change blinds settings ...") }
ListElement { value: qsTr("Use saved blinds settings") },
ListElement { value: qsTr("Change blinds settings ...") }
]
myValue: "0"
myValueIsIndex: true
}
ListElement {
myId: "comboBox_GameSpeed"
myTitle: qsTr("Game speed")
myType: "ComboBox"
// myValuesInt: [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
myValuesList: [
ListElement { value: "11" },
ListElement { value: "10" },
ListElement { value: "9" },
ListElement { value: "8" },
ListElement { value: "7" },
ListElement { value: "6" },
ListElement { value: "5" },
ListElement { value: "4" },
ListElement { value: "3" },
ListElement { value: "2" },
ListElement { value: "1" }
]
myValue: "5"
myValueIsIndex: false
}
ListElement {
myId: "comboBox_GameSpeed"
myTitle: qsTr("Game speed")
myType: "ComboBox"
// myValuesInt: [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
myValuesList: [
ListElement { value: "11" },
ListElement { value: "10" },
ListElement { value: "9" },
ListElement { value: "8" },
ListElement { value: "7" },
ListElement { value: "6" },
ListElement { value: "5" },
ListElement { value: "4" },
ListElement { value: "3" },
ListElement { value: "2" },
ListElement { value: "1" }
]
myValue: "5"
myValueIsIndex: false
}
}
delegate: ListViewDelegateFactory {
myListViewsHeight: myListView.height
myListViewsWidth: myListView.width
delegate: MyListViewDelegateFactory {
myListViewsHeight: createLocalGameViewList.height
myListViewsWidth: createLocalGameViewList.width
myListViewRoot: createLocalGameViewRoot
myListViewModel: createLocalGameViewModel
}
}
}
-25
View File
@@ -1,25 +0,0 @@
#include <QQmlApplicationEngine>
#include "startview.h"
startView::startView()
{
qDebug("startViewKonstruktor");
myEngine.reset(new QQmlApplicationEngine);
}
startView::~startView()
{
}
startView::startView(const startView&)
{
}
void startView::show()
{
qDebug("show() in startView");
myEngine->load(QUrl(QStringLiteral("qrc:/main.qml")));
}
-21
View File
@@ -1,21 +0,0 @@
#ifndef STARTVIEW_H
#define STARTVIEW_H
#include <boost/shared_ptr.hpp>
class QQmlApplicationEngine;
class startView
{
public:
startView();
~startView();
startView(const startView&);
void show();
private:
boost::shared_ptr<QQmlApplicationEngine> myEngine;
};
#endif // STARTVIEW_H
+10 -2
View File
@@ -30,14 +30,22 @@
*****************************************************************************/
#ifdef QML_CLIENT
//START THE QML SWITCH HERE
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <QApplication>
#include <boost/shared_ptr.hpp>
#include "configfile.h"
#include "qmlwrapper.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlWrapper myQml;
boost::shared_ptr<ConfigFile> myConfig;
myConfig.reset(new ConfigFile(argv[0], false));
QmlWrapper myQml(myConfig);
return app.exec();
}