舒尔特表是一种训练注意力的表格,表格内容是打乱顺序的自然数序列,练习时,需要按照顺序从最小数点到最大数,用时越少越好。下面说明如何以QML/javascript为主要编程语言来构建这么一个小程序。
首先创建一个Qt Quick项目,构建套件选择两个,一个是Windows平台的,一个是android平台的,日后可以在android手机上玩儿,而且在Windows平台上调试比较方便。项目自动生成了两个代码文件,一个是main.cpp,一个是main.qml.前者不用修改,我们不去关注,后者是程序运行的主要框架代码文件,见下面的清单。
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import "qrc:///schulteGrid.js" as SchulteGrid
Window {
id:screen
visible: true
SystemPalette { id: activePalette }
Rectangle{
id:toolbar
width:parent.width
height:30
color:activePalette.window
anchors.bottom: screen.bottom
Button{
id:button
anchors{
left:parent.left
verticalCenter: parent.verticalCenter
}
text:"开始"
onClicked: {
SchulteGrid.setCurrentIndex(1);
globalVar.rank = rank.value;
SchulteGrid.createGrid(globalVar.rank);
globalVar.seconds = 0;
timer.running = true;
}
}
SpinBox
{
id:rank
minimumValue: 3
maximumValue: 9
anchors{
left: button.right
verticalCenter: parent.verticalCenter
}
}
Text{
id:time
anchors{
right:parent.right
verticalCenter: parent.verticalCenter
}
text:"时间"
}
}
Item{
id:globalVar
property int currentIndex
property int seconds
property int rank
Timer{
id:timer
interval: 1000
running: false
repeat: true
onTriggered: {
globalVar.seconds += 1;
time.text = "时间:" + globalVar.seconds.toString() + "秒"
}
}
}
}
这段代码中有两处值得关注的,一个是按钮是自己画的,这个按钮的定义是另外一个QML文件“Button.qml"定义的,清单见下面。
import QtQuick 2.0
Rectangle {
id:container
property string text:"Button"
signal clicked
SystemPalette { id: activePalette }
width: textLabel.width + 20
height: textLabel.height + 5
border{
width: 1
color: Qt.darker(activePalette.button)
}
antialiasing: true
radius: 5
gradient:Gradient{
GradientStop{
position: 0.0
color: {
if(mouseArea.pressed)
return activePalette.dark
else
return activePalette.light
}
}
GradientStop{
position: 1.0
color: activePalette.button
}
}
MouseArea{
id: mouseArea
anchors.fill: parent
onClicked: container.clicked()
}
Text{
id: textLabel
anchors.centerIn: parent
color: activePalette.buttonText
text: container.text
}
}
另外一处则是程序的运行逻辑由”import "qrc:///schulteGrid.js" as SchulteGrid"这句话导入,是放在了"schulteGrid.js"里面,清单见下面。
var gridFactory;
var grid = new Array(100);
var index = new Array(100);
function createGrid(r) {
for(var i=0; i<100; i++)
{
if(grid[i] != null)
grid[i].opacity = 0;
grid[i] = null;
}
for(var i=0; i<100; i++)
{
index[i] = i;
}
gridFactory = Qt.createComponent("qrc:///grid.qml");
if(gridFactory.status == Component.Ready)
{
for(var i=0; i<r; i++)
{
for(var j=0; j<r; j++)
{
var random = getRandomNum(1, r*r-(i*r+j))
var dynamicObject = gridFactory.createObject(screen);
if(dynamicObject != null)
{
dynamicObject.size = screen.width/r;
dynamicObject.pointSize = dynamicObject.size*3/4;
dynamicObject.x = j*dynamicObject.size;
dynamicObject.y = i*dynamicObject.size + 30;
dynamicObject.text = (index[random]).toString();
dynamicObject.color = "#0080ff";
dynamicObject.index = index[random];
grid[i*r+j] = dynamicObject;
for(var k=random; k<r*r; k++)
{
index[k] = index[k+1];
}
}
else
{
console.log("createObject error");
}
}
}
}
else
{
console.log("component not ready");
console.log(gridFactory.errorString());
}
}
function getRandomNum(Min,Max)
{
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
}
function getCurrentIndex()
{
return globalVar.currentIndex;
}
function setCurrentIndex(_currentIndex)
{
globalVar.currentIndex = _currentIndex;
}
function getGridCount()
{
return globalVar.rank * globalVar.rank;
}
这个文件的主要作用就是动态创建一堆表格,每个格都显示一个数字,不能重复,这里面又用到了另外一个QML文件“grid.qml",用于创建单独的一个格,清单见下面。
import QtQuick 2.0
import "qrc:///schulteGrid.js" as SchulteGrid
Item {
id:grid
property int index
property string text
property string color
property int size
property int pointSize
Rectangle
{
width:grid.size
height:grid.size
color:grid.color//"#0080ff"
border.width:1
border.color:"#000000"
Text{
text:grid.text
font.pointSize: grid.pointSize
anchors.centerIn: parent
}
MouseArea{
id: mouseArea
anchors.fill: parent
onPressed: {
if(grid.index != SchulteGrid.getCurrentIndex())
{
grid.color = "#dd0000";
}
else
{
grid.color = "#00ff00";
SchulteGrid.setCurrentIndex(grid.index + 1);
if(grid.index == SchulteGrid.getGridCount())
{
timer.running = false;
}
}
}
onReleased:grid.color = "#0080ff"
}
}
}
程序到这儿就完事儿了,总共200来行代码,不算简洁,但也可以看到QML/javascript编程方式的这种能力,可以将界面与运行逻辑分开处理,并且还可以将一些界面元素单独分离出来,比如说Button元素和Grid元素,我想这是符合现代程序设计理念的。