簡體   English   中英

在 python 中生成“Ctrl+c”事件的最佳方法是什么?

[英]What is the best way to generate 'Ctrl+c' event in python?

我正在開發一個 GUI,它可以使用 sounddevice 和 soundfile 庫錄制任意持續時間的音頻。 按“ctrl+c”組合鍵停止錄制過程。

我正在嘗試使用“開始”和“結束”按鈕實現 GUI。 “開始”按鈕應調用記錄 function,“結束”按鈕應模擬“ctrl+c”事件。 我不知道如何將此事件實現為 python 中的 function。非常感謝實現的想法。

如果您使用 windows 命令提示符python record.py運行代碼,代碼將正常運行

記錄.py如下:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import time
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading


class Ui_MainWindow(object):
    def __init__(self):
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(640, 480)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.start_button_func)

        self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
        self.pushButton_1.setObjectName("pushButton")
        self.pushButton_1.clicked.connect(self.end_button_func)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Start"))
        self.pushButton_1.setText(_translate("MainWindow", "End"))

    def record(self):
        self.q = queue.Queue()
        self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
        try:
            # Make sure the file is open before recording begins
            with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
                with self.s:
                    # 1 second silence before the recording begins
                    time.sleep(1)
                    print('START')
                    print('#' * 80)
                    print('press Ctrl+C to stop the recording')
                    while True:
                        file.write(self.q.get())
        except OSError:
            print('The file to be recorded already exists.')
            sys.exit(1)
        except KeyboardInterrupt:
            print('The utterance is recorded.')

    def callback(self, indata, frames, time, status):
        """
        This function is called for each audio block from the record function.
        """

        if status:
            print(status, file=sys.stderr)
        self.q.put(indata.copy())

    def start_button_func(self):
        self.worker = mythreading.Worker(self.record)
        self.threadpool.start(self.worker)

    def end_button_func(self):
        print('how to stop?')


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

mythreading.py如下:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Worker(QRunnable):

    def __init__(self, fn, *args, **kwargs):
        super(Worker, self).__init__()
        self.fn = fn

    @pyqtSlot()
    def run(self):
        self.fn()

如果命令

 exit()

使應用程序沒有響應我們可以模擬 ctrl 事件

signal.CTRL_C_EVENT

在窗戶里

signal.SIGINT

在 Linux 中

記住導入信號所以函數變成......

import signal
...
...
...
...

def end_button_func(self):
    signal.SIGINT # if you are using ubuntu or mac
    signal.CTRL_C_EVENT # if you are using windows

我有一台 Mac,所以我沒有嘗試 signal.CTRL_C_EVENT 所以無論如何都嘗試一下

希望它會起作用!

查看 sounddevice 的源代碼,看起來像KeyboardInterrupt事件在他們的示例中調用了 argparser 的 exit 方法來記錄rec_unlimited.py

parser = argparse.ArgumentParser(description=__doc__)

...

try:
    # Make sure the file is opened before recording anything:
    with sf.SoundFile(args.filename, mode='x', samplerate=args.samplerate,
                      channels=args.channels, subtype=args.subtype) as file:
        with sd.InputStream(samplerate=args.samplerate, device=args.device,
                            channels=args.channels, callback=callback):
            print('#' * 80)
            print('press Ctrl+C to stop the recording')
            print('#' * 80)
            while True:
                file.write(q.get())

except KeyboardInterrupt:
    print('\nRecording finished: ' + repr(args.filename))
    parser.exit(0)

這個例子對你有用嗎? 我認為這里的退出無論如何都會簡單地調用系統退出。 如果這有效,那么從那里開始並確保您的 GUI 中的停止命令正在做同樣的事情(即引發KeyboardInterrupt或退出)。

如果 sounddevice 正在創建線程(queue.get 建議這樣做),則使用線程也可能是一個問題,因此退出調用不會終止所有線程。

如果此退出在 Windows 中不起作用,則調用sd.stop()可能是一個跨平台解決方案(盡管我懷疑無論如何都要離開with塊)。

基於討論的更新:

由於示例工作正常,但end_button_func凍結了 GUI,似乎記錄過程需要一個單獨的線程,因此您的 GUI 可以響應,直到傳遞信號以停止它。 我認為最好的方法是傳遞一個參數,當按下停止按鈕時,它會在線程中觸發KeyboardInterrupt異常。 要與線程進行通信,您需要發送一個信號,如this answerthis中所示,並基於此,在線程中引發KeyboardInterrupt

這個例子( PyQt: How to send a stop signal into a thread where an object is running a Condition while loop? )似乎最接近,您可以在其中調整work函數以引發異常,如下所示,

@pyqtSlot()
def work(self):
    while self.running():
        time.sleep(0.1)
        print 'doing work...'
    self.sgnFinished.emit()
    raise KeyboardInterrupt

我這里沒有 PyQt5 或 windows,所以無法進一步測試。 請注意,您似乎需要將主類設為QObject才能使用 pyqtSignal。

你可以像這個無花果那樣做。 安裝 OpenCV 的 lib 以使用cv2.waitKey()通過鍵盤控制程序。

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM