本想找一个拖放实现分类的app,竟然没有找到,现在想用QTableWidget表格实现,
用到了全局数据,实在太丑了了;在列和列之间拖动单元格
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QDropEvent
from PyQt5.QtWidgets import QTableWidget, QAbstractItemView, QTableWidgetItem, QWidget, QHBoxLayout,QGridLayout, QApplication,QCheckBox
from PyQt5 import QtCore, QtGui, QtWidgets
def transpose_2dA(data,padd=0):
if padd:
ln=[len(row) for row in data]
ln=max(ln)
#transposed = [[row[col] if col<len(row) else '' for row in data] for col in range(ln)]
data2=[data[ii]+['']*(ln-len(data[ii])) for ii in range(len(data))]
transposed = [[row[col] for row in data2] for col in range(ln)]
else:
transposed = [[row[col] for row in data] for col in range(len(data[0]))]
return transposed
def maxminfun(vv,mn,mx):
if vv<mn:
return mn
if vv>mx:
return mx
return vv
globaldata=[]
fgMoveAction=0
class TableWidgetDragRows(QTableWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.viewport().setAcceptDrops(True)
self.setDragDropOverwriteMode(False)
self.setDropIndicatorShown(True)
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.setSelectionBehavior(QAbstractItemView.SelectItems)#(QAbstractItemView.SelectRows)
self.setDragDropMode(QAbstractItemView.InternalMove)
def dropEvent(self, event: QDropEvent):
global globaldata,fgMoveAction
if not event.isAccepted() and event.source() == self:
drop_row,drop_col = self.drop_on(event)
if drop_col<0: return
cc=list(set(item.column() for item in self.selectedItems()))
if len(cc)>1: return #单列
drag_col=cc[0]
rows = sorted(set(item.row() for item in self.selectedItems()))
if rows[-1]!=rows[0]+len(rows)-1: return #连续单元 简化算法
drag_row=rows[0]
data=transpose_2dA(globaldata,padd=1)
if drag_col==drop_col:
datacol=data[drop_col]
if drag_row>drop_row:
datacol=datacol[:drop_row]+datacol[rows[0]:rows[-1]+1]+datacol[drop_row:rows[0]]+datacol[rows[-1]+1:]
else:
datacol=datacol[:rows[0]]+datacol[rows[-1]+1:drop_row]+datacol[rows[0]:rows[-1]+1]+datacol[drop_row:]
data[drop_col]=datacol
else:
datacol=data[drop_col]
datacol=datacol[:drop_row]+data[drag_col][rows[0]:rows[-1]+1]+datacol[drop_row:]
data[drop_col]=datacol
if fgMoveAction:
datacol=data[drag_col]
datacol=datacol[:rows[0]]+datacol[rows[-1]+1:]
data[drag_col]=datacol
globaldata=transpose_2dA(data,padd=1)
#debug_trace()
event.accept()
print(globaldata)
self.setRowCount(len(globaldata))
for row, data in enumerate(globaldata):
for col, txt in enumerate(data):
self.setItem(row, col, QTableWidgetItem(txt))
super().dropEvent(event)
#self.show()
def drop_on(self, event):
index = self.indexAt(event.pos())
cc=index.column()
if cc>=self.columnCount():
cc=-1
rr=maxminfun(index.row(),0,self.rowCount())
return rr,cc
def is_below(self, pos, index):
rect = self.visualRect(index)
margin = 2
if pos.y() - rect.top() < margin:
return False
elif rect.bottom() - pos.y() < margin:
return True
# noinspection PyTypeChecker
return rect.contains(pos, True) and not (int(self.model().flags(index)) & Qt.ItemIsDropEnabled) and pos.y() >= rect.center().y()
class Window(QWidget):
def __init__(self):
global globaldata,fgMoveAction
super(Window, self).__init__()
self.hlayout = QGridLayout()#QHBoxLayout()
self.setLayout(self.hlayout)
self.table_widget = TableWidgetDragRows()
self.btnmyquit = QtWidgets.QPushButton('quit')
self.btnmyquit.clicked.connect(self.myquit_fun)
self.btnadditems = QtWidgets.QPushButton('add items')
self.btnadditems.clicked.connect(self.btnadditems_fun)
self.btnloadlst = QtWidgets.QPushButton('loadlist')
self.btnloadlst.clicked.connect(self.btnloadlst_fun)
self.btnloadfile = QtWidgets.QPushButton('loadfile')
self.btnloadfile.clicked.connect(self.btnloadfile_fun)
self.movecheckbox=QCheckBox('move') #
self.movecheckbox.stateChanged.connect(self.movecheckboxfun)
self.hlayout.addWidget(self.table_widget, 1, 0,15,36)
self.hlayout.addWidget(self.btnloadlst, 36, 0,1,1)
self.hlayout.addWidget(self.btnadditems, 36, 2,1,1)
self.hlayout.addWidget(self.btnloadfile, 36, 3,1,1)
self.hlayout.addWidget(self.movecheckbox, 36, 5,1,1)
self.hlayout.addWidget(self.btnmyquit, 36, 6,1,1)
# setup table widget
self.table_widget.setColumnCount(2)
self.table_widget.setHorizontalHeaderLabels(['Type', 'Name'])
self.data = [['Red', 'Toyota'], ['Blue', 'RV'], ['Green', 'Beetle'], ['Silver', 'Chevy'], ['Black', 'BMW']]
self.table_widget.setRowCount(len(self.data))
globaldata=self.data
for i, [color, model] in enumerate(self.data):
self.table_widget.setItem(i, 0, QTableWidgetItem(color))
self.table_widget.setItem(i, 1, QTableWidgetItem(model))
self.resize(400, 400)
self.show()
def movecheckboxfun(self):
global fgMoveAction
fgMoveAction=self.movecheckbox.isChecked()
def btnadditems_fun(self):
pass
def btnloadlst_fun(self):
pass
def btnloadfile_fun(self):
pass
def myquit_fun(self):
app.instance().quit()
sys.exit()#退出 quit
#自定义右键按钮
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
其实一开始不必太在意代码的美丑,能跑起来,能满足需求是最重要的。
跑起来之后,可以开始思考如何让代码更优雅简洁,这一步通常也称为重构,重构完成意味着更好的可维护性,有时也意味着更好的性能。
开始重构之前,最好先写一些测试用例,避免重构完成之后出现意想不到的bug。有了测试用例,重构起来也会更有信心,不会束手束脚。
重构一般可以专注于这几个方面: