2014-01-08 3 views
0

Я создаю приложение для фортепиано (для OSX), которое имеет экранную клавиатуру, отображающую, что пользователь играет на своей синтезаторной клавиатуре. Все связано с каркасом CoreMIDI. Я создал некоторые пользовательские кнопки, подклассифицируя NSButton в классе под названием PianoKey. Класс можно посмотреть ниже:Пользовательский 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-данные с клавиатуры.

а) Этот 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 

б) функция обратного вызова вызывает кучу функций, которые Handl e данные 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: пользовательский интерфейс (экранный рисунок) обновляется только в основном потоке.

Поместите в ответ на запрос журнала или точку останова, чтобы узнать, вызвано ли оно вызовом. Если это так, проблема возникает из-за этой проблемы.


Update:

Так сказать кнопку, чтобы обновить себя - но в основном потоке (я думаю, что у меня есть право syntaxt - по крайней мере, для прошивки - OSX может различаться)

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

Я не совсем уверен ... Я не думаю, что это главная тема того, что я читал. Опять же, в CoreMIDI не так много информации, поэтому я не знаю, что взять иногда как правду:/ Что вы хотите, чтобы я попытался вызвать метод обратного вызова? – 02fentym

+0

Я только использовал CoreMidi в iOS, но из того, что я прочитал, проблема потока для обновления графического интерфейса - это то же самое. Сначала просто поместите инструкцию NSLog (или эквивалент какао) в свой метод 'updateLayer', чтобы узнать, вызвана ли она. Если это так, это проблема с потоком. В этом случае вы хотите использовать 'performSelectorOnMainThread'.Одно предостережение: поскольку обновление клавиатуры может происходить быстрее, чем частота обновления, может быть бессмысленно называть обновление для каждого. В iOS есть метод, который можно вызвать перед каждым обновлением экрана. Не знаю в OSX. Может быть, попробуйте выполнить 'performSelectorOnMainThread' первое объявление, если это работает –

+0

Хорошо, я знаю, о чем вы сейчас говорите. В настоящее время у меня есть указатель на экземпляр кнопки, так как я передал его в свою функцию обратного вызова. Если бы у меня не было этой ссылки, она ничего не узнает о моем объекте кнопки. Итак, вы правы, это проблема с потоком. Как вы используете 'performSelectorOnMainThread'? Я все равно, но я быстро научусь (думаю). Должен ли я опубликовать это как новый вопрос? Кстати, если у меня есть экземпляр моей кнопки, и я могу назвать 'updatelayer', как будет' performSelectorOnMainThread'? – 02fentym