winform listview 设置选中项 图片_实战PyQt5: 069-MV框架中的项视图拖放功能
模型-視圖框架完全支持Qt的基本拖放操作,列表、樹形和表格部件中的項可以在視圖間拖動,數據可以以MIME類型的格式進行導入和導出
Qt提供的標準視圖自動支持在視圖內部的拖放,其中的項可以被移動以改變顯示順序。在默認情況下,這些視圖是不能進行拖放操作的,如果要使用拖放功能,除了項本身也是允許拖放,還需要開啟視圖的一些屬性。
使用項視圖部件
QListWidget,QTabWidget和QTreeWidget每一種類型的項都默認配置了一套不同的標識。比如,QListWidgetItem或QTreeWidgetItem的初始標識是啟用了enabled, 可復選checkable,可選擇selectbale這些標識,同時它們也可以作為拖放操作的數據源;QTableWidgetItem則可以進行編輯操作,并且可以作為拖放操作的目標。
Qt中提供的所有標準項都有一個或兩個標志用于拖放操作,為了利用內置的拖放支持,需要在視圖中設置相應的屬性。
要啟動對項的拖動功能,需要把視圖的dragEnabled屬性設定為True。
要實現將內部或外部項拖放到視圖中,需要把視圖的viewport()的acceptDrops屬性設定為True。
要顯示當前拖動的項將被放置在什么地方,則需要設置視圖的showDropIndicator屬性,它會提供關于項在視圖中的持續位置更新信息。
例如,可以用下面的代碼在列表部件中啟用拖放功能。
???????? listWidget=QListWidget(self)???????? listWidget.setSelectionMode(QAbstractItemView.SingleSelection)???????? listWidget.setDragEnabled(True)???????? listWidget.viewport().setAcceptDrops(True)???????? listWidget.setDropIndicatorShown(True)這樣就可以得到一個可以讓項在視圖里進行復制的列表部件,它甚至可以讓用戶在包含相同類型數據的視圖間拖動項。注意,在這兩種情況下,項是本復制而不是被移動。
如果用戶要在視圖間移動項,那就要設定列表部件的拖放模式dragDropMode。
???????? listWidget.setDragDropMode(QAbstractItemView.InternalMove)使用Model-View框架類
建立一個支持拖放的視圖和跟使用項視圖部件的方式是一樣的,比如,可以用建立QListWidget的方法建立一個QListView視圖:
???????? listView=QListView(self)???????? listView.setSelectionMode(QAbstractItemView.ExtendedSelection)???????? listView.setDragEnabled(True)???????? listView.setAcceptDrops(True)???????? listView.setDropIndicatorShown(True)因為視圖所顯示的數據由模型來控制存取,所以模型類也要提供對拖放操作的支持。模型類多拖放動作的支持可以通過重新實現QAbstractItemModel.supportedDropActions()函數來指定。下面我們以自定義類DragDropListModel(QStringListModel)來演示拖放功能。
以下的代碼實現復制和移動的操作:
???????? def supportedDropActions(self):?????????????????? return Qt.CopyAction | Qt.MoveAction雖然可是設定Qt.DropActions里的值的任意組合,但是還是需要重新實現模型中的一些函數才能完成需要支持的功能。例如,為了讓一個列表模型能正確地支持Qt.MoveAction動作,不管是直接還是間接從其基類繼承,模型必須重新實現QAbstractItemModel.remove()函數。
啟動對項的拖放功能
通過重新實現QAbstractItemModel.flags()函數來提供合適的標識,指示模型視圖哪些項可以拖動,哪些項可以接收項。例如,通過在返回的標識中包含Qt.ItemsDragEnabled 和Qt.ItemsDropEnabled, 一個基于QAbstractListModel的列表模型就可以使每個項都可以拖放:
???????? def flags(self, index):?????????????????? defaultFlags=QStringListModel.flags(self, index)?????????????????? if index.isValid():?????????????????? ???????? return Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | defaultsFlags?????????????????? else:??????????????????????????? return Qt.ItemIsDropEnabled | defaultFlags注意,項可以放置在模型的頂層,而拖動操作只對合法項有效。編碼導出數據
當通過拖放操作從模型中導出數據項時,會將它們編碼成與一種或多種MIME類型相對應的適當格式。通過重新實現回標準MIME類型的列表的QAbstractItemModel .mimeTypes()函數,來聲明可用供項使用的MIME類型。例如,一個僅提供純文本的模型需提供以下實現:
???????? def mimeTypes(self):?????????????????? return ['application/vnd.text.list']模型同時還需要提供對公開格式的數據進行編碼的代碼實現,這可以通過重新實現QAbstractItemModel.mimeData()函數來提供。
以下代碼實現將索引參數相關的項數據編碼成純文本并存儲在QMiMeData對象中。
???????? def mimeData(self, indexes):?????????????????? mmData =QMimeData()?????????????????? encodedData=QByteArray()?????????????????? stream =QDataStream(encodeData, QIODevice.WriteOnly)???????? ???????? for index in indexes:?????????????????? ???????? if index.isValid():??????????????????????????? ???????? text =self.data(index, Qt.DisplayRole)??????????????????????????? ???????? stream.writeQString(str(text))?????????????????? mmData.setData('application/vnd.text.list', ecodedData)?????????????????? return mmData注意:自定義的數據類型必須申明為meta objects,并且要為其實現流操作。
將釋放的數據插入到模型中
模型處理釋放的數據的方法依賴于的類型(列表,表格或樹形)以及它向用戶顯示其內容的方法。通常情況下,最適合模型底層數據存儲的方法就是處理釋放的數據的方法。
不同類型的模型會用不同的方法處理釋放的數據。列表和表格模型只提供一個存儲項的平面結構。因此,當數據被釋放到視圖中的一個現有的項上面時,它們可以插入新的行(和列),或者使用提供的數據覆蓋掉模型里項的內容。樹形模型一般是向他們的底層數據增加包含新數據的子項。
通過重新實現模型的QAbstractItemModel::dropMimeData()函數來實現對釋放數據的處理。例如,一個處理簡單字符串列表的模型可以提供一種實現,該實現將處理放入現有項目的數據與放入模型頂層(即無效項目)的數據分開處理。
通過重新實現QAbstractItemModel :: canDropMimeData(),模型可以禁止刪除某些項目,或者取決于刪除的數據。該模型首先必須確保應該執行操作,所提供的數據采用可以使用的格式,并且其在模型中的目的地是有效的:
???????? def canDropMimeData(self, data, action, row, column, parent):?????????????????? if data.hasFormat('application/vnd.text.list') is False:??????????????????????????? return False?????????????????? if column > 0:??????????????????????????? return False?????????????????? return True????????? def dropMimeData(self, data, action, row, column, parent):?????????????????? if self.canDropMimeData(data,action,row,column,parent) is False??????????????????????????? return False?????????????????? if action == Qt.IgnoreAction:??????????????????????????? return True如果提供的數據不是純文本,或者給出的用于放置的列號是無效的,那么這個字符串列表模型可以將此操作標志為失敗。
根據數據是否被放置在一個現有的項上面作為判斷,插入模型的數據將做不同的處理。在這個例子中,我們允許把數據放在現有項之間,列表的第一個項之前,以及在列表的最后一個項之后。
當一個放下操作發生時,如果父項相對應的模型索引是有效的,意味著放下操作發生在一個項上面,如果是無效的,則意味著放下操作發生在視圖中對應于模型頂層的某個位置。
?????????????????? beginRow =-1?????????????????? if row != -1:??????????????????????????? beginRow =row先檢查指定的行號看它是否可以用來將項插入到模型中,不管父項的索引是否有效:
?????????????????? elif parent.isValid():??????????????????????????? beginRow=parent.row()如果父項索引是有的,則放下操作發生在一個項上。在本列表模型中,我們找出項的行號,并用這個值把放下的項插入到模型的頂層。
?????????????????? else:??????????????????????????? beginRow =self.rowCount(QModelIndex())當放下動作發生在視圖的某個位置,同時行號又是不可用的,那我們就把項添加在模型的頂層項。在層次結構模型中,當放下動作發生在一個項上時,插入的項作為該項的子項插入到模型中。
解碼導入的數據
對dropMimeData()實現的同時也必須對數據進行解碼, 并把它插入到模型的底層數據結構中。在本文模型中,編碼后的項可以被解碼并加入到一個字符串列表中。
???????? encodedData = data.data('application/vnd.text.list')???????? stream = QDataStream (encodeData, QIODevice.ReadOnly)???????? newItems =[]???????? rows = 0???????? while stream.atEnd() is False:?????????????????? text = stream.readQString()?????????????????? newItem.append(str(text)?????????????????? rows += 1字符串就可以插入到底層數據。為了保持一致性,可以通過模型自己的接口實現:
???????? self.insertRows(beginRow, rows, QModelIndex())???????? for text in newItems:?????????????????? idx = self.index(beginRow, 0, QModelIndex())?????????????????? self.setData(idx, text)?????????????????? beginRow += 1???????? return True注意,模型通常要提供 QAbstractItemModel::insertRows()函數和 QAbstractItemModel::setData()函數的實現。
演示代碼
建立演示文件dragdropdemo.py完整代碼如下:
import?sysfrom?PyQt5?import?QtCore,?QtGui,?QtWidgetsfrom?PyQt5.QtCore?import?(Qt,?QStringListModel,QModelIndex,??????????????????????????QMimeData,QByteArray,?QDataStream,?QIODevice)from?PyQt5.QtWidgets?import?(QApplication,?QMainWindow,?QListView,?QAbstractItemView)?class?DragDropListModel(QStringListModel):????def?__init__(self,?parent=None):????????super(DragDropListModel,?self).__init__(parent)????????????def?supportedDropActions(self):????????return?Qt.CopyAction?|?Qt.MoveAction????????def?flags(self,?index):????????defaultFlags?=?QStringListModel.flags(self,index)????????????????if?index.isValid():????????????return?Qt.ItemIsDragEnabled?|?Qt.ItemIsDropEnabled?|?defaultFlags????????else:????????????return?Qt.ItemIsDropEnabled?|?defaultFlags????????????def?mimeTypes(self):????????return?['application/vnd.text.list']????????def?mimeData(self,?indexes):????????mmData?=?QMimeData()????????encodedData?=?QByteArray()????????stream?=?QDataStream(encodedData,?QIODevice.WriteOnly)????????????????for?index?in?indexes:????????????if?index.isValid():????????????????text?=?self.data(index,?Qt.DisplayRole)????????????????stream.writeQString(str(text))????????????????????????mmData.setData('application/vnd.text.list',?encodedData)????????return?mmData????????def?canDropMimeData(self,?data,?action,?row,?column,?parent):????????if?data.hasFormat('application/vnd.text.list')?is?False:????????????return?False????????if?column?>?0:????????????return?False???????????????return?True????????def?dropMimeData(self,?data,?action,?row,?column,?parent):????????if?self.canDropMimeData(data,?action,?row,?column,?parent)?is?False:????????????return?False????????????????if?action?==?Qt.IgnoreAction:????????????return?True????????????????beginRow?=?-1????????if?row?!=?-1:????????????beginRow?=?row????????elif?parent.isValid():????????????beginRow?=?parent.row()????????else:????????????beginRow?=?self.rowCount(QModelIndex())????????????????????encodedData?=?data.data('application/vnd.text.list')????????stream?=?QDataStream(encodedData,?QIODevice.ReadOnly)????????newItems=[]????????rows?=?0????????????????while?stream.atEnd()?is?False:????????????text?=?stream.readQString()????????????newItems.append(str(text))????????????rows?+=?1????????????????????self.insertRows(beginRow,?rows,?QModelIndex())????????for?text?in?newItems:????????????idx?=?self.index(beginRow,?0,?QModelIndex())????????????self.setData(idx,?text)????????????beginRow?+=?1????????????????????return?True?????????????class?DemoDragDrop(QMainWindow):????def?__init__(self,?parent=None):????????super(DemoDragDrop,?self).__init__(parent)????????????????????#?設置窗口標題????????self.setWindowTitle('實戰PyQt5:?Model-View框架?拖放?演示')??????????????#?設置窗口大小????????self.resize(480,?320)??????????????self.initUi()????????????def?initUi(self):????????listView?=?QListView(self)????????listView.setSelectionMode(QAbstractItemView.ExtendedSelection)????????listView.setDragEnabled(True)????????listView.setAcceptDrops(True)????????listView.setDropIndicatorShown(True)????????????????ddm?=?DragDropListModel()????????ddm.setStringList(['Item?1',?'Item?2',?'Item?3',?'Item?4'])????????listView.setModel(ddm)????????????????self.setCentralWidget(listView)????if?__name__?==?'__main__':????app?=?QApplication(sys.argv)????window?=?DemoDragDrop()????window.show()????sys.exit(app.exec())??運行結果如下圖:
視圖中條目的拖放功能演示
本文知識點
- 啟動MV框架視圖類的拖放功能;
- 設置項的拖放操作;
- 編碼導出數據;
- 將數據插入到釋放的位置;
- 解碼導入數據。
喜歡本文內容就關注, 收藏,點贊,評論和轉發。
總結
以上是生活随笔為你收集整理的winform listview 设置选中项 图片_实战PyQt5: 069-MV框架中的项视图拖放功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浏览器快捷键_干货 | 掌握这些快捷键,
- 下一篇: 全排列代码python_python全排