Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python QListWidget处理来自单击和itemSelectionChanged的多个信号_Python_Pyqt - Fatal编程技术网

Python QListWidget处理来自单击和itemSelectionChanged的多个信号

Python QListWidget处理来自单击和itemSelectionChanged的多个信号,python,pyqt,Python,Pyqt,我有两个基本上是项目选择器的列表小部件。当我在任一列表中选择一个项目时,我需要它来触发一个方法。这里只讨论一个程序。我需要在选择更改或单击某个项目时执行该过程,但我不希望这种情况发生两次,这是我遇到的问题 这有点难以描述,但请看下面的代码 场景1:两个列表仅连接“itemSelectionChanged” 点击“奶酪” 单击“否” 现在这两个都被选中了,当您交替单击它们时,不会发生任何事情,因为没有选择发生更改,但是当我从不同的列表中选择一个项目时,我需要调用某个方法 场景2:两个列表仅连接“已

我有两个基本上是项目选择器的列表小部件。当我在任一列表中选择一个项目时,我需要它来触发一个方法。这里只讨论一个程序。我需要在选择更改或单击某个项目时执行该过程,但我不希望这种情况发生两次,这是我遇到的问题

这有点难以描述,但请看下面的代码

场景1:两个列表仅连接“itemSelectionChanged” 点击“奶酪” 单击“否” 现在这两个都被选中了,当您交替单击它们时,不会发生任何事情,因为没有选择发生更改,但是当我从不同的列表中选择一个项目时,我需要调用某个方法

场景2:两个列表仅连接“已单击” 单击某个对象时会发生,但当我单击并拖动以更改选择时,不会触发任何事件,因为“单击”不会发生,并且itemSelectionChanged不会连接到任何对象。当选择也以这种方式更改时,我需要调用something_ocated方法

场景3:两个列表都连接“itemSelectionChanged”和“clicked” 单击并拖动以更改选择会使某些事情发生(好),但当我对一个新项目进行一次“单击”时,两个信号都会发送,并且我想要发生的事件会发生两次(坏)

鉴于上述情况,我希望同时实现以下所有目标:

  • 单击新项目时,仅处理一个事件(同时发出itemSelectionChanged和itemClicked,导致两个事件)
  • 当我单击一个已选择的项目(发出itemClicked信号)时,处理一个事件
  • 通过单击并拖动更改选择时处理一个事件(会发出itemSelectionChagned信号)
下面是示例代码:

from PyQt4 import QtGui
QtWidgets = QtGui
# from PyQt5 import QtWidgets
import sys
import time


def something_happened():
    print(time.time())

app = QtWidgets.QApplication(sys.argv)

widget = QtWidgets.QWidget(None)
vlay = QtWidgets.QVBoxLayout(widget)

list_widget1 = QtWidgets.QListWidget(None)
list_widget1.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
list_widget1.addItems(("Cheese", "Whiz", "tastes", "great"))
list_widget1.itemSelectionChanged.connect(something_happened)
list_widget1.clicked.connect(something_happened)

list_widget2 = QtWidgets.QListWidget(None)
list_widget2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
list_widget2.addItems(("No", "it", "tastes", "bad"))
list_widget2.itemSelectionChanged.connect(something_happened)
# list_widget2.clicked.connect(something_happened)

vlay.addWidget(list_widget1)
vlay.addWidget(list_widget2)

widget.show()

app.exec_()

在本例中,我将对QListWidget进行子类化。这是没有必要的,但我认为如果您将选择更改的决定封装在小部件本身中,那么代码会更干净。我制作了两种类型的小部件,每个小部件都有自己的行为来决定选择是否改变。您可以使用mousePress/mouseRelease/selectionChanged组合,希望这段代码能为您提供所需的工具。 运行此程序,并注意两个小部件之间的差异

class SomeFrame(object):
    """A container to place all the widgets, and control
       present the output from the selections.
    """
    def __init__(self):
        self.frame = QtWidgets.QFrame()

        # Creating content
        list_widget1 = MyQListWidgetA()
        list_widget1.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        list_widget1.addItems(("Cheese", "Whiz", "tastes", "great"))

        list_widget2 = MyQListWidgetB()
        list_widget2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        list_widget2.addItems(("No", "it", "tastes", "bad"))

        # Creating Layout
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(list_widget1)
        layout.addWidget(list_widget2)

        self.frame.setLayout(layout)

        # Connections
        from functools import partial
        list_widget1.selection_changed.connect(partial(self.selectionChangedCB, 'list_1'))
        list_widget2.selection_changed.connect(partial(self.selectionChangedCB, 'list_2'))

        self.frame.show()

    def selectionChangedCB(self, list_name, selected_items):
        print(list_name + ' changed: ' + str(selected_items))


from PyQt5 import QtWidgets, QtCore
class MyQListWidgetA(QtWidgets.QListWidget):
    """This widget emits selection_changed whenever its
       itemSelectionChanged signal is emitted, AND there
       was an actual change in the selected items.
    """
    selection_changed = QtCore.pyqtSignal(object)

    def __init__(self):
        QtWidgets.QListWidget.__init__(self)

        self.selected_items = set()

        self.itemSelectionChanged.connect(self.something_happened)

    def something_happened(self):
        # Create a set of the newly selected items, so we can compare
        # to the old selected items set
        newly_selected_items = set([item.text() for item in self.selectedItems()])
        if newly_selected_items != self.selected_items:
            # Only emit selection_changed signal if a change was detected.
            self.selected_items = newly_selected_items
            self.selection_changed.emit(self.selected_items)


class MyQListWidgetB(QtWidgets.QListWidget):
    """This widget emits selection_changed whenever it is pressed
       (mimic "clicked" signal) and again when the user is done
       selecting the items (mouse release) IFF the selection
       has changed.
    """
    selection_changed = QtCore.pyqtSignal(object)

    def __init__(self):
        QtWidgets.QListWidget.__init__(self)

        self.selected_items = set()

    def something_happened(self, initial_click=False):
        # Create a set of the newly selected items, so we can
        # compare to the old selected items set
        newly_selected_items = set([item.text() for item in self.selectedItems()])
        if newly_selected_items != self.selected_items:
            # Only emit selection_changed signal if a change was detected
            self.selected_items = newly_selected_items
            self.selection_changed.emit(self.selected_items)

    def mousePressEvent(self, event):
        QtWidgets.QListWidget.mousePressEvent(self, event)
        self.something_happened()

    def mouseReleaseEvent(self, event):
        QtWidgets.QListWidget.mouseReleaseEvent(self, event)
        self.something_happened()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)         
    theFrame = SomeFrame()
    sys.exit(app.exec_())
编辑:我意识到我从来没有考虑过“当我点击一个已经选择的项目时处理一个事件(它发出itemClicked信号)”。 我将其视为相同的单个项目单击,但也可以解决相同的多个项目单击(使用mouseReleaseEvent,并比较新旧列表)。 只需添加MyQListWidgetC,并将其连接到两个信号。B和C之间的主要区别在于,在mousePressEvent中,我们检查是否按下了单个项目,以及它是否是相同的项目

class MyQListWidgetC(QtWidgets.QListWidget):
    """This widget emits selection_changed whenever it is pressed
       (mimic "clicked" signal) and again when the user is done
       selecting the items (mouse release) IFF the selection
       has changed. If a single item was clicked, AND it is the
       same item, the widget will emit same_item_clicked, which
       the owner can listen to and decide what to do.
    """
    selection_changed = QtCore.pyqtSignal(object)
    same_item_clicked = QtCore.pyqtSignal(object)

    def __init__(self):
        QtWidgets.QListWidget.__init__(self)

        self.selected_items = set()

    def something_happened(self, initial_click=False):
        # Create a set of the newly selected items, so we can
        # compare to the old selected items set
        newly_selected_items = set([item.text() for item in self.selectedItems()])
        if newly_selected_items != self.selected_items:
            # Only emit selection_changed signal if a change was detected
            self.selected_items = newly_selected_items
            self.selection_changed.emit(self.selected_items)

    def mousePressEvent(self, event):
        QtWidgets.QListWidget.mousePressEvent(self, event)
        newly_selected_items = set([item.text() for item in self.selectedItems()])
        if len(newly_selected_items) == 1 and newly_selected_items == self.selected_items:
            self.same_item_clicked.emit(self.selected_items)
        else:
            self.something_happened()

    def mouseReleaseEvent(self, event):
        QtWidgets.QListWidget.mouseReleaseEvent(self, event)
        self.something_happened()

令人惊叹的。非常感谢。我喜欢你是怎么想出来的,这样物体就能跟踪自己了。我想我必须将列表中的所有信号通过一个外部对象进行路由,但这要好得多。谢谢