Browse Source

Switch deleteOnIdle to a lower timer level and use a python loop to clean up instead of the qtimer itself in freewheeling mode. This hopefully improves performance

master
Nils 7 months ago
parent
commit
2f420b19bd
  1. 24
      qtgui/scorescene.py
  2. 46
      qtgui/scoreview.py

24
qtgui/scorescene.py

@ -48,9 +48,9 @@ class GuiScore(QtWidgets.QGraphicsScene):
self.tracks = {} #trackId:guiTrack, #if we don't save the instances here in Python space Qt will loose them and they will not be displayed without any error message.
self.deleteOnIdleStack = [] # a stack that holds hidden items that need to be deleted. Hiding is much faster than deleting so we use that for the blocking function. Since we always recreate items and never re-use this is ok as a list. no need for a set.
self.deleteOnIdleStack = set() # a stack that holds hidden items that need to be deleted. Hiding is much faster than deleting so we use that for the blocking function.
self._deleteOnIdleLoop = QtCore.QTimer()
self._deleteOnIdleLoop.start(0) #0 means "if there is time"
self._deleteOnIdleLoop.start(100) #0 means "if there is time"
self._deleteOnIdleLoop.timeout.connect(self._deleteOnIdle) #processes deleteOnIdleStack
self.duringTrackDragAndDrop = None #switched to a QGraphicsItem (e.g. GuiTrack) while a track is moved around by the mouse
@ -106,6 +106,12 @@ class GuiScore(QtWidgets.QGraphicsScene):
self.grid.updateMode(nameAsString)
def updateModeSingleTrackRedraw(self, nameAsString:str, trackId:int, trackExport:tuple):
"""trackExport is a tuple of block export dicts"""
self.tracks[trackId].updateMode(nameAsString)
if nameAsString == "block":
self.tracks[trackId].stretchXCoordinates(0.25) #go into small scaling mode. 0.25 is hardcoded and the same as scoreView.updateMode
def maxTrackLength(self):
if self.tracks:
return max(tr.lengthInPixel for tr in self.tracks.values())
@ -123,7 +129,6 @@ class GuiScore(QtWidgets.QGraphicsScene):
self.tracks[trackId].redraw(staticRepresentationList)
#else:
#hidden track. But this can still happen through the data editor
self.parentView.updateMode()
self.updateSceneRect()
def trackPaintBlockBackgroundColors(self, trackId, staticBlocksRepresentation):
@ -240,19 +245,22 @@ class GuiScore(QtWidgets.QGraphicsScene):
-just hide items, never delete them is fast but gets slower the more items are hidden in the track
"""
item.hide()
self.deleteOnIdleStack.append(item) #This will actually delete the item and remove it from the scene when there is idle time
self.deleteOnIdleStack.add(item) #This will actually delete the item and remove it from the scene when there is idle time
def _deleteOnIdle(self):
"""Hiding a QGraphicsItem is much faster than removing it from the scene. To keep the
GUI responsive but also to get rid of the old data we hide in createGraphicItemsFromData
and whenever there is time the actual removing and deleting will happen here.
This function is connected to a timer(0) defined in self init.
This function is connected to a timer defined in self init.
"""
if self.deleteOnIdleStack:
deleteMe = self.deleteOnIdleStack.pop()
#if self.deleteOnIdleStack:
# deleteMe = self.deleteOnIdleStack.pop()
# self.removeItem(deleteMe) #This is the only line in the program that should call scene.removeItem
# del deleteMe
for deleteMe in self.deleteOnIdleStack:
self.removeItem(deleteMe) #This is the only line in the program that should call scene.removeItem
del deleteMe
self.deleteOnIdleStack = set()
def trackAt(self, qScenePosition):

46
qtgui/scoreview.py

@ -65,7 +65,8 @@ class ScoreView(QtWidgets.QGraphicsView):
api.callbacks.setCursor.append(self.centerOnCursor) #returns a dict
api.callbacks.updateBlockTrack.append(self.updateMode) # We need this after every update because the track is redrawn after each update and we don't know what to show
self._lastSavedMode = None #CC, Blocks, Notes. for self.updateMode
api.callbacks.updateBlockTrack.append(self.updateModeSingleTrackRedraw) # We need this after every update because the track is redrawn after each update and we don't know what mode-components to show
style = """
QScrollBar:horizontal {
@ -86,6 +87,8 @@ class ScoreView(QtWidgets.QGraphicsView):
"""
self.setStyleSheet(style)
def wheelEvent(self, event):
if QtWidgets.QApplication.keyboardModifiers() in (QtCore.Qt.ControlModifier, QtCore.Qt.ControlModifier|QtCore.Qt.ShiftModifier): #a workaround for a qt bug. see score.wheelEvent docstring.
event.ignore() #do not send to scene, but tell the mainWindow to use it.
@ -103,6 +106,7 @@ class ScoreView(QtWidgets.QGraphicsView):
#we register a callback in self init that checks constantsAndConfigs.followPlayhead
def stretchXCoordinates(self, factor):
"""Cumulative factor, multiplication"""
self.scoreScene.stretchXCoordinates(factor)
self.centerOnCursor(None)
@ -134,6 +138,14 @@ class ScoreView(QtWidgets.QGraphicsView):
self.toggleNoteheadsRectangles()
function() #this is most likely an api function
def resizeEvent(self, event):
"""Triggers mostly when new notes are entered"""
self.scoreScene.grid.reactToresizeEventOrZoom()
super().resizeEvent(event)
def changeGridRhythm(self):
GridRhytmEdit(mainWindow=self.mainWindow) #handles everything.
def mode(self):
"""Return the current edit mode as string.
Mostly needed for structures blockAt and other
@ -147,13 +159,10 @@ class ScoreView(QtWidgets.QGraphicsView):
else:
raise ValueError("Edit Mode unknown")
def resizeEvent(self, event):
"""Triggers mostly when new notes are entered"""
self.scoreScene.grid.reactToresizeEventOrZoom()
super().resizeEvent(event)
def updateModeSingleTrackRedraw(self, trackId:int, trackExport:tuple):
"""trackExport is a tuple of block export dicts"""
self.scoreScene.updateModeSingleTrackRedraw(nameAsString=self.mode(), trackId=trackId, trackExport=trackExport)
def changeGridRhythm(self):
GridRhytmEdit(mainWindow=self.mainWindow) #handles everything.
def updateMode(self, *args):
"""Switch through different views for editing:
@ -171,6 +180,14 @@ class ScoreView(QtWidgets.QGraphicsView):
Therefore: Every mode switch is only allowed through this function.
There is no direct setting of the mode. You should call the menu
action directly if you want to programatically change the mode.
Different functions and callbacks call this as an update, and they just send their arguments,
which have different types and formats. We don't care since our only information is the menu
state and the variables we set ourselves.
This is rarely called without arguments, manually, on program start just to
filter out the unused part.
"""
assert onlyOne((self.mainWindow.ui.actionCC_Mode.isChecked(), self.mainWindow.ui.actionNotation_Mode.isChecked(), self.mainWindow.ui.actionBlock_Mode.isChecked()))
@ -179,22 +196,37 @@ class ScoreView(QtWidgets.QGraphicsView):
#no modechange in the track editor
return
calledByMenu = args==(True,) # and not by track update or manually on e.g. program start to only show the right portions of the scene
if self.mainWindow.ui.actionCC_Mode.isChecked():
if calledByMenu and self._lastSavedMode == "block":
self.stretchXCoordinates(4.0) #return from half sized mode. If we do not come from block mode this is not needed. CC and Note mode have the same scaling
self.mainWindow.menuActionDatabase.ccEditMode()
self.mainWindow.menuActionDatabase.writeProtection(True)
self.scoreScene.updateMode("cc")
self.mainWindow.menuActionDatabase.loadToolbarContext("cc")
elif self.mainWindow.ui.actionNotation_Mode.isChecked():
if calledByMenu and self._lastSavedMode == "block":
self.stretchXCoordinates(4.0) #return from half sized mode. If we do not come from block mode this is not needed. CC and Note mode have the same scaling
self.mainWindow.menuActionDatabase.noteEditMode()
self.mainWindow.menuActionDatabase.writeProtection(False)
self.scoreScene.updateMode("notation")
self.mainWindow.menuActionDatabase.loadToolbarContext("notation")
elif self.mainWindow.ui.actionBlock_Mode.isChecked():
assert calledByMenu, "We currently assume that only the program start calls this function not via the menu, and that chooses notation mode"
if not self._lastSavedMode == "block": #check that we don't go from block mode to block mode again, since XScaling is cumulative
self.stretchXCoordinates(0.25) #go into small scaling mode. 0.25 is hardcoded and the same as scene.updateModeSingleTrackRedraw
self.mainWindow.menuActionDatabase.noteEditMode()
self.mainWindow.menuActionDatabase.writeProtection(True)
self.scoreScene.updateMode("block")
self.mainWindow.menuActionDatabase.loadToolbarContext("block")
else:
raise ValueError("Edit Mode unknown")
self._lastSavedMode = self.mode()

Loading…
Cancel
Save