在Cascades框架中,使用Signals(信号)和slots(信号槽)机制来实现对象间通讯,如类A中封装了登录的相关操作,有一个signal为loginResult(bool result)函数,你可以在B中设置一个slot为onLoginResult(bool result)函数,把它们绑定起来:connect(A, SIGNAL(loginResult(bool)), B, onLoginResult(bool)),这样当A中emit loginResult(bool)的时候(发送信号),会通知调用B中onLoginResult(bool),这样就可以在B中进行相应的处理了,而且A和B的耦合度非常低。signal和slot都是类的成员函数,它们之间不是一对一的关系,你可以不为signal设置slot,也可以为一个signal设置多个slot;同时也可以让signal和另一个对象的signal绑定,这样当signal被emit的时候,另一个signal也会被emit。
1. 使用UI控件中预定义的signals和slots
Cascades框架中的很多UI控件声明了一些signals,当用户与app进行交互的时就会触发某个signal,如点击按钮、滑动滑块等,你可以在QML或者C++中处理这些信号。
(1)在QML中,操作起来比较简单,预定义signals对应的signal处理程序会自动创建,名字为:signal名字前+on且把signal首字母大写,采用驼峰命名风格。如:Button的一个signal为clicked(),对应的信号处理程序则为onClicked,如:
1
2
3
4
5
6
7
8
9
|
Page {
content: Button {
text: "Click me"
onClicked: {
text = "Clicked!"
}
}
}
|
一些预定义的signals也包含了参数,你可以在对应的信号处理程序中直接使用,如CheckBox控件的一个signal:checkedChanged (bool checked),你可以在onCheckedChanged中直接使用checked:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Page {
content: Container {
CheckBox {
onCheckedChanged: {
if (checked)
checkLabel.text = "Checked";
else
checkLabel.text = "Not checked";
}
}
Label {
id: checkLabel
text: "Not checked"
}
} // end of Container
} // end of Page
|
(2)在C++中,需要使用QObject::connect(A, SIGNAL(a()), B, b())这样的形式将A中的signal和B中的slot连接起来,A发送信号,B接收信号。SIGNAL和SLOT是两个宏,目的就是为了把signal a和slot b转换成字符串常量。下面可以实现这样一个效果:通过拖动滑块改变一个矩形区域的宽度。实现思路很简单,把拖动滑块时发送的signal跟设置矩形区域宽度的slot连接起来,示例代码:
1
2
3
4
5
6
7
8
9
10
11
|
Slider* mySlider = Slider::create()
.from(100)
.to(500);
Container* mySizedContainer = Container::create()
.preferredWidth(100)
.preferredHeight(100)
.background(Color::DarkGreen);
bool
res = QObject::connect(mySlider, SIGNAL(immediateValueChanged(
float
)),
mySizedContainer, SLOT(setPreferredWidth(
float
)));
Q_ASSERT(res);
Q_UNUSED(res);
|
由于,connect函数中的东东容易写错,所以这里使用Q_ASSERT()对返回值res进行检验。需要注意的是,signal和slot参数匹配时类型必须是一样的,如果signal参数为int,而slot参数为QString,就会connect不成功。不过参数的个数不需要是相同的,slot可以比signal的参数个数少,如signal(int i, String s)跟slot(int i)连接时,是可以connect成功的,只不过signal的String类型的参数被忽略掉了,不能出现signal参数比slot参数少。还要注意的是如果signal和slot的参数类型为Cascades定义的类型,则需要写上类的完全限定名:前面加上命名空间,如:
1
2
3
4
|
QObject::connect(myImageView,
SIGNAL(imageChanged(bb::cascades::Image*)),
myHandler,
SLOT(onImageChanged(bb::cascades::Image*)));
|
2. 创建自定义的signals和slots
(1)在QML中,自定义signal很简单,在函数前面加上signal关键字就行了,emit的时候直接调用函数。如:
1
2
3
4
5
6
7
8
9
10
11
|
Button {
id: myButton
signal clickedWithText(string currentText)
text:
"Hello world"
onClicked: {
clickedWithText(text)
}
onClickedWithText: {
console.debug(
"onClickedWithText: "
+ text)
}
}
|
点击按钮的时候会emit clickedWithText,跟预定义的信号一样,会自动生成一个onXXsignal处理程序,因此在控制台会打印出内容 onClickedWithText:Hello World, 如图
你也可以将自定义的JavaScript函数指定为slot,然后跟自定义的signal connect起来,可以分别把signal和slot定义在不同的qml文件,如:新建MyLabel.qml,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import bb.cascades
1.0
Container {
function handleText(message) {
label.text = message
console.debug(
"handleText: "
+ message)
}
Label {
id: label
text: qsTr(
"Hello World"
)
textStyle.base: SystemDefaults.TextStyles.BigText
horizontalAlignment: HorizontalAlignment.Center
}
}
|
main.qml中添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
MyLabel {
id: myLabel
}
Button {
id: myButton
signal clickedWithText(string currentText)
text:
"Click me"
onClicked: {
myButton.clickedWithText.connect(myLabel.handleText)
myButton.clickedWithText(
"Alex Zhou"
)
}
}
|
点击按钮的时候,handleText函数会被调用,打印日志(handleText: Alex Zhou):
(2)在C++中:在头文件中定义signals和slots,下面来模拟实现一个登陆验证的例子,创建LoginService类,用来进行登陆时验证用户名和密码,LoginService.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/*
* LoginService.h
*
* Created on: 2013-3-23
* Author: Administrator
*/
#ifndef LOGINSERVICE_H_
#define LOGINSERVICE_H_
#include <QObject>
class
LoginService :
public
QObject{
Q_OBJECT
public
:
LoginService();
virtual
~LoginService();
signals:
void
loginResult(
bool
result);
public
slots:
void
startLogin(
const
QString& username,
const
QString &passwd);
};
#endif /* LOGINSERVICE_H_ */
|
声明了一个signal(登陆处理结果信号)和一个slot(验证登陆请求),来实现LoginService.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/*
* LoginService.cpp
*
* Created on: 2013-3-23
* Author: Administrator
*/
#include "LoginService.h"
#include <QDebug>
LoginService::LoginService() {
// TODO Auto-generated constructor stub
}
LoginService::~LoginService() {
// TODO Auto-generated destructor stub
}
void
LoginService::startLogin(
const
QString &username,
const
QString &passwd)
{
qDebug() <<
"startLogin: username="
<< username <<
"&password="
<< passwd;
if
(username ==
"alexzhou"
&& passwd ==
"123456"
)
emit loginResult(
true
);
else
emit loginResult(
false
);
}
|
接着来创建UserLogin类,内部也封装了一个signal和一个slot,该类可以封装一些函数供qml调用。
UserLogin.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/*
* UserLogin.h
*
* Created on: 2013-3-23
* Author: Administrator
*/
#ifndef USERLOGIN_H_
#define USERLOGIN_H_
#include <QObject>
class
LoginService;
class
UserLogin :
public
QObject{
Q_OBJECT
public
:
UserLogin();
virtual
~UserLogin();
signals:
void
login(
const
QString &username,
const
QString &passwd);
public
slots:
void
onLoginResult(
bool
result);
private
:
LoginService *m_pLoginService;
};
#endif /* USERLOGIN_H_ */
|
UserLogin.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/*
* UserLogin.cpp
*
* Created on: 2013-3-23
* Author: Administrator
*/
#include "UserLogin.h"
#include "LoginService.h"
#include <QDebug>
UserLogin::UserLogin() {
// TODO Auto-generated constructor stub
m_pLoginService =
new
LoginService();
bool
result = QObject::connect(
this
, SIGNAL(login(
const
QString&,
const
QString&)), m_pLoginService, SLOT(startLogin(
const
QString&,
const
QString&)));
Q_ASSERT (result);
result = QObject::connect(m_pLoginService, SIGNAL(loginResult(
bool
)),
this
, SLOT(onLoginResult(
bool
)));
Q_ASSERT(result);
Q_UNUSED(result);
emit login(
"alexzhou"
,
"123456"
);
}
UserLogin::~UserLogin() {
if
(m_pLoginService)
{
delete
m_pLoginService;
m_pLoginService = NULL;
}
}
void
UserLogin::onLoginResult(
bool
result) {
qDebug() <<
"login result: "
<< result;
}
|
这里在UserLogin类的构造函数中进行了相关绑定和emit login操作,只是为了方便,在实际开发中可以在UserLogin定义一个登陆接口,然后在登陆按钮的onClicked处理程序中调用该登陆接口。
使用的时候在(ProjectName).cpp的构造函数中加入UserLogin userLogin;就行了。运行程序,打印日志为:
转载请注明来自:Alex Zhou的程序世界,本文链接:http://codingnow.cn/blackberry/1173.html