Ubuntuでシンプルなデスクトップアプリケーションを書きたいのですが、QMLをGUIとして使用し、Python=をロジックの言語として使用するのが簡単な方法だと思います。Pythonに多少慣れているからです。 。
現在、何時間かGUIとロジックを接続しようとしていますが、機能していません。私は接続QMLを管理しました-> Pythonしかし、その逆ではありません。データモデルを表すPythonクラスがあり、JSONエンコードとデコードを追加しましたつまり、今のところSQLデータベースは含まれていませんが、QMLビューと一部のデータベースを直接接続すると、物事が簡単になるのではないでしょうか。
だから今いくつかのコード。
QML-> Python
QMLファイル:
ApplicationWindow {
// main window
id: mainWindow
title: qsTr("Test")
width: 640
height: 480
signal tmsPrint(string text)
Page {
id: mainView
ColumnLayout {
id: mainLayout
Button {
text: qsTr("Say Hello!")
onClicked: tmsPrint("Hello!")
}
}
}
}
次に、slots.pyがあります。
from PySide2.QtCore import Slot
def connect_slots(win):
win.tmsPrint.connect(say_hello)
@Slot(str)
def say_hello(text):
print(text)
そして最後に私のmain.py:
import sys
from controller.slots import connect_slots
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine
if __name__ == '__main__':
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load('view/main.qml')
win = engine.rootObjects()[0]
connect_slots(win)
# show the window
win.show()
sys.exit(app.exec_())
これは正常に機能し、「Hello!」を印刷できます。しかし、これはそれを行うための最良の方法ですか、それともスロットを持つクラスを作成し、setContextProperty
を使用して、追加の信号を追加せずに直接呼び出すことができるようにする方が良いですか?
Python-> QML
私はこれを成し遂げることができません。さまざまな方法を試しましたが、どれも機能せず、どの方法が最適かわかりません。私がしたいことは、たとえばオブジェクトのリストを表示し、アプリケーションなどでデータを操作する手段を提供することです。
application.js
何かを出力するだけの関数を使用しましたが、おそらくテキストフィールドのコンテキストの設定などに使用できます。その後、QMetaObjectとinvokeMethodを使用しようとしましたが、引数が間違っているなどのエラーが発生しました。このアプローチは意味がありますか?実際、私はjavascriptを知らないので、必要なければJavaScriptを使用しません。
ViewModelアプローチファイルviewmodel.pyを作成しました
from PySide2.QtCore import QStringListModel
class ListModel(QStringListModel):
def __init__(self):
self.textlines = ['hi', 'ho']
super().__init__()
そしてmain.pyに追加しました:
model = ListModel()
engine.rootContext().setContextProperty('myModel', model)
listViewは次のようになります。
ListView {
width: 180; height: 200
model: myModel
delegate: Text {
text: model.textlines
}
}
「myModelが定義されていません」というエラーが表示されますが、デリゲートはリストではなく要素を1つしか取らないため、とにかく機能しません。このアプローチは良いものですか?はいの場合、どのように機能させるのですか?
私はあなたの助けに感謝します! Qtのドキュメントは知っていますが、満足していません。だから私は何かが足りないのかもしれません。しかし、PyQtはPySide2よりもはるかに人気があるようで(少なくともgoogle検索はそれを示しているようです)、PySide参照はしばしばPySide1を使用するか、QML QtQuickの方法を使用しない...
あなたの質問には多くの側面があるので、私は私の回答で詳細に説明するようにします。また、このタイプの質問はよく聞かれるので、この回答は継続的に更新されますが、それらは特定のケースの解決策なので、自由に答えます一般的なアプローチと可能なシナリオで具体的です。
QMLからPythonへ:
pythonの型変換は動的なので、この方法は機能します。C++では起こりません。小さなタスクでは機能しますが、メンテナンスできません。ロジックはビューから分離する必要があるため、具体的には、印刷されたテキストがロジックによって処理され、信号の名前を変更した場合、またはデータがApplicationWindow
に依存していない場合、別の要素などでは、多くの接続コードを変更する必要があります。
あなたが示すように推奨されるのは、ロジックが必要なデータのマッピングを担当するクラスを作成し、それをQML
に埋め込むことです。そのため、ビューで何かを変更する場合は、接続を変更するだけです。
例:
main.py
_import sys
from PySide2.QtCore import QObject, Signal, Property, QUrl
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
class Backend(QObject):
textChanged = Signal(str)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.m_text = ""
@Property(str, notify=textChanged)
def text(self):
return self.m_text
@text.setter
def setText(self, text):
if self.m_text == text:
return
self.m_text = text
self.textChanged.emit(self.m_text)
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
backend = Backend()
backend.textChanged.connect(lambda text: print(text))
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("backend", backend)
engine.load(QUrl.fromLocalFile('main.qml'))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
_
main.qml
_import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
Column{
TextField{
id: tf
text: "Hello"
}
Button {
text: qsTr("Click Me")
onClicked: backend.text = tf.text
}
}
}
_
次に、テキストを別の要素で提供する場合は、_onClicked: backend.text = tf.text
_の行を変更するだけです。
PythonからQML:
コードが表示されていないため、この方法で何がおかしいのかはわかりませんが、欠点は指摘しています。主な欠点は、このメソッドを使用するには、メソッドにアクセスする必要があり、2つの可能性があることです。1つ目は、最初の例に示されているようにrootObjectsであるか、objectNameを検索することですが、最初にオブジェクトを探し、それを取得すると、QMLから削除されます。たとえば、ページを変更するたびにStackViewのページが作成および削除されるため、このメソッドは正しくありません。
私にとって2番目の方法は正しい方法ですが、ロールが使用されるQMLの行と列に焦点を合わせるQtWidgetsとは異なり、正しく使用していません。まず、コードを正しく実装しましょう。
最初のtextlines
はQML
ではないため、qproperty
からアクセスできません。ロールを通じてアクセスする必要があると述べたように、モデルのロールを確認するには、roleNames()
の結果を出力できます。
_model = QStringListModel()
model.setStringList(["hi", "ho"])
print(model.roleNames())
_
出力:
_{
0: PySide2.QtCore.QByteArray('display'),
1: PySide2.QtCore.QByteArray('decoration'),
2: PySide2.QtCore.QByteArray('edit'),
3: PySide2.QtCore.QByteArray('toolTip'),
4: PySide2.QtCore.QByteArray('statusTip'),
5: PySide2.QtCore.QByteArray('whatsThis')
}
_
テキストを取得する場合は、ロール_Qt::DisplayRole
_を使用する必要があります。その数値は docs に応じて次のようになります。
_Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)
_
したがって、QML
では_model.display
_(またはdisplay
)のみを使用する必要があります。したがって、正しいコードは次のとおりです。
main.py
_import sys
from PySide2.QtCore import QUrl, QStringListModel
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
model = QStringListModel()
model.setStringList(["hi", "ho"])
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("myModel", model)
engine.load(QUrl.fromLocalFile('main.qml'))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
_
main.qml
_import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
ListView{
model: myModel
anchors.fill: parent
delegate: Text { text: model.display }
}
}
_
編集可能にしたい場合は、_model.display = foo
_を使用する必要があります。
_import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
ListView{
model: myModel
anchors.fill: parent
delegate:
Column{
Text{
text: model.display
}
TextField{
onTextChanged: {
model.display = text
}
}
}
}
}
_
QMLを使用してPython/C++を操作する方法は他にもたくさんありますが、最良の方法は、Python [/ C++]で作成されたオブジェクトをsetContextProperty
を介して埋め込むことです。
PySide2のドキュメントはそれほど多くないことを示しているので、PySide2は実装されており、次の link で確認できます。最も存在するのはPyQt5の多くの例であるため、両方の同等性を理解して翻訳することをお勧めします。これらの翻訳は最小限の変更であるため、難しくありません。