Interagir entre qml et c++
-
bonjours tout le monde je suis un projet entraînement
J'ai un éditeur de texte fait avec qml (cote interface) mais l'editeur (côté fonctionnement fait avec c++)
code interface
import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs ApplicationWindow { id: appWindow width: 640 height: 480 visible: true title: qsTr("Note-Black") StackView { id: stack anchors.fill: parent initialItem: Page{ // Les raccourise Shortcut { sequence: "Ctrl+P" onActivated: myMenu.onPresseKeyParametre() } // Les Action Action{ id: onOpenMenuAction onTriggered: myMenu.openMenu() } Action{ id: newNoteAction onTriggered: onLauncerNewNote() } Action{ id: openFileAction onTriggered: onOpenFile.open() } // Header header: ToolBar{ anchors.top: parent.top RowLayout { id: rowLayout anchors.fill: parent spacing: 6 ToolButton { icon.source: "qrc:/Icon//Note-Black/24x24/menu" icon.height: 24 icon.width: 24 Layout.alignment: Qt.AlignLeft action: onOpenMenuAction } ToolSeparator{Layout.fillHeight: true} Label { id: nomeApp2 text: "Note-Black" // color: "white" font.bold: true font.letterSpacing: 2 font.pixelSize: 24 horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter } ToolButton { icon.source: "qrc:/Icon//Note-Black/24x24/search" icon.height: 24 icon.width: 24 Layout.alignment: Qt.AlignJustify } ToolButton { icon.source: "qrc:/Icon//Note-Black/24x24/sorting" icon.height: 24 icon.width: 24 Layout.alignment: Qt.AlignRight //action: onSortingAction } } } MyMenu { id: myMenu anchors.left: parent.left } MyEditeur{ id: edit visible: false } footer: ToolBar{ id: footerPage anchors.bottom: parent.bottom RowLayout { id: rowLayout2 anchors.fill: parent spacing: 6 ToolButton{ icon.source: "qrc:/Icon/Note-Black/24x24/file.png" icon.width: 24 icon.height: 24 action: openFileAction } ToolButton { icon.source: "qrc:/Icon/Note-Black/24x24/camera.png" icon.width: 24 icon.height: 24 } ToolButton { id: toolLanguage icon.source: "qrc:/Icon/Note-Black/24x24/language.png" icon.width: 24 icon.height: 24 onClicked: pop.open() } ToolButton { icon.source: "qrc:/Icon/Note-Black/24x24/add.png" icon.width: 24 icon.height: 24 action: newNoteAction Layout.alignment: Qt.AlignRight } } } Popup { id: pop x: toolLanguage.x - 50 y: toolLanguage.y + 148 width: parent.width / 5 height: parent.height - 150 modal: true focus: true ColumnLayout { anchors.fill: parent RadioButton { checked: true text: qsTr("Français") onClicked: console.log(text) } RadioButton { text: qsTr("Arabe") onClicked: console.log(text) } RadioButton { text: qsTr("Somalie") onClicked: console.log(text) } } closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside } } } FileDialog { id: onOpenFile fileMode: FileDialog.OpenFile selectedNameFilter.index: 1 nameFilters: ["Fichier texte (*.txt)", "Fichier Html (*.html *.htm)", "Fichier Source Cpp/C (*.cpp *.c *.cxx)", "Fichier header Cpp/C (*.h *.hpp *.hxx)", "Tous les fichier (*.*)"] currentFolder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) onAccepted: onLauncerNewNotef(onOpenFile.selectedFile) } function onLauncerNewNotef(string) { stack.push("qrc:/MyEditeur.qml") edit.onLauncerOpenDialog() } function onLauncerNewNote() { stack.push("qrc:/MyEditeur.qml") } }
code editeur.cpp
#include "editeur.h" #include <QFile> #include <QFileInfo> #include <QFileSelector> #include <QMimeDatabase> #include <QQmlFile> #include <QQmlFileSelector> #include <QQuickTextDocument> #include <QTextCharFormat> #include <QStringDecoder> #include <QTextDocument> #include <QDebug> Editeur::Editeur(QObject *parent) : QObject(parent) , m_document(nullptr) , m_cursorPosition(-1) , m_selectionStart(0) , m_selectionEnd(0) { } QQuickTextDocument *Editeur::document() const { return m_document; } void Editeur::setDocument(QQuickTextDocument* document) { if(document == m_document) return; if(m_document) disconnect(m_document->textDocument(), &QTextDocument::modificationChanged, this, &Editeur::modifiedChanged); m_document = document; if(m_document) connect(m_document->textDocument(), &QTextDocument::modificationChanged, this, &Editeur::modifiedChanged); emit documentChanged(); } int Editeur::cursorPosition() const { return m_cursorPosition; } void Editeur::setCursorPosition(int position) { if (position == m_cursorPosition) return; m_cursorPosition = position; reset(); emit cursorPositionChanged(); } int Editeur::selectionStart() const { return m_selectionStart; } void Editeur::setSelectionStart(int position) { if (position == m_selectionStart) return; m_selectionStart = position; emit selectionStartChanged(); } int Editeur::selectionEnd() const { return m_selectionEnd; } void Editeur::setSelectionEnd(int position) { if (position == m_selectionEnd) return; m_selectionEnd = position; emit selectionEndChanged(); } QString Editeur::fileName() const { const QString filePath = QQmlFile::urlToLocalFileOrQrc(m_fileUrl); const QString fileName = QFileInfo(filePath).fileName(); if(fileName.isEmpty()) return QStringLiteral("untitled.txt"); return fileName; } QString Editeur::fileType() const { return QFileInfo(fileName()).suffix(); } QUrl Editeur::fileUrl() const { return m_fileUrl; } void Editeur::load(const QUrl& fileUrl) { if (fileUrl == m_fileUrl) return; QQmlEngine *engine = qmlEngine(this); if (!engine) { qWarning() << "load() called before DocumentHandler has QQmlEngine"; return; } const QUrl path = QQmlFileSelector::get(engine)->selector()->select(fileUrl); const QString fileName = QQmlFile::urlToLocalFileOrQrc(path); if (QFile::exists(fileName)) { QMimeType mime = QMimeDatabase().mimeTypeForFile(fileName); QFile file(fileName); if (file.open(QFile::ReadOnly)) { QByteArray data = file.readAll(); if (QTextDocument *doc = textDocument()) { doc->setBaseUrl(path.adjusted(QUrl::RemoveFilename)); doc->setModified(false); if (mime.inherits("text/markdown")) { emit loaded(QString::fromUtf8(data), Qt::MarkdownText); } else { auto encoding = QStringConverter::encodingForHtml(data); if (encoding) { QStringDecoder decoder(*encoding); emit loaded(decoder(data), Qt::AutoText); } else { // fall back to utf8 emit loaded(QString::fromUtf8(data), Qt::AutoText); } } } reset(); } } m_fileUrl = fileUrl; emit fileUrlChanged(); } void Editeur::saveAs(const QUrl &fileUrl) { QTextDocument *doc = textDocument(); if(!doc) return; const QString filePath = fileUrl.toLocalFile(); const bool isHtml = QFileInfo(filePath).suffix().contains(QLatin1String("htm")); QFile file(filePath); if(!file.open(QFile::WriteOnly| QFile::Truncate | (isHtml ? QFile::NotOpen : QFile::Text))) { emit error(tr("Impossible d'enregistre") + file.errorString()); return; } file.write((isHtml ? doc->toHtml() : doc->toPlainText()).toUtf8()); file.close(); if(fileUrl == m_fileUrl) return; m_fileUrl = fileUrl; emit fileUrlChanged(); } void Editeur::save(const QUrl &fileUrl) { QTextDocument *doc = textDocument(); if(!doc) return; const QString filePath = QQmlFile::urlToLocalFileOrQrc(m_fileUrl); fileUrl.fromLocalFile(filePath); // const QString filePath = fileUrl.toLocalFile(); const bool isHtml = QFileInfo(filePath).suffix().contains(QLatin1String("htm")); QFile file(filePath); if(!file.open(QFile::WriteOnly| QFile::Truncate | (isHtml ? QFile::NotOpen : QFile::Text))) { emit error(tr("Erreur d'enregistre le fichier\nVeuillez refaire a nouveaux\n") + file.errorString()); return; } file.write((isHtml ? doc->toHtml() : doc->toPlainText()).toUtf8()); file.close(); if(fileUrl == m_fileUrl) return; m_fileUrl = fileUrl; emit fileUrlChanged(); } void Editeur::reset() { // emit alignmentChanged(); // emit textColorChanged(); emit fontChanged(); } QTextCursor Editeur::textCursor() const { QTextDocument *doc = textDocument(); if(!doc) return QTextCursor(); QTextCursor cursor = QTextCursor(doc); if(m_selectionStart != m_selectionEnd){ cursor.setPosition(m_selectionStart); cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor); } else{ cursor.setPosition(m_cursorPosition); } return cursor; } QTextDocument *Editeur::textDocument() const { if (!m_document) return nullptr; return m_document->textDocument(); } void Editeur::mergeFormatOnWordOrSelection(const QTextCharFormat &format) { QTextCursor cursor = textCursor(); if (!cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor); cursor.mergeCharFormat(format); } bool Editeur::modified() const { return m_document && m_document->textDocument()->isModified(); } void Editeur::setModified(bool m) { if (m_document) m_document->textDocument()->setModified(m); } QFont Editeur::font() const { QTextCursor cursor = textCursor(); if (cursor.isNull()) return m_document->textDocument()->defaultFont(); QTextCharFormat format = cursor.charFormat(); return format.font(); } void Editeur::setFont(const QFont & font){ QTextCursor cursor = textCursor(); if (!cursor.isNull() && cursor.charFormat().font() == font) return; QTextCharFormat format; format.setFont(font); mergeFormatOnWordOrSelection(format); emit fontChanged(); } bool Editeur::bold() const{ const QTextCursor cursor = textCursor(); if(cursor.isNull()) return m_document->textDocument()->defaultFont().bold(); return cursor.charFormat().font().bold(); } void Editeur::setBold(bool bold) { const QTextCursor cursor = textCursor(); if(!cursor.isNull() && cursor.charFormat().font().bold() == bold) return; QFont font = cursor.charFormat().font(); font.setBold(bold); QTextCharFormat format; format.setFont(font); mergeFormatOnWordOrSelection(format); emit boldChanged(); }bool Editeur::underline() const { const QTextCursor cursor = textCursor(); if(cursor.isNull()) return m_document->textDocument()->defaultFont().underline(); return cursor.charFormat().font().underline(); } void Editeur::setUnderline(bool underline) { const QTextCursor cursor = textCursor(); if (!cursor.isNull() && cursor.charFormat().font().underline() == underline) return; QFont font = cursor.charFormat().font(); font.setUnderline(underline); QTextCharFormat format; format.setFont(font); mergeFormatOnWordOrSelection(format); emit underlineChanged(); } bool Editeur::italic() const { const QTextCursor cursor = textCursor(); if (cursor.isNull()) return m_document->textDocument()->defaultFont().italic(); return cursor.charFormat().font().italic(); } void Editeur::setItalic(bool italic) { const QTextCursor cursor = textCursor(); if (!cursor.isNull() && cursor.charFormat().font().italic() == italic) return; QFont font = cursor.charFormat().font(); font.setItalic(italic); QTextCharFormat format; format.setFont(font); mergeFormatOnWordOrSelection(format); emit italicChanged(); } #include "moc_editeur.cpp"
code editeur.h
#ifndef EDITEUR_H #define EDITEUR_H #include "include.h" #include <QObject> #include <QTextCursor> #include <QUrl> QT_BEGIN_NAMESPACE class QTextDocument; class QQuickTextDocument; QT_END_NAMESPACE class Editeur : public QObject { Q_OBJECT Q_PROPERTY(QQuickTextDocument *document READ document WRITE setDocument NOTIFY documentChanged) Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString fileName READ fileName NOTIFY fileUrlChanged) Q_PROPERTY(QString fileType READ fileType NOTIFY fileUrlChanged) Q_PROPERTY(QUrl fileUrl READ fileUrl NOTIFY fileUrlChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) Q_PROPERTY(bool modified READ modified WRITE setModified NOTIFY modifiedChanged) Q_PROPERTY(bool bold READ bold WRITE setBold NOTIFY boldChanged) Q_PROPERTY(bool underline READ underline WRITE setUnderline NOTIFY underlineChanged) Q_PROPERTY(bool italic READ italic WRITE setItalic NOTIFY italicChanged) public: explicit Editeur(QObject *parent = nullptr); QQuickTextDocument *document() const; void setDocument(QQuickTextDocument* document); int cursorPosition() const; void setCursorPosition(int position); int selectionStart() const; void setSelectionStart(int position); int selectionEnd() const; void setSelectionEnd(int position); QFont font() const; void setFont(const QFont & font); bool bold() const; void setBold(bool bold); bool underline()const; void setUnderline(bool underline); bool italic() const; void setItalic(bool italic); QString fileName() const; QString fileType() const; QUrl fileUrl() const; bool modified() const; void setModified(bool m); public Q_SLOTS: void load(const QUrl& fileUrl); void saveAs(const QUrl &fileUrl); void save(const QUrl &fileUrl); Q_SIGNALS: void documentChanged(); void cursorPositionChanged(); void selectionStartChanged(); void selectionEndChanged(); void fontChanged(); void boldChanged(); void underlineChanged(); void italicChanged(); void textChanged(); void fileUrlChanged(); void loaded(const QString& file, int format); void error(const QString &message); void modifiedChanged(); private: void reset(); QTextCursor textCursor() const; QTextDocument *textDocument() const; void mergeFormatOnWordOrSelection(const QTextCharFormat& format); QQuickTextDocument *m_document; int m_cursorPosition; int m_selectionStart; int m_selectionEnd; QUrl m_fileUrl; }; #endif // EDITEUR_H
donc voilà les codes
je voudrais ouvrier le fichier récupéré depuis le filedialog et le charger sur l'éditeurmerci
-
@Fortiga Hello,
Si j'ai bien compris, le but est de charger le fichier dans la fonction onLaunchNewNotef ?
Je n'ai pas fait de qml depuis longtemps mais ne serait-il pas possible de faire quelque chose comme ci-dessous ?
function onLauncerNewNotef(filepath) { var component = Qt.createComponent("qrc:/MyEditeur.qml") // Container is the parent of editor var editor = component.createObject(container); editor.load(filepath) stack.push(editor) }
-
@Fortiga Bonjour
Je n'ai pas examiné le code dans toutes ses profondeurs, mais pour commencer, il faut déjà savoir que cela dépend fortement de quel côté (C++ ou QML) le nouveau composant est instancié. Pour une instanciation en QML, le cas qui semble vous intéresser, il convient de définir la macro QML_ELEMENT dans la déclaration de classe, à la suite de Q_OBJECT.
Je ne dis pas que c'est le seul problème dans votre code, mais c'est le seul problème que j'ai remarqué en survolant (et le seul que j'ai spécifiquement cherché d'ailleurs).La documentation se trouve ici : https://doc.qt.io/qt-6/qtqml-index.html
-
@ankou29666 je viens de le faire mais c'est toujours le même
-
je pense dans ce cas qu'il faudrait voir du côté de qt_add_qml_module dans le CMakeLists.txt
pour l'instant je n'ai instancié que du côté C++, côté QML c'est pas encore fait, donc si c'est pas ça après je sêche.
-
@ankou29666 Honnêtement je ne compris rien du tout
Jutilise qmake donc je fais CONFIG += qmltypes
QML_IMPORT_NAME = com .mycompany.Qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1
et ça m'aide pas -
non c'est sûr, vous parlez en qmake, moi en cmake. forcément c'est pas la même chose. dans cmake il faut définir la variable qt_add_qml_modules, dans laquelle on met habituellement le code QML et de ce que j'ai compris c'est aussi là qu'il faut déclarer les sources et headers du nouveau composant qui sera mis à disposition en QML. il faut trouver la variable correspondante en qmake.
-
@ankou29666 non en fait après des recherches pour qmake c'est ça
CONFIG += qmltypes
QML_IMPORT_NAME = le nom du component
QML_IMPORT_MAJOR_VERSION = 1et ça m'aide pas honnêtement
-
en cmake, les fichiers du module sont définis explicitement.
Or, la documentation pour qmake ne les spécifie pas, et je ne vois pas par quel miracle qmake pourrait deviner tout seul quels sont les fichiers du module à générer. c'est assez étonnant.
-
@ankou29666 je pense que qmlRegisterType suffit
Mais c'est pas ça qui fait l'erreur -
@Fortiga Hello,
Si j'ai bien compris, le but est de charger le fichier dans la fonction onLaunchNewNotef ?
Je n'ai pas fait de qml depuis longtemps mais ne serait-il pas possible de faire quelque chose comme ci-dessous ?
function onLauncerNewNotef(filepath) { var component = Qt.createComponent("qrc:/MyEditeur.qml") // Container is the parent of editor var editor = component.createObject(container); editor.load(filepath) stack.push(editor) }
-
@Gojir4 Presque le but est de lancer le fichier texte ou HTML récupérer depuis le filedialog sur l'éditeur de texte
je viens d'essayer votre suggestion mais il me dit
invalid write to global property component
Je pense que je me suis mal exprimé. Je voudrais charge le fichier texte ou HTML récupérer depuis le filedialog sur l'éditeur (MyEditeur).qml Côté interface qui est fait avec (éditeur).cpp côté fonctionnement
Pour l'instant j'arrive à récupérer le fichier et afficher le type de fichier. Mais quand je lancer la fonction load du MyEditeur ça ne charge pas le fichier -
@Gojir4 Non il m'affiche un erreur type :
TypeError: Property 'load' of object MyEditeur_QMLTYPE_22(0×2bb32b92270) is not a function
pour le container je le remplace appWindow qui est mon id sur la fenêtre principale
Function onLauncerNewNotef(filePath) { var component = Qt.createComponent("qrc:/MyEditeur.qml") appWindow est id sur la fenêtre ApplicationWindow var editor =component.createObject(appWindow) editor.load(filePath) Starck.pus(editor) }
Enfaite la fonction load est définie dans le code c++
enfin je viens d'essayer de définir un nouveau function loads qui prendre un string, sur mon fichier MyEditeur.qml et sur cette function j'appelle document.load(string) et ça marche
Ça fait 8 jours complet que je cherche une solution
Merci pour votre aide précieux -
-
This post is deleted!