QtアプリケヌションをMac OS Xに統合するCocoaずObjective-C ++を䜿甚

すべおの人に良い䞀日を



最近、Mac OS Xでりィンドりタむトルをカスタマむズするこずに぀いお曞いたのですが、QtずCocoaの盞互䜜甚に぀いおさらに詳しく曞くようにずいうリク゚ストがありたした。 トピックを少し広げお、Qtを䜿甚しお䜜成されたアプリケヌションのMac OS Xぞの統合に぀いお説明できるず思いたす。Qtfor Cocoaがこの堎合に䜿甚されるこずに蚀及したす。Qtfor Carbonを䜿甚する堎合は、炭玠のみを䜿甚する必芁がありたす。 しかし、それは時代遅れであり、極端な堎合にのみ䜿甚する䟡倀がありたす。



通垞のQtプログラムには、Apple HIGずの倚くの矛盟がありたす。 より正確には、すべおのプログラムが远加機胜を必芁ずするわけではないので、持っおいるかもしれたせん。 たずえば、すべおのプログラムでドックのアむコンの䞊にバッゞを付けたり、ドックメニュヌを展開したり、ポピヌメニュヌの䞀郚の機胜を削陀/耇補する必芁はありたせん。



しかし、この機胜が必芁な堎合はどうでしょうか ドックSkypeなどで通知の数を衚瀺する必芁がある堎合は、ドックのアむコンをクリックしお凊理し、メニュヌ項目をドックに远加し、通垞のメニュヌを䜿甚しお、䞀般的に、プログラムをMac OSのネむティブのようにしたすか これのいく぀かは、通垞たたは半文曞化されたQt関数を䜿甚しお実行できたす。たた、Cocoaず、したがっおObjective-Cを䜿甚しおのみ実行できるものもありたす。



Objective-C ++が圹立ちたす



それはどんな動物で、䜕ず䞀緒に食べたすか 本質的に、これはObjective-CずC ++クラスを1぀の゜ヌスファむルに結合する機胜です。 さらに、芋出しの拡匵子は暙準.hのたたですが、゜ヌスに぀いおは、拡匵子.mmを指定する必芁がありたす。これにより、コンパむラはそれを食べおチョヌクしたせん。



ここで、Qtで䜜成されたおそらく倧きなプロゞェクトがあるず想像しおください。 圓初はWindowsたたはLinuxで曞かれおいたしたが、今ではマクロに転送する必芁がありたす。そのため、ケシの栜培者がこの怪物を芋たずきに錻にしわが寄らないように、矎しく䟿利です。



手始めに、Apple HIGのプログラムむンタヌフェヌスを調敎する必芁があるこずは明らかです。ただし、これはこの蚘事の範囲倖です。異なるOS向けに異なるコヌドをコンパむルできる䟿利なQ_WS_ *定矩に぀いおのみ蚀及したす。 アプリケヌションを新しい環境に適応させる方法に぀いお説明したすたたはQtでMacアプリケヌションをれロから䜜成する方法-目暙によっお異なりたす。



順番に行きたしょう。



䞀般的な統合





たず、プログラムに名前ずアむコンを付けたす。 いいえ、バンドルの名前ではなく、アプリケヌションメニュヌに衚瀺される名前です。 これを行うには、qmakeが生成するものではなく、独自のInfo.plistファむルが必芁です。 これは、.proの1行で実行されたす。



macx: QMAKE_INFO_PLIST = MyInfo.plist
      
      





.plistでは、次のように蚘述したす。



 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>LSHasLocalizedDisplayName</key> <true/> <key>CFBundleIconFile</key> <string>myicon.icns</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleGetInfoString</key> <string>Created by Qt/QMake</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleExecutable</key> <string>MyAppName</string> <key>CFBundleIdentifier</key> <string>com.mycompany.myapp</string> <key>NOTE</key> <string>This file was generated by Qt/QMake.</string> </dict> </plist>
      
      





もちろん、「MyAppName」ず「com.mycompany.myapp」の代わりに、プログラムの英語名ずそのバンドル識別子を蚘述したす。 なぜ英語 はい、別のファむルにロヌカラむズするため。 これは、リストの最初のパラメヌタヌLSHasLocalizedDisplayNameによっお瀺されたす。 ディレクトリ「ru.lproj」ずその䞭にファむルInfoPlist.stringsを䜜成したす。 このファむルでは、次のように蚘述したす。



 /* Localized versions of Info.plist keys */ CFBundleName = "  "; CFBundleDisplayName = "";
      
      





ここでは、バンドルのロヌカラむズされた名前ず、アプリケヌションメニュヌに衚瀺される名前を指定する必芁がありたす。 これを機胜させるには、プログラムをむンストヌルするずきにこのディレクトリをAppName.app/Contents/Resourcesにコピヌする必芁がありたす。.proファむルでINSTALLSを指定するこずをお勧めしたす。詳现に぀いおは、qmakeのドキュメントを参照しおください。 スクリヌンショットは、バンドル自䜓にラテン語の名前があるにもかかわらず、アプリケヌションメニュヌの名前がロシア語であるこずを瀺しおいたす。





プログラムアむコンMyInfo.plistファむルのmyicon.icnsを参照を蚭定するには、グラフィック゚ディタヌで自分で䜜成するか、 プログラムたたはオンラむンサヌビスを䜿甚しお.icoたたは䞀連の.pngから倉換できる.icnsファむルが必芁です。 アむコンの芋栄えを良くするには、512x512、256x256、128x128、64x64、48x48、32x32、16x16のいく぀かのサむズにするこずをお勧めしたす。 システム自䜓が、どの状況でどのサむズを衚瀺するかを遞択したす。 アむコンのあるファむルもリ゜ヌスにむンストヌルする必芁がありたす。 むンストヌルする最も簡単な方法は、.proファむルに以䞋を曞き蟌むこずです。



 macx: ICON = myicon.icns
      
      





コヌド分​​離





Objective-C ++には倚くの制限がありたす。 たずえば、.cpp゜ヌスファむルにObjective-Cクラスむンタヌフェむスの宣蚀にヘッダヌを含めるこずはできたせん。コンパむラがチョヌクするからです。 Mac OS X専甚に蚭蚈された新しいプロゞェクトの堎合、これは制限ではありたせん。すべおのC ++コヌドを.mmファむルに保持し、楜しむこずができるからです。 しかし、Qtの意味はクロスプラットフォヌムなので、゜ヌスコヌドはただ.cppファむルにあるず想定したす。



出口は簡単です。 C ++でObjective-C呌び出しずクラスのラッパヌを䜜成する必芁がありたす。 私はこの構造を遞択したした。MacOS Xずの統合を提䟛するQt / C ++クラスがありたす。それ自䜓でいく぀かの䜜業を行い、Cocoa / Objective-Cを積極的に䜿甚するプラむベヌトクラス「デリゲヌト」ぞのデリゲヌトを行いたす。 同時に、次のファむルを取埗したす。



* myclass.h-メむンクラスのヘッダヌ

* myclass.cpp-実装

* myclass_p.h-プラむベヌトクラスヘッダヌObjective-Cむンタヌフェむスなし

* myclass_p.mm-プラむベヌトクラス゜ヌス、Objective-Cクラスのむンタヌフェむスず実装、ヘッダヌなどを含めるこずができたす。



したがっお、C ++ずObjective-C ++を明確に区別したす。



ずころで、Objective-C ++が機胜するためには、.proファむルでそれを䜿甚するすべおのヘッダヌ/゜ヌスをOBJECTIVE_HEADERSおよびOBJECTIVE_SORCESセクションに配眮する必芁がありたす。 そしおもちろん、macxブロック内でそれを行いたす{}。 たた、Cocoaを䜿甚する堎合は、このフレヌムワヌクをプロゞェクトに远加する必芁がありたす。 .proで曞き蟌みたす。



 macx: QMAKE_LFLAGS += -framework Cocoa
      
      





そしお今、楜しみが来るでしょう。



Dockを䜿甚する





ドックを操䜜する5぀の䞻芁な機胜を考えおみたしょう。バッゞの远加、オヌバヌレむの远加、ドック内のアむコンのクリック凊理、ドック内のプログラムアむコンの「トス」、独自のメニュヌの远加。 Qtを䜿甚するず、最埌の問題だけでなく、文曞化が䞍十分な関数qt_mac_set_dock_menuQMenu *でも解決できたす。 たた、倖郚から宣蚀する必芁がありたす。



 extern void qt_mac_set_dock_menu(QMenu *); // Qt internal function
      
      





個人的な経隓に基づいお、「ネむティブ」マックメニュヌず比范しお、メニュヌにはいく぀かの制限が課されおいたす。



*非アクティブ無効メニュヌ項目は䜕らかの理由でアクティブになりたす

* QMenuはaboutToHideおよびaboutToShow信号を出力したせん

*芁玠をむンデントするこずはできたせん

*メニュヌの最初のQActionがセパレヌタヌである堎合、それは衚瀺されたす他のすべおのQMenuマニフェストずは異なりたす



したがっお、それに適応する必芁がありたす。 もちろん、Objective-C / Cocoaですべおを実行できたすが、QActionずネむティブメニュヌ項目をマッピングする独自のメカニズムを䜜成する必芁がありたす。 ただし、これらの制限を排陀する必芁性が非垞に高い堎合にのみ、これを行うこずは理にかなっおいたす。





次に、ドックのクリックを怜蚎したす。 Cocoaで蚘述した堎合、問題はありたせん。AppDelegateでapplicationShouldHandleReopenhasVisibleWindowsメ゜ッドを実装すれば十分です。 しかし、Qtの腞で䜜成されたプログラムデリゲヌトに盎接アクセスするこずはできたせん。 したがっお、 ランタむムのマゞックを䜿甚しお、このメ゜ッドの実装を远加したす 。 たず、必芁なものを実装する関数を宣蚀したす。 これを行うには、プラむベヌトクラスをシングルトンに倉換しずにかく、このクラスの耇数のオブゞェクトは必芁ありたせん、次の関数を蚘述したす。



 void dockClickHandler(id self, SEL _cmd) { Q_UNUSED(self) Q_UNUSED(_cmd) MyPrivate::instance()->emitClick(); }
      
      





関数は、デリゲヌトに埋め蟌たずに死んでいたす。 これをためらわないでください



 MyPrivate::MyPrivate() : QObject(NULL) { Class cls = [[[NSApplication sharedApplication] delegate] class]; if (!class_addMethod(cls, @selector(applicationShouldHandleReopen:hasVisibleWindows:), (IMP) dockClickHandler, "v@:")) NSLog(@"MyPrivate::MyPrivate() : class_addMethod failed!"); } void MyPrivate::emitClick() { emit dockClicked(); }
      
      





ここで、アプリケヌションのデリゲヌトクラスを取埗し、メ゜ッドをその堎で远加したす。 同時に、emitClickメ゜ッドを実装したす。このメ゜ッドは、クリックに関するQtシグナルを発行したす。 実際、これですべおです。たずえば、メむンプログラムりィンドりなどを衚瀺できるドックをクリックするだけです。



次に、ドックのプログラムアむコンを攟り投げるこずができたす。 私の最初の考え「QApplication :: alertQWidget *は同じこずをするこずができたす」その考えは真実ですが、時期尚早に楜芳的です。 問題は、Mac OS X 10.6の堎合です。*この関数は正垞に機胜したすが、10.7の堎合です。*䜕らかの理由で䞍芁ですこれはQt 4.7.xが公匏にLionをサポヌトしおいないためかもしれたせんが、 4.8では修正されたす。 私はこれがなぜ起こるのか理解できず、Cocoaにトスを曞いただけです。



 void MyPrivate::requestAttention() { [NSApp requestUserAttention: NSInformationalRequest]; }
      
      





このコヌドはQt-shn alertを耇補したすが、Mac OS Xのすべおのバヌゞョンで動䜜したす。他のシステムでも、alertを䜿甚できたす。



次に、バッゞを扱いたしょう。 誰かが知らない堎合、これはドックのプログラムアむコンの䞊にテキストが衚瀺された赀い円です。 たずえば、Mail.appの未読メッセヌゞの数を衚瀺するために䜿甚されたす。 Appleのドキュメントでは、これは次のように行う必芁があるず曞かれおいたす。



 [[NSApp dockTile] setBadgeLabel: badgeString];
      
      





ここで、badgeStringはNSString *型です。 ええ、これは最初の䞍䟿です Qtでは、QStringは通垞操䜜されたす。぀たり、文字列の特定の「コンバヌタヌ」を蚘述する必芁がありたす。



 // warning! nsstring isn't released! NSString * nsStringFromQString(const QString & s) { const char * utf8String = s.toUtf8().constData(); return [[NSString alloc] initWithUTF8String: utf8String]; }
      
      





コヌドおよびコメントからわかるように、返された文字列は解攟されないため、呌び出しコヌドでそれを行う必芁がありたすQtはARCを䜿甚しないため、メモリを監芖したす。



これで、ドックのバッゞに必芁な行を衚瀺するプラむベヌトクラスの関数を䜜成できたす。



 void MyPrivate::setDockBadge(const QString & badgeText) { NSString * badgeString = nsStringFromQString(badgeText); [[NSApp dockTile] setBadgeLabel: badgeString]; [badgeString release]; }
      
      







ドックを䜿甚する最埌の偎面は、任意のオヌバヌレむをドックに远加するこずです。 これは、次のコヌドを䜿甚しお行われたす。



 [[NSApp dockTile] setContentView: view];
      
      





ここでのビュヌはNSView *です。 しかし、私たちはQtで䜜業しおいたす そのため、オヌバヌレむにQWidget *を配眮する必芁がありたす。 NSViewをQWidgetから取埗する方法は 簡単な関数を曞きたす



 NSView * nsViewFromWidget(QWidget * w) { return (NSView *)w->winId(); }
      
      





簡単です。Qtの䜜成者は、ほがすべおの䜜業を行っおくれたした。



しかし、残念ながら、残念なこずに私たちは埅っおいたす。QWidgetから取埗したNSViewは、ドックぞのむンストヌルには適しおいたせん。 ぀たり、それは眮かれ、NSDockTileはそれを食べたすが、ドック内のりィゞェットのコンテンツの代わりに、空のスペヌスが圢成されたす。 理由はわかりたせん。 しかし、Qt Creatorでさえ、ドックの進行状況バヌは、このために特別に䜜成された玔粋なNSViewを介しお正確にハングアップしたす。 そのため、独自のオヌバヌレむが必芁な堎合は、Cocoaでビュヌを䜜成しおもかたいたせん。 ああ。



メニュヌを操䜜する





ポピヌメニュヌトップパネルのメニュヌに進みたしょう。 デフォルトでは、Qtプログラムは䜜成したせんシステム機胜を備えた暙準のアプリケヌションメニュヌを陀く。 Qt開発者にずっお最初に思い浮かぶのはQMenuBarです。 確かに、それに関するドキュメントは、ポピヌメニュヌの機胜を実行できるず述べおいたす。 ただし、2぀のオプションがありたす。プログラムりィンドりごずに個別のQMenuBarを䜜成するか、1぀のグロヌバルを䜜成したす。 吊定できない利点があるため、2番目のオプションを遞択したす。



繰り返しになりたすが、ドキュメントに基づいお、芪がれロのQMenuBar、぀たりQMenuBar * macMenuBar = new QMenuBarNULLを䜜成する必芁がありたす。これはグロヌバルになりたす。 より正確には、こうしお䜜成された最初のメニュヌバヌがグロヌバルになりたす。



そしお今-手で単調な仕事がたくさん。 「線集」、「ファむル」、「ヘルプ」メニュヌなどを䜜成したす。 これはかなり退屈な仕事ですが、それなしではプログラムは良く芋えたせん。 さらに、暙準のショヌトカット⌘Wおよび⌘Mは、それぞれりィンドりを閉じたり最小化したりしたせん。 たた、自分で行う必芁がありたす少なくずも、wellQはすぐに動䜜したす。



Mac OS XのQActionのいく぀かの機胜に泚目したす。それらにショヌトカットを指定する堎合、「Ctrl + M」をQKeySequenceコンストラクタヌに枡しお⌘Mショヌトカットを䜜成する必芁がありたす。 そしお䞀般に、ケシの䞋のQtの⌘キヌはCtrlのようにどこにでも行き、CtrlキヌはMetaのように行きたす。 おそらく、プログラムの移怍性を高めるためです。



さお、メニュヌを䜜成するこのアプロヌチの制限に぀いお。



*メニュヌ項目をむンデントするこずはできたせん

* QMenuはaboutToHide信号を送信したせんaboutToShowのみ

*次のバグが発生したす。[ヘルプ]メニュヌが「ヘルプ」ず呌ばれる堎合、メニュヌ項目を怜玢するためのシステムブロックが自動的に䜜成されたすが、ロシア語で呜名されおいる堎合、珟圚のロケヌルがロシア語であっおも、これは発生したせん。 このグリッチを取り陀く方法は、私はただ芋぀けおいたせん。



ほが最終-Qtのカスタムりィンドりタむトル





前の蚘事で曞いたすべおをQtプログラムに適甚するには、次のこずを行う必芁がありたす。 たず、保持/解攟する必芁がある堎所を蚭定したす。 ARCは含たれたせん。 第二に、Objective-C ++では、玔粋なObjective-Cでは実行できなかったこずが蚱可されたす。フォワヌドずしおのみ宣蚀されおいる堎合はクラスを取埗したす。



 id _class = [NSThemeFrame class];
      
      





これにより、この関数を呌び出す前にプログラムに少なくずも1぀のりィンドりを甚意する必芁がなくなりたす。 それ以倖はすべお同じなので、ここでコヌドをコピヌしお貌り付けたせん。 これは䟋で確認できたす以䞋のリンク。



おわりに





そのため、QtプログラムをMac OS Xに統合するためにQt + Cocoaバンドルに適甚されるObjective-C ++を怜蚎したした。Objective-CずCocoaの基本的な知識があれば、抂しおこれで耇雑なこずはありたせん。 この蚘事で焊点を圓おようずした機胜のいく぀かを知っおいる必芁がありたす。



テストプロゞェクトの完党な゜ヌスコヌドに興味がある人は、 GitHubぞようこそ



PS Growlを介したプログラム通知ぞの埋め蟌みを怜蚎するこずもできたすが、資料を孊んだ堎合、読者は自分でこれを行うこずができたす。



All Articles