[英]How to start Go's main function from within the NSApplication event loop?
我正在嘗試將Sparkle添加到我的Qt( 綁定Go )應用程序中,以使其可以自動更新。
問題: 運行最新版本時沒有彈出對話框
這是代碼: https : //github.com/sparkle-project/Sparkle/blob/master/Sparkle/SUUIBasedUpdateDriver.m#L104
作者指出的原因是NSAlert
需要一個運行循環才能工作。
我找到了一些文檔:
因此,據我所知,我們必須在創建QApplication
之前實例化NSApplication
。
void NSApplicationMain(int argc, char *argv[]) {
[NSApplication sharedApplication];
[NSBundle loadNibNamed:@"myMain" owner:NSApp];
[NSApp run];
}
我的Go的主要功能是這樣的:
func main() {
widgets.NewQApplication(len(os.Args), os.Args)
...
action := widgets.NewQMenuBar(nil).AddMenu2("").AddAction("Check for Updates...")
// http://doc.qt.io/qt-5/qaction.html#MenuRole-enum
action.SetMenuRole(widgets.QAction__ApplicationSpecificRole)
action.ConnectTriggered(func(bool) { sparkle_checkUpdates() })
...
widgets.QApplication_Exec()
}
問題:如何從NSApplicationMain
事件循環中啟動Go的主要功能?
將QApplication與Runloop一起使用
關於如何將QApplication與NSRunloop一起使用的問題:您已經這樣做了。 由於您使用的是QApplication(而不是QCoreApplication),因此您已經運行了Runloop,
見http://code.qt.io/cgit/qt/qt.git/plain/src/gui/kernel/qeventdispatcher_mac.mm和http://code.qt.io/cgit/qt/qt.git/plain /src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm
證明
NSTimer需要運行循環才能工作。 因此,我們可以使用您在問題中引用的存儲庫中的現有示例Qt應用程序“widget”添加快速測試。
添加一個小的Objective-C測試類TimerRunloopTest和一個可以從GO調用的C函數包裝器:
#import <Foundation/Foundation.h>
#include <os/log.h>
@interface TimerRunloopTest : NSObject
- (void)run;
@end
void runTimerRunloopTest() {
[[TimerRunloopTest new] run];
}
@implementation TimerRunloopTest
- (void)run {
os_log_t log = os_log_create("widget.example", "RunloopTest");
os_log(log, "setup happening at %f", NSDate.timeIntervalSinceReferenceDate);
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
}
- (void)timerTick:(NSTimer *)timer {
os_log_t log = os_log_create("widget.example", "RunloopTest");
os_log(log, "timer tick %f", NSDate.timeIntervalSinceReferenceDate);
}
@end
GO對應的timerrunlooptest.go
package main
/*
#cgo LDFLAGS: -framework Foundation
void runTimerRunloopTest();
*/
import "C"
func runTimerRunloopTest() { C.runTimerRunloopTest() }
main.go的變化
在app.Exec()之前的末尾添加以下行:
runTimerRunloopTest()
構建並運行它
切換登錄以獲取我們的日志消息:
sudo log config --subsystem widget.example --mode level:debug
然后建立一個運行它:
$(go env GOPATH)/bin/qtdeploy test desktop examples/basic/widgets
測試
在macOS Console uitlity中,我們現在可以看到,顯示了計時器滴答,證明運行循環正在運行
NSAlert
然后你在你的問題中引用了NSAlert需要一個運行循環來工作。 我們已經證明我們有一個,但明確地測試它是有道理的。
所以我們可以修改timerrunlooptest.go來通知它,我們想再次連接Cocoa,不僅僅是基金會:
package main
/*
#cgo LDFLAGS: -framework Foundation
#cgo LDFLAGS: -framework Cocoa
void runTimerRunloopTest();
*/
import "C"
func runTimerRunloopTest() { C.runTimerRunloopTest() }
然后我們可以將以下代碼添加到TimerRunLoopTest的run方法中:
#import <Cocoa/Cocoa.h>
...
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Message";
alert.informativeText = @"Info";
[alert addButtonWithTitle:@"OK"];
[alert runModal];
結果
做完之后
$(go env GOPATH)/bin/qtdeploy test desktop examples/basic/widgets
GO / QT應用程序按預期顯示本機警報:
將Qt與本機代碼混合使用
雖然我們似乎能夠以上述方式顯示本機警報,但QT文檔中的這一提示可能有用,也可能沒用:
Qt的事件調度程序比Cocoa提供的更靈活,並允許用戶旋轉事件調度程序(並運行QEventLoop :: exec),而不必考慮是否在屏幕上顯示模態對話框(這與Cocoa相比有所不同) 。 因此,我們需要在Qt中進行額外的管理才能正確處理這個問題,不幸的是,這使得混合原生面板變得困難。 目前執行此操作的最佳方法是遵循以下模式,我們使用本機代碼發布對函數的調用,而不是直接調用它。 然后我們知道Qt在顯示本機面板之前已經干凈地更新了任何掛起的事件循環遞歸。
請參閱https://doc.qt.io/qt-5/macos-issues.html#using-native-cocoa-panels
還有一個小代碼示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.