У меня есть простая программа, которая включает передачу сигналов между QML и C ++.
В настоящее время у меня есть два случая, когда мне нужно передать сигнал с C ++ на QML.
Первый - из одного из моих исходных файлов / классов, «Поиск», а второй - из другогоc ++ исходный файл / класс "Node".
Сигналы в первом случае принимаются динамически созданным объектом QML с использованием parent.dynamic_object_name = Qt.createQmlObject(QString,parent,'name');
. В этом динамическом объекте следующий код получает сигнал "someAction"
import Search 1.0
...
Search {
id: search
}
Connections {
target: search
onSomeAction: {
dosomething()
}
}
И это сработало для меня. Поиск регистрируется через qmlregistertype. И dosomething () успешно вызывается.
Однако во втором случае, хотя я убедился, что формат точно такой же, он не работает.
Во втором случае я получаю сигнал от "Node.cpp". Я следовал той же процедуре, регистрируя «Узел» с помощью qmlRegisterType. На этот раз я пытаюсь получить сигнал в main.qml.
import Node 1.0
...
Node {
id: node
}
Connections {
target: node
onCreateNode: {
newNode()
}
}
Не выдается сообщение об ошибке. Показывая, что программа знает, что мой сигнал существует, он просто не реагирует на него. Я просмотрел онлайн и увидел, что не может быть более одного обработчика сигналов, в противном случае активен только последний. Таким образом, я попытался удалить свой обработчик сигнала в моем динамическом объекте, однако я все еще не могу получить сигнал. Таким образом, это не проблема.
Я рассмотрел возможность того, что мой эмиттер использует экземпляр "Node", отличный от того, который я зарегистрировал. Это действительно было так, но после исправления проблема осталась.
Здесь приведены соответствующие фрагменты:
Класс узла:
class Node: public QObject
{
Q_OBJECT
public:
Node(QObject * parent = nullptr);
Q_INVOKABLE void getNode(int id);
Q_INVOKABLE void acceptedSelection(QString selection, int x, int y);
void generateNode(int id);
int xPos;
int yPos;
private:
struct nodeInfo{
int x;
int y;
QString text;
int width;
int height;
int fontSize;
int color;
int parent;
QVector<int> children;
};
QVector<nodeInfo> nodeMap;
signals:
void createNode(QString nodeData);
public slots:
};
Сигнал, отправленный с узла. Программа успешно выдает «сгенерировать по имени».
void Node::generateNode(int id)
{
QString xpos = QString::number(nodeMap[id].x);
QString ypos = QString::number(nodeMap[id].y);
QString width = QString::number(nodeMap[id].width);
QString height = QString::number(nodeMap[id].width);
QString nodeData = QString("import QtQuick 2.0; Rectangle{x:%1;y:%2;width:%3;height:%4}").arg(
xpos,ypos,width,height);
qDebug()<<"generate called";
emit createNode(nodeData);
}
main.qml:
ApplicationWindow {
id:mywin
objectName: "AppWindow"
visible: true
width: 1600
height: 900
title: qsTr("Qmap")
Node {
id: mynode;
}
Item{
id: myitem
anchors.fill: parent
focus:true
Connections {
id: nodeconnect;
target: mynode;
onCreateNode:{
console.log("hi");
}
}
Чтобы уточнить, я не понимаю, почему в одной и той же программе с той же реализацией одинсигнал работает, а другой нет. Если я пропустил любую необходимую информацию, пожалуйста, сообщите мне. Любая помощь приветствуется.
Полный код: main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick 2.0
import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Controls 1.4
import Node 1.0
import Search 1.0
ApplicationWindow {
id:mywin
objectName: "AppWindow"
visible: true
width: 1600
height: 900
title: qsTr("Qmap")
menuBar: MenuBar{
Menu {
title: "File"
MenuItem{text: "open"}
}
Menu {
title: "Edit"
MenuItem{text:"undo"}
}
}
Node {
id: mynode;
}
Item{
id: myitem
anchors.fill: parent
focus:true
property int mouse_lastx: 0;
property int mouse_lasty: 0;
MouseArea{
id: mousearea
hoverEnabled: true
anchors.fill: parent
onPositionChanged: {
myitem.mouse_lastx = mouseX
myitem.mouse_lasty = mouseY
}
}
Connections {
id: nodeconnect;
target: mynode;
onCreateNode:{
console.log("hi");
}
}
Keys.onTabPressed: {
create_rect(mouse_lastx,mouse_lasty)
}
property string find:"
import QtQuick 2.0;
import Search 1.0
import Node 1.0
FocusScope{
id: scope;
focus:true;
x:%1;
y:%2;
Rectangle {
id: suggestionBox;
color: 'grey';
border.width:2;
width:200;
height:135;
x:-5000
y:34
Text {
id: first;
x: 5;
y: 5;
text: '';
}
Text {
id: second;
x: 5;
y: 30;
text: '';
}
Text {
id: third;
x: 5;
y: 55;
text: '';
}
Text {
id: fourth;
x: 5;
y: 80;
text: '';
}
Text {
id: fith;
x: 5;
y: 105;
text: '';
}
Rectangle {
id: selectionBox;
color:'#33000000';
border.width:2;
width: 200;
height:25;
x: 0;
y: 0;
}
}
Rectangle {
id:newrect;
color: 'grey';
border.width: 4;
width: 200;
height: 30;
focus:true;
x:0;
y:0;
Node {
id: node;
}
Search {
id: search;
}
Connections {
id: searchconnect
target: search;
onBoxHide: {
suggestionBox.x = -10000;
}
onBoxUpdated: {
suggestionBox.height = (5-empty)*27;
suggestionBox.x = 0;
first.text = search.getSuggestions(0)
second.text = search.getSuggestions(1)
third.text = search.getSuggestions(2)
fourth.text = search.getSuggestions(3)
fith.text = search.getSuggestions(4)
}
onSpacebarPressed: {
selectionBox.y = selectionBox.y + 25;
}
onCycleSelection: {
selectionBox.y = 0;
}
}
property int xbuffer: %3;
property int ybuffer: %4;
TextInput {
id: input;
focus: true;
x:5;
y:5;
onTextChanged: {
search.searchBox(input.text)
}
onAccepted: {
node.acceptedSelection(search.getSuggestions(search.getSelection()),newrect.xbuffer,newrect.ybuffer);
scope.x = -400;
scope.y = -100;
}
}
Component.onCompleted:{
input.forceActiveFocus();
}
}
}"
property var dynamic_object: Qt.createQmlObject((find.arg(-300).arg(-100)).arg(-300).arg(-100),myitem,'rect')
function create_rect(x,y){
var xloc = x;
var yloc = y;
myitem.dynamic_object.destroy(0);
myitem.dynamic_object = Qt.createQmlObject((find.arg(xloc).arg(yloc).arg(xloc).arg(yloc)),myitem,'rect');
myitem.dynamic_object.forceActiveFocus();
}
}
}
node.h, за которым следует node.cpp
//node.h
#ifndef NODE_H
#define NODE_H
#include <QObject>
#include <QVector>
#include <QDebug>
#include <string>
using namespace std;
class Node: public QObject
{
Q_OBJECT
public:
Node(QObject * parent = nullptr);
Q_INVOKABLE void getNode(int id);
Q_INVOKABLE void acceptedSelection(QString selection, int x, int y);
void generateNode(int id);
int xPos;
int yPos;
private:
struct nodeInfo{
int x;
int y;
QString text;
int width;
int height;
int fontSize;
int color;
int parent;
QVector<int> children;
};
QVector<nodeInfo> nodeMap;
signals:
void createNode(QString nodeData);
public slots:
};
#endif // NODE_H
//node.cpp
#include "node.h"
using namespace std;
Node::Node(QObject * parent):
QObject (parent)
{
}
void Node::getNode(int id)
{
}
void Node::acceptedSelection(QString selection, int x, int y)
{
if(selection=="new node"){
nodeInfo temp;
temp.x = y;
temp.y = x;
temp.width = 40;
temp.height = 30;
nodeMap.append(temp);
int id = nodeMap.size() - 1;
qDebug()<<"nodeCalled";
QString data = "hello";
generateNode(id);
}
}
void Node::generateNode(int id)
{
QString xpos = QString::number(nodeMap[id].x);
QString ypos = QString::number(nodeMap[id].y);
QString width = QString::number(nodeMap[id].width);
QString height = QString::number(nodeMap[id].width);
QString nodeData = QString("import QtQuick 2.0; Rectangle{x:%1;y:%2;width:%3;height:%4}").arg(
xpos,ypos,width,height);
qDebug()<<"generate called";
emit createNode(nodeData);
}
search.h, за которым следует search.cpp
#ifndef SEARCH_H
#define SEARCH_H
#include <QObject>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QVector>
#include <string>
using namespace std;
class Search:public QObject
{
Q_OBJECT
public:
Search(QObject * parent = nullptr);
Q_INVOKABLE void searchBox(QString txt);
Q_INVOKABLE QString getSuggestions(int pos);
Q_INVOKABLE int getSelection();
int match(QString arg,QString reference);
void arrange(int ar[],int ar_len);
int suggestionsMax = 5;
private:
QVector<QString> suggestions;
string userFunctions[10] = {"new node","relationship","note","frame","create set","move node","format menu","copy format","paste format","zone"};
QString inputBuffer;
int matches[10];
int currentSelection = 0;
int suggestionsAvailable = 5;
signals:
void boxUpdated(QVector<QString> suggestions,int empty);
void boxHide();
void spacebarPressed();
void cycleSelection();
public slots:
};
#endif // SEARCH_H
//search.cpp
#include "search.h"
#include <QDebug>
#include <bits/stdc++.h>
#include <node.h>
Search::Search(QObject * parent):
QObject (parent)
{
}
//searchBox: parent function for generating suggestions in the suggestion box.
/*
* This function is called each time the user types in a character, backspaces, or does anything to edit the text in the
* search bar.
*
* input: Qstring txt
* User input.
*
* Action: uses Search::match to match txt to userFunctions, sorts userFunctions in order of decreasing match value using
* Search::arrange, appends userFunctions to suggestions array, emits signal notifying QML that suggestions has been updated.
*/
void Search::searchBox(QString txt)
{
int txtlength = txt.size();
int bufferlength = inputBuffer.size();
//Compare buffer vs new input: see if user extended input or pressed backspace.
if(txtlength>bufferlength){
//if the user extended the input, did the user press spacebar? if yes, push selection
if(txt[txtlength-1] == " "){
//Has the selection reached the end of the list? if not, continue pushing selection down
if(currentSelection<suggestionsAvailable-1){
currentSelection+=1;
//this signal simply tells QML to visually move the selection box.
emit spacebarPressed();
}
//the selection has reached the end of the list. restart selection from 0.
else{
currentSelection = 0;
//This signal tells QML to reset selection box to top position.
emit cycleSelection();
}
}
//if user continues typing after inputing spacebar, reset selection to default position
//this means the user intended to use spacebar as spacebar rather than to cycle selection.
else{
emit cycleSelection();
currentSelection = 0;
}
}
//If user presses backspace, reset selection to default position
//user doesn't want to select anything on the current list. Reset selection to default.
else{
emit cycleSelection();
currentSelection = 0;
}
//set buffer in preparation for next call. Reset empty to default value.
inputBuffer = txt;
int empty = 0;
//is there anything in txt? if yes, begin analyzing txt.
if(txtlength!=0){
int n = sizeof(userFunctions)/sizeof(*userFunctions);
//see how much txt matches with each userFunction. Values stored in matches[]
for(int i=0; i<n; i++){
matches[i]=match(txt,QString::fromStdString(userFunctions[i]));
}
//arrange in order of descent; greatest first.
arrange(matches,n);
//Reset suggestions from previous appends.
suggestions = {};
//Select first 5 suggestions to place on suggest box.
//This works because suggestions are already ordered from best match to least match.
//If first five contains suggestions that are low match, exclude these.
for(int i=0; i<5; i++){
if(matches[i]>5){
suggestions.append(QString::fromStdString(userFunctions[i]));
}
else{
empty+=1;
suggestions.append("");
}
}
suggestionsAvailable = suggestionsMax-empty;
emit boxUpdated(suggestions,empty);
}
//if user preses backspace and clears the search box: clear suggestions
else{
suggestions = {"","","","",""};
empty = suggestionsMax;
suggestionsAvailable = 0;
emit boxUpdated(suggestions,empty);
emit boxHide();
}
}
int Search::getSelection()
{
return(currentSelection);
}
//This function swaps values held by two pointers.
void swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
/*
* Sorting algorithm. selective sorting method
* Sorts provided array in descending magnitude. The sorting of userFunctions is coupled to this process.
*/
void Search::arrange(int ar[],int ar_len)
{
int n = ar_len;
int flag = 0;
for(int i = 0; i<n-1; i++){
flag = i;
for(int j = i+1; j<n; j++){
if(ar[j]>ar[flag]){
flag=j;
}
}
swap(&ar[flag],&ar[i]);
string temp;
temp = userFunctions[flag];
userFunctions[flag] = userFunctions[i];
userFunctions[i] = temp;
}
for(int i=0;i<n;i++)
{
matches[i] = ar[i];
}
}
//fetches suggestions. Called from QML.
QString Search::getSuggestions(int pos)
{
return suggestions[pos];
}
//This function takes two strings, and sees how much the first string matches the second string.
/*
* input: string1, string2
* output: integer
*
* The higher the integer, the higher the match.
*/
int Search::match(QString arg,QString reference)
{
int temp = 0;
int l = arg.size();
\
QStringList split;
for(int i=l; i>0; i--){
QString sub = arg.mid(0,i);
\
if(reference.contains(sub)){
temp+=i*i;
}
split = reference.split(" ");
int s = split.size();
\
for(int j=0; j<s; j++){
QString spsub = split[j].mid(0,i);
if(sub==spsub){
temp+=i*i;
if(j==0){
temp+=5;
}
}
}
}
return temp;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QObject>
#include <search.h>
#include <node.h>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<Search>("Search",1,0,"Search");
qmlRegisterType<Node>("Node",1,0,"Node");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
``