在 Objective-C 中处理 Cocoa setAction 消息

发布于 2024-12-28 15:10:20 字数 448 浏览 3 评论 0原文

如何在 Objective-C++ 中处理 setAction 消息? (不是 Objective-C。

例如,假设我有:

my_class.mm

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

应用程序:我正在使用 Qt (C++) 进行编程,并且需要一个围绕一些 Cocoa 小部件的包装器想直接使用。我继承自 QMacCocoaViewContainer,但无法弄清楚如何处理我正在包装的 NSSegmentedControl 的“点击”。最终这将发出一个标准的 Qt 信号。

How do you handle the setAction message in Objective-C++? (Not Objective-C.)

For example, suppose I have:

my_class.mm

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

Application: I am programming in Qt (C++) and need a wrapper around some Cocoa widgets I want to use directly. I am inheriting from QMacCocoaViewContainer but can't figure out how to handle the "clicks" of the NSSegmentedControl I am wrapping. Eventually this will emit a standard Qt signal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱殇璃 2025-01-04 15:10:20

action 只是一个选择器 - 它与 target 一起使用。因此,为 target+action 编写一个 objc 方法,它可以调用或执行您真正想要的操作。 actions' 参数是发送者,但如果不需要,可以忽略它。发送者将是发送消息的任何东西(例如控件)。在 ObjC++ 中没有什么不同 - 这必须包装在 objc 方法中,因为目标必须是 objc 对象。

所以它看起来像这样:

obj.action = @selector(pressDoStuff:);

方法是:

- (void)pressDoStuff:(id)sender

action is just a selector - it is used in tandem with target. so write an objc method for target+action which calls through or does what you really want. actions' arguments are the sender, but you can omit that if you don't need it. the sender will be whatever is sending the message (e.g. the control). it's no different in ObjC++ - this has to be wrapped in an objc method because the target must be an objc object.

so it would look like this:

obj.action = @selector(pressDoStuff:);

and the method is:

- (void)pressDoStuff:(id)sender
风吹短裙飘 2025-01-04 15:10:20

@Justin 有正确的答案;我会接受它,但也会包括最终的解决方案,以防它对其他人有帮助。诀窍是您需要一个代理类,正如 @smparkes 所指出的。

为了简洁起见,忽略 .h 文件:

ma​​c_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++.
}

ma​​c_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

@Justin has the right answer; I'll accept it, but also include the final solution in case it helps others. The trick is you need a proxy class, as @smparkes noted.

Ignoring the .h files for brevity:

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
噩梦成真你也成魔 2025-01-04 15:10:20

我正在跟进戴夫·马特尔的回答(这非常有帮助!)。

我在设置 C++ 目标(从 Objective-C++ 类中)时遇到问题,并使用 [NSValue valueWithPointer:theTargetCxxClass] 将目标传递给 Proxy.mm 类。

因此,在我的 Objective-C++ 类中,而不是这样做:

[proxy_ setTarget:this];

我这样做了:

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

或者

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

这样做消除了将 C++ 类(不扩展类型“id”)传递给 Objective-C++ 代理类的错误。

在代理类内部,您需要使用 NSValue 的 pointValue 方法,然后强制转换回 C++ 类,以便向其发送消息。

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

我首先注意到 这篇文章

I'm following up on Dave Mateer's answer (which was super helpful!).

I was having issues setting the C++ target (from within a objective-C++ class) and used [NSValue valueWithPointer:theTargetCxxClass] to pass the target to the Proxy.mm class.

So, inside of my Objective-C++ class, rather than doing this:

[proxy_ setTarget:this];

I did this:

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

or

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

And doing this got rid of an error about passing a C++ class (which does not extend type "id") to the Objective-C++ proxy class.

Inside of the proxy class, you then need to use NSValue's pointerValue method and then cast back to the C++ class in order to send a message to it.

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

I first was alerted to the "valueWithPointer" trick in this post.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文