所以我目前有一个在QListView中显示的视频剪辑列表,并创建了一个自定义委托,使用来自QStandardItemModel的数据为它们绘制预览缩略图。
最终,我希望能够在鼠标悬停在缩略图上时为其设置动画,以便他们播放剪辑的预览(仅显示几帧)。我想要两个版本。一个只是播放,另一个根据你的鼠标位置显示帧(进一步向左是剪辑的开头,当你向右移动时,它会擦过)。
现在我正试图弄清楚如何实现动画片段。我是否应该使用Delegate绘制框架并更新我的模型上的自定义框架数据,委托将使用它来知道要使用重新实现的绘制功能绘制哪些框架(已经具有绘制功能的框架)?或者这会太耗费资源?那么最好的方法是什么?我查看了编辑器小部件,但似乎似乎没有实时编辑模型数据/更新代理,而只是在完成编辑后。此外,我希望在mouseover上进行初始化,这似乎不是内置编辑触发器中的一个选项。
class AnimatedThumbDelegate(QItemDelegate):
def __init__(self,parent=None):
super().__init__(parent)
self.height=200
self.width=self.height*1.77
self.frames=10
def paint(self,painter,option,index):
painter.save()
image=index.data(FootageItem.FILMSTRIP)
if not image.isNull():
painter.drawPixmap(QRect(option.rect),image,QRect(image.width()/self.frames*index.data(FootageItem.FRAME),0,image.width()/self.frames,image.height()))
painter.restore()
def sizeHint(self,option,index):
return QSize(self.width,self.height)
此委托描绘了我用于预览帧的条形图像的一部分,并通过引用framedata来实现。 FootageItem只是一个QStandardItem类,它有助于构建我想为这些剪辑存储的数据,我只是在这里使用它的索引。它从我的模型中获取QPixmap。我使用的幻灯片图像如下所示:
我可以使用编辑器小部件更新值并根据mouseMoveEvents强制重新绘制委托对象吗?然后我可以让编辑器出现在鼠标悬停上吗?或者我应该重新实现QListView以使用鼠标事件更新委托?或者还有另一种我没有发现的方式吗?
我创建了一个小部件,其行为大致如我希望更新框架部分能够工作,但是希望将其移植到委托类而不是QWidget,这样我就可以让它显示来自表的数据并利用它QT必须提供的模型/视图编程。
class ScrollingThumbnail(QWidget):
def __init__(self,parent,image,rect):
super().__init__(parent)
self.image=image
self.paused=False
self.frame=5
self.frames=10
self.bar=False
self.vis=True
self.thumbRect=rect
self.setMouseTracking(True)
def leaveEvent(self):
self.stop()
def mouseMoveEvent(self,e):
if(e.pos().y()>self.height*0.6):
self.bar=True
self.pause()
self.frame=int(e.pos().x()/(self.width/self.frames))
self.repaint()
elif self.paused:
self.paused=False
self.bar=False
self.play()
def paintEvent(self,e):
qP=QPainter()
qP.begin(self)
if self.vis:
self.drawWidget(qP)
qP.end()
def drawWidget(self,qP):
if not self.image.isNull():
qP.drawPixmap(self.thumbRect,self.image,QRect(self.image.width()/self.frames*self.frame,0,self.image.width()/self.frames,self.image.height()))
if self.bar:
pen=QPen(QColor(255,255,255,50),self.height/60,cap=Qt.RoundCap)
qP.setPen(pen)
off=self.height/20
inc=((self.width-(off*2))/(self.frames-1))
qP.drawLine(off,self.height-off-20,off+(inc)*(self.frame),self.height-off-20)
def play(self):
if not self.paused:
self.frame=(self.frame+1)%self.frames
self.repaint()
self.timer=threading.Timer(0.1,self.play)
self.timer.start()
def pause(self):
try:
self.timer.cancel()
except:
pass
self.paused=True
def stop(self):
try:
self.timer.cancel()
except:
pass
self.frame=5
self.repaint()
它使用线程计时器作为在循环中播放帧的廉价黑客方式。可能会更多地寻找更好的方法来实现这一目标(可能使用QThread?)另外还有一个关于期望行为的gif:i.imgur.com/aKoKs3m.gifv
干杯, 亚历
答案 0 :(得分:0)
想想我找到了一种方法来使用一些信号并连接一些插槽。以下是概念类的证明。
创建此编辑器类,它将根据鼠标位置通过信号更新帧数据,然后在光标离开窗口小部件/项目时销毁编辑器。它并不需要一个痛苦的尝试,但我只是把一个放在那里,所以我可以看到编辑活动时。
class TestEditor(QWidget):
editingFinished = Signal()
updateFrame = Signal()
def __init__(self,parent):
super().__init__(parent)
self.setMouseTracking(True)
self.frame=5
def mouseMoveEvent(self,e):
currentFrame=int(e.pos().x()/(self.width()/10))
if self.frame!=currentFrame:
self.frame=currentFrame
self.updateFrame.emit()
def leaveEvent(self,e):
self.frame=5
self.updateFrame.emit()
self.editingFinished.emit()
def paintEvent(self,e):
painter=QPainter()
painter.begin(self)
painter.setBrush(QColor(255,0,0,100))
painter.drawRect(self.rect())
painter.end()
我的代表将编辑器信号连接到一些基本功能。一个将关闭编辑器,另一个将更新我的模型上的帧数据。
class TestDelegate(QItemDelegate):
def __init__(self,parent):
super().__init__(parent)
self.height=200
self.width=300
def createEditor(self,parent,option,index):
editor=TestEditor(parent)
editor.editingFinished.connect(self.commitEditor)
editor.updateFrame.connect(self.updateFrames)
return editor
def setModelData(self, editor, model, index):
model.setData(index,editor.frame,TestData.FRAME)
def paint(self,painter,option,index):
painter.save()
painter.setBrush(QColor(0,255,0))
painter.drawRect(option.rect)
painter.setPen(QColor(255,255,255))
painter.setFont(QFont('Ariel',20,QFont.Bold))
painter.drawText(option.rect,Qt.AlignCenter,str(index.data(TestData.FRAME)))
painter.restore()
def sizeHint(self,option,index):
return QSize(self.width,self.height)
def commitEditor(self):
editor = self.sender()
self.closeEditor.emit(editor)
def updateFrames(self):
editor=self.sender()
self.commitData.emit(editor)
然后我所要做的就是启用鼠标跟踪并将“输入”信号连接到我的查看器上的“编辑()”插槽
dataView=QListView()
dataView.setViewMode(1)
dataView.setMovement(0)
dataView.setMouseTracking(True)
dataView.entered.connect(dataView.edit)
还有一个用于构建测试数据项的超级简单类。基本上只需将空角色设置为5即帧数据。
class TestData(QStandardItem):
FRAME=15
def __init__(self,data=None):
super().__init__(data)
self.setData(5,self.FRAME)
它目前还没有完全发挥作用,包括一个自动擦除帧的“播放”功能。但我认为应该很容易设置。还需要弄清楚如何处理选择,因为当您移动某个项目时,编辑器会变为活动状态,从而阻止它被选中。目前正在考虑实施一个鼠标注册事件,然后将更新附加到我的查看器的选择模型。