Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.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 PyQt5 QListView拖放可创建新的隐藏项_Python_Python 3.x_Pyqt_Pyqt5 - Fatal编程技术网

Python PyQt5 QListView拖放可创建新的隐藏项

Python PyQt5 QListView拖放可创建新的隐藏项,python,python-3.x,pyqt,pyqt5,Python,Python 3.x,Pyqt,Pyqt5,我有一个PyQt5 QListview,其中有一个项目列表,可以通过拖放和选中复选框来重新排列。问题是,当我重新排列列表中的项目时,项目在GUI中正确地重新排列,但当我尝试保存输出时,在其原始位置和新位置都有一个移动项目的副本 用于创建列表的函数 def create_methods_list(self): self.methods_list = QListView() self.methods_list.setDragDropMode(QListView.InternalMov

我有一个PyQt5 QListview,其中有一个项目列表,可以通过拖放和选中复选框来重新排列。问题是,当我重新排列列表中的项目时,项目在GUI中正确地重新排列,但当我尝试保存输出时,在其原始位置和新位置都有一个移动项目的副本

用于创建列表的函数

def create_methods_list(self):
    self.methods_list = QListView()
    self.methods_list.setDragDropMode(QListView.InternalMove)
    self.methods_list.setDefaultDropAction(Qt.MoveAction)
    self.methods_list.setDragDropMode(False)
    self.methods_list.setAcceptDrops(True)
    self.methods_list.setDropIndicatorShown(True)
    self.methods_list.setDragEnabled(True)
    self.methods_list.setWindowTitle('Method Order')

    self.methods_model = QtGui.QStandardItemModel(self.methods_list)

    # self.methods is a list of strings
    for method in self.methods:
        item = QtGui.QStandardItem(method)
        item.setData(method)
        item.setCheckable(True)
        item.setDragEnabled(True)
        item.setDropEnabled(False)
        item.setCheckState(True)

        self.methods_model.appendRow(item)

    self.methods_model.itemChanged.connect(self.method_item_changed)
    self.methods_list.setModel(self.methods_model)
重新排列列表时调用的函数:

def method_item_changed(self):
    print(self.methods_model.rowCount())
    i = 0
    new_methods = []
    while self.methods_model.item(i):
        if self.methods_model.item(i).checkState():
            new_methods.append(self.methods_model.item(i).data())
        i += 1
    print(new_methods)
    self.methods = new_methods
第一个print语句返回的项目数比原始列表中的项目数高一个。第二个print语句返回列表中的项,但移动的项同时位于其原始位置和新位置

我尝试了一个解决方案,其中包括添加一个间隔很短的QTimer,但没有成功

任何帮助都将不胜感激

完整工作版本:

from PyQt5.QtWidgets import (
QAction, QWidget, QLabel, QDesktopWidget,
QApplication, QComboBox, QPushButton, QGridLayout,
QMainWindow, qApp, QVBoxLayout, QSlider,
QHBoxLayout, QLineEdit, QListView, QAbstractItemView
)
from PyQt5.QtCore import Qt
from PyQt5 import QtGui
import sys

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.methods = ['option 1', 'option 2', 'option 3']
        self.central_widget = QWidget(self)
        self.layout = QVBoxLayout(self.central_widget)
        self.layout.addStretch()
        self.create_methods_list()
        self.layout.addWidget(self.methods_list)
        self.layout.addStretch()
        self.setCentralWidget(self.central_widget)
        self.show()

    def create_methods_list(self):
        self.methods_list = QListView()
        self.methods_list.setDragDropMode(QListView.InternalMove)
        self.methods_list.setDefaultDropAction(Qt.MoveAction)
        self.methods_list.setDragDropMode(False)
        self.methods_list.setAcceptDrops(True)
        self.methods_list.setDropIndicatorShown(True)
        self.methods_list.setDragEnabled(True)
        self.methods_list.setWindowTitle('Method Order')

        self.methods_model = QtGui.QStandardItemModel(self.methods_list)
        for method in self.methods:
            item = QtGui.QStandardItem(method)
            item.setData(method)
            item.setCheckable(True)
            item.setDragEnabled(True)
            item.setDropEnabled(False)
            item.setCheckState(True)

            self.methods_model.appendRow(item)

        self.methods_model.itemChanged.connect(self.method_item_changed)
        self.methods_list.setModel(self.methods_model)
        self.methods_list.setMinimumHeight(
            self.methods_list.sizeHintForRow(0)
            * (self.methods_model.rowCount() + 2))

    def method_item_changed(self):
        print(self.methods_model.rowCount())
        i = 0
        new_methods = []
        while self.methods_model.item(i):
            if self.methods_model.item(i).checkState():
                new_methods.append(self.methods_model.item(i).data())
            i += 1
        self.methods = new_methods
        print(self.methods)

if __name__=='__main__':
    app = QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

当项目从位置
i
移动到位置
j
时,所做的是:

  • 将项目插入位置
    j
  • 将数据复制到新项目,此时会发出
    itemChanged
    信号,因此您会看到更多的元素
  • 删除位于
    i
    位置的项目
这就是这种行为的原因。但我不理解有必要更新该列表。正常的做法是获取所需的已检查项目,也就是说,有一个函数被调用,并在必要时进行计算

import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.methods = ['option 1', 'option 2', 'option 3']
        central_widget = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout(central_widget)
        self.create_methods_list()
        layout.addWidget(self.methods_list)
        layout.addStretch()
        self.setCentralWidget(central_widget)

    def create_methods_list(self):
        self.methods_list = QtWidgets.QListView()
        self.methods_list.setDragDropMode(QtWidgets.QListView.InternalMove)
        self.methods_list.setDefaultDropAction(QtCore.Qt.MoveAction)
        self.methods_list.setAcceptDrops(True)
        self.methods_list.setDropIndicatorShown(True)
        self.methods_list.setDragEnabled(True)

        self.methods_model = QtGui.QStandardItemModel(self.methods_list)
        for method in self.methods:
            item = QtGui.QStandardItem(method)
            item.setData(method)
            item.setCheckable(True)
            item.setDragEnabled(True)
            item.setDropEnabled(False)
            item.setCheckState(QtCore.Qt.Checked)
            self.methods_model.appendRow(item)

        self.methods_list.setModel(self.methods_model)
        self.methods_list.setMinimumHeight(
            self.methods_list.sizeHintForRow(0)
            * (self.methods_model.rowCount() + 2))

    def get_items_Checked(self):
        checkeds = []
        for i in range(self.methods_model.rowCount()):
            it = self.methods_model.item(i)
            if it is not None and it.checkState() == QtCore.Qt.Checked:
                checkeds.append(it.text())
        return checkeds


if __name__=='__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

您的问题似乎出现在
itemChanged
信号的插槽中。您可以始终重载
dragEnterEvent
dropEvent
,然后确定已更改的索引,使用
super()
调用原始方法,然后在删除时移动该索引。如果您需要使用
dragEnterEvent
dropEvent
的示例帮助,请,这可能是更好的方法,我可以用示例代码作为答案。请提供一个感谢@AlexanderHuszagh的例子将非常感谢链接@eyllanesc,我编辑了我的问题。谢谢,你是对的,我没有理由每次更改都更新列表。一旦我将get_items_checked方法移动到一个按钮而不是listview回调,我就得到了想要的结果。