2014-01-08 55 views
0

我正在創建一個鋼琴應用程序(用於OSX),它有一個屏幕鍵盤,顯示用戶在他們的合成鍵盤上正在播放的內容。一切都使用CoreMIDI框架進行連接。我創建了一些海關按鈕,通過在名爲PianoKey的課程中對NSButton進行繼承。該類可以看到如下:定製NSButton不能從CoreMIDI回調函數中工作

#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]; 

} 

[按鈕updateLayer]叫我updateLayer()方法來自PianoKey,但它不會改變圖像。有什麼我失蹤?看起來好像視圖或窗口沒有被更新,即使我的按鈕說它是「高亮顯示」。請幫忙!在此先感謝:)

回答

2

只是一個猜測(但一個很好的...... ;-)是在主線程上調用回調函數?如果不是的話,那可能是問題 - 至少它是在iOS中工作的方式:UI(屏幕繪圖)僅在主線程中更新。

在回調中放入一個日誌語句或斷點以查看它是否正在調用。如果是這樣,那麼問題是由於這個線程問題。


更新:

所以告訴按鈕來更新自己 - 而是在主線程(我覺得我有syntaxt正確的 - 至少對於iOS版 - OSX可能會發生變化)

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

我不完全確定......我不認爲這是從我一直在閱讀的主線上。再說一遍,CoreMIDI上的信息並不多,所以我不知道有時候該說些什麼:/ 你想讓我嘗試在回調方法中調用什麼? – 02fentym

+0

我只在iOS中使用CoreMidi,但從我讀過的內容來看,GUI更新的線程問題是相同的。首先在你的'updateLayer'方法中放一個NSLog(或Cocoa等價)語句,看它是否被調用。如果是,那麼這是一個線程問題。在這種情況下,你想使用'performSelectorOnMainThread'。一個警告:由於鍵盤更新速度可能會比刷新速度快,因此每次調用更新可能毫無意義。在iOS中,有一種方法可以在每次刷新屏幕前調用。不知道在OSX中。也許嘗試'performSelectorOnMainThread'第一個廣告看看是否有效 –

+0

好吧,我知道你在說什麼了。我現在有一個指向我的按鈕實例的指針,因爲我將它傳遞給了我的回調函數。如果我沒有這個參考,它會對我的按鈕對象一無所知。所以你是對的,這是一個線程問題。你如何使用'performSelectorOnMainThread'?我對這一切都很樂觀,但我快速學習(我認爲)。我應該將此作爲一個新問題嗎?順便說一句,如果我有一個我的按鈕的實例,我可以調用'updatelayer','performSelectorOnMainThread'將如何幫助? – 02fentym