Qt Quick für Android-Studio-Projekte

Die Qt Quick für Android API Beispiele werden als Android Studio Projekte zur Verfügung gestellt. Die Projektordner befinden sich in Ihrem Qt-Installationsverzeichnis.

Unter dem Standard-Windows-Installationspfad sind sie beispielsweise hier zu finden:

C:\Qt\Examples\Qt-/1\platforms\android

Übersicht

Dieses Beispiel enthält ein QML-Projekt, das Sie mit dem Qt Tools for Android Studio-Plugin in Android Studio importieren können, sowie Java- und Kotlin-Projekte, die das QML-Projekt als Ansicht verwenden, indem sie die QtQuickView-API nutzen.

Weitere Informationen darüber, wie QML funktioniert, finden Sie in der Qt Qml. Diese Dokumentation konzentriert sich darauf, wie eine QML-Komponente in Java- und Kotlin-basierte Android-Anwendungen eingebettet wird.

Zuerst schauen wir uns die MainActivity's onCreate() Methode der Java und Kotlin Projekte an.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    m_qmlViewBackgroundText = findViewById(R.id.qmlViewBackgroundText);
    m_qmlStatus = findViewById(R.id.qmlStatusText);
    m_androidControlsLayout = findViewById(R.id.javaRelative);
    m_colorBox = findViewById(R.id.qmlColorBox);
    m_switch = findViewById(R.id.disconnectQmlListenerSwitch);
    m_switch.setOnClickListener(view -> switchListener());
    QtQuickView m_firstQuickView = new QtQuickView(this);
    QtQuickView m_secondQuickView = new QtQuickView(this);

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_firstQmlContent.setStatusChangeListener(this);
    m_secondQmlContent.setStatusChangeListener(this);
    final ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    FrameLayout m_firstQmlFrameLayout = findViewById(R.id.firstQmlFrame);
    m_firstQmlFrameLayout.addView(m_firstQuickView, params);
    FrameLayout m_secondQmlFrameLayout = findViewById(R.id.secondQmlFrame);
    m_secondQmlFrameLayout.addView(m_secondQuickView, params);
    m_firstQuickView.loadContent(m_firstQmlContent);
    m_secondQuickView.loadContent(m_secondQmlContent);

    Button m_changeColorButton = findViewById(R.id.changeQmlColorButton);
    m_changeColorButton.setOnClickListener(view -> onClickListener());
    Button m_rotateQmlGridButton = findViewById(R.id.rotateQmlGridButton);
    m_rotateQmlGridButton.setOnClickListener(view -> rotateQmlGrid());
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    m_binding = ActivityMainBinding.inflate(layoutInflater)
    val view = m_binding.root
    setContentView(view)

    m_binding.disconnectQmlListenerSwitch.setOnCheckedChangeListener { button, checked ->
        switchListener(
            button,
            checked
        )
    }

    val firstQtQuickView = QtQuickView(this)
    val secondQtQuickView = QtQuickView(this)

    // Set status change listener for m_qmlView
    // listener implemented below in OnStatusChanged
    m_firstQmlContent.setStatusChangeListener(this)
    m_secondQmlContent.setStatusChangeListener(this)

    val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
    )
    m_binding.firstQmlFrame.addView(firstQtQuickView, params)
    m_binding.secondQmlFrame.addView(secondQtQuickView, params)
    firstQtQuickView.loadContent(m_firstQmlContent)
    secondQtQuickView.loadContent(m_secondQmlContent)

    m_binding.changeQmlColorButton.setOnClickListener { onClickListener() }
    m_binding.rotateQmlGridButton.setOnClickListener { rotateQmlGrid() }
}

Hinweis: Im Kotlin-Projekt verwenden wir View-Binding für den Zugriff auf die UI-Komponenten der Anwendung:

m_binding = ActivityMainBinding.inflate(layoutInflater)
val view = m_binding.root
setContentView(view)

Innerhalb der Methode onCreate() werden zuvor deklarierte Variablen mit neuen QtQuickViews initialisiert. Diese neuen Instanzen von QtQuickView werden erstellt, indem man ihnen den Context der Java/Kotlin Activity als Argumente mitgibt.

QtQuickView m_firstQuickView = new QtQuickView(this);
QtQuickView m_secondQuickView = new QtQuickView(this);
val firstQtQuickView = QtQuickView(this)
val secondQtQuickView = QtQuickView(this)

Die QtQuickViews werden dem Android-Layout mit entsprechenden Layout-Parametern hinzugefügt.

final ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout m_firstQmlFrameLayout = findViewById(R.id.firstQmlFrame);
m_firstQmlFrameLayout.addView(m_firstQuickView, params);
FrameLayout m_secondQmlFrameLayout = findViewById(R.id.secondQmlFrame);
m_secondQmlFrameLayout.addView(m_secondQuickView, params);
val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
m_binding.firstQmlFrame.addView(firstQtQuickView, params)
m_binding.secondQmlFrame.addView(secondQtQuickView, params)

Die Java-Klassen Main und Second erben von der Klasse QtQuickViewContent. Diese Klassen werden aus dem QML-Projekt generiert, das wir importiert haben.

private final Main m_firstQmlContent = new Main();
private final Second m_secondQmlContent = new Second();
private val m_firstQmlContent: Main = Main()
private val m_secondQmlContent: Second = Second()

Der Inhalt von Qt Quick wird über die Methode QtQuickView.loadContent() geladen, die ein QtQuickViewContent als Argument annimmt.

m_firstQuickView.loadContent(m_firstQmlContent);
m_secondQuickView.loadContent(m_secondQmlContent);
firstQtQuickView.loadContent(m_firstQmlContent)
secondQtQuickView.loadContent(m_secondQmlContent)

Interaktion mit den QML-Komponenten

Um mit den eingebetteten QML-Komponenten zu interagieren, implementieren wir die QtQmlStatusChangeListener -Schnittstelle und überschreiben die onStatusChanged-Methode, um den Ladestatus des QtQuickViewContent zu erhalten, der gerade in die QtQuickViews geladen wird.

public class MainActivity extends AppCompatActivity implements
QtQmlStatusChangeListener {
    ...
}
class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener {
    ...
}

Die onStatusChanged Implementierung:

@Override
public void onStatusChanged(QtQmlStatus qtQmlStatus, QtQuickViewContent content) {
    Log.i(TAG, "Status of QtQuickView: " + qtQmlStatus);

    // Show current QML View status in a textview
    m_qmlStatus.setText(getString(R.string.qml_view_status, m_statusNames.get(qtQmlStatus)));
    updateColorDisplay();

    if (content == m_firstQmlContent) {
        // Connect signal listener to "onClicked" signal from main.qml
        // addSignalListener returns int which can be used later to identify the listener
        if (qtQmlStatus == QtQmlStatus.READY && m_switch.isChecked()) {
            m_qmlButtonSignalListenerId = m_firstQmlContent.connectOnClickedListener(
                    (String name, Void v) -> {
                        Log.i(TAG, "QML button clicked");
                        m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                                m_colors.getColor()
                        ));
                    });
        }
    }
}
override fun onStatusChanged(status: QtQmlStatus?, content: QtQuickViewContent?) {
    Log.v(TAG, "Status of QtQuickView: $status")

    // Show current QML View status in a textview
    m_binding.qmlStatusText.text = getString(R.string.qml_view_status, m_statusNames[status])

    updateColorDisplay()

    if (content == m_firstQmlContent) {
        // Connect signal listener to "onClicked" signal from main.qml
        // addSignalListener returns int which can be used later to identify the listener
        if (status == QtQmlStatus.READY && m_binding.disconnectQmlListenerSwitch.isChecked) {
            m_qmlButtonSignalListenerId =
                m_firstQmlContent.connectOnClickedListener { _: String, _: Void? ->
                    Log.i(TAG, "QML button clicked")
                    m_binding.kotlinRelative.setBackgroundColor(
                        Color.parseColor(
                            m_colors.getColor()
                        )
                    )
                }
        }
    }
}

Die MainActivity wird als statusChangeListener der m_mainQmlContent und m_secondQmlContent mit der Methode QtQuickViewContent.setStatusChangeListener gesetzt.

m_firstQmlContent.setStatusChangeListener(this);
m_secondQmlContent.setStatusChangeListener(this);
m_firstQmlContent.setStatusChangeListener(this)
m_secondQmlContent.setStatusChangeListener(this)

Die überschriebene Callback-Funktion onStatusChanged() empfängt ein StatusChanged() Signal, das den aktuellen Status (public Enum QtQmlStatus) des Ladens des aktuellen QtQuickViewContent in die QtQuickView enthält. Wenn dieses QtQmlStatus als QtQmlStatus.READY bestätigt wird, können wir mit der QML-Ansicht interagieren.

Abrufen und Setzen von Eigenschaftswerten der QML-Komponente

Das Abrufen und Setzen von Eigenschaftswerten von QML-Komponenten erfolgt über die in der Klasse Main.java beschriebenen Methoden. In diesem Fall verwenden wir die Methoden m_mainQmlContent.setColorStringProperty() und m_mainQmlContent.getColorStringProperty(). Diese Methoden werden je nachdem, welche Eigenschaften die QML-Komponente enthält, generiert.

public void onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_firstQmlContent.setColorStringFormat(m_colors.getColor());
    updateColorDisplay();
}
private void updateColorDisplay() {
    String qmlBackgroundColor = m_firstQmlContent.getColorStringFormat();
    // Display the QML View background color code
    m_qmlViewBackgroundText.setText(qmlBackgroundColor);

    // Display the QML View background color in a view
    // if qmlBackGroundColor is not null
    if (qmlBackgroundColor != null) {
        m_colorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
    }
}
private fun onClickListener() {
    // Set the QML view root object property "colorStringFormat" value to
    // color from Colors.getColor()
    m_firstQmlContent.colorStringFormat = m_colors.getColor()
    updateColorDisplay()
}

private fun updateColorDisplay() {
    val qmlBackgroundColor = m_firstQmlContent.colorStringFormat
    // Display the QML View background color code
    m_binding.qmlViewBackgroundText.text = qmlBackgroundColor
    // Display the QML View background color in a view
    // if qmlBackgroundColor is not null
    if (qmlBackgroundColor != null) {
        m_binding.qmlColorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor))
    }
}

Mit der Methode m_mainQmlContent.setColorStringProperty() setzen wir den Eigenschaftswert colorStringFormat des m_mainQmlContent auf einen zufälligen Farbwert, der aus der Klasse Colors.java (oder Colors.kt) geholt wird.

Die Methode m_mainQmlContent.getColorStringProperty() wird hier verwendet, um die aktuelle Hintergrundfarbe des Root-Objekts des m_mainQmlContent abzurufen und sie dann dem Benutzer auf der Java/Kotlin-Android-Seite der Anwendung anzuzeigen.

m_secondQmlContent hat eine Grid QML-Komponente, die wir von der Java-Seite aus mit der generierten m_secondQmlContent.setGridRotation() -Methode drehen können.

private void rotateQmlGrid() {
    Integer previousGridRotation = m_secondQmlContent.getGridRotation();
    if (previousGridRotation != null) {
        m_secondQmlContent.setGridRotation(previousGridRotation + 45);
    }
}
private fun rotateQmlGrid() {
    val previousGridRotation = m_secondQmlContent.gridRotation
    if (previousGridRotation != null) {
        m_secondQmlContent.gridRotation = previousGridRotation + 45
    }
}

Signal-Listener

Die Klasse QtQuickViewContent bietet die Methoden connectSignalListener() und disconnectSignalListener(), die zum Verbinden und Trennen von Signalhörern zwischen Signalen verwendet werden, die im Stammobjekt der QML-Komponente deklariert sind. Die Methode QtQuickViewContent.connectSignalListener() gibt eine eindeutige Signal-Listener-ID zurück, die wir speichern und später zum Identifizieren und Trennen des Listeners verwenden.

Hier verbinden wir einen Signal-Listener mit dem onClicked() Signal der QML-Komponente.

if (qtQmlStatus == QtQmlStatus.READY && m_switch.isChecked()) {
    m_qmlButtonSignalListenerId = m_firstQmlContent.connectOnClickedListener(
            (String name, Void v) -> {
                Log.i(TAG, "QML button clicked");
                m_androidControlsLayout.setBackgroundColor(Color.parseColor(
                        m_colors.getColor()
                ));
            });
}
if (status == QtQmlStatus.READY && m_binding.disconnectQmlListenerSwitch.isChecked) {
    m_qmlButtonSignalListenerId =
        m_firstQmlContent.connectOnClickedListener { _: String, _: Void? ->
            Log.i(TAG, "QML button clicked")
            m_binding.kotlinRelative.setBackgroundColor(
                Color.parseColor(
                    m_colors.getColor()
                )
            )
        }
}

Das Signal onClicked() wird jedes Mal ausgesendet, wenn die Schaltfläche der QML-Komponente angeklickt wird. Dieses Signal wird dann von diesem Listener empfangen und die Hintergrundfarbe des Layouts, das die Android-Seite der Anwendung enthält, wird auf einen zufälligen Farbwert gesetzt, der aus der Klasse Colors.java abgerufen wird.

Als Nächstes wird der Signal-Listener mit der Methode QtQuickViewContent.disconnectSignalListener() getrennt, indem man ihm die eindeutige Signal-Listener-ID gibt.

m_firstQmlContent.disconnectSignalListener(m_qmlButtonSignalListenerId);
m_firstQmlContent.disconnectSignalListener(m_qmlButtonSignalListenerId)

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.