Получение значений выбранных элементов

Имеется функция написанная другим программистом (К сожалению другую написать не получится и использовать придется только ее. Имеем то что имеем) Функция вызывает чек бокс с мульти выбором элементов и принимает 3 элемента и возвращает Bool:

  • Заголовок окна "String"
  • Варианты выбора "String"
  • Переменная типа Integer, куда и будет возращено номер выбранного элемента
function SelectMultiVariantDialog(aTitle: String; aVariant: String; var aTupel: Integer): Boolean;

И так чек бокс вызывается и в переменную Tupel возвращается число, но возвращается не индекс выбранного элемента, а суммы элементов, то есть При выборе элемента 1 = 1, 2 = 2, 3 = 4, 4 = 8, 5 = 16, 6 = 32, 7 = 64, 8 = 128 в переменную заносится соответствующее значение

И вот вопрос, при выборе множества элементов выдает сумму соответствующих значений, то есть 6 и 7 элемент нам выдаст в переменной 96. Как мне на основании этого определить какие элементы были выбраны. Может кто ни будь подскажет.


P.S. через aVariant я передаю варианты выбора для пользователя. Например:

  • 1 3001
  • 2 3002
  • 3 3003
  • ....

И даю возможность выбрать несколько вариантов. После выбора в aTupel передаётся битовое значение выбранного элемента или сумма битовых элементов(если выбрано несколько)

Я пытаюсь понять после получение значение в переменную aTupel, как мне понять какие элементы были выбраны, Например выбрали 1 и 2 вариант и теперь хочу получить значения выбранных элементов чтоб в дальнейшем можно было передать значения 3001 и 3002 передать для обработки в sql запрос(это уже отдельная история. И там все готово)

var aTupel: integer;

begin
  SelectMultiVariantDialog('Пожалуйста выберите событие',
    'Событие генерации отчёта 3001|Событие генерации отчёта 3002|' +
    'Событие генерации отчёта 3003|Событие генерации отчёта 3004|',
    aTupel);
end;

В SQL хочу передать эти события

where code in ('3001,3003,3007')

P.S.S. Я попробовал слепить то что мне тут порекомендовали и вроде получилось то что я ожидал. Представляю мое решение, вдруг кто посоветует более изящное решение

const    ET_ZERO     = $00;
const    ET_ONE      = $01;
const    ET_TWO      = $02;
const    ET_THREE    = $04;
const    ET_FOUR     = $08;
const    ET_FIVE     = $10;
const    ET_SIX      = $20;
const    ET_SEVEN    = $40;
const    ET_EIGHT    = $80;

var iActionsMask: integer;
var sActions: String;

begin
if iActionsMask <= 0 then
    begin
      if not SelectMultiVariantDialog('Выбирите события для получение отчета!',
                                '3001- аааа|3002- бббб|' +
                                '3003- вввв|3004- гггг|' +
                                '3005- дддд', iActionsMask) then Exit;


      //ShowMessage(IntToStr(iActionsMask));

if iActionsMask <= 0 then
        begin
          ShowMessage('Ничего не выбрано!');
          Exit;
        end
      else
      begin
          sActions:='';
          if (iActionsMask and ET_ZERO) > 0 then
             if Length(sActions) > 0 then sActions := sActions + ', 3001'  else sActions := '3001';
          if (iActionsMask and ET_ONE) > 0 then
             if Length(sActions) > 0 then sActions := sActions + ', 3002'  else sActions := '3002';
          if (iActionsMask and ET_TWO) > 0 then
             if Length(sActions) > 0 then sActions := sActions + ', 3003'  else sActions := '3003';
          if (iActionsMask and ET_THREE) > 0 then
             if Length(sActions) > 0 then sActions := sActions + ', 3004'  else sActions := '3004';
          if (iActionsMask and ET_FOUR) > 0 then
             if Length(sActions) > 0 then sActions := sActions + ', 3005'  else sActions := '3005';
      end;
    end;
        //ShowMessage('Выбраны позиции ' + sActions);
   end;

Правда я переименовал переменные и


Ответы (3 шт):

Автор решения: Kromster

Это называется не сумма, а битовый набор, где каждому флагу/значению соответствует один бит.

Можно проверить выставлен ли каждый бит применив логическое И с соответствующей маской (в которой выставлен только этот бит) вот так, например:

isOne  := ret and $01 <> 0; // Выбран первый элемент
isTwo  := ret and $02 <> 0; // Выбран второй элемент
isThre := ret and $04 <> 0; // Выбран третий элемент
isFour := ret and $08 <> 0; // Выбран четвертый элемент
isFive := ret and $10 <> 0; // Выбран пятый элемент
isSix  := ret and $20 <> 0; // Выбран шестой элемент
isSeve := ret and $40 <> 0; // Выбран седьмой элемент
isEigh := ret and $80 <> 0; // Выбран восьмой элемент

Как будут выглядеть несколько флагов? Например 42, в битовом представлении, это будет 00101010 (2 + 8 + 32 в десятичном виде. Или же $02 + $08 + $20 в шестнадцатеричном)


P.S. Лучше и правильнее было бы перейти на перечисления:

type
  TSomeFlag = (sfOne, sfTwo, sfThree, sfFour ...)
  TSomeFlagSet = set of TSomeFlag;

var
  ret: TSomeFlagSet;

isOne  := sfOne in ret;
isTwo  := sfTwo in ret;
...
→ Ссылка
Автор решения: MBo

В дополнение к ответу Kromster:

for i := 0 to 31 do
  if (aTupel and (1 shl i)) <> 0 then 
    вывести i
→ Ссылка
Автор решения: Old Skull

@AzatGafarov, слишком мало контекста, чтобы советовать более изящное рещение. Но как вариант...

...
var
  iActionsMask : integer;
      sActions : string;
          list : TStringList;
             i : integer;

begin
  // your code here...

  list := TStringList.Create();
  try
    for i := 0 to 31 do
      if ( iActionsMask and (1 shl i) ) <> 0 then
        list.Add( (i + 3001).ToString() );

    sActions := list.CommaText;
  finally
    list.Free();
  end;

  // your code here...
end;

UPD. Можно чуть иначе, без сдвигов...

type
  TElement = 0..7;

...
var
  iActionsMask : integer;
  elements     : set of TElement absolute iActionsMask;
  sActions     : string;
          list : TStringList;
             e : TElement;

begin
  // your code here...

  list := TStringList.Create();
  try
    for e := Low(TElement) to High(TElement) do
      if ( e in elements ) then
        list.Add( IntToStr(e + 3001) );

    sActions := list.CommaText;
  finally
    list.Free();
  end;

  // your code here...
end;
→ Ссылка