簡體   English   中英

如何從NSApplication事件循環中啟動Go的主要功能?

[英]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.mmhttp://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應用程序按預期顯示本機警報:

來自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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM