使用 PyQt4 线程时仍然冻结

Still Freezing when using PyQt4 Thread

尽管使用了 QThread,GUI 仍然冻结

(代码贴在最后) space 栏被击中,它通过创建线程并发出对播放函数的调用来开始播放 midi 音符

if self.playing is False:
    # PlayThread is initiated in PianoRoll when the space bar is hit. 
    Loop iterates and plays data, freezing the GUI

else:
    # This section is not reached because another space bar hit cannot be received while data is looping

我查看了以下教程和 Whosebug 上的各种回复:

  1. https://manojbits.wordpress.com/2013/01/24/threading-in-pyqt4/
  2. joplaete 教程

我试过以下方法:

  1. 将所有循环代码放在信号函数运行中
  2. 将循环放在线程的 运行 函数中,并使用 emit
  3. 将数据传递给有信号的函数
  4. 将函数与处理对它的调用的小部件分开
  5. 使数据结构全局化(尝试任何方法)

请让我知道我遗漏了什么或者是否需要任何其他代码。

我正在使用开源 MIDI 音序器模板 https://github.com/rhetr/seq-gui

class PlayThread(QtCore.QThread):

    def __init__(self):

        # qtcore.QThread.__init__(self, parent=app)

        super(PlayThread , self).__init__()

        self.signal = QtCore.SIGNAL("signal")

    def run(self):

        global xLocToNoteItems

        # this loop was attempted in the signaled function as well
        for xloc in xLocToNoteItems:

            self.emit(self.signal, xloc)

        # self.emit(self.signal, "arbitrary?")

        # self.emit(QtCore.SIGNAL('update(QString)') + str(i))

钢琴卷:

if event.key() == QtCore.Qt.Key_Space:

    if self.playing:

        self.playing = False

        # terminate play thread

        main.playThread.quit()

    else:

        self.playing = True

        # playThread previously attempted to be stored in this (piano roll) class
            # ...was moved to main in case the call was freezing the piano roll
        main.playThread = PlayThread()

    main.connect(main.playThread, main.playThread.signal, main.play)

    main.playThread.start()

播放功能在钢琴卷帘小部件中,现在在主

def play(self, xloc):

    # for xloc in main.xLocToNoteItems:


    global xLocToRhythms
    global xLocToNoteItems

    for noteItem in xLocToNoteItems[xloc]:

        player.note_on(noteItem.note[0], noteItem.note[3], 1)

    offtime = xLocToRhythms[xloc]

    time.sleep(offtime)

    for noteItem in xLocToNoteItems[xloc]:

        player.note_off(noteItem.note[0], noteItem.note[3], 1)

您的线程故意发出多个信号来执行主线程中的 play() 方法。您的 play 方法必须 运行 一段合理的时间并阻塞主线程(例如它有一个 time.sleep )。

您可能还需要将 play 代码移动到线程中,但前提是您使用的 MIDI 库可以安全地从辅助线程调用。请注意,如果您打算从多个线程调用该库,您还应该检查该库是否是线程安全的。