I'm working on an application that uses the Microsoft Cognitive services Speech-to-Text API. I'm trying to create a GUI where the transcribed text should show up in a textbox once the start button is pushed and the transcription is stopped once a stop-button is pressed. I'm pretty new to creating GUI's and have been using PyQt5. I have divided the application according to MVC (Model-View-Controller). The code for the GUI is as follows:
import sys
import time
from functools import partial
import azure.cognitiveservices.speech as speechsdk
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class test_view(QMainWindow):
def __init__(self):
super().__init__()
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
self._createApp()
def _createApp(self):
self.startButton = QPushButton('Start')
self.stopButton = QPushButton('Stop')
buttonLayout = QHBoxLayout()
self.startButton.setFixedWidth(220)
self.stopButton.setFixedWidth(220)
buttonLayout.addWidget(self.startButton)
buttonLayout.addWidget(self.stopButton)
self.text_box = QTextEdit()
self.text_box.setReadOnly(True)
self.text_box.setFixedSize(1500, 400)
layout_text = QHBoxLayout()
layout_text.addWidget(self.text_box)
layout_text.setAlignment(Qt.AlignCenter)
self.generalLayout.addLayout(buttonLayout)
self.generalLayout.addLayout(layout_text)
def appendText(self, text):
self.text_box.append(text)
self.text_box.setFocus()
def clearText(self):
return self.text_box.setText('')
class test_ctrl:
def __init__(self, view):
self._view = view
def main():
application = QApplication(sys.argv)
view = test_view()
view.showMaximized()
test_ctrl(view=view)
sys.exit(application.exec_())
if __name__ == "__main__":
main()
The Speech-to-Text Transcribe code is:
import azure.cognitiveservices.speech as speechsdk
import time
def setupSpeech():
speech_key, service_region = "speech_key", "service_region"
speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=service_region)
speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config)
return speech_recognizer
def main():
speech_recognizer = setupSpeech()
done = False
def stop_cb(evt):
print('CLOSING on {}'.format(evt))
speech_recognizer.stop_continuous_recognition()
nonlocal done
done = True
all_results = []
def handle_final_result(evt):
all_results.append(evt.result.text)
speech_recognizer.recognizing.connect(lambda evt: print(evt))
speech_recognizer.recognized.connect(handle_final_result)
speech_recognizer.session_stopped.connect(stop_cb)
speech_recognizer.canceled.connect(stop_cb)
speech_recognizer.start_continuous_recognition()
while not done:
time.sleep(.5)
print(all_results)
if __name__ == "__main__":
main()
I know for sure that both of the pieces of code work, but I'm not sure how to build the speech-to-text code into the MVC code. I think it should work with a model and it should be connected through the controller to the view. I tried doing this in multiple ways but I just can't figure it out. I also figured I need some kind of threading to keep the code from freezing the GUI. I hope someone can help me with this.
You need to replace this part
print(all_results)
and push all_results asynchronously to ur code for processing the text.
If not, expose a button in the UI to invoke the speech_recognizer.start_continuous_recognition() as a separate function and pick the results to process. This way you can avoid freezing the UI
Related
I had tried various workarounds about this problem and tried to fix code according to other examples, but ultimately I had failed to make a workable code. While I do have idea of why it fails, I lack skill to create a workaround about this error. Could you please help me with making this code to work?
The problem:
Then I press ''Duomenų apdorojimas'' and proceed to press ''Pavaizduoti signalą'' I get error saying: QCoreApplication::exec: The event loop is already running. I tried various workarounds about this and some legacy code is left inside my functions. I will tidy and optimize my code later, I just need to know how to work properly with GUI in order to avoid this problem. If needed I will send you entire program with txt files, but this part is essential and here problem arises.
import os
import os.path
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from tkinter import *
import tkinter.messagebox
import sys
from functools import partial
import matplotlib.pyplot as p
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("")
self.setWindowIcon(QtGui.QIcon('pythonlogo.png'))
openFile = QtGui.QAction("&Atverkite duomenų failą", self)
openFile.setShortcut("Ctrl+Q")
openFile.setStatusTip('Duomenų failas')
openFile.triggered.connect(self.file_open)
extractAction = QtGui.QAction("&Duomenys iš Arduino", self)
extractAction.setShortcut("Ctrl+W")
extractAction.setStatusTip('Prijunkite iš Arduino ateinančius duomenis')
extractAction.triggered.connect(self.upload_usb)
saveFile = QtGui.QAction("&Įšsaugoti failą", self)
saveFile.setShortcut("Ctrl+E")
saveFile.setStatusTip('Nurodykite failo direktoriją bei pavadinimą')
saveFile.triggered.connect(self.file_save)
quitFile = QtGui.QAction("&Išeiti", self)
quitFile.setShortcut("Ctrl+R")
quitFile.setStatusTip('Programa bus uždaryta')
quitFile.triggered.connect(self.close_application)
openEditor = QtGui.QAction("&Skaitytuvas", self)
openEditor.setShortcut("Ctrl+T")
openEditor.setStatusTip('Skaitytuvas visados įjungtas')
openEditor.triggered.connect(self.editor)
additionalData = QtGui.QAction("&Paciento duomenys", self)
additionalData.setShortcut("Ctrl+A")
additionalData.setStatusTip('Įveskite paciento amžiaus grupę')
additionalData.triggered.connect(self.group)
dataProcessing = QtGui.QAction("&Filtruoti signalą", self)
dataProcessing.setShortcut("Ctrl+S")
dataProcessing.setStatusTip('Bus atliekami signalo apdorojimo procesai')
dataProcessing.triggered.connect(self.editor)
showGraph = QtGui.QAction("&Pavaizduoti signalą", self)
showGraph.setShortcut("Ctrl+D")
showGraph.setStatusTip('Bus atvaizduotas šiuo metu turimas signalas')
showGraph.triggered.connect(self.close_application)
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&Progamos funkcijos')
fileMenu.addAction(openFile)
fileMenu.addAction(extractAction)
fileMenu.addAction(saveFile)
fileMenu.addAction(quitFile)
resultsMenu = mainMenu.addMenu("&Duomenų apdorojimas")
resultsMenu.addAction(dataProcessing)
resultsMenu.addAction(showGraph)
editorMenu = mainMenu.addMenu("&Programos nustatymai")
editorMenu.addAction(openEditor)
editorMenu.addAction(additionalData)
self.statusBar()
self.home()
def openFile(self,n):
print(n)
def home(self):
self.show()
def close_application(self):
graphics()
sys.exit()
def run():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
run()
Well, it turns out that I was trying to open semi-new program in graphics(). I found out how not to create GUI. Thank you for you help, but I have found out solution. For the next time I will post code in onedrive or something in order for people to get whole program with its supporting documents.
I'm working on a GUI that basically hold multiple widgets that each contain a figure as well as a few buttons/whatever. One of the figures is supposed to be interactive, calling a function whenever the user clicks on any part of the plot. Yet I can't get the function to fire using mpl_connect, even after playing with focus and whatnot. I'm somewhat new to PySide/Qt, so I don't exactly understand why my code is behaving like this (I've been searching for days for a solution, but haven't found anything about it).
I used Qt Designer to create the layout for the GUI. I'm using Spyder from Anaconda 2.2.0 (32-bit), Python 2.7, and PySide to develop the GUI. If it's any help, I come from more of a MATLAB background where I developed a full version of the GUI I'm trying to make in Python.
Below is the relevant code (scroll down a bit to see where the problem is):
from PySide import QtCore, QtGui
from PySide.QtCore import *
from PySide.QtGui import *
import numpy as np
import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import matplotlib.pyplot as plt
from PySide.QtGui import QPalette, QCursor
import matplotlib.colors as colors
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1316, 765)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = QtGui.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(75, 40, 375, 490))
self.widget.setObjectName("widget")
color = self.centralwidget.palette().color(QPalette.Window)
self.leftPlot = MatplotlibWidget(None,'','','',False,color)
self.setupPlot(self.widget,self.leftPlot)
self.leftPlot.figure.tight_layout()
self.leftImage = self.leftPlot.axes.imshow(self.defaultSlide, cmap = mymap)
Snippet of interest:
self.leftPlot.figure.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.leftPlot.figure.canvas.setFocus()
cid = self.leftPlot.figure.canvas.mpl_connect('button_release_event', self.getCoordinates) # doesn't get called
plt.show()
def getCoordinates(self, event):
print 'dasdsadadsa'
print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(event.button, event.x, event.y, event.xdata, event.ydata)
The rest:
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None,xlabel='x',ylabel='y',title='Title',showTicks=False,color=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
if color != None:
self.figure = Figure(facecolor=(color.red()/256.0,color.green()/256.0,color.blue()/256.0),frameon=0)
else:
self.figure = Figure(frameon=0)
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
self.axes.set_xlabel(xlabel)
self.axes.set_ylabel(ylabel)
self.axes.set_title(title)
self.axes.get_xaxis().set_visible(showTicks)
self.axes.get_yaxis().set_visible(showTicks)
class ControlMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
plt.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = ControlMainWindow()
mySW.show()
sys.exit(app.exec_())
I'm aware the code is messy, but any input is greatly appreciated.
Update (2015-09-04) : I've updated the MWE I provided as part of my original answer to use instead the approach that is suggested in the matplotlib documentation to embed a mpl figure in an application. This approach does not use the pyplot interface (as in my original answer) and use the Object Oriented API of mpl instead. Also, since all the mpl artists (figure, axes, etc.) know each other, there is no need to explicitly create new class variables. This allows a structure of code that is, IMO, easier to read and to maintain.
The problem comes from the fact that you are not connecting correctly your event to self.leftPlot (FigureCanvasQTAgg), but to self.leftPlot.figure.canvas (FigureCanvasQTAgg.figure.FigureCanvasQTAgg) instead. You are creating a canvas within a canvas in the MatplotlibWidget class (which is already a subclass of FigureCanvasQTAgg). You only need to create one mpl canvas, pass a figure to it, and then connect the event to it directly.
I've put together a MWE to demonstrate how this can be done using the Object Oriented API of Matplotlib as suggested in the documentation:
from PySide import QtGui
import numpy as np
import sys
import matplotlib as mpl
mpl.use('Qt4Agg')
mpl.rcParams['backend.qt4']='PySide'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
class ControlMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.setupUi()
def setupUi(self):
figure = mpl.figure.Figure(figsize=(5, 5))
leftPlot = MatplotlibWidget(figure)
self.setCentralWidget(leftPlot)
class MatplotlibWidget(FigureCanvasQTAgg):
def __init__(self, fig):
super(MatplotlibWidget, self).__init__(fig)
#-- set up an axe artist --
ax = fig.add_axes([0.1, 0.1, 0.85, 0.85])
ax.plot(np.arange(15), np.arange(15))
self.draw()
#---- setup event ----
self.mpl_connect('button_press_event', self.onclick)
def onclick(self, event):
x, y = event.x, event.y
print(x, y)
if x != None and y != None:
ax = self.figure.axes[0]
ax.plot(event.xdata, event.ydata, 'ro')
self.draw()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = ControlMainWindow()
mySW.show()
sys.exit(app.exec_())
The code above results in:
I'm looking for a way to refresh camera miniature images from snapshots. I have this piece of code, but after first refresh (not the one in the reloadMiniatures thread) I get nothing (black screen).
I have tried other solutions but showing 6x mjpeg streams was to heavy (and I don't really need high framerate). Had some success with AsyncImage and saving images to file, but it wasn't very efficient and I had this loading_image to get rid of.
from kivy.app import App
from kivy.uix.image import Image
import time
import threading
import urllib
from kivy.core.image import Image as CoreImage
from io import BytesIO
class TestApp(App):
def reloadMiniatures(self):
while True:
data = BytesIO(urllib.urlopen("http://10.0.13.206:9000/?action=snapshot").read())
time.sleep(3)
self.image.texture = CoreImage(data, ext='jpg').texture
def build(self):
data = BytesIO(urllib.urlopen("http://10.0.13.206:9000/?action=snapshot").read())
self.image = Image()
self.image.texture = CoreImage(data, ext='jpg').texture
miniatures = threading.Thread(target=self.reloadMiniatures)
miniatures.daemon = True
miniatures.start()
return self.image
TestApp().run()
You could try using Loader instead:
def load_miniatures(self, *args):
proxy = Loader.image('http://10.0.13.206:9000/?action=snapshot')
proxy.bind(on_load=self.receive_miniatures)
def receive_miniatures(self, proxy):
if proxy.image.texture:
self.image.texture = proxy.image.texture
Clock.schedule_once(self.load_miniatures, 0.1)
def build(self):
self.image = Image()
self.load_miniatures()
return self.image
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os, time
class SetName(QWidget):
def __init__(self):
QWidget.__init__(self)
self.show()
toplayout = QVBoxLayout()
self.setWindowTitle('Personal Info')
self.form_layout = QFormLayout()
self.setLayout(self.form_layout)
self.line_edit_param = QLineEdit(self)
self.line_edit_param.setPlaceholderText("Write Here")
self.form_layout.addRow('Write Name', self.line_edit_param)
toplayout.addLayout(self.form_layout)
self.setFocus()
class LearnApp(QDialog):
def __init__(self):
super(QDialog, self).__init__()
self.setWindowTitle("LearnApp")
self.active = False
close_button = QPushButton("Close")
close_button.clicked.connect(self.close)
self.check_button = QPushButton("Check")
self.check_button.clicked.connect(self.set_data)
self.tr = QTextEdit()
self.tr.setReadOnly(True)
# layout
layout = QHBoxLayout()
#layout.addWidget(self.button3)
sub_layout = QVBoxLayout()
sub_layout.addWidget(self.check_button)
sub_layout.addWidget(close_button)
layout.addLayout(sub_layout)
layout.addWidget(self.tr)
self.setLayout(layout)
self.setFocus()
def set_data(self):
print "in set_data"
SetName()
app = QApplication(sys.argv)
dialog = LearnApp()
dialog.show()
app.exec_()
This is the code I'm trying. If edit it with toplayout = QGridLayout(), program works fine but with toplayout = QVBoxLayout(), it gives message QLayout::addChildLayout: layout "" already has a parentand just flashes the new window. What could be the problem? How should I tackle this? I wanna use QVBoxLayout instead of QGridLayout
Firstly, the new window disappears straight away because you don't store a reference to it. You need to store a reference to the instance in your LearnApp class, or parent it to another Qt object outside of set_data() if you want it to stick around.
The error message regarding the layouts is not occurring because of your choice of layouts, but because you are calling
self.setLayout(self.form_layout)
and then
toplayout.addLayout(self.form_layout)
The first call assigns the layout to the instance of SetName, but in doing so also makes the instance the parent of self.form_layout. The second call is trying to add the same layout to toplayout and set it as the parent, but Qt sees that self.form_layout already has a parent (i.e. is being used elsewhere). This is what the error message is trying to tell you.
I suspect that instead of self.setLayout(self.form_layout), you intended to write something like
self.setLayout(toplayout)
I'm trying to open a window (QWidget) when clicking on a button. My problem is that the second window doesn't show up when I click on the button no matter what I've tried. The two windows are created using QTDesigner.
Here is a little snippet explaining what I'm trying to do:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from win1 import *
from win2 import *
import sys
class win1(QWidget, Ui_Win1):
def __init__(self, parent = None):
self.parent = parent
QWidget.__init__(self)
self.setupUi(parent)
self.connect(self.pushButton, SIGNAL("clicked()"), self.on_btn_clicked)
def on_btn_clicked(self):
self.child = win2(self.parent)
self.child.show()
class win2(QWidget, Ui_Win2):
def __init__(self, parent = None):
QWidget.__init__(self)
self.setupUi(parent)
def main(args):
app = QApplication(args)
win = QWidget()
a = win1(win)
win.show()
result = app.exec_()
if __name__=="__main__":
main(sys.argv)
What am I missing here ?
Thanks.
Not sure, but two random thoughts:
If you add a print statement to on_btn_clicked, do you see anything when you click on the button? This would diagnose whether it's an event triggering issue
Does it work if you change the setupUI(parent) commands to setupUI(self)?