QKeyPress event in PyQt

2019-03-30 04:16发布

问题:

I am having issues with my software. In my piano software if I keep pressing a key on the keyboard then it is making multiple repeated same tones of that particular key. But actually I need a single tone until the release of that particular key. I'm providing a part of my code that detects the keyPress event and calls the corresponding method. So what should be the changes that I've to do with my code??

def keyPressEvent(self, event):
    if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_A : 
        self.Playnote('/home/hemanth/hemanth/Piano/C.mp3')
        self.ui.pushButton.animateClick(100)
    if type(event) == QtGui.QKeyEvent and event.key() == QtCore.Qt.Key_S:
        self.Playnote('/home/hemanth/hemanth/Piano/D.mp3')
        self.ui.pushButton_2.animateClick(100)

回答1:

You should check event.isAutoRepeat() to determine if the event is caused by keyboard autorepeat or an actual keypress. If it is an autorepeat, ignore that press.



回答2:

Since a keyPressEvent will always receive a QKeyEvent, you won't need to check its type at all. You can already start by simplifying this example:

def keyPressEvent(self, event):
    key = event.key()
    if key == QtCore.Qt.Key_A : 
        self.Playnote('/home/hemanth/hemanth/Piano/C.mp3')
        self.ui.pushButton.animateClick(100)
    elif key == QtCore.Qt.Key_S:
        self.Playnote('/home/hemanth/hemanth/Piano/D.mp3')
        self.ui.pushButton_2.animateClick(100)

Now, like you said, this will simply fire your sounds every time a key is pressed. There would be a few steps needed to get the entire functionality you require.

  1. The Playnote needs to be able to keep looping until told to stop
  2. You need to keep a reference to that Playnote object in order to stop it later
  3. A keyReleaseEvent will have to use the Playnote reference to stop it

1) Playnote needs to loop

If you are using Phonon for the functionality of this Playnote, then you can use an approach suggested by the docs. This would be to connect the Media Objects' aboutToFinish signal to a method that will enqueue another version of the same media source.

It might look something like this:

class Playnote(QtCore.QObject):

    def __init__(self, soundFile, parent=None):
        super(Playnote, self).__init__(parent)

        self._isStopped = True

        self.mediaSource = Phonon.MediaSource(soundFile)
        self.mediaObject = Phonon.MediaObject(self)
        self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
        Phonon.createPath(self.mediaObject, self.audioOutput)
        self.mediaObject.setCurrentSource(self.mediaSource)

        self.mediaObject.aboutToFinish.connect(self.doRequeue)


    def doRequeue(self):
        if not self._isStopped:
            self.mediaObject.enqueue(self.mediaSource)


    def play(self):
        self._isStopped = True
        # other code here

    def stop(self):
        self._isStopped = False
        # other code here

You are connecting that signal to a method that will requeue the same sound if the player has not been stopped.

2) Need a Playnote object

When you start your sound with the keyPressEvent, you will have to store a reference to the object that is now playing. Maybe you can create a dictionary, and store a mapping of the key to the current playing object?

# in your class
self.keysPlaying = {}

def keyPressEvent(self, event):
    key = event.key()
    if key == QtCore.Qt.Key_A :
        c_note = Playnote('/home/hemanth/hemanth/Piano/C.mp3')
        self.keysPlaying['c'] = c_note

3) keyReleaseEvent stops Playnote object

Now that you have started, and looped your sound, you can use the reference to stop it later in a keyReleaseEvent:

def keyReleaseEvent(self, event):
    key = event.key()
    if key == QtCore.Qt.Key_A :
        note = self.keysPlaying.get('c', None)
        if note:
            note.stop()
            self.keysPlaying['c'] = None