自定义NSButton无法使用CoreMIDI回调函数

时间:2014-01-08 03:05:14

标签: cocoa nsbutton coremidi

我正在创建一个钢琴应用程序(用于OSX),它有一个屏幕键盘,显示用户在合成键盘上播放的内容。使用CoreMIDI框架连接所有内容。我通过在名为 PianoKey 的类中继承NSButton来创建一些关键按钮。课程如下:

#import "PianoKey.h"

@implementation PianoKey

//updates the core animation layer whenever it needs to be changed
- (BOOL)wantsUpdateLayer {
    return YES;
}

- (void)updateLayer {
    //tells you whether or not the button is pressed
    if ([self.cell isHighlighted]) {
        NSLog(@"BUTTON PRESSED");
        self.layer.contents = [NSImage imageNamed:@"buttonpressed.png"];
    }
    else {
        NSLog(@"BUTTON NOT PRESSED");
        self.layer.contents = [NSImage imageNamed:@"button.png"];
    }
}

@end

“PianoKeys”以编程方式创建。未按下时,钢琴键为蓝色,按下时为粉红色(仅为临时颜色)。如果单击屏幕上的按钮,颜色开关工作正常,但当我尝试通过MIDI键盘播放时,它们没有改变。

有些注意事项: 1)MIDI键盘工作 2)我从键盘上成功获取MIDI数据。

a)此MIDI数据传递给名为 midiInputCallback 的回调函数,如下所示: [来自AppController.m课程]

void midiInputCallback(const MIDIPacketList *list, void *procRef, void *srcRef) {
    PianoKey *button = (__bridge PianoKey*)procRef;

    UInt16 nBytes;
    const MIDIPacket *packet = &list->packet[0]; //gets first packet in list

    for(unsigned int i = 0; i < list->numPackets; i++) {
        nBytes = packet->length; //number of bytes in a packet

        handleMIDIStatus(packet, button);
        packet = MIDIPacketNext(packet);
    }
}

对象按钮是对我按照AppController.h中的定义以编程方式创建的按钮的引用:

@property PianoKey *button; //yes, this is synthesized in AppController.m

b)回调函数调用一堆处理MIDI数据的函数。如果检测到某个音符正在播放,这就是我将自定义按钮设置为高亮显示的位置...这可以在下面的函数中看到:

void updateKeyboardButtonAfterKeyPressed(PianoKey *button, int key, bool keyOn) {
    if(keyOn)
        [button highlight:YES];
    else
        [button highlight:NO];

    [button updateLayer];

}

[button updateLayer]从PianoKey调用我的updateLayer()方法,但它不会更改图像。有什么我想念的吗?看起来好像视图或窗口没有被更新,即使我的按钮说它被“突出显示”。请帮忙!在此先感谢:)

1 个答案:

答案 0 :(得分:2)

只是一个猜测(但是一个好的...... ;-)是否在主线程上调用了回调函数?如果没有,那可能就是问题了 - 就像它在iOS中的工作方式一样:UI(屏幕绘图)只在主线程中更新。

在回调中放置一个日志语句或断点,以查看它是否被调用。如果是,则问题是由于此线程问题。


<强>更新

所以告诉按钮更新自己 - 但是在主线程上(我认为我的语法合适 - 至少对于iOS - OSX可能会有所不同)

[button performSelectorOnMainThread:@selector(updateLayer) 
                         withObject:nil 
                      waitUntilDone:FALSE];