[英]How to start Go's main function from within the NSApplication event loop?
I'm trying to add Sparkle into my Qt ( binding for Go ) app to make it can be updated automatically. 我正在尝试将Sparkle添加到我的Qt( 绑定Go )应用程序中,以使其可以自动更新。
Problem: there is no popup dialog when running the latest version 问题: 运行最新版本时没有弹出对话框
Here's the code: https://github.com/sparkle-project/Sparkle/blob/master/Sparkle/SUUIBasedUpdateDriver.m#L104 这是代码: https : //github.com/sparkle-project/Sparkle/blob/master/Sparkle/SUUIBasedUpdateDriver.m#L104
The reason as the author pointed out is NSAlert
needs a run loop to work. 作者指出的原因是NSAlert
需要一个运行循环才能工作。
I found some docs: 我找到了一些文档:
So, as I understand, we have to instantiate NSApplication
before creating a QApplication
. 因此,据我所知,我们必须在创建QApplication
之前实例化NSApplication
。
void NSApplicationMain(int argc, char *argv[]) {
[NSApplication sharedApplication];
[NSBundle loadNibNamed:@"myMain" owner:NSApp];
[NSApp run];
}
My Go's main function is something like this: 我的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()
}
Question: how can I start Go's main function from within the NSApplicationMain
event loop? 问题:如何从NSApplicationMain
事件循环中启动Go的主要功能?
Using QApplication together with a Runloop 将QApplication与Runloop一起使用
Regarding your question how to use your QApplication together with a NSRunloop: you are doing it already. 关于如何将QApplication与NSRunloop一起使用的问题:您已经这样做了。 Since you are using QApplication (and not QCoreApplication) you already have a Runloop running, 由于您使用的是QApplication(而不是QCoreApplication),因此您已经运行了Runloop,
see http://code.qt.io/cgit/qt/qt.git/plain/src/gui/kernel/qeventdispatcher_mac.mm and http://code.qt.io/cgit/qt/qt.git/plain/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm 见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
Proof 证明
A NSTimer needs a run loop to work. NSTimer需要运行循环才能工作。 So we could add quick test with an existing example Qt app called 'widget' from the repository you referenced in your question. 因此,我们可以使用您在问题中引用的存储库中的现有示例Qt应用程序“widget”添加快速测试。
Adding a small Objective-C test class TimerRunloopTest with a C function wrapper that can be called from GO: 添加一个小的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 counterpart timerrunlooptest.go GO对应的timerrunlooptest.go
package main
/*
#cgo LDFLAGS: -framework Foundation
void runTimerRunloopTest();
*/
import "C"
func runTimerRunloopTest() { C.runTimerRunloopTest() }
Change in main.go main.go的变化
At the end before app.Exec() add this line: 在app.Exec()之前的末尾添加以下行:
runTimerRunloopTest()
Build and Run it 构建并运行它
Switch loggin on for our logging messages: 切换登录以获取我们的日志消息:
sudo log config --subsystem widget.example --mode level:debug
Afterwards build an run it: 然后建立一个运行它:
$(go env GOPATH)/bin/qtdeploy test desktop examples/basic/widgets
Test 测试
In the macOS Console uitlity we can now see, that the timer ticks are shown, proofing that a run-loop is running 在macOS Console uitlity中,我们现在可以看到,显示了计时器滴答,证明运行循环正在运行
NSAlert NSAlert
Then you cited in your question, that NSAlert needs a run loop to work. 然后你在你的问题中引用了NSAlert需要一个运行循环来工作。 We already proofed that we have one, but testing it explicitely makes sense. 我们已经证明我们有一个,但明确地测试它是有道理的。
So we can modify timerrunlooptest.go to inform it, that we want to link agains Cocoa also, not only Foundation: 所以我们可以修改timerrunlooptest.go来通知它,我们想再次连接Cocoa,不仅仅是基金会:
package main
/*
#cgo LDFLAGS: -framework Foundation
#cgo LDFLAGS: -framework Cocoa
void runTimerRunloopTest();
*/
import "C"
func runTimerRunloopTest() { C.runTimerRunloopTest() }
Then we could add the following code to the run method of TimerRunLoopTest: 然后我们可以将以下代码添加到TimerRunLoopTest的run方法中:
#import <Cocoa/Cocoa.h>
...
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Message";
alert.informativeText = @"Info";
[alert addButtonWithTitle:@"OK"];
[alert runModal];
Result 结果
After doing a 做完之后
$(go env GOPATH)/bin/qtdeploy test desktop examples/basic/widgets
the native Alert is shown from the GO/QT application as expected: GO / QT应用程序按预期显示本机警报:
Mixing Qt with Native Code 将Qt与本机代码混合使用
Although we seem to be able to display native alerts in the way described above, there is this hint in the QT documents that may or may not be useful: 虽然我们似乎能够以上述方式显示本机警报,但QT文档中的这一提示可能有用,也可能没用:
Qt's event dispatcher is more flexible than what Cocoa offers, and lets the user spin the event dispatcher (and running QEventLoop::exec) without having to think about whether or not modal dialogs are showing on screen (which is a difference compared to Cocoa). Qt的事件调度程序比Cocoa提供的更灵活,并允许用户旋转事件调度程序(并运行QEventLoop :: exec),而不必考虑是否在屏幕上显示模态对话框(这与Cocoa相比有所不同) 。 Therefore, we need to do extra management in Qt to handle this correctly, which unfortunately makes mixing native panels hard. 因此,我们需要在Qt中进行额外的管理才能正确处理这个问题,不幸的是,这使得混合原生面板变得困难。 The best way at the moment to do this, is to follow the pattern below, where we post the call to the function with native code rather than calling it directly. 目前执行此操作的最佳方法是遵循以下模式,我们使用本机代码发布对函数的调用,而不是直接调用它。 Then we know that Qt has cleanly updated any pending event loop recursions before the native panel is shown. 然后我们知道Qt在显示本机面板之前已经干净地更新了任何挂起的事件循环递归。
see https://doc.qt.io/qt-5/macos-issues.html#using-native-cocoa-panels 请参阅https://doc.qt.io/qt-5/macos-issues.html#using-native-cocoa-panels
There is also a small code example for this. 还有一个小代码示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.