[英]Drone QGC : How to get a value from C++ to QML
Before my Drone take off, in QGC, I need to check Base Station status is on or off.在我的无人机起飞之前,在 QGC 中,我需要检查基站状态是打开还是关闭。 I need to write a TCP checking function with a timer to trigger the TCP checking, and pass the result to QML namely MainToolBar.qml.
我需要写一个 TCP 检查 function 用定时器来触发 TCP 检查,并将结果传递给 QML 即 MainToolBar.qml。 I try to first test to send a string from main.cc to MainToolBar.qml, like below:
我尝试首先测试将字符串从 main.cc 发送到 MainToolBar.qml,如下所示:
QQuickView view;
QQmlContext* context = view.engine()->rootContext();
context->setContextProperty("_aStr", QString(“true”));
view.setSource(QUrl(“qrc:MainToolBar.qml”));
view.show();
Look like in my QML I can recognize _aStr, but when I want to show the value, nothing came out… I removed the QGuiApplication bcos it carsh with QGCApplication(redefined problem) I tried to use: QQmlApplicationEngine* pEngine = new QQmlApplicationEngine(parent) and create my _aStr here but QML can recognize but still no data…看起来在我的 QML 中我可以识别 _aStr,但是当我想显示该值时,什么也没有出来……我删除了 QGuiApplication bcos 它与 QGCApplication 的结合(重新定义的问题)我尝试使用:QQmlApplicationEngine* pEngine = new QQmlApplicationEngine(parent)并在这里创建我的 _aStr 但 QML 可以识别但仍然没有数据......
So my question are: 1.) If I to put a timer to do TCP function, where should I put the timer and function?所以我的问题是:1.) 如果我要放一个定时器来做 TCP function,我应该把定时器和 function 放在哪里? 2.) once the function return the value(on or off), how to pass to MainToolBar.qml?
2.) 一旦 function 返回值(开或关),如何传递给 MainToolBar.qml?
I have been struggle with this for months, sincerely hope someone can help or give me some hints, thanks so much.我已经为此苦苦挣扎了几个月,真诚地希望有人能帮助我或给我一些提示,非常感谢。
This is the QGroundControl main.cc(the few lines between //alan inserted by me, others all from open source)这是QGroundControl main.cc(我插入的//alan之间的几行,其他都来自开源)
#include "QGC.h"
#include <QtGlobal>
#include <QApplication>
#include <QIcon>
#include <QSslSocket>
#include <QMessageBox>
#include <QProcessEnvironment>
#include <QHostAddress>
#include <QUdpSocket>
#include <QtPlugin>
#include <QStringListModel>
#include "QGCApplication.h"
#include "AppMessages.h"
#include <QGuiApplication>
#include <QQuickView>
#ifndef __mobile__
#include "QGCSerialPortInfo.h"
#include "RunGuard.h"
#endif
#ifdef UNITTEST_BUILD
#include "UnitTest.h"
#endif
#ifdef QT_DEBUG
#include "CmdLineOptParser.h"
#ifdef Q_OS_WIN
#include <crtdbg.h>
#endif
#endif
#ifdef QGC_ENABLE_BLUETOOTH
#include <QtBluetooth/QBluetoothSocket>
#endif
#include <iostream>
#include "QGCMapEngine.h"
/* SDL does ugly things to main() */
#ifdef main
#undef main
#endif
#ifndef __mobile__
#ifndef NO_SERIAL_LINK
Q_DECLARE_METATYPE(QGCSerialPortInfo)
#endif
#endif
#ifdef Q_OS_WIN
#include <windows.h>
/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
Q_UNUSED(reportType);
std::cerr << message << std::endl; // Output message to stderr
*returnValue = 0; // Don't break into debugger
return true; // We handled this fully ourselves
}
#endif
#if defined(__android__)
#include <jni.h>
#include "JoystickAndroid.h"
#if defined(QGC_ENABLE_PAIRING)
#include "PairingManager.h"
#endif
#if !defined(NO_SERIAL_LINK)
#include "qserialport.h"
#endif
static jobject _class_loader = nullptr;
static jobject _context = nullptr;
//-----------------------------------------------------------------------------
extern "C" {
void gst_amc_jni_set_java_vm(JavaVM *java_vm);
jobject gst_android_get_application_class_loader(void)
{
return _class_loader;
}
}
//-----------------------------------------------------------------------------
static void
gst_android_init(JNIEnv* env, jobject context)
{
jobject class_loader = nullptr;
jclass context_cls = env->GetObjectClass(context);
if (!context_cls) {
return;
}
jmethodID get_class_loader_id = env->GetMethodID(context_cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return;
}
class_loader = env->CallObjectMethod(context, get_class_loader_id);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return;
}
_context = env->NewGlobalRef(context);
_class_loader = env->NewGlobalRef (class_loader);
}
//-----------------------------------------------------------------------------
static const char kJniClassName[] {"org/mavlink/qgroundcontrol/QGCActivity"};
void setNativeMethods(void)
{
JNINativeMethod javaMethods[] {
{"nativeInit", "()V", reinterpret_cast<void *>(gst_android_init)}
};
QAndroidJniEnvironment jniEnv;
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
jclass objectClass = jniEnv->FindClass(kJniClassName);
if(!objectClass) {
qWarning() << "Couldn't find class:" << kJniClassName;
return;
}
jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
if (val < 0) {
qWarning() << "Error registering methods: " << val;
} else {
qDebug() << "Main Native Functions Registered";
}
if (jniEnv->ExceptionCheck()) {
jniEnv->ExceptionDescribe();
jniEnv->ExceptionClear();
}
}
//-----------------------------------------------------------------------------
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
Q_UNUSED(reserved);
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
setNativeMethods();
#if defined(QGC_GST_STREAMING)
// Tell the androidmedia plugin about the Java VM
gst_amc_jni_set_java_vm(vm);
#endif
#if !defined(NO_SERIAL_LINK)
QSerialPort::setNativeMethods();
#endif
JoystickAndroid::setNativeMethods();
#if defined(QGC_ENABLE_PAIRING)
PairingManager::setNativeMethods();
#endif
return JNI_VERSION_1_6;
}
#endif
//-----------------------------------------------------------------------------
#ifdef __android__
#include <QtAndroid>
bool checkAndroidWritePermission() {
QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE" );
r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
return false;
}
}
return true;
}
#endif
//-----------------------------------------------------------------------------
/**
* @brief Starts the application
*
* @param argc Number of commandline arguments
* @param argv Commandline arguments
* @return exit code, 0 for normal exit and !=0 for error cases
*/
int main(int argc, char *argv[])
{
#ifndef __mobile__
RunGuard guard("QGroundControlRunGuardKey");
if (!guard.tryToRun()) {
// QApplication is necessary to use QMessageBox
QApplication errorApp(argc, argv);
QMessageBox::critical(nullptr, QObject::tr("Error"),
QObject::tr("A second instance of %1 is already running. Please close the other instance and try again.").arg(QGC_APPLICATION_NAME)
);
return -1;
}
#endif
//-- Record boot time
QGC::initTimer();
#ifdef Q_OS_UNIX
//Force writing to the console on UNIX/BSD devices
if (!qEnvironmentVariableIsSet("QT_LOGGING_TO_CONSOLE"))
qputenv("QT_LOGGING_TO_CONSOLE", "1");
#endif
// install the message handler
AppMessages::installHandler();
#ifdef Q_OS_MAC
#ifndef __ios__
// Prevent Apple's app nap from screwing us over
// tip: the domain can be cross-checked on the command line with <defaults domains>
QProcess::execute("defaults write org.qgroundcontrol.qgroundcontrol NSAppSleepDisabled -bool YES");
#endif
#endif
#ifdef Q_OS_WIN
// Set our own OpenGL buglist
qputenv("QT_OPENGL_BUGLIST", ":/opengl/resources/opengl/buglist.json");
// Allow for command line override of renderer
for (int i = 0; i < argc; i++) {
const QString arg(argv[i]);
if (arg == QStringLiteral("-angle")) {
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
break;
} else if (arg == QStringLiteral("-swrast")) {
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
break;
}
}
#endif
// The following calls to qRegisterMetaType are done to silence debug output which warns
// that we use these types in signals, and without calling qRegisterMetaType we can't queue
// these signals. In general we don't queue these signals, but we do what the warning says
// anyway to silence the debug output.
#ifndef NO_SERIAL_LINK
qRegisterMetaType<QSerialPort::SerialPortError>();
#endif
#ifdef QGC_ENABLE_BLUETOOTH
qRegisterMetaType<QBluetoothSocket::SocketError>();
qRegisterMetaType<QBluetoothServiceInfo>();
#endif
qRegisterMetaType<QAbstractSocket::SocketError>();
#ifndef __mobile__
#ifndef NO_SERIAL_LINK
qRegisterMetaType<QGCSerialPortInfo>();
#endif
#endif
// We statically link our own QtLocation plugin
#ifdef Q_OS_WIN
// In Windows, the compiler doesn't see the use of the class created by Q_IMPORT_PLUGIN
#pragma warning( disable : 4930 4101 )
#endif
Q_IMPORT_PLUGIN(QGeoServiceProviderFactoryQGC)
bool runUnitTests = false; // Run unit tests
#ifdef QT_DEBUG
// We parse a small set of command line options here prior to QGCApplication in order to handle the ones
// which need to be handled before a QApplication object is started.
bool stressUnitTests = false; // Stress test unit tests
bool quietWindowsAsserts = false; // Don't let asserts pop dialog boxes
QString unitTestOptions;
CmdLineOpt_t rgCmdLineOptions[] = {
{ "--unittest", &runUnitTests, &unitTestOptions },
{ "--unittest-stress", &stressUnitTests, &unitTestOptions },
{ "--no-windows-assert-ui", &quietWindowsAsserts, nullptr },
// Add additional command line option flags here
};
ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false);
if (stressUnitTests) {
runUnitTests = true;
}
if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
_CrtSetReportHook(WindowsCrtReportHook);
#endif
}
#ifdef Q_OS_WIN
if (runUnitTests) {
// Don't pop up Windows Error Reporting dialog when app crashes. This prevents TeamCity from
// hanging.
DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX);
}
#endif
#endif // QT_DEBUG
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QGCApplication* app = new QGCApplication(argc, argv, runUnitTests);
//alan
QQuickView view;
QQmlContext* context = view.engine()->rootContext();
context->setContextProperty("_aString", QString("WWW"));
// ...
//--> hide
view.setSource(QUrl("qrc:/toolbar/MainToolBar.qml"));
view.show();
//alan
Q_CHECK_PTR(app);
if(app->isErrorState()) {
app->exec();
return -1;
}
#ifdef Q_OS_LINUX
QApplication::setWindowIcon(QIcon(":/res/resources/icons/qgroundcontrol.ico"));
#endif /* Q_OS_LINUX */
// There appears to be a threading issue in qRegisterMetaType which can cause it to throw a qWarning
// about duplicate type converters. This is caused by a race condition in the Qt code. Still working
// with them on tracking down the bug. For now we register the type which is giving us problems here
// while we only have the main thread. That should prevent it from hitting the race condition later
// on in the code.
qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
app->_initCommon();
//-- Initialize Cache System
getQGCMapEngine()->init();
int exitCode = 0;
#ifdef UNITTEST_BUILD
if (runUnitTests) {
for (int i=0; i < (stressUnitTests ? 20 : 1); i++) {
if (!app->_initForUnitTests()) {
return -1;
}
// Run the test
int failures = UnitTest::run(unitTestOptions);
if (failures == 0) {
qDebug() << "ALL TESTS PASSED";
exitCode = 0;
} else {
qDebug() << failures << " TESTS FAILED!";
exitCode = -failures;
break;
}
}
} else
#endif
{
#ifdef __android__
checkAndroidWritePermission();
#endif
if (!app->_initForNormalAppBoot()) {
return -1;
}
exitCode = app->exec();
}
app->_shutdown();
delete app;
//-- Shutdown Cache System
destroyMapEngine();
qDebug() << "After app delete";
return exitCode;
}
And I got this warning: qrc:/toolbar/MainToolBar.qml:194: ReferenceError: _aString is not defined That meant QML still not getting my C++ _aString我收到了这个警告:qrc:/toolbar/MainToolBar.qml:194: ReferenceError: _aString is not defined 这意味着 QML 仍然没有得到我的 C++ _aString
Below is the MainToolBar.qml where added by me ref to _aString, others all from open source:下面是我添加的 MainToolBar.qml 引用到 _aString,其他都来自开源:
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import QtQuick.Dialogs 1.3
import QGroundControl 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.MultiVehicleManager 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controllers 1.0
//Many lines omitted due to space constraint
//Alan
Text {
id: bs
text: _aString // = true ? qsTr("Base Station On") : qsTr("Base Station Off")
font.pointSize: ScreenTools.largeFontPointSize
color: flag.visible ? "lightgreen" : "red"
}
//Alan
can show a Minimal, Reproducible Example?可以展示一个最小的、可重现的例子吗?
seems your code can show the value似乎您的代码可以显示价值
#include <QtWidgets/QApplication>
#include<string>
#include<sstream>
#include<fstream>
#include<iomanip>
#include<QElapsedTimer>
#include<QThread>
#include<QTimer>
#include<QSerialPort>
#include<QTextStream>
#include<QTreeWidget>
#include<QTreeWidgetItem>
#include<QQuickView>
#include<QQmlEngine>
#include<QQmlContext>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto view = new QQuickView();
QString str = "test";
view->engine()->rootContext()->setContextProperty("backend", str);
view->setSource(QUrl("qrc:/QtWidgetsApplication1/main.qml"));
view->show();
return a.exec();
}
import QtQuick 2.3
Rectangle {
width: 200
height: 100
color: "red"
Text {
anchors.centerIn: parent
text: backend
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.