class MainWindow(QMainWindow): def __init__(self): super().__init__() self.view = QTableView() self.view.horizontalHeader().hide() self.view.verticalHeader().hide() self.view.setGridStyle(Qt.NoPen) delegate = PreviewDelegate() self.view.setItemDelegate(delegate) self.model = PreviewModel() self.view.setModel(self.model) self.setCentralWidget(self.view) # Add a bunch of images. image_files = glob.glob("*.jpg") for n, fn in enumerate(image_files): image = QImage(fn) item = preview(n, fn, image) self.model.previews.append(item) self.model.layoutChanged.emit() self.view.resizeRowsToContents() self.view.resizeColumnsToContents()
class DebugBreakpointsWidget(QWidget, DockContextHandler): def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugBreakpointsListModel(self.table, data) self.table.setModel(self.model) self.item_delegate = DebugBreakpointsItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth(i, self.item_delegate.sizeHint(self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.table) self.setLayout(layout) def notifyOffsetChanged(self, offset): pass def notifyBreakpointsChanged(self, new_rows): self.model.update_rows(new_rows) def contextMenuEvent(self, event): self.m_contextMenuManager.show(self.m_menu, self.actionHandler) def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True
class SQLite(QSqlDatabase): """ Класс для инициализации и открытия базы данных каталога, полученный из Slot'а (openFile) """ def __init__(self, path=None): """ Инициализация экземпляра класса :param path: путь до каталога, полученный изиз Slot'а (openFile) """ super().__init__() self.path = path self.width = 0 self.heigh = 0 self.db = QSqlDatabase.addDatabase('QSQLITE') self.db.setDatabaseName(self.path) self.db.open() self.window = QWidget() self.window.setWindowTitle("Каталог книг") self.conn = sqlite3.connect(self.path) cursor = self.conn.cursor() sql = f'select * from sqlite_master where type = "table"' # получение имени таблицы(первая в списке), к которой будет # осуществлено подключение cursor.execute(sql) self.search_result = cursor.fetchall()[0][1] self.model = QSqlTableModel(parent=self.window, db=self.db) self.model.setTable(self.search_result) self.db_record = QSqlRecord(self.db.record(self.search_result)) self.tableView = QTableView() def on(self): """ Метод для подключения и отображения подключенного каталога :return: виджет self.window """ self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.select() self.model.setHeaderData(-1, Qt.Horizontal, self.db_record.fieldName(0)) vbox = QVBoxLayout() self.tableView.setModel(self.model) self.tableView.resizeColumnsToContents() self.tableView.resizeRowsToContents() for i in range(self.model.columnCount() + 2): self.width += self.tableView.columnWidth(i) for j in range(self.model.rowCount() + 1): self.heigh += self.tableView.rowHeight(j) self.tableView.resize(self.width + 50, self.heigh + 50) vbox.addWidget(self.tableView) self.window.setLayout(vbox) self.window.resize(self.tableView.width() + 30, self.tableView.height() + 120) return self.window
def table_insert(self, TableModel: TableModel, TableView: QtWidgets.QTableView): print('Inserting a row into table.') # get selected row index selected_indexes = TableView.selectionModel().selectedIndexes() selected_row_index = selected_indexes[-1].row() print(f'row index {selected_row_index}.') # insert TableModel.insertRow(selected_row_index) print(TableView == self.ui.tableView_emitters) TableView.model().layoutChanged.emit() TableView.resizeRowsToContents() self.repaint()
def table_remove(self, TableModel: TableModel, TableView: QtWidgets.QTableView): if TableModel.rowCount(TableView) <= 1: raise ValueError('Not enough rows to delete.') # get selected row index selected_indexes = TableView.selectionModel().selectedIndexes() if len(selected_indexes) > 1: selected_row_index = selected_indexes[-1].row() else: selected_row_index = selected_indexes[0].row() # remove TableModel.removeRow(selected_row_index) TableView.model().layoutChanged.emit() TableView.resizeRowsToContents() self.repaint()
def test(): class XTest( XBase ): def __init__( self ): XBase.__init__( self ) self.name = "" self.vorname = "" self.alter = 0 self.haarfarbe = "" self.schuhgroesse = 0 self.bemerkung = "" x1 = XTest() x1.name = "Kendel" x1.vorname = "Martin" x1.alter = 66 x1.haarfarbe = "grau" x1.schuhgroesse = 44 x1.bemerkung = "Das ist alles \nein riesengroßer Irrtum" x2 = XTest() x2.name = "Haaretz" x2.vorname = "Yosh" x2.alter = 56 x2.haarfarbe = "schwarz" x2.schuhgroesse = 42 tm = DefaultIccTableModel( (x1, x2 ) ) tm.setSortable( True ) tm.setKeyHeaderMappings( { "Nachname": "name", "Vorname": "vorname", "Alter": "alter", "Bemerkung": "bemerkung" } ) tm.setNumColumnsIndexes( (2,) ) from PySide2.QtWidgets import QApplication app = QApplication() tv = QTableView( ) tv.setModel( tm ) tv.setAlternatingRowColors( True ) tv.setSortingEnabled( True ) tv.resizeColumnsToContents() tv.resizeRowsToContents() tm.layoutChanged.connect( tv.resizeRowsToContents ) ## <======== WICHTIG bei mehrzeiligem Text in einer Zelle! tv.show() app.exec_()
class DebugThreadsWidget(QWidget, DockContextHandler): def __init__(self, parent, name, data): if not type(data) == BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugThreadsListModel(self.table) self.table.setModel(self.model) self.table.clicked.connect(self.threadRowClicked) self.item_delegate = DebugThreadsItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth(i, self.item_delegate.sizeHint(self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.table) self.setLayout(layout) def notifyOffsetChanged(self, offset): pass # called from QTableView's clicked signal # index: QModelIndex def threadRowClicked(self, index): index = self.model.createIndex(index.row(), 0) tid_str = self.model.data(index, Qt.DisplayRole) #print('clicked to change to thread %s' % tid_str) stateObj = binjaplug.get_state(self.bv) if stateObj.connected and not stateObj.running: tid = int(tid_str, 16) stateObj.threads.current = tid stateObj.ui.context_display() stateObj.ui.on_step() else: print('cannot set thread in current state') # called from plugin's context_display() function def notifyThreadsChanged(self, new_threads): idx_selected = self.model.update_rows(new_threads) if idx_selected: self.table.setCurrentIndex(idx_selected) def contextMenuEvent(self, event): self.m_contextMenuManager.show(self.m_menu, self.actionHandler) def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True
class TreeCard(QDialog): def __init__(self, db=0, mode=0): super().__init__() layout = QGridLayout() #self.central_widget.setLayout(layout) self.resize(800, self.height()) self.lb_find = QInvisibleButton('Поиск') self.lb_find.setFont(mainfont) self.te_find = QLineEdit() self.te_find.setFont(mainfont) self.pid = 0 layout.addWidget(self.te_find, 0, 0, 1, 1) layout.addWidget(self.lb_find, 0, 0, 1, 1) #if mode: # te.setReadOnly(False) self.lb_find.clicked.connect(self.button_pressed) self.te_find.returnPressed.connect(self.line_edit_return_pressed) self.database = db self.table = QTableView() # Создаём таблицу self.table.doubleClicked.connect(self.viewPerson) #self.table = table self.model = TableModel(self.database.get_peoples()) self.table.setModel(self.model) self.table.resizeRowsToContents() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) #self.table.setSelectionMode(QAbstractItemView.SingleSelection); self.model.dataChanged.connect(self.table.update) layout.addWidget(self.table) self.setLayout(layout) def viewPerson(self): select = self.table.selectionModel() pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: self.pid = int(pid_list[0]) print(int(pid_list[0])) self.accept() return 0 def button_pressed(self): #sender = self.sender() self.lb_find.stackUnder(self.te_find) self.te_find.setFocus() def line_edit_return_pressed(self): print(self.te_find.text()) self.model = TableModel(self.database.get_peoples()) self.proxy_model = QSortFilterProxyModel(self.model) self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterFixedString(self.te_find.text()) self.proxy_model.setFilterKeyColumn(-1) #print(self.proxy_model.filterKeyColumn()) self.table.setModel(self.proxy_model) self.table.update() self.table.resizeRowsToContents() #sender = self.sender() self.te_find.stackUnder(self.lb_find) self.lb_find.setFocus()
class DebugModulesWidget(QWidget, DockContextHandler): def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugModulesListModel(self.table, data) self.table.setModel(self.model) self.item_delegate = DebugModulesItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth( i, self.item_delegate.sizeHint( self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) update_layout = QHBoxLayout() update_layout.setContentsMargins(0, 0, 0, 0) update_label = QLabel("Data is Stale") update_button = QPushButton("Refresh") update_button.clicked.connect(lambda: self.refresh()) update_layout.addWidget(update_label) update_layout.addStretch(1) update_layout.addWidget(update_button) self.update_box = QWidget() self.update_box.setLayout(update_layout) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.layout.addWidget(self.table) self.setLayout(self.layout) def notifyOffsetChanged(self, offset): pass def refresh(self): debug_state = binjaplug.get_state(self.bv) debug_state.ui.update_modules() def notifyModulesChanged(self, new_modules): self.model.update_rows(new_modules) self.table.resizeColumnsToContents() self.layout.removeWidget(self.update_box) self.update_box.setVisible(False) def mark_dirty(self): self.layout.addWidget(self.update_box) self.update_box.setVisible(True) def contextMenuEvent(self, event): self.m_contextMenuManager.show(self.m_menu, self.actionHandler) def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True
class TdisMainForm(QMainWindow): def __init__(self, parent=None): super().__init__() self.setWindowTitle("Родословная") self.resize(800, self.height()) self.distance = 1000 self.central_widget = QWidget() self.setCentralWidget(self.central_widget) layout = QGridLayout() self.central_widget.setLayout(layout) self.lb_find = QInvisibleButton('Поиск') self.lb_find.setFont(mainfont) self.te_find = QLineEdit() self.te_find.setFont(mainfont) layout.addWidget(self.te_find, 0, 0, 1, 1) layout.addWidget(self.lb_find, 0, 0, 1, 1) #if mode: # te.setReadOnly(False) self.lb_find.clicked.connect(self.button_pressed) self.te_find.returnPressed.connect(self.line_edit_return_pressed) self.table = QTableView() # Создаём таблицу self.table.doubleClicked.connect(self.viewPerson) layout.addWidget(self.table) self.table.setFocus() timer = QTimer(self) timer.singleShot(0, self.async_init) def async_init(self): self.database = AllTables('database/objects') self.model = TableModel(self.database.get_peoples()) self.table.setModel(self.model) self.table.resizeRowsToContents() self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.model.dataChanged.connect(self.table.update) # Работаем с выпадающим меню def openMenu(position): menu = QMenu() relAction = menu.addAction('Связи') menu.addSeparator() albAction = menu.addAction('Альбомы') menu.addSeparator() miniatureAction = menu.addAction('Миниатюра') menu.addSeparator() viewAction = menu.addAction('Просмотреть') addAction = menu.addAction('Добавить') editAction = menu.addAction('Редактировать') delAction = menu.addAction('Удалить') menu.addSeparator() drawGraphAction = menu.addAction('Построить дерево') menu.addSeparator() quitAction = menu.addAction('Выход') action = menu.exec_(self.table.mapToGlobal(position)) if action == viewAction: self.viewPerson() if action == miniatureAction: p = self.get_selected_people() print('p = ' + str(p)) if p is not None: photo_ids = self.database.get_all_photo_ids(p['pid']) path = 0 if photo_ids and type(photo_ids) == type( []) and len(photo_ids) > 0: path = self.database.get_photo_path( p['pid'], photo_ids[0]) gm = GalleryMiniature(p['pid'], path) gm.exec() if action == albAction: p = self.get_selected_people() if p is not None: self.albuns = AlbumViewer(p['pid'], self.database, 1) self.albuns.show() if action == addAction: self.personal_card = PersonalCard( self.database.get_people(self.database.add_people({})), self.database, 1) self.personal_card.exec_() self.line_edit_return_pressed() if action == editAction: p = self.get_selected_people() if p is not None: self.personal_card = PersonalCard(p, self.database, 1) self.personal_card.exec_() self.line_edit_return_pressed() if action == delAction: res = QMessageBox.question( self, 'ВНИМАНИЕ!!!', "Вы действительно хотите выполнить удаление?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if res == QMessageBox.Yes: select = self.table.selectionModel() if select.hasSelection(): id_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] print(id_list) self.database.del_people(id_list) self.database.peoples.save() for pid in id_list: print('remove = ' + str(self.model.removeRow(pid))) self.line_edit_return_pressed() if action == relAction: pid = self.get_selected_pid() backup_relations = copy.deepcopy(self.database.relations) self.relation_card = RelationCard(pid, self.database, 2) if not self.relation_card.exec_(): self.database.relations = backup_relations if action == drawGraphAction: print('draw graph') #dialog = MyDialog() #dialog.exec_() #engine = dialog.engine engine = 'dot' self.gd = GraphDrawer(self.database, engine) if action == quitAction: qApp.quit() self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(openMenu) def get_selected_pid(self): pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: return int(pid_list[0]) return None def get_selected_people(self): pid_list = [ index.data() for index in self.table.selectionModel().selection().indexes() if index.column() == 0 ] if len(pid_list) == 1: return self.database.get_people(int(pid_list[0])) return None def viewPerson(self): p = self.get_selected_people() if p is not None: self.personal_card = PersonalCard(p, self.database, 0) self.personal_card.show() def button_pressed(self): self.lb_find.stackUnder(self.te_find) self.te_find.setFocus() def line_edit_return_pressed(self): print(self.te_find.text()) self.model = TableModel(self.database.get_peoples()) self.proxy_model = QSortFilterProxyModel(self.model) self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterFixedString(self.te_find.text()) self.proxy_model.setFilterKeyColumn(-1) self.table.setModel(self.proxy_model) self.table.update() self.table.resizeRowsToContents() #sender = self.sender() self.te_find.stackUnder(self.lb_find) self.lb_find.setFocus()
class DataOpenDialog(QDialog): def __init__( self, expected_columns, obligatory_columns, all_columns=None, parent: typing.Optional[PySide2.QtWidgets.QWidget] = None, ): super().__init__(parent) self.file = None self.allcolumns = all_columns if all_columns else expected_columns self.columns = expected_columns self.obligatorycolumns = obligatory_columns self.setWindowTitle('Open Data File') self.filename = QLineEdit() self.filename.setReadOnly(True) self.filename.setMinimumWidth(150) self.loadbutton = QPushButton("Load...") self.loadbutton.clicked.connect(self.file_dialog) layout_left = QVBoxLayout() filebox = QGroupBox('File') layoutf = QFormLayout() layoutf.addRow('File', self.filename) layoutf.addRow('', self.loadbutton) filebox.setLayout(layoutf) layout_left.addWidget(filebox) self.columnsbox = ColumnsGroupBox('Columns order', expected_columns=expected_columns, all_columns=all_columns) self.columnsbox.columns_changes.connect(self.on_columns_order_changed) layout_left.addWidget(self.columnsbox) layout_left.addStretch() layout_right = QVBoxLayout() previewbox = QGroupBox('File 10 lines preview') previewboxlayout = QVBoxLayout() self.preview = QTextEdit() self.preview.setReadOnly(True) self.preview.setLineWrapMode(QTextEdit.NoWrap) self.preview.setMinimumWidth(500) self.preview.setMinimumHeight(170) previewboxlayout.addWidget(self.preview) previewbox.setLayout(previewboxlayout) layout_right.addWidget(previewbox) self.tablemodel = PandasDataFrameModel(df=pd.DataFrame()) self.tableview = QTableView() self.tableview.setModel(self.tablemodel) tablebox = QGroupBox('Data preview') tableboxlayout = QVBoxLayout() self.tableview.setMinimumWidth(500) self.tableview.setMinimumHeight(250) self.tableview.setWordWrap(False) self.tableview.setShowGrid(False) tableboxlayout.addWidget(self.tableview) tablebox.setLayout(tableboxlayout) layout_right.addWidget(tablebox) layout = QHBoxLayout() layout.addLayout(layout_left) layout.addLayout(layout_right) layoutmain = QVBoxLayout() layoutmain.addLayout(layout) self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonbox.accepted.connect(self.accept) self.buttonbox.rejected.connect(self.reject) layoutmain.addWidget(self.buttonbox) self.setLayout(layoutmain) self.update_ok() @property def df(self): return self.tablemodel.df def file_dialog(self): filedialog = QFileDialog(caption='Select Data File') filedialog.setFileMode(QFileDialog.ExistingFile) if filedialog.exec(): self.file = filedialog.selectedFiles()[0] self.filename.setText(self.file) lines = [] with open(self.file) as fd: for _ in range(10): lines.append(fd.readline()) self.preview.setText(''.join(lines)) reader = DataFrameReader(self.file) self.tablemodel.set_df(reader.df) self.tablemodel.set_columns(self.columnsbox.columns) self.tableview.resizeRowsToContents() self.update_ok() @Slot() def on_columns_order_changed(self): self.tablemodel.set_columns(self.columnsbox.columns) self.update_ok() def is_ok(self): columns = set(self.tablemodel.df.columns) for c in self.obligatorycolumns: if not isinstance(c, tuple): c = (c, ) c = set(c) if c.isdisjoint(columns): return False return True def update_ok(self): self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(self.is_ok())
class RemoverDialog(QDialog): def __init__(self, parent=None): super(RemoverDialog, self).__init__(parent) self.setupUi() def setupUi(self): self.menuBar = QMenuBar() self.menuBar.show() self.pathInputBox = QLineEdit(self) self.pathInputBox.setEnabled(False) self.pathInputBox.setToolTip( 'Input a path or drag a directory here...') self.openPathButton = QPushButton('Open...', self) self.openPathButton.clicked.connect(self.openPath) inputLayout = QHBoxLayout() inputLayout.addWidget(QLabel('Path:', self)) inputLayout.addWidget(self.pathInputBox) inputLayout.addWidget(self.openPathButton) self.filterFolderCheckBox = QCheckBox('Folders', self) self.filterFolderCheckBox.setChecked(True) self.filterFolderCheckBox.toggled.connect(self.filter) self.filterFileCheckBox = QCheckBox('Files', self) self.filterFileCheckBox.setChecked(True) self.filterFileCheckBox.toggled.connect(self.filter) self.filterSuffixCheckBox = QCheckBox('Suffixes', self) self.filterSuffixCheckBox.setChecked(True) self.filterSuffixCheckBox.toggled.connect(self.filter) filterLayout = QHBoxLayout() filterLayout.addWidget(self.filterFolderCheckBox) filterLayout.addWidget(self.filterFileCheckBox) filterLayout.addWidget(self.filterSuffixCheckBox) filterLayout.addStretch() self.trashButton = QPushButton('Trash', self) self.trashButton.clicked.connect(self.trash) self.deleteButton = QPushButton('Delete', self) self.deleteButton.clicked.connect(self.delete) confirmLayout = QHBoxLayout() confirmLayout.addStretch() confirmLayout.addWidget(self.trashButton) confirmLayout.addWidget(self.deleteButton) layout = QVBoxLayout() layout.addLayout(inputLayout) layout.addLayout(filterLayout) layout.addWidget(self.createResultView()) layout.addLayout(confirmLayout) self.setAcceptDrops(True) self.setLayout(layout) self.setMinimumWidth(600) self.setWindowTitle('Remover') self.setWindowIcon(QApplication.style().standardIcon( QStyle.SP_DirIcon)) def createResultView(self): self.resultModel = ResultModel(self) self.resultView = QTableView(self) self.resultView.setSortingEnabled(True) self.resultView.setShowGrid(False) self.resultView.setAlternatingRowColors(True) self.resultView.verticalHeader().hide() self.resultView.setSelectionBehavior(QAbstractItemView.SelectRows) self.resultView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.sortFilterModel = SortFilterResultModel(self.resultModel, self) self.resultView.setModel(self.sortFilterModel) return self.resultView def dragEnterEvent(self, event): if event.mimeData().hasUrls() and len(event.mimeData().urls()) == 1: event.acceptProposedAction() def dropEvent(self, event): if event.mimeData().hasUrls() and len(event.mimeData().urls()) == 1: self.pathInputBox.setText(event.mimeData().urls()[0].toLocalFile()) self.reloadPath(self.pathInputBox.text()) def openPath(self): path = QFileDialog.getExistingDirectory( parent=self, caption='Open', options=QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) if path: self.pathInputBox.setText(path) self.reloadPath(path) def filter(self): filters = [] if self.filterFolderCheckBox.isChecked(): filters.append('folder') if self.filterFileCheckBox.isChecked(): filters.append('file') if self.filterSuffixCheckBox.isChecked(): filters.append('suffix') self.sortFilterModel.setFilterRegularExpression('|'.join(filters)) self.sortFilterModel.filterRegularExpression() self.resultView.resizeRowsToContents() def trash(self): folders, files = self.collectSelectedFolderFiles() try: for file in files: send2trash(file) for folder in folders: if QFile(folder).exists(): send2trash(folder) except: QMessageBox.warning(self, 'Failed', 'Failed to trash selected files/folders') return self.reloadPath(self.pathInputBox.text()) def delete(self): folders, files = self.collectSelectedFolderFiles() try: for file in files: os.remove(file) for folder in folders: shutil.rmtree(folder) except: QMessageBox.warning(self, 'Failed', 'Failed to delete selected files/folders') return self.reloadPath(self.pathInputBox.text()) def collectSelectedFolderFiles(self): folders, files, suffixes = [], [], [] for index in self.resultView.selectedIndexes(): if index.column() != 0: # 忽略第二列的selection continue item = self.sortFilterModel.data(index, Qt.UserRole) if 'folder' == item.type: folders.append(item.name) elif 'file' == item.type: files.append(item.name) elif 'suffix' == item.type: suffixes.append(item.name[2:]) # 将后缀符合选中条件的文件添加到files中 path = self.pathInputBox.text() iterator = QDirIterator(path, filter=QDir.Files | QDir.Dirs | QDir.Hidden | QDir.NoDotAndDotDot, flags=QDirIterator.Subdirectories) folderPaths, filePaths = set(), set() while iterator.hasNext(): file = iterator.next() if '.' == file[-1] or '..' == file[-2]: continue fileInfo = QFileInfo(file) if fileInfo.isDir(): if fileInfo.fileName() in folders: folderPaths.add(fileInfo.absoluteFilePath()) if fileInfo.isFile(): if fileInfo.fileName() in files: filePaths.add(fileInfo.absoluteFilePath()) if fileInfo.suffix() in suffixes: filePaths.add(fileInfo.absoluteFilePath()) return sorted(folderPaths), filePaths def reloadPath(self, path): self.resultModel.reload(path) self.resultView.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.resultView.horizontalHeader().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.filter() self.resultView.sortByColumn(1, Qt.DescendingOrder)