新信号连接到旧插槽而不是单独的插槽

2023-12-08

我正在尝试标记数据跟踪的 x 跨度,并使用 tagNames、起始 x 值和结束 x 值填充表。我正在使用“突出显示”对象的字典来跟踪 x 跨度,以防以后需要对其进行编辑(增加或减少)。字典将 x 起始值映射到突出显示对象,因为 x 起始值应是唯一的(标记的 x 跨度没有重叠)。

为了做到这一点,当用户编辑表格上的单元格时,我会发出一个信号。第一个信号连接的函数发出另一个信号(理想情况下是 xStart 与 xEnd 是否发生更改,但到目前为止我只实现了 xStart),这实际上改变了跨度的外观以匹配编辑。

几周前我问过类似的问题,但未能得到答案。老问题在这里:PyQT5 插槽参数在第一次调用后未更新。为了响应那里给出的提示,我编写了以下示例:

import sys

from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.widgets as mwidgets
from functools import partial

class Window(QMainWindow):

    def __init__(self, parent = None):
        super(Window, self).__init__(parent)
        self.resize(1600, 800)
        self.MyUI()
        
    def MyUI(self):

        canvas = Canvas(self, width=14, height=12, dpi=100)
        canvas.move(0,0)

 #use this object in the dictionary to hold onto all the spans. 
class highlight:
    def __init__(self, tag, xStart, xEnd, highlightObj):
        self.tag = tag
        self.xStart = xStart
        self.xEnd = xEnd
        self.highlightObj = highlightObj

class Canvas(FigureCanvas):
    def __init__(self, parent, width = 14, height = 12, dpi = 100):
        Plot = Figure(figsize=(width, height), dpi=dpi)
        self.Axes = Plot.add_subplot(111)
        self.Axes.set_position([0.05, 0.58, 0.66, 0.55])
        self.rowCount = 0
        super().__init__(Plot)
        self.setParent(parent)

        
        ##add all relevant lines to plot 
        self.Axes.plot([0,1,2,3,4], [3, 4, 5, 6, 7])
        self.Axes.set_xlabel('Frame', fontsize = 10) 
        self.Axes.grid()
        self.Axes.set_aspect(1)
        Plot.canvas.draw()

        
        self.highlights = {} #empty dictionary to store all the tags.

        ##define a table to hold the values postselection
        self.taggingTable = QTableWidget(self)
        self.taggingTable.setColumnCount(3)
        self.taggingTable.setRowCount(100)
        self.taggingTable.setGeometry(QRect(1005,85, 330, 310))
        self.taggingTable.setHorizontalHeaderLabels(['Behavior','Start Frame', 'End Frame'])


        Canvas.span = mwidgets.SpanSelector(self.Axes, self.onHighlight, "horizontal", 
                                        interactive = True, useblit=True, props=dict(alpha=0.5, facecolor="blue"),)
        self.draw_idle()

        self.taggingTable.selectionModel().selectionChanged.connect(self.onCellSelect)
        self.draw_idle()

        ##highlighting adds a highlight item to the directory. 
    def onHighlight(self, xStart, xEnd):
        tagName = "No Tag"
        self.taggingTable.setItem(self.rowCount, 0, QTableWidgetItem(tagName))
        self.taggingTable.setItem(self.rowCount, 1, QTableWidgetItem(str(int(xStart))))
        self.taggingTable.setItem(self.rowCount, 2, QTableWidgetItem(str(int(xEnd))))
        self.rowCount = self.rowCount + 1
        highlightObj = self.Axes.axvspan(xStart, xEnd, color = 'blue', alpha = 0.5)
        self.highlights[int(xStart)] = highlight(tagName, xStart, xEnd, highlightObj)
        self.draw_idle()
                
    def xStartChanged(self, xStart, rowVal):
        if self.inCounter == 0:
            print("xStart in slot: ", xStart)
            xEnd = self.highlights[xStart].xEnd
            xStartNew = int(self.taggingTable.item(rowVal, 1).text())
            self.highlights[xStart].highlightObj.remove() #remove old from the plot
            del self.highlights[xStart]                   #remove old from directory
            highlightObj = self.Axes.axvspan(xStartNew, xEnd, color = 'blue', alpha = 0.5) #add new to plot
            self.highlights[xStartNew] = highlight("No tagName", xStartNew, xEnd, highlightObj) #add new to directory
            self.taggingTable.clearSelection() #deselect value from table
            self.draw_idle()
        self.inCounter = self.inCounter + 1

    def onCellSelect(self):
        index = self.taggingTable.selectedIndexes()
        if len(index) != 0:
            rowVal = index[0].row()
            if not (self.taggingTable.item(rowVal, 1) is None):
                xStart = int(self.taggingTable.item(rowVal, 1).text())
                print("--------------")
                print("xStart in signal: ", xStart)
                self.inCounter = 0
                self.taggingTable.itemChanged.connect(lambda: self.xStartChanged(xStart, rowVal))        
    
    


app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()

我运行的测试是当我突出显示两条痕迹时:

two traces and their table values

然后我成功更改了第一条跟踪:

editing first trace

但是,当我尝试编辑第二条跟踪时,程序崩溃了:

editing second trace before hitting enter

为了调试,我尝试检查发送和接收的信号。它产生以下输出:

--------------
xStart in signal:  0
xStart in slot:  0 ##First slot call gets correct signal 
--------------
xStart in signal:  3
xStart in slot:  0 ## Second slot gets the first signal instead of the second
Traceback (most recent call last):
  File "//Volumes/path/file.py", line 105, in <lambda>
    self.taggingTable.itemChanged.connect(lambda: self.xStartChanged(xStart, rowVal))        
  File "//Volumes/path/file.py", line 86, in xStartChanged
    xEnd = self.highlights[xStart].xEnd
KeyError: 0
zsh: abort      python Volumes/path file.py

我尝试使用有关独特连接的在线信息,但我不确定如何实施它们。预先感谢您的任何帮助。


看来您需要的是发出项目的表小部件信号and每当对特定列进行更改时,都会使用旧的文本值。不幸的是,项目已更改信号不太合适,因为它没有表明what改变了,并且它不提供以前的值。因此,要解决此限制,一种解决方案是子类化 QTableWidget / QTableWidgetItem 并发出具有所需参数的自定义信号。这将完全回避多个信号槽连接的问题。

子类的实现非常简单:

class TableWidgetItem(QTableWidgetItem):
    def setData(self, role, value):
        oldval = self.text()
        super().setData(role, value)
        if role == Qt.EditRole and self.text() != oldval:
            table = self.tableWidget()
            if table is not None:
                table.itemTextChanged.emit(self, oldval)

class TableWidget(QTableWidget):
    itemTextChanged = pyqtSignal(TableWidgetItem, str)

下面是基于您的示例的基本演示,展示了如何使用它们。 (请注意,我也没有尝试处理 xEnd,因为这超出了当前问题的范围)。

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.widgets as mwidgets

class Window(QMainWindow):
    def __init__(self, parent = None):
        super(Window, self).__init__(parent)
        self.resize(1600, 800)
        self.MyUI()

    def MyUI(self):
        canvas = Canvas(self, width=14, height=12, dpi=100)
        canvas.move(0,0)

# CUSTOM SUBCLASSES

class TableWidgetItem(QTableWidgetItem):
    def setData(self, role, value):
        oldval = self.text()
        super().setData(role, value)
        if role == Qt.EditRole and self.text() != oldval:
            table = self.tableWidget()
            if table is not None:
                table.itemTextChanged.emit(self, oldval)

class TableWidget(QTableWidget):
    itemTextChanged = pyqtSignal(TableWidgetItem, str)


 #use this object in the dictionary to hold onto all the spans.
class highlight:
    def __init__(self, tag, xStart, xEnd, highlightObj):
        self.tag = tag
        self.xStart = xStart
        self.xEnd = xEnd
        self.highlightObj = highlightObj

class Canvas(FigureCanvas):
    def __init__(self, parent, width = 14, height = 12, dpi = 100):
        Plot = Figure(figsize=(width, height), dpi=dpi)
        self.Axes = Plot.add_subplot(111)
        self.Axes.set_position([0.05, 0.58, 0.66, 0.55])
        self.rowCount = 0
        super().__init__(Plot)
        self.setParent(parent)

        ##add all relevant lines to plot
        self.Axes.plot([0,1,2,3,4], [3, 4, 5, 6, 7])
        self.Axes.set_xlabel('Frame', fontsize = 10)
        self.Axes.grid()
        self.Axes.set_aspect(1)
        Plot.canvas.draw()

        self.highlights = {} #empty dictionary to store all the tags.

        ##define a table to hold the values postselection
        # USE CUSTOM TABLE SUBCLASS
        self.taggingTable = TableWidget(self)
        self.taggingTable.setColumnCount(3)
        self.taggingTable.setRowCount(100)
        self.taggingTable.setGeometry(QRect(1005,85, 330, 310))
        self.taggingTable.setHorizontalHeaderLabels(['Behavior','Start Frame', 'End Frame'])
        # CONNECT TO CUSTOM SIGNAL
        self.taggingTable.itemTextChanged.connect(self.xStartChanged)

        Canvas.span = mwidgets.SpanSelector(self.Axes, self.onHighlight, "horizontal",
                                        interactive = True, useblit=True, props=dict(alpha=0.5, facecolor="blue"),)
        self.draw_idle()

        ##highlighting adds a highlight item to the directory.
    def onHighlight(self, xStart, xEnd):
        tagName = "No Tag"
        self.taggingTable.setItem(self.rowCount, 0, QTableWidgetItem(tagName))
        # USE CUSTOM ITEM SUBCLASS
        self.taggingTable.setItem(self.rowCount, 1, TableWidgetItem(str(int(xStart))))
        self.taggingTable.setItem(self.rowCount, 2, QTableWidgetItem(str(int(xEnd))))
        self.rowCount = self.rowCount + 1
        highlightObj = self.Axes.axvspan(xStart, xEnd, color = 'blue', alpha = 0.5)
        self.highlights[int(xStart)] = highlight(tagName, xStart, xEnd, highlightObj)
        self.draw_idle()

    def xStartChanged(self, item, oldVal):
        try:
            # VALIDATE NEW VALUES
            xStart = int(oldVal)
            xStartNew = int(item.text())
        except ValueError:
            pass
        else:
            print("xStart in slot: ", xStart)
            xEnd = self.highlights[xStart].xEnd
            self.highlights[xStart].highlightObj.remove() #remove old from the plot
            del self.highlights[xStart]                   #remove old from directory
            highlightObj = self.Axes.axvspan(xStartNew, xEnd, color = 'blue', alpha = 0.5) #add new to plot
            self.highlights[xStartNew] = highlight("No tagName", xStartNew, xEnd, highlightObj) #add new to directory
            self.taggingTable.clearSelection() #deselect value from table
            self.draw_idle()


app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

新信号连接到旧插槽而不是单独的插槽 的相关文章

  • Django:如何测试“HttpResponsePermanentRedirect”

    我正在为我的 django 应用程序编写一些测试 在我看来 它使用 HttpResponseRedirect 重定向到其他一些网址 那么我该如何测试呢 姜戈TestCase类有一个方法assertRedirects https docs d
  • 优化 Keras 以使用所有可用的 CPU 资源

    好吧 我真的不知道我在说什么 所以请耐心听我说 我正在使用 Theano 后端运行 Keras 以在 MNIST 图像上运行基本的神经网络 目前只是一个教程 过去 我一直使用我的旧 HP 笔记本电脑 因为我有 Windows 和 Ubunt
  • Paramiko - 使用私钥连接 - 不是有效的 OPENSSH 私钥/公钥文件

    我正在尝试找到解决方案 但无法理解我做错了什么 在我的 Linux 服务器上 我运行了以下命令 ssh keygen t rsa 这产生了一个id rsa and id rsa pub file 然后我将它们复制到本地并尝试运行以下代码 s
  • PIL Image.size 返回相反的宽度/高度

    使用PIL确定图像的宽度和高度 在特定图像上 幸运的是只有这一个 但这很麻烦 从 image size 返回的宽度 高度是相反的 图片 http storage googleapis com cookila 533ebf752b9d1f7c
  • 如何从 Dockerfile 安装 Python 3.7 和 Pip

    我正在尝试构建基于 Ubuntu 18 04 的自定义 Docker 映像 Ubuntu 预装了 Python 3 6 但我想 1 安装 Python 3 7 2 将其设置为默认 Python 版本 这样就可以使用python代替pytho
  • Python igraph:从图中删除顶点

    我正在使用安然电子邮件数据集 并尝试删除没有 enron com 的电子邮件地址 即我只想拥有安然电子邮件 当我尝试删除那些没有 enron com 的地址时 一些电子邮件由于某些原因被跳过 下面显示了一个小图 其中顶点是电子邮件地址 这是
  • “char”/“character”类型的类型提示

    char 或 character 没有内置的原始类型 因此显然必须使用长度为 1 的字符串 但是为了暗示这一点并暗示它应该被视为一个字符 如何通过类型提示来实现这一点 grade chr A 一种方法可能是使用内置的 chr 函数来表示这一
  • 如何在python中检索aws批处理参数值?

    流程 Dynamo DB gt Lambda gt 批处理 如果将角色 arn 插入动态数据库 它是从 lambda 事件中检索的 然后使用submit job角色 arn 的 API 被传递为 parameters role arn ar
  • 如何使用Python的super()来更新父值?

    我对继承很陌生 之前所有关于继承和 Python 的 super 函数的讨论都有点超出我的理解 我当前使用以下代码来更新父对象的值 usr bin env python test py class Master object mydata
  • 如何在Python和Selenium中通过标签名称或id获取元素[重复]

    这个问题在这里已经有答案了 我正在尝试使用 Python 和 Selenium 获取输入 但它向我显示错误 我该如何解决这个错误 inputElement send keys getStock getStocklFunc 0 Error i
  • 将 Pandas 列中的列表拆分为单独的列

    这是我在 pandas 数据框中的 特征 列 Feature Cricket 82379 Kabaddi 255 Reality 4751 Cricket 15640 Wildlife 730 LiveTV 13 Football 4129
  • select() 可以在 Windows 下使用 Python 中的文件吗?

    我正在尝试在 Windows 下运行以下 python 服务器 An echo server that uses select to handle multiple clients at a time Entering any line o
  • Pandas Dataframe:将包含列表的行扩展到多行,并为所有列提供所需的索引

    我在 pandas 数据框中有时间序列数据 索引为测量开始时的时间 列中包含以固定采样率记录的值列表 连续索引 列表中元素数量的差异 这是它的样子 Time A B Z 0 1 2 3 4 1 2 3 4 2 5 6 7 8 5 6 7 8
  • 将一个列表的元素除以另一个列表的元素

    我有两个清单 比如说 a 10 20 30 40 50 60 b 30 70 110 正如你所看到的 列表 b 由一个列表的元素总和组成 其中 window 2 b 0 a 0 a 1 10 20 30 etc 如何获得另一个列表 该列表由
  • 查找给定节点的最高权重边

    我在 NetworkX 中有一个有向图 边缘的权重从 0 到 1 表示它们发生的概率 网络连通性非常高 所以我想修剪每个节点的边缘 只保留最高概率的节点 我不确定如何迭代每个节点并仅保留最高权重in edges在图中 有没有一个networ
  • Python 3.2 中 **kwargs 和 dict 有什么区别?

    看起来Python的很多方面都只是功能的重复 除了我在 Python 中的 kwargs 和 dict 中看到的冗余之外 还有什么区别吗 参数解包存在差异 许多人使用kwargs 并通过dict作为论据之一 使用参数解包 Prepare f
  • 如何在sphinx中启用数学?

    我在用sphinx http sphinx pocoo org index html与pngmath http sphinx pocoo org ext math html module sphinx ext pngmath扩展来记录我的代
  • 如何禁止 celery 中的 pickle 序列化

    Celery 默认使用 pickle 作为任务的序列化方法 如中所述FAQ http ask github com celery faq html isn t using pickle a security concern 这代表一个安全漏
  • 异步和协程与任务队列

    我一直在阅读有关 python 3 中的 asyncio 模块的内容 以及更广泛地了解 python 中的协程的内容 但我不明白是什么让 asyncio 成为如此出色的工具 我的感觉是 你可以用协程做的所有事情 通过使用基于多处理模块 例如
  • 在 Python 模块中使用 InstaLoader

    我正在尝试使用 Instaloader 下载与主题标签相关的照片以进行图像分析 我在GitHub存储库中找到了一个全面的方法 如何在终端中执行它 但是 我需要将脚本集成到Python笔记本中 这是脚本 instaloader no vide

随机推荐

  • 发送电子邮件到本地域

    我有一个从网站发送电子邮件的简单方法 local vars using var mail new MailMessage from sendTo using var smtp new SmtpClient mail CC Add cc ma
  • Lua中获取随机数的其他方法

    我正在寻找一种替代方法来在Lua中获取一个介于最小和最大数字之间的随机数 而不使用math random 有什么办法吗 它不一定是一个简单的方法 就像评论所暗示的那样 在类 Unix 系统上 您可以从中读取字节 dev random or
  • 如何转换 Oracle 中的“旧版”左外连接语句?

    我在 Oracle 数据库中有两个表 A 和 G 可以根据帐号将它们连接在一起 需要注意的是 其中一个表 G 的记录比另一个表少大约 80 条 当我一起查询两个表时 我需要获取所有行 以便我们在缺失的 80 行的列中看到 NULL 数据 我
  • 科尔多瓦中的文件大小函数

    也许这是一个简单的问题 但我已经搜索了两天 但找不到答案 我正在科尔多瓦开发一个文件管理器只是为了学习科尔多瓦插件文件 我使用此函数获得了文件夹中的文件列表 window resolveLocalFileSystemURL cordova
  • 量角器 - 无法读取未定义的属性“$$testability”

    我收到一条错误 内容如下 Error while waiting for Protractor to synce with the page Cannot read property testability of undefined 下面是
  • Scala - 用特定文本替换 xml 元素

    所以我有这个XML a blah a 我想把它改成 a someValueIDoNotKnowAtCompileTime a 目前 我正在看这个问题 然而 这只是将值更改为 2 我想要的是完全相同的东西 但是能够定义值 以便它可以在运行时更
  • 从主机名获取域名扩展

    Extract 域名扩展 e g com 不是使用正则表达式从主机名中获取的域名 例如 google com 输入 gt 输出 www google com gt com google com gt com google co uk gt
  • 在 AWS AppSync 中对 SQL 查询的 JSON 对象进行字符串化

    Question 如何在 Appsync 速度模板中对 SQL 语句的 JSON 对象进行字符串化 解释 我有一个 Aurora RDS 表 其中有一列数据类型为 JSON AppSync API 已连接到 RDS 我的 GraphQL 模
  • 将一个数据表的列添加到另一个数据表

    嘿 所有人都需要一点帮助来排序这个表的循环 似乎无法将工作示例应用于模型 无论如何 它就在这里 我有 2 个数据表 每个数据表都有不同的数据和不同的值 唯一的共同值是日期 第一个表包含我想要的所有内容 除了一列值 来自另一个表 因此我需要将
  • 在现有 geom_sf 图层下方插入 geom_sf 图层

    我有一张印度的基本地图 其中包含州和边界 一些标签以及存储为 gg 对象的许多其他规范 我想生成许多带有区域图层的地图 这些地图将承载来自不同变量的数据 为了防止地区地图覆盖州和国家边界 它必须位于之前所有代码之前 我想避免重复 我想我可以
  • 法律散文使用 Corda

    这是之前回答的后续问题法律散文乔尔提出的问题 根据要求创建了单独的问题 LegalProseReference uri foo bar com my legal doc html public class MyContract implem
  • 在 PHP 中,为什么我的会话变量保留为引用?

    这是代码 通过验证 IP 地址来检查会话 ID 是否被欺骗是一个简单的操作 session start session ip address SERVER REMOTE ADDR if isset SESSION SESSION IP AD
  • 如何更新表中的行或插入不存在的行?

    我有以下计数器表 CREATE TABLE cache key text PRIMARY KEY generation int 我想增加其中一个计数器 或者如果相应的行尚不存在 则将其设置为零 有没有办法在标准 SQL 中没有并发问题的情况
  • 标签内的按钮触发(有时是双触发\双击)

    有类似的问题 但我没有足够的声誉来发布答案 所以我将其作为 新问题 问题是
  • dll 的 app.config 中的连接字符串

    我创建了一个 C dll 它使用来自的连接字符串应用程序配置文件连接到数据库 我在 Web 应用程序 Visual Studio 2013 Windows 7 中使用它 该应用程序也连接到数据库并在其中有自己的连接字符串网络配置文件 但是
  • WPF透明边框导致UI停止重绘

    作为后续我之前的问题 我想知道如何正确使用透明窗 如果我将窗口设置为使用透明度 UI 有时会出现停止响应的情况 实际发生的情况是 UI 根本没有按其应有的方式更新 不出现动画 页面似乎无法导航 然而 如果你观察调试器点击按钮 链接等 确实有
  • 你能强制将枚举值序列化为整数吗? [复制]

    这个问题在这里已经有答案了 可能的重复 如何将枚举值序列化为 int Hi all 我想知道是否有一种方法可以强制将枚举值序列化为其整数值 而不是其字符串表示形式 让您了解一下上下文 在严重依赖 Web 服务的 Web 应用程序中 我们为所
  • 不能子类化 UIColor 吗?

    我正在尝试对 UIColor 进行子类化 但我似乎无法弄清楚出了什么问题 在我的 PColor h 中 import
  • 为什么“隔空敲击”手势在我的 Unity/MRTK 应用程序中的 HoloLens1 上不起作用?

    我有一个 Unity 应用程序 我想将其与 Microsoft 混合现实工具包 MRTK 集成 当我将 MRTK v2 1 或 v2 2 包添加到 Unity 项目时 我可以在 Unity 编辑器中模拟 隔空敲击 手势 并且应用程序会注册该
  • 新信号连接到旧插槽而不是单独的插槽

    我正在尝试标记数据跟踪的 x 跨度 并使用 tagNames 起始 x 值和结束 x 值填充表 我正在使用 突出显示 对象的字典来跟踪 x 跨度 以防以后需要对其进行编辑 增加或减少 字典将 x 起始值映射到突出显示对象 因为 x 起始值应