Обработка сообщения Cocoa setAction в Objective-C++

Как вы обрабатываете сообщение setAction в Objective-C++? (Не в Objective-C)

Например, предположим, что у меня есть:

мой_класс.mm

NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
[segmented setSegmentCount:5];
// etc.
[segmented setAction:???];

Применение: я программирую на Qt (C++), и мне нужна оболочка для некоторых виджетов Cocoa, которые я хочу использовать напрямую. Я наследую от QMacCocoaViewContainer, но не могу понять, как обрабатывать «щелчки» NSSegmentedControl, которые я оборачиваю. В конце концов это выдаст стандартный сигнал Qt.


person Dave Mateer    schedule 20.01.2012    source источник


Ответы (3)


action — это просто селектор — он используется в паре с target. поэтому напишите метод objc для target+action, который вызывает или делает то, что вы действительно хотите. Аргументы actions' являются отправителем, но вы можете опустить их, если они вам не нужны. отправителем будет то, что отправляет сообщение (например, элемент управления). в ObjC++ все то же самое - это должно быть заключено в метод objc, потому что целью должен быть объект objc.

так что это будет выглядеть так:

obj.action = @selector(pressDoStuff:);

и метод:

- (void)pressDoStuff:(id)sender
person justin    schedule 20.01.2012
comment
Что сказал @Justin. В итоге я пишу множество небольших прокси-классов Objective C, которые имеют методы Objective C, вызывающие методы C++. - person smparkes; 21.01.2012
comment
Это дает мне ожидаемый неквалифицированный идентификатор перед ошибкой компиляции токена «-». - person Dave Mateer; 23.01.2012
comment
@ Дэйв, в коде, который я разместил, нет ничего плохого. вы положили его в нужное место? и ваш исходный код скомпилирован как ObjC или ObjC++? - person justin; 23.01.2012

У @Justin есть правильный ответ; Я приму это, но также включу окончательное решение на случай, если оно поможет другим. Хитрость в том, что вам нужен прокси-класс, как заметил @smparkes.

Игнорирование файлов .h для краткости:

mac_control.mm

MacControl::MacControl(QWidget *parent) : QMacCocoaViewContainer(NULL, parent) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
  // Set up NSSegmentedControl...

  // The proxy class marshalls between Objective-C and C++.
  proxy_ = [[MacControlProxy alloc] init];
  [proxy_ setTarget:this];
  [segmented setTarget:proxy_];
  [segmented setAction:@selector(handleToggle:)];

  setCocoaView(segmented);
  [segmented release];

  [pool release];
}

MacControl::~MacControl() {
  delete proxy_;
}

void MacControl::TriggerAction(int index) {
  // Trigger the action in Qt/C++.
}

mac_control_proxy.mm

@implementation MacControlProxy

- (id)init {
  [super init];
  target_ = NULL;
  return self;
}

-(void) handleToggle: (id)sender {
  if (target_) {
    target_->TriggerAction([sender selectedSegment]);
  }
}

-(void) setTarget: (MacToolbarButtonControlImpl*)target {
  target_ = target;
}

@end
person Dave Mateer    schedule 25.01.2012

Я слежу за ответом Дэйва Мэтира (который был очень полезен!).

У меня возникли проблемы с настройкой цели C++ (из класса Objective-C++) и я использовал [NSValue valueWithPointer:theTargetCxxClass] для передачи цели классу Proxy.mm.

Итак, внутри моего класса Objective-C++ вместо этого:

[proxy_ setTarget:this];

Я сделал это:

[proxy_ setTarget:[NSValue valueWithPointer:this]];

or

[proxy_ setTarget:[NSValue valueWithPointer:ptrToMyCxxObject]];

Благодаря этому удалось избавиться от ошибки, связанной с передачей класса C++ (который не расширяет тип «id») в прокси-класс Objective-C++.

Затем внутри прокси-класса вам нужно использовать метод pointerValue NSValue, а затем вернуться к классу C++, чтобы отправить ему сообщение.

-(void) myButtonAction: (id)sender {
  ((MyCxxClass*)[target pointerValue])->someMethodInMyCxxClass();
}

Сначала я был предупрежден о трюке «valueWithPointer» в это сообщение.

person Angus Forbes    schedule 07.07.2013