Не понимаю Qt амперсанд и побитовую операцию И: if (ev-> buttons () & Qt :: RightButton) - PullRequest
0 голосов
/ 24 июня 2018

У меня есть следующий код:

void OpenGLRenderer::mouseMoveEvent(QMouseEvent *ev)
{
    //...

    if(ev->buttons() & Qt::RightButton)
    {
        if(ev->modifiers() & Qt::ShiftModifier)
        {
            // ...
        }
        else
        {
            // ...
        }
    }
}

Я не понимаю, как работают сравнения амперсандов и &. Является ли операция & побитовой AND? Как работает утверждение ev->buttons() & Qt::RightButton?

1 Ответ

0 голосов
/ 24 июня 2018

За оператором возврата ev->buttons() / ev->modifiers() и Qt::RightButton / Qt::ShiftModifier стоит числовое значение.

Чтобы понять, как все работает, вы должны быть знакомы с enum s и в дополнение к действительно аккуратному 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.

Вы можете заметить, что значения не являются последовательными, а некоторые отсутствуют.Например, где 3, или 5, или 6 и т. Д.?Допустим, вы хотите справиться с ситуацией, когда нажаты правая и левая кнопки.

За этими числами (которые в виде шестнадцатеричных чисел) лежат простые двоичные числа (0 и 1).Если мы применим логическое ИЛИ к 0x01 и 0x02, мы получим 0x03:

0x01 | 0x02 = 0x03

Если мы посмотрим на эти числа как 0 и 1, мы получим

0x01 (hex) = 01 (bin)
0x02 (hex) = 10 (bin)
0x03 (hex) = 11 (bin)

Как вы можете видеть, потому чтоиз логического ИЛИ мы скомбинировали 1 из 0x01 и 1 из 0x02 в 11, что является 0x03.

Теперь давайте все изменим и возьмем 0x03 и посмотрим, что произойдет, если ev->buttons() вернет его.Если эта функция возвращает этот результат, мы знаем, что в данный момент нажаты и 0x01 (слева), и 0x02 (справа).Зачем?Потому что нет другой комбинации из значений нашего перечисления, которая создает 0x03!Если мы добавим логический оператор AND, мы можем переписать условие if следующим образом (используя только числовые значения)

if (0x03 & 0x02)
{
  // do something
}

Но каков результат 0x03 & 0x02?Это 0x02, и это потому, что на двоичном уровне у нас есть

     11
AND  10
-------
     10

, поскольку 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!)

Если нам нужен оператор if, тело которого вводится только при нажатии правой и средней кнопки, нам нужно выполнить некоторые математические операции (снова;)).Сначала нам нужно получить значение, которое говорит нам, что обе требуемые кнопки были нажаты:

   010 (right button)
OR 100 (middle button)
------
   110 (bin) = 0x06 (hex) (yet another of the missing values in the enumeration above!)

Затем нам нужно поместить эту комбинацию против оператора возврата ev->buttons(), который в этом случае возвращает 0x07 (нажаты все три вышеуказанные кнопки):

    110 (Qt::MidButton | Qt::RightButton)
AND 111 (Qt::MidButton | Qt::RightButton | Qt::LeftButton)
-------
    110

Если мы поместим это в условие if, мы получим

if (ev->buttons() & (Qt::MidButton | Qt::RightButton)
{
  // do something
}

Ясно, если ev->buttons() вернет что-то вроде Qt::RightButton | Qt::XButton1(какой бы XButton не был: D) наше условие if не выполнится.Зачем?Потому что

   0010 (Qt::RightButton)
OR 1000 (Qt::XButton1)
-------
   1010

в сочетании с проверкой на Qt::MidButton | Qt::RightButton дает нам

    1010 (Qt::RightButton | Qt::XButton1)
AND 0110 (Qt::RightButton | Qt::MidButton)
--------
    0010 (Qt::RightButton)

Вышеприведенное может показаться немного странным, но все это говорит нам о том, что нажатая правая кнопка является единственнымштука, соединяющая две кнопки и среднюю кнопку X, явно не совпадает, поэтому наше условие if не будет выполнено.

Теперь, если вы хотите просто проверить правильную кнопку в обоих случаях, вы можете пойти, так как

    1010 (Qt::RightButton | Qt::XButton1)
AND 0010 (Qt::RightButton)
--------
    0010 (Qt::RightButton)

, а также

    0110 (Qt::RightButton | Qt::MidButton)
AND 0010 (Qt::RightButton)
--------
    0010 (Qt::RightButton)

С другой стороны, если ev->buttons() вернет просто Qt::MidButton, но вы проверите для Qt::RightButton, используя оператор AND, вы получите

    0100 (Qt::MidButton)
AND 0010 (Qt::RightButton)
--------
    0000

И с точки зрения логики в C / C ++ числовое значение 0 совпадает с логическим значением false, следовательно, тело if не будет введено.

Youможет применить ту же логику ко всем флагам в Qt.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...