【问题标题】:PyQt live editing/drawing of DelegatePyQt 实时编辑/绘制 Delegate
【发布时间】:2018-02-13 04:21:34
【问题描述】:

因此,我目前在 QListView 中显示了一个视频剪辑列表,并创建了一个自定义委托来使用来自 QStandardItemModel 的数据为它们绘制预览缩略图。

最终,我希望能够在您将鼠标悬停在缩略图上时为其设置动画,以便它们播放剪辑的预览(仅显示几帧)。我想要这个的两个版本。一个只是播放,另一个根据您的鼠标位置显示帧(进一步向左是剪辑的开头,当您向右移动时,它会擦过)。

现在我正试图弄清楚如何实现动画片段。我是否应该使用委托来绘制框架并更新模型上的自定义框架数据,委托将使用该数据来了解使用重新实现的绘制函数绘制哪些帧(那里已经有了绘制函数的框架)?或者这会不会太耗费资源?那么最好的方法是什么?我查看了编辑器小部件,但那些似乎不是实时编辑模型数据/更新委托,而是仅在完成编辑后。此外,我希望它在鼠标悬停时初始化,这似乎不是内置编辑触发器中的选项。

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)

此委托绘制我用于预览帧的条形图像的一部分,并通过引用帧数据来实现。 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

干杯, 亚历克斯

【问题讨论】:

  • 据我所见,您有一个图像,根据情况,需要一个片段并且必须在委托中显示。你想使用什么鼠标事件:mousePressEvent、mouseMoveEvent、mouseReleaseEvent?行为应该是什么,请提供更多详细信息?如果它正在使用它显示的图像,那就太好了。
  • 这是一个我希望它如何操作的示例(我在走代理路线之前制作的小部件版本的屏幕截图)。 i.imgur.com/aKoKs3m.gifv 当您将鼠标移到图像上时,这一切都会发生。根据您的光标是在顶部还是底部滚动条式部分上切换播放“模式”。所以可能是mouseMoveEvent。
  • 从我通常看到的图像序列显示,并且通过鼠标可以控制序列,您可以显示该代码。
  • 更新了原来的帖子。这是一个小部件的代码,这是我最初的方法,虽然我假设使用委托是要走的路?特别是在有很多条目的情况下,并且希望以后能够过滤/排序它们。
  • 图片是QPixmap还是QImage?

标签: python pyqt real-time-updates qitemdelegate


【解决方案1】:

我想我想出了一种方法来使用一些信号并连接一些插槽。这是概念证明类。

创建了这个编辑器类,它将根据鼠标位置通过信号更新帧数据,然后在光标离开小部件/项目时销毁编辑器。它实际上并不需要一个paintevent,但我只是在其中放了一个,这样我就可以看到编辑何时处于活动状态。

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()

My Delegate 将编辑器信号连接到一些基本功能。一个将关闭编辑器,另一个将更新我模型上的帧数据。

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)

然后我要做的就是启用鼠标跟踪并将“输入”信号连接到查看器上的“edit()”插槽

    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)

目前它还没有完全发挥作用,包括一个“播放”功能,它会自动浏览帧。但我认为这应该很容易设置。还需要弄清楚现在如何处理选择,因为当您移动一个项目时编辑器会变为活动状态,从而有效地阻止它被选中。目前正在研究可能实现一个 Mouse up 事件,然后更新附加到我的查看器的选择模型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2013-03-27
    • 2012-11-26
    • 2023-03-16
    • 2021-08-18
    • 2015-08-19
    • 1970-01-01
    相关资源
    最近更新 更多