PyQt 启动时加载函数(qml 加载器)
Posted
技术标签:
【中文标题】PyQt 启动时加载函数(qml 加载器)【英文标题】:PyQt load function on startup (qml loader) 【发布时间】:2018-05-01 14:51:54 【问题描述】:您好,我有以下问题:
这是我的工作代码
import sys
from PyQt5.QtCore import QObject, QUrl, Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine
import os
import vlc
from time import sleep
# define VLC instance
instance = vlc.Instance()
# Define VLC player
instance = vlc.Instance('--input-repeat=-1', '--fullscreen')
player = instance.media_player_new()
list_test = []
list_name = []
def prepare_url(url):
media = instance.media_new(url)
player.set_media(media)
if __name__ == "__main__":
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
ctx = engine.rootContext()
ctx.setContextProperty("main", engine)
engine.load('SimpleQML.qml')
win = engine.rootObjects()[0]
win.show()
button = win.findChild(QObject, "playBtn")
def myFunction():
print("A fine piece of text")
button.clicked.connect(myFunction) # works on click
myFunction() #works with out clicking
sys.exit(app.exec_())
现在我想通过执行以下代码来扩展它:
import sys
from PyQt5.QtCore import QObject, QUrl, Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine
import os
import vlc
from time import sleep
# define VLC instance
instance = vlc.Instance()
# Define VLC player
instance = vlc.Instance('--input-repeat=-1', '--fullscreen')
player = instance.media_player_new()
list_test = []
list_name = []
def prepare_url(url):
media = instance.media_new(url)
player.set_media(media)
if __name__ == "__main__":
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
ctx = engine.rootContext()
ctx.setContextProperty("main", engine)
engine.load('SimpleQML.qml')
win = engine.rootObjects()[0]
win.show()
button = win.findChild(QObject, "playBtn")
comboBox = win.findChild(QObject, "comboBox")
def myFunction():
print("das")
def list_fill():
with open("config/stations.txt") as f:
content = f.readlines()
content = [x.strip() for x in content]
list_t = [item.split("|")[0] for item in content if item]
list_n = [item.split("|")[1] for item in content if item]
del list_test[:]
del list_name[:]
comboBox.clear()
for x in list_t:
list_test.append(x)
for x in list_n:
list_name.append(x)
addItems(list_name)
button.clicked.connect(myFunction) # works too
myFunction()
list_fill() #calling this crashes program
sys.exit(app.exec_())
最后这是错误
das
Traceback (most recent call last):
File "/home/flea/Desktop/quick qt/main.py", line 65, in <module>
list_fill()
File "/home/flea/Desktop/quick qt/main.py", line 55, in list_fill
comboBox.clear()
AttributeError: 'QObject' object has no attribute 'clear'
我尝试使用硬编码列表来做 ti,但列表不是问题,由于某种原因,我的组合框无法被 python 识别。我不确定这里有什么问题。 我可以加载我的按钮并向它添加一个点击事件(这有效),但我无法将列表添加到我的组合框。
这是我的 Qml
import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import QtQuick.Controls.Material 2.3
ApplicationWindow
id: applicationWindow
Material.theme: Material.Light
title: qsTr("Test Invoke")
width: 600
height: 500
Row
id: row
width: 200
height: 400
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
Button
id: playBtn
objectName: "playBtn"
text : "Play"
checked: false
padding: 6
rightPadding: 8
font.wordSpacing: 0
font.pointSize: 10
font.family: "Times New Roman"
topPadding: 4
highlighted: true
Material.accent: Material.Red
Button
id: stopBtn
objectName: "stopBtn"
text: qsTr("Stop")
anchors.left: playBtn.right
anchors.leftMargin: 5
Button
id: stfBtn
text: qsTr("Save")
objectName: "stfBtn"
anchors.left: stopBtn.right
anchors.leftMargin: 5
Button
id: minimize
objectName: "minBtn"
text: qsTr("Min")
anchors.left: stfBtn.right
anchors.leftMargin: 5
Column
id: column
x: 135
y: 100
width: 200
height: 400
TextField
objectName: "nameText"
id: nameText
width: 300
text: qsTr("")
TextField
objectName: "urlText"
id: urlText
width: 300
text: qsTr("")
ComboBox
objectName: "comboBox"
id: comboBox
width: 200
Slider
id: slide
objectName: "slider"
x: 160
y: 311
value: 0.5
【问题讨论】:
ComboBox 没有明确的功能。 QComboBox 与 ComboBox 不同 什么是 addItems? 【参考方案1】:从 Python 或 C++ 实例化在 QML 中创建的对象既不好也不可维护。
适当的做法是在 Python 或 C++ 中创建一个对象并将其发送到 QML,然后创建允许与 QML 交互的 qproperties 和槽。
在你的情况下,我猜 list_fill 试图将数据添加到 ComboBox,但 ComboBox 没有明确的方法,所以如果你想清理它,只需传递一个空列表,或者在你的情况下传递它新列表。
另一方面,调用show()并不优雅,最好将ApplicationWindow的visible属性设置为true。
main.py
import sys
import os
from PyQt5.QtCore import QObject, QUrl, Qt, pyqtSlot, pyqtSignal, pyqtProperty
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine
import vlc
# define VLC instance
instance = vlc.Instance()
# Define VLC player
instance = vlc.Instance('--input-repeat=-1', '--fullscreen')
player = instance.media_player_new()
list_test = []
list_name = []
def prepare_url(url):
media = instance.media_new(url)
player.set_media(media)
class Manager(QObject):
stationsChanged = pyqtSignal()
currentStationChanged = pyqtSignal()
def __init__(self):
QObject.__init__(self)
self.m_stations = []
self.m_currentStation = ""
self.currentStationChanged.connect(self.on_currentStationChanged)
@pyqtProperty(str, notify=currentStationChanged)
def currentStation(self):
return self.m_currentStation
@currentStation.setter
def currentStation(self, val):
if self.m_currentStation == val:
return
self.m_currentStation = val
self.currentStationChanged.emit()
@pyqtProperty(list, notify=stationsChanged)
def stations(self):
return self.m_stations
@stations.setter
def stations(self, val):
if self.m_stations == val:
return
self.m_stations = val[:]
self.stationsChanged.emit()
@pyqtSlot()
def play(self):
print("play", self.currentStation)
@pyqtSlot()
def stop(self):
print("stop")
@pyqtSlot()
def on_currentStationChanged(self):
print(self.currentStation)
def list_fill(self):
l = []
with open("config/stations.txt") as f:
content = f.readlines()
content = [x.strip() for x in content]
list_t = [item.split("|")[0] for item in content if item]
list_n = [item.split("|")[1] for item in content if item]
l += list_t + list_n
self.stations = l
if __name__ == "__main__":
os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
manager = Manager()
ctx = engine.rootContext()
ctx.setContextProperty("Manager", manager)
engine.load('main.qml')
if not engine.rootObjects():
sys.exit(-1)
manager.list_fill()
sys.exit(app.exec_())
main.qml
import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2
import QtQuick.Controls.Material 2.3
ApplicationWindow
id: applicationWindow
Material.theme: Material.Light
title: qsTr("Test Invoke")
visible: true
width: 600
height: 500
Row
id: row
width: 200
height: 400
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
Button
id: playBtn
text : "Play"
checked: false
padding: 6
rightPadding: 8
font.wordSpacing: 0
font.pointSize: 10
font.family: "Times New Roman"
topPadding: 4
highlighted: true
Material.accent: Material.Red
onClicked: Manager.play()
Button
id: stopBtn
text: qsTr("Stop")
anchors.left: playBtn.right
anchors.leftMargin: 5
onClicked: Manager.stop()
Button
id: stfBtn
text: qsTr("Save")
objectName: "stfBtn"
anchors.left: stopBtn.right
anchors.leftMargin: 5
Button
id: minimize
objectName: "minBtn"
text: qsTr("Min")
anchors.left: stfBtn.right
anchors.leftMargin: 5
Column
id: column
x: 135
y: 100
width: 200
height: 400
TextField
id: nameText
width: 300
text: qsTr("")
TextField
id: urlText
width: 300
text: qsTr("")
ComboBox
id: comboBox
width: 200
model: Manager.stations
onCurrentTextChanged: Manager.currentStation = currentText
Slider
id: slider
x: 160
y: 311
value: 0.5
这种实现的优点是您可以独立修改设计和逻辑部分。如果您通过setContextProperty
传递一个对象,它将在所有 .qml 文件中可见。如果你有很多 .qml 文件,你会遇到问题
【讨论】:
非常感谢您的回答,但这让我想到了主要问题。如果我在 python 文件中没有引用我的组合框,我如何获得它的值。为了清楚起见:在同一个示例中,我将如何打印出组合框选定的值,而不是硬编码字符串。我不想提出一个新问题,因为我认为这可以在这个问题中得到澄清。一般来说,如何访问 UI 元素所持有的值。 @ImRaphael 好的,我明白了,我将根据该要求更新我的答案。 @ImRaphael 现在 currentStation 具有所选项目。例如,如果您选择一个新项目并按下播放,则所选项目将在 python 中打印。 @ImRaphael 我还添加了一个新插槽,每次您选择新项目时都会收到通知。 太棒了,非常感谢。我现在将尝试使用其他东西,看看它们是如何协同工作的。干杯以上是关于PyQt 启动时加载函数(qml 加载器)的主要内容,如果未能解决你的问题,请参考以下文章