我有两个Python脚本需要彼此通信。第一个是用PySide2制作的GUI。GUI包含用于控制蓝牙音频设备的简单控件(播放、暂停、下一步、上一步等)。这些命令使用我找到的第二个python脚本进行操作。第二个脚本是一个循环,它等待输入这些命令,并在执行这些命令后作出响应。我对编程相当陌生,我猜这实际上是连接前端和后端,但这是我以前从未做过的事情
我已经编写了一个简化版的GUI,只显示我需要的控件。“后端”也在下面,但最初可以在这里找到:https://scribles.net/controlling-bluetooth-audio-on-raspberry-pi/
我之前问过一个类似的问题,@eyllanesc在这里给了我一个可靠而有效的答案:Execute command to a Python script from separate Python script?但是,使用QProcess方法,我无法确定如何将print
输出从后端输入前端脚本。但是,错误消息打印正确。我尝试过在后端使用sys.stdout
,使用process.read
的变体和QbyteArray,但似乎没有任何进展
我遇到的另一个问题是,只有在启动脚本之前连接了蓝牙设备,脚本才会工作。如果在它运行时断开连接并尝试重新连接,它将不再接受命令。如果还有一种方法可以监控设备是否正在播放/暂停,以便播放/暂停按钮可以根据设备状态进行更新,这也会很有用,但在这个阶段并不重要
有很多方法可以做到这一点,但我觉得最终将两个脚本集成到一个脚本中会更好,不过我愿意接受任何可行的解决方案。如果有人有任何建议或可以让我开始,我将非常感激
前端:
import sys
from PySide2.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.playbtn = QPushButton("Play")
self.nextbtn = QPushButton("Next")
self.prevbtn = QPushButton("Prev")
layout = QVBoxLayout()
layout.addWidget(self.playbtn)
layout.addWidget(self.nextbtn)
layout.addWidget(self.prevbtn)
self.setLayout(layout)
self.playbtn.released.connect(self.btnplay)
self.nextbtn.released.connect(self.btnnext)
self.prevbtn.released.connect(self.btnprev)
def btnplay(self): #play button turns into pause button upon being pressed
status = self.playbtn.text()
if status == "Play":
self.playbtn.setText("Pause")
print("Play Pressed")
elif status == "Pause":
self.playbtn.setText("Play")
print("Pause pressed")
def btnnext(self):
print("Next pressed")
def btnprev(self):
print("Prev pressed")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
后端:
import dbus, dbus.mainloop.glib, sys
from gi.repository import GLib
def on_property_changed(interface, changed, invalidated):
if interface != 'org.bluez.MediaPlayer1':
return
for prop, value in changed.items():
if prop == 'Status':
print('Playback Status: {}'.format(value))
elif prop == 'Track':
print('Music Info:')
for key in ('Title', 'Artist', 'Album'):
print(' {}: {}'.format(key, value.get(key, '')))
def on_playback_control(fd, condition):
str = fd.readline()
if str.startswith('play'):
player_iface.Play()
elif str.startswith('pause'):
player_iface.Pause()
elif str.startswith('next'):
player_iface.Next()
elif str.startswith('prev'):
player_iface.Previous()
elif str.startswith('vol'):
vol = int(str.split()[1])
if vol not in range(0, 128):
print('Possible Values: 0-127')
return True
transport_prop_iface.Set(
'org.bluez.MediaTransport1',
'Volume',
dbus.UInt16(vol))
return True
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
obj = bus.get_object('org.bluez', "/")
mgr = dbus.Interface(obj, 'org.freedesktop.DBus.ObjectManager')
player_iface = None
transport_prop_iface = None
for path, ifaces in mgr.GetManagedObjects().items():
if 'org.bluez.MediaPlayer1' in ifaces:
player_iface = dbus.Interface(
bus.get_object('org.bluez', path),
'org.bluez.MediaPlayer1')
elif 'org.bluez.MediaTransport1' in ifaces:
transport_prop_iface = dbus.Interface(
bus.get_object('org.bluez', path),
'org.freedesktop.DBus.Properties')
if not player_iface:
sys.exit('Error: Media Player not found.')
if not transport_prop_iface:
sys.exit('Error: DBus.Properties iface not found.')
bus.add_signal_receiver(
on_property_changed,
bus_name='org.bluez',
signal_name='PropertiesChanged',
dbus_interface='org.freedesktop.DBus.Properties')
GLib.io_add_watch(sys.stdin, GLib.IO_IN, on_playback_control)
GLib.MainLoop().run()
更新日期:2020年10月31日:
我一直在玩上面链接的问题中建议的QProcess
类。通过在按钮按下功能上使用它,并在命令执行后添加sys.exit
,它消除了始终连接设备的需要,但我仍然找不到从后端脚本接收print
输出的方法。这也感觉像是一种非常肮脏的工作方式。它还保留了播放/暂停状态未自动更新的问题。如果有人有任何建议,我将不胜感激
import sys
import os.path
from PySide2.QtCore import *
from PySide2.QtWidgets import *
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.playbtn = QPushButton("Play")
self.nextbtn = QPushButton("Next")
self.prevbtn = QPushButton("Prev")
layout = QVBoxLayout()
layout.addWidget(self.playbtn)
layout.addWidget(self.nextbtn)
layout.addWidget(self.prevbtn)
self.setLayout(layout)
self.playbtn.released.connect(self.btnplay)
self.nextbtn.released.connect(self.btnnext)
self.prevbtn.released.connect(self.btnprev)
def btnplay(self):
self.process = QProcess()
self.process.readyReadStandardError.connect(self.handle_readyReadStandardError)
self.process.readyReadStandardOutput.connect(self.handle_readyReadStandardOutput)
self.process.setProgram(sys.executable)
script_path = os.path.join(CURRENT_DIR, "test2.py")
self.process.setArguments([script_path])
self.process.start()
status = self.playbtn.text()
if status == "Play":
command = "play"
self.playbtn.setText("Pause")
print("play pressed")
elif status == "Pause":
command = "pause"
self.playbtn.setText("Play")
print("pause pressed")
msg = "{}\n".format(command)
self.process.write(msg.encode())
def btnnext(self):
self.process = QProcess()
self.process.readyReadStandardError.connect(self.handle_readyReadStandardError)
self.process.readyReadStandardOutput.connect(self.handle_readyReadStandardOutput)
self.process.setProgram(sys.executable)
script_path = os.path.join(CURRENT_DIR, "test2.py")
self.process.setArguments([script_path])
self.process.start()
command = "next"
msg = "{}\n".format(command)
self.process.write(msg.encode())
print("next pressed")
def btnprev(self):
self.process = QProcess()
self.process.readyReadStandardError.connect(self.handle_readyReadStandardError)
self.process.readyReadStandardOutput.connect(self.handle_readyReadStandardOutput)
self.process.setProgram(sys.executable)
script_path = os.path.join(CURRENT_DIR, "test2.py")
self.process.setArguments([script_path])
self.process.start()
command = "prev"
msg = "{}\n".format(command)
self.process.write(msg.encode())
print("prev pressed")
def handle_readyReadStandardError(self):
print(self.process.readAllStandardError().data().decode())
def handle_readyReadStandardOutput(self):
print(self.process.readAllStandardOutput().data().decode())
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
我不熟悉您在后端使用的是什么,但应该是这么简单:
在后端,您还应该删除这一行:
if __name__ == '__main__':
并取消它下面的所有代码。我不知道该如何正常调用该函数,或者第二个变量“condition”的作用是什么。但这就是我能想到的IMHO OP有一个XY问题,这给应用程序增加了不必要的复杂性,因为dbus eventloop可以与Qt one共存,如我在下面的示例中所示:
相关问题 更多 >
编程相关推荐