我有以下代码:
void OpenGLRenderer::mouseMoveEvent(QMouseEvent *ev)
{
//...
if(ev->buttons() & Qt::RightButton)
{
if(ev->modifiers() & Qt::ShiftModifier)
{
// ...
}
else
{
// ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不明白&符号的&比较是如何起作用的.这是&一个有点明智的AND操作吗?该声明如何ev->buttons() & Qt::RightButton运作?
在ev->buttons()/ ev->modifiers()和Qt::RightButton/ 的返回语句后面Qt::ShiftModifier有一个数值.
为了理解工作原理你需要熟悉enums,除了真正的整洁之外QFlags,它允许你轻松地组合多个数值(标志)以创建复杂的数值.
我们来看看鼠标按钮:
Qt::NoButton 0x00000000 The button state does not refer to any button (see QMouseEvent::button()).
Qt::LeftButton 0x00000001 The left button is pressed, or an event refers to the left button. (The left button may be the right button on left-handed mice.)
Qt::RightButton 0x00000002 The right button.
Qt::MidButton 0x00000004 The middle button.
Qt::MiddleButton MidButton The middle button.
Qt::XButton1 0x00000008 The first X button.
Qt::XButton2 0x00000010 The second X button.
Run Code Online (Sandbox Code Playgroud)
您可能会注意到这些值不是连续的,而是缺少某些值.例如,3,或5,或6等在哪里?假设您想要处理按下右侧和左侧按钮的情况.
在这些数字后面(以十六进制表示)是简单的二进制数字(0和1).如果我们将逻辑OR应用于0x01和0x02,则得到0x03:
0x01 | 0x02 = 0x03
Run Code Online (Sandbox Code Playgroud)
如果我们将这些数字看作0和1,我们就有了
0x01 (hex) = 01 (bin)
0x02 (hex) = 10 (bin)
0x03 (hex) = 11 (bin)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,由于逻辑OR,我们将0x01中的1和0x02中的1组合成一个0x03的11.
现在让我们反转并获取0x03,看看如果ev->buttons()返回它会发生什么.如果该函数返回此结果,我们知道当前正在按下0x01(左)和0x02(右).为什么?因为我们的枚举值中没有其他组合可以创建0x03!如果我们添加逻辑AND运算符,我们可以if如下重写条件(仅使用数值)
if (0x03 & 0x02)
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
但结果是0x03 & 0x02什么?这0x02是因为在二进制级别上我们有
11
AND 10
-------
10
Run Code Online (Sandbox Code Playgroud)
因为1和1是1(第一列)但是1和0是0(第二列).如果我们把它翻译成一个句子,我们有"如果当前按下右键,那么......".
让我们做一个更复杂的情况,我们按下右,左和中间按钮(0x01,0x02和0x04).
001
OR 010
OR 100
------
111 (bin) = 0x07 (hex) (one of the missing values in the enumeration above!)
Run Code Online (Sandbox Code Playgroud)
如果我们想要一个if声明,只有当按下右侧和中间按钮时才输入正文,我们需要做一些数学运算(再次;)).首先,我们需要获得告诉我们按下所需按钮的值:
010 (right button)
OR 100 (middle button)
------
110 (bin) = 0x06 (hex) (yet another of the missing values in the enumeration above!)
Run Code Online (Sandbox Code Playgroud)
接下来我们需要将该组合放在the return语句中ev->buttons(),在这种情况下返回0x07(按下以上所有三个按钮):
110 (Qt::MidButton | Qt::RightButton)
AND 111 (Qt::MidButton | Qt::RightButton | Qt::LeftButton)
-------
110
Run Code Online (Sandbox Code Playgroud)
如果我们把它放在if我们得到的条件下
if (ev->buttons() & (Qt::MidButton | Qt::RightButton)
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
很明显,如果ev->buttons()返回类似的东西Qt::RightButton | Qt::XButton1(无论XButton是什么:D),我们的if条件将会失败.为什么?因为
0010 (Qt::RightButton)
OR 1000 (Qt::XButton1)
-------
1010
Run Code Online (Sandbox Code Playgroud)
结合检查Qt::MidButton | Qt::RightButton给我们
1010 (Qt::RightButton | Qt::XButton1)
AND 0110 (Qt::RightButton | Qt::MidButton)
--------
0010 (Qt::RightButton)
Run Code Online (Sandbox Code Playgroud)
上面可能看起来有点奇怪,但它告诉我们按下右键是唯一连接两个按钮,X按钮和中间按钮显然不匹配,因此我们的if条件将失败.
现在,如果你想在两种情况下只检查正确的按钮,你就可以去了
1010 (Qt::RightButton | Qt::XButton1)
AND 0010 (Qt::RightButton)
--------
0010 (Qt::RightButton)
Run Code Online (Sandbox Code Playgroud)
以及
0110 (Qt::RightButton | Qt::MidButton)
AND 0010 (Qt::RightButton)
--------
0010 (Qt::RightButton)
Run Code Online (Sandbox Code Playgroud)
另一方面,如果ev->buttons()返回只是Qt::MidButton你检查Qt::RightButton使用AND运算符将得到你
0100 (Qt::MidButton)
AND 0010 (Qt::RightButton)
--------
0000
Run Code Online (Sandbox Code Playgroud)
就C/C++中的逻辑而言,数值0与布尔值相同,false因此if不会输入正文.
您也可以在Qt中应用相同的逻辑所有标志.