Rectangle{}-Debugging in QML, genau wie printf(), aber für QT

 C Programming >> C-Programmierung >  >> Tags >> Qt
Rectangle{}-Debugging in QML, genau wie printf(), aber für QT

Vor kurzem habe ich eine Debugging-Technik in QT/QML verwendet, der ich den Namen Rectangle{} gegeben habe Debuggen, in der gleichen Weise wie printf() Debuggen. QML ist eine Auszeichnungssprache (Teil des QT-Frameworks) wie HTML/CSS innerhalb von JavaScript, die mit dem C++-Code Ihrer (QT-)Anwendung interagieren kann. QML hat das Konzept von anchors zur relativen Positionierung von Elementen. Insgesamt anchors funktionieren ganz gut, können aber komplex werden, wenn Vererbung und komplizierte Layouts ins Spiel kommen. Die Rectangle{} Der Debugging-Stil platziert ein halbtransparentes Rechteck mit einem Rahmen um Ihr Element, sodass Sie die Positionierung visualisieren und sehen können, welche Auswirkungen Ihre Änderungen haben. Dieser Artikel zeigt ein Beispiel, in dem ich diesen Debugging-Stil kürzlich bei der Arbeit in unserer Kaffeemaschinen-Benutzeroberfläche angewendet habe, einschließlich einiger Tipps zur tatsächlichen Durchführung von printf() Stil-Debugging (aber mit Console.log ).

Ich habe schon früher über QT / QML geschrieben, dieser Artikel befasste sich mit Signalisierung und Slots, einer Methode zur Kommunikation zwischen C++ und QML.

Mit dem Qt Quick-Ankersystem können Sie Beziehungen zwischen den Ankerlinien verschiedener Elemente definieren. Sie können zum Beispiel schreiben:

Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; ... }

In diesem Fall der linke Rand von rect2 wird an den rechten Rand von rect1 gebunden , was Folgendes erzeugt:

Wie gesagt, das wird schnell komplex, besonders wenn Anker/Positionen von dynamischen Variablen abhängen, die über Signale von der C++-Seite hereinkommen. QT Design Studio ist aufgrund plattformspezifischer Einschränkungen in unseren Projekten ebenfalls nicht verwendbar.

Was ist printf() Debuggen? Es ist eine Technik, die nach der ubiquitousC-Funktion benannt ist. Wird verwendet, um Debugging-Arbeiten zu beschreiben, die durch Einfügen von Befehlen ausgeführt werden, die mehr oder weniger sorgfältig ausgewählte Statusinformationen an Schlüsselpunkten im Programmablauf ausgeben, diese Informationen beobachten und basierend auf diesen Informationen ableiten, was falsch ist.

Ich bevorzuge einen dedizierten Debugger, aber er muss gut und in meine IDE integriert sein. CLion hat dies, Visual Studio hat einen vernünftigen und der QML-Debugger von QT Creator ist einfach schlecht.

Bei visuellen Elementen wie in QML ist es schwieriger, die Positionierung und relative Dinge zu debuggen. Daneben hat QT Creator einen QML-Debugger, aber das ist schrecklich zu benutzen. Nicht reagierende, fehlende Breakpoints, alle möglichen anderen seltsamen Dinge, die einfach schrecklich funktionieren. Mit diesem Rechteck-Trick werden Elemente, Grenzen und Änderungen sehr gut sichtbar. Um ein Objekt zu zentrieren, verwenden Sie anchors.centerIn: parent oder anchors.horizontalCenter: parent.horizontalCenter ? Mit einem großen Rechteck um Ihre Änderung ist es viel besser sichtbar, was eine Änderung bewirkt.

Rectangle{}-Debugging

Kürzlich musste ich die berührungslose Kaffeefunktion für eine unserer Maschinenbenutzeroberflächen implementieren, die QT verwendet. Die QML-Steuerung war bereits vorhanden, musste jedoch auf einigen Bildschirmen platziert werden und je nach Einstellung ein anderes Element bedingt ersetzen. Der erste Versuch, das Steuerelement in diesem anderen Element zu platzieren, führte zu einem kleinen, nicht zentrierten Element. Unten sehen Sie ein Bild, das links den ersten Versuch und rechts das Endergebnis zeigt:

Die Unschärfe in den Screenshots ist darauf zurückzuführen, dass ich sie in der Größe angepasst habe, damit sie besser auf die Website passen, auf dem Computer sind sie super scharf.

Das Element, das bedingt ersetzt wurde, wurde in der Größe geändert und zentriert, die QML-Syntax wurde kopiert und führte zu etwas Unerwartetem. Das erste, was ich tat, war ein Rechteck um den Container zu ziehen, um zu visualisieren, was vor sich ging:

Rectangle {
    anchors.fill: parent
    color: "#ffffff"
    visible: true
    opacity: 0.8
    border.color: "#ff0000"

    //insert your objects here
}

Es sieht so aus:

Wie Sie sehen können, befindet sich das neue QR-Bild nicht genau in der Ecke ganz oben links, sodass innerhalb des QR-Steuerelements einige Positionierungen stattfinden. Lassen Sie uns eine weitere Rectangle eingeben in der QR-Code-Steuerung, um zu sehen, was das tut. Diesmal ist die Hintergrundfarbe hellorange, um sie vom äußeren Container abzuheben:

Innerhalb der QR-Steuerung ist die Größe auch nicht so, wie ich es erwarten würde, die Zentrierung stimmt. Denken Sie daran, dass dieses spezifische Steuerelement bereits auf anderen Benutzeroberflächen verwendet wird und ordnungsgemäß funktioniert. Lassen Sie uns mit Image.Fillmode herumspielen , Pad oderPreserveAspectFit sollte ausreichen, ebenso wie einige anchors.fill: parent hier und da bestreut:

Fast da, wie Sie sehen können, die Code: Text befindet sich jetzt außerhalb beider Steuerelemente. Das hat einen anchor.top: qrimage.bottom , was korrekt ist, aber wenn dieses Steuerelement beschnitten würde, wäre der Text nicht sichtbar. Wenn ich diesen Rectangle{} nicht verwendet hätte Debugging-Methode hätte ich das nicht bemerkt, was in Zukunft zu Fehlern führen könnte.

Lassen Sie uns mit Image.width: ### * 0.85 testen :

Besser, aber wenn der Regler größer ist, immer noch nicht richtig, zu viel Platz unten. Das zu beheben liegt außerhalb des Rahmens dieses Artikels. Fahren Sie mit dem Zentrieren des Reglers fort. Das war ein Fall der richtigen Kombination von anchors.fill: parent und anchors.horizontalCenter: parent.horizontalCenter in ein paar Kontrollen. Ich erspare Ihnen die Details, nach ein paar Minuten habe ich die richtige Kombination gefunden:

Jetzt müssen nur noch die Rechtecke entfernt (oder, noch schlimmer, transparent gemacht) und das Feature fertiggestellt werden.

Ohne die Rechteck-Debugging-Technik hätte ich wahrscheinlich nicht bemerkt, dass sich der Text außerhalb des Bildes befindet. Oder es würde darüber diskutiert werden, ob ein Regler genau in der Mitte ist. Es ist in diesem Fall viel hilfreicher, es sichtbar und sichtbar zu machen, als auf einen Debugger zu starren.

Falls Sie sich fragen, so sieht die Webseite aus, nachdem Sie den QR-Code gescannt haben:

Dieser spezielle QR-Code hat nie funktioniert, da er nur in einer Entwicklungsumgebung aktiv war, aber Sie fragen sich vielleicht, was passieren würde, wenn Sie den Code scannen würden. Es gibt Ihnen eine Webseite mit allen Maschinenverbrauchen, wählen Sie eine aus, passen Sie das Getränk an und drücken Sie auf Bestellen. Die Maschine beginnt mit der Produktion, ohne dass der Benutzer den Bildschirm berühren muss. Verwendet MQTT im Backend, weniger als 7 MBa Monat Datenverbrauch, super reaktionsschnell, wirklich cool zu entwickeln. Aber das ist eine Geschichte für einen anderen Tag.

Console.log-QML-Debugging

QML mischt Auszeichnungssprache mit Inline-JavaScript, was in meinem Fall beim Debuggen hilfreich sein kann. Beispielsweise kann die Sichtbarkeit eines Elements durch QML-Eigenschaften oder über C++-Signale und -Slots bestimmt werden. Durch Ersetzen des visible: varName Mit einem JavaScript-Funktionsaufruf können wir den Wert in der Konsole protokollieren. Dadurch kann ich diesen booleschen Wert ausschließen, wenn ein Element unsichtbar ist, aber sichtbar sein sollte. Es hilft herauszufinden, ob das Styling (z-Index zum Beispiel) der Issuer oder der tatsächlich zurückgegebene Wert ist.

Hier ist eine Beispiel-QML-Datei:

Item {
  function logAndReturnValue(varToLog)
  {
    console.log("value: " + varToLog);
    return varToLog;
  }
  property bool varName: false;

  Text {
    visible: logAndReturnValue(varName)
    text: "Example Text"
  }
}

Diese einfache Beispielfunktion nimmt eine Variable, protokolliert sie in der Konsole und gibt das Ergebnis zurück. Der Text Element hat die Zeile visible: , das ist der boolean Wert wahr oder falsch, oder eine andere Variable, die einen booleschen Wert enthält, oder eine Funktion, die einen booleschen Wert zurückgibt. Durch die Verwendung von Signalen können Sie dies über C++-Code festlegen, siehe meinen anderen Beispielartikel, um zu erfahren, wie das funktioniert.

Effektiv könnten Sie einfach visible: varName schreiben , aber mit dieser Protokollierungsmethode wird es auch gedruckt.

Neben dieser Methode können Sie sich auch in Component.onCompleted einklinken Signalhandler, der ausgegeben wird, nachdem ein Objekt instanziiert wurde:

Text {
    Component.onCompleted: console.log("Text onCompleted.")
    text: "Example Text"
}

Meiner Erfahrung nach ist die Arbeit mit dem QML-Debugger mühsam, nicht einmal annähernd so ausgefeilt wie die GDB-Integration von CLion. Es ist manchmal auch ein bisschen komisch, keine Ergebnisse zu aktualisieren, nicht richtig zu übersteigen, alle möglichen kleinen Probleme. Ich bevorzuge oft dieses Debugging im printf-Stil in QML, weil QT Creator und sein QML-Debugger so schlecht sind.