def get_view_for_submodel(submodel): main_widget = QWidget() hbox_layout = QHBoxLayout(main_widget) vbox_layout = QVBoxLayout() table_view = QTableView() table_view.setSelectionBehavior(QAbstractItemView.SelectRows) table_view.setSelectionMode(QAbstractItemView.SingleSelection) table_view.setModel(submodel) add_button = QPushButton("+") add_button.clicked.connect(lambda: add_item_to_model(submodel)) remove_button = QPushButton("-") remove_button.clicked.connect( lambda: remove_item_from_model(submodel, table_view)) vbox_layout.addWidget(add_button) vbox_layout.addWidget(remove_button) vbox_layout.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) hbox_layout.addWidget(table_view) hbox_layout.addLayout(vbox_layout) return main_widget
def setupTabs(self): """ Setup the various tabs in the AddressWidget. """ groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ"] for group in groups: proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) tableView = QTableView() tableView.setModel(proxyModel) tableView.setSortingEnabled(True) tableView.setSelectionBehavior(QAbstractItemView.SelectRows) tableView.horizontalHeader().setStretchLastSection(True) tableView.verticalHeader().hide() tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) tableView.setSelectionMode(QAbstractItemView.SingleSelection) # This here be the magic: we use the group name (e.g. "ABC") to # build the regex for the QSortFilterProxyModel for the group's # tab. The regex will end up looking like "^[ABC].*", only # allowing this tab to display items where the name starts with # "A", "B", or "C". Notice that we set it to be case-insensitive. reFilter = "^[%s].*" % group proxyModel.setFilterRegExp(QRegExp(reFilter, Qt.CaseInsensitive)) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) # This prevents an application crash (see: http://www.qtcentre.org/threads/58874-QListView-SelectionModel-selectionChanged-Crash) viewselectionmodel = tableView.selectionModel() tableView.selectionModel().selectionChanged.connect( self.selectionChanged) self.addTab(tableView, group)
def setupTabs(self): """ Setup the various tabs in the AddressWidget. """ groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ"] for group in groups: proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) tableView = QTableView() tableView.setModel(proxyModel) tableView.setSortingEnabled(True) tableView.setSelectionBehavior(QAbstractItemView.SelectRows) tableView.horizontalHeader().setStretchLastSection(True) tableView.verticalHeader().hide() tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) tableView.setSelectionMode(QAbstractItemView.SingleSelection) # This here be the magic: we use the group name (e.g. "ABC") to # build the regex for the QSortFilterProxyModel for the group's # tab. The regex will end up looking like "^[ABC].*", only # allowing this tab to display items where the name starts with # "A", "B", or "C". Notice that we set it to be case-insensitive. reFilter = "^[%s].*" % group proxyModel.setFilterRegExp(QRegExp(reFilter, Qt.CaseInsensitive)) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) # This prevents an application crash (see: http://www.qtcentre.org/threads/58874-QListView-SelectionModel-selectionChanged-Crash) viewselectionmodel = tableView.selectionModel() tableView.selectionModel().selectionChanged.connect(self.selectionChanged) self.addTab(tableView, group)
class AddressWidget(QDialog): selectionChanged = Signal(QItemSelection) def __init__(self, parent=None): super(AddressWidget, self).__init__(parent) self.tableModel = TableModel() self.tableView = QTableView() self.setupTable() statusLabel = QLabel("Tabular data view demo") layout = QVBoxLayout() layout.addWidget(self.tableView) layout.addWidget(statusLabel) self.setLayout(layout) self.setWindowTitle("Address Book") self.resize(800,500) # add test data self.populateTestData() def setupTable(self): proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) self.tableView.setModel(proxyModel) self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().hide() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) viewselectionmodel = self.tableView.selectionModel() self.tableView.selectionModel().selectionChanged.connect(self.selectionChanged) def populateTestData(self): addresses = [{"name": "John Doe", "address": "Alameda"}, {"name": "Alan Turing", "address": "San Deigo"}, {"name": "Bjarne Stroutsup", "address": "Columbia"}, {"name": "Herb Sutter", "address": "Seattle"}, {"name": "Micheal Konin", "address": "Colorado"}] for i in range(len(addresses)): self.tableModel.insertRows(0) ix = self.tableModel.index(0, 0, QModelIndex()) self.tableModel.setData(ix, addresses[i]["name"], Qt.EditRole) ix = self.tableModel.index(0, 1, QModelIndex()) self.tableModel.setData(ix, addresses[i]["address"], Qt.EditRole) self.tableView.resizeRowToContents(ix.row())
class ScoresWidget(QDockWidget): """Widget that display a solution scores.""" def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Scores") # Build widgets self.search_field = QLineEdit(self) self.checkbox_positive = QCheckBox("Positive", self) self.checkbox_positive.setChecked(True) self.checkbox_negative = QCheckBox("Negative", self) self.checkbox_negative.setChecked(True) self.checkbox_neutral = QCheckBox("Neutral", self) self.table = QTableView(self) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) # Build layout layout_header = QHBoxLayout() layout_header.addWidget(self.search_field) layout_header.addWidget(self.checkbox_positive) layout_header.addWidget(self.checkbox_negative) layout_header.addWidget(self.checkbox_neutral) layout_main = QVBoxLayout() layout_main.addLayout(layout_header) layout_main.addWidget(self.table) main_widget = QWidget(self) main_widget.setLayout(layout_main) self.setWidget(main_widget) # Configure models self.model = PointsTableModel(self) self._proxy_model = ScoreProxyModel() self._proxy_model.setSourceModel(self.model) self._proxy_model.sort( 1, Qt.AscendingOrder) # sort by lowest score by default # Configure table self.table.setModel(self._proxy_model) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # Connect signals for signal, callback in ( (self.search_field.textChanged, self._proxy_model.setFilterWildcard), (self.checkbox_positive.stateChanged, self._proxy_model.set_positive), (self.checkbox_negative.stateChanged, self._proxy_model.set_negative), (self.checkbox_neutral.stateChanged, self._proxy_model.set_neutral), ): signal.connect(callback)
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
def __init__(self, data_list, header, *args): QWidget.__init__(self, *args) # setGeometry(x_pos, y_pos, width, height) self.setGeometry(300, 200, 570, 450) self.setWindowTitle('Click on column title to sort') # Setup the model and view '''tmodel = MyTableModel(self, data_list, header) tview = QTableView() tview.setModel(tmodel) delegate = MyDelegate() tview.setItemDelegate(delegate)''' # Setup the proxy model for sorting and filtering tmodel = MyTableModel(self, data_list, header) pmodel = QSortFilterProxyModel() pmodel.setSourceModel(tmodel) tview = QTableView() tview.setModel(pmodel) delegate = MyDelegate() tview.setItemDelegate(delegate) # TableView properties tview.resizeColumnsToContents() # set column width to fit contents tview.setShowGrid(False) # hide gridlines #tview.verticalHeader().hide() # row labels #tview.horizontalHeader().hide() # column labels # Select a single row at a time tview.setSelectionBehavior(QTableView.SelectRows) tview.setSelectionMode(QTableView.SingleSelection) # Enable sorting tview.setSortingEnabled(True) # Drag and drop reordering using header labels '''tview.verticalHeader().setSectionsMovable(True) tview.verticalHeader().setDragEnabled(True) tview.verticalHeader().setDragDropMode(QAbstractItemView.InternalMove) tview.horizontalHeader().setSectionsMovable(True) tview.horizontalHeader().setDragEnabled(True) tview.horizontalHeader().setDragDropMode(QAbstractItemView.InternalMove)''' # Drag and drop reordering using rows tview.setDragEnabled(True) tview.setAcceptDrops(True) tview.setDragDropMode(QTableView.InternalMove) tview.setDragDropOverwriteMode(False) layout = QVBoxLayout(self) layout.addWidget(tview) self.setLayout(layout)
def _create_device_table(self) -> QTableView: device_table = QTableView() device_table.setModel(self._device_model) device_table.setSelectionBehavior(QAbstractItemView.SelectRows) device_table.setSelectionMode(QAbstractItemView.SingleSelection) device_table.selectionModel().selectionChanged.connect( self._on_device_table_selection_changed) horizontal_header = device_table.horizontalHeader() vertical_header = device_table.verticalHeader() horizontal_header.setSectionResizeMode(QHeaderView.ResizeToContents) vertical_header.setSectionResizeMode(QHeaderView.ResizeToContents) horizontal_header.setStretchLastSection(True) return device_table
class WorkSpaceWidget(QWidget): def __init__(self, parent, file_clicked): super().__init__(parent) self.main_layout = QVBoxLayout() # Tool Bar self.toolbar = QToolBar(self) # delete action on toolbar self.delete_action_tb = QAction("DELETE TABLE ROW", self) self.delete_action_tb.setStatusTip("Obrisi Red U Tabeli") self.delete_action_tb.triggered.connect(self.delete_table_row_tb) self.toolbar.addAction(self.delete_action_tb) # ADD ONE TOOLBAR BUTTON self.add_one_action_tb = QAction("ADD TABLE ROW", self) self.add_one_action_tb.setStatusTip("ADD SINGLE ROW TO TABLE") self.add_one_action_tb.triggered.connect(self.add_table_row_handler) self.toolbar.addAction(self.add_one_action_tb) self.setLayout(self.main_layout) self.file_clicked = file_clicked self.abstract_table_model = AbstractTableModel(self.file_clicked) self.database_type = self.abstract_table_model.database_type self.create_tab_widget() self.check_database_type_and_run() self.tab_widget.addTab(self.main_table, QIcon("img/iconXLNK.png"), self.file_clicked) self.main_layout.addWidget(self.toolbar) self.main_layout.addWidget(self.tab_widget) # TODO Srediti da funkcija bise element iz tabele klikom na dugme delete u ToolBar-u. def delete_table_row_tb(self): print("Ugraditi funkciju za brisanje reda iz tabele.") # TODO srediti dodavnje u tabelu. def add_table_row_handler(self): self.addWindow = InsertOneForm( self.abstract_table_model.file_handler.metadata[0]["columns"], self.check_data) self.main_layout.addWidget(self.addWindow) # chekiranje validnosti podataka def check_data(self): self.return_data = self.addWindow.final_data self.return_metadata = self.addWindow.metadata_columns not_valid = False i = 0 for data in self.return_data: if data.get(self.return_metadata[i]) == "" or data.get( self.return_metadata[i]) == " " or data.get( self.return_metadata[i]) == None: print("Nije uredu") not_valid = True else: print("sve ok") i += 1 if not_valid != True: self.new_instanc = SmartPhone(self.return_data[0]["brand"], self.return_data[1]["model"], self.return_data[2]["price"], self.return_data[3]["made_in"], self.return_data[4]["dealer"], self.return_data[5]["imei_code"], self.return_data[6]["stores"]) self.abstract_table_model.file_handler.insert(self.new_instanc) def check_database_type_and_run(self): if self.database_type == "serial" or self.database_type == "sequential": self.create_table() else: # TODO Obraditi izuzetak. pass def create_tab_widget(self): self.tab_widget = QTabWidget(self) self.tab_widget.setTabsClosable(True) def create_table(self): self.main_table = QTableView(self.tab_widget) self.main_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.main_table.setSelectionMode(QAbstractItemView.SingleSelection) self.main_table.setModel(self.abstract_table_model) # makes responsive tabel sizes max_width = 1620 // self.abstract_table_model.column_number() for width in range(self.abstract_table_model.column_number()): self.main_table.setColumnWidth(width, max_width)
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)
class MetricsDialog(PluginDialog): ENABLE = True def __init__(self, conn=None, parent=None): super().__init__(parent) self.conn = conn self.view = QTableView() self.model = MetricModel() self.buttons = QDialogButtonBox(QDialogButtonBox.Ok) self.view.setModel(self.model) self.view.setAlternatingRowColors(True) self.view.horizontalHeader().hide() self.view.verticalHeader().hide() self.view.setSelectionMode(QAbstractItemView.SingleSelection) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.buttons.accepted.connect(self.accept) self.setWindowTitle(self.tr("Project metrics")) v_layout = QVBoxLayout() v_layout.addWidget(self.view) v_layout.addWidget(self.buttons) self.setLayout(v_layout) # Async stuff self.metrics_runnable = None self.populate() def populate(self): """Async implementation to populate the view Notes: When closing the dialog window, the thread is not stopped. """ def compute_metrics(conn): """Async function""" return { "variants": get_variant_count(conn), "snps": get_snp_count(conn), "transitions": get_variant_transition(conn), "transversions": get_variant_transversion(conn), "samples": get_sample_count(conn), } self.model.add_metrics(self.tr("Loading..."), self.tr("data...")) self.metrics_runnable = SqlRunnable(self.conn, compute_metrics) self.metrics_runnable.finished.connect(self.loaded) QThreadPool.globalInstance().start(self.metrics_runnable) def loaded(self): """Called at the end of the thread and populate data""" results = self.metrics_runnable.results self.model.clear() ratio = results["transitions"] / results["transversions"] self.model.add_metrics("Variant count", results["variants"]) self.model.add_metrics("Snp count", results["snps"]) self.model.add_metrics("Transition count", results["transitions"]) self.model.add_metrics("Transversion count", results["transversions"]) self.model.add_metrics("Tr/tv ratio", ratio) self.model.add_metrics("Sample count", results["variants"]) self.view.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.view.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch)
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 AddressWidget(QDialog): selectionChanged = Signal(QItemSelection) def __init__(self, parent=None): super(AddressWidget, self).__init__(parent) self.tableModel = TableModel() self.tableView = QTableView() self.setupTable() statusLabel = QLabel("Tabular data view demo") layout = QVBoxLayout() layout.addWidget(self.tableView) layout.addWidget(statusLabel) self.setLayout(layout) self.setWindowTitle("Address Book") self.resize(800, 500) # add test data self.populateTestData() def setupTable(self): proxyModel = QSortFilterProxyModel(self) proxyModel.setSourceModel(self.tableModel) proxyModel.setDynamicSortFilter(True) self.tableView.setModel(proxyModel) self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().hide() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) proxyModel.setFilterKeyColumn(0) # Filter on the "name" column proxyModel.sort(0, Qt.AscendingOrder) viewselectionmodel = self.tableView.selectionModel() self.tableView.selectionModel().selectionChanged.connect( self.selectionChanged) def populateTestData(self): addresses = [{ "name": "John Doe", "address": "Alameda" }, { "name": "Alan Turing", "address": "San Deigo" }, { "name": "Bjarne Stroutsup", "address": "Columbia" }, { "name": "Herb Sutter", "address": "Seattle" }, { "name": "Micheal Konin", "address": "Colorado" }] for i in range(len(addresses)): self.tableModel.insertRows(0) ix = self.tableModel.index(0, 0, QModelIndex()) self.tableModel.setData(ix, addresses[i]["name"], Qt.EditRole) ix = self.tableModel.index(0, 1, QModelIndex()) self.tableModel.setData(ix, addresses[i]["address"], Qt.EditRole) self.tableView.resizeRowToContents(ix.row())
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 BaseList(BasePage): """ Generic table viewer widget. Subclasses should set the model_class attribute to a subclass of BaseListModel. If a subclass defines an open_item method that accepts one argument, when an item in the table is clicked on, that method will be called with the ID of the clicked item. Alternatively, if the details_class attribute is set to a tab page widget class, that will be used to open the item. """ def __init__(self, *args, **kwargs): self._model = self.model_class() self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self._model) layout = QVBoxLayout() self.table_view = QTableView() self.table_view.setModel(self.proxy_model) self.table_view.setSortingEnabled(True) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.doubleClicked.connect(self.table_double_clicked) layout.addWidget(self.table_view) self.extra_data = dict() super().__init__(*args, **kwargs) self.setLayout(layout) def table_double_clicked(self, index): """ Called when the QTableView is double clicked. If the open_item() method is defined, call it and pass the ID of the item that was clicked on. Args: The QModelIndex passed by the table_view.doubleClicked signal. """ if hasattr(self, "open_item"): # TODO: Figure out a better way to get the ID besides assuming that # it's in the first (or any) column id_index = index.siblingAtColumn(0) try: data_id = int(index.model().itemData(id_index)[0]) self.open_item(data_id) except ValueError: pass def open_item(self, data_id): """ If the details_class attribute is defined, use it to open a Details tab for the specified item. """ if hasattr(self, "details_class"): self.details_class.create_or_focus(self.gui, data_id) @property def data(self): """The page's current data set (a 2-dimensional sequence).""" return self._model.dataset @data.setter def data(self, data): self._model.populate(data) self.proxy_model.invalidate() @property def tab_name(self): """ The name of the tab page. Determined by the tab_name_fmt attribute and the widget's current supplemental data set. """ return self.tab_name_fmt.format(**self.extra_data)
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 SydTableWidget(QtWidgets.QWidget, Ui_SydTableWidget): table_reloaded = Signal() def __init__(self, filename, table_name, parent=None): super().__init__(parent) self.setupUi(self) # internal members self._filename = filename self._table_name = table_name self._db = None self._data = None self._model = None self._filter_proxy_model = None self._header = None self._toggle_width_menus = [] self.button_reload.clicked.connect(self.slot_on_reload) self.button_view.hide() self.button_view.clicked.connect(self.slot_on_view) # initial UI # self.setAutoFillBackground(True) self.scrollArea.setVisible(False) self.button_view.setEnabled(False) # pop-up window self.w = None def table_name(self): return self._table_name def model(self): return self._model def set_data(self, data): self._data = data db = self._db table_name = self._table_name # define and set the model self._model = SydTableModel(self._filename, db, table_name, data) # remove previous widget self.table_view.setParent(None) del self.table_view # create new one self.table_view = QTableView(self) self.verticalLayout.addWidget(self.table_view) # define own header (with column filter) self._header = SydColumnFilterHeader(self.table_view) ncol = self._model.columnCount(0) # define and set the filter/sort proxy self._filter_proxy_model = SydTableSortFilterProxyModel(self._header) self._filter_proxy_model.setSourceModel(self._model) self._filter_proxy_model.setSortLocaleAware(True) self._filter_proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive) self.table_view.setModel(self._filter_proxy_model) # selection model for the button_view self.table_view.setSelectionBehavior(QTableView.SelectRows) selection = self.table_view.selectionModel() selection.selectionChanged.connect(self.on_selection_change) # set the columns filters self._header.set_filter_editors(ncol, self._filter_proxy_model) # setup the context menu self._header.setContextMenuPolicy(Qt.CustomContextMenu) self._header.customContextMenuRequested.connect( self.slot_on_column_header_popup) self._header.filterActivated.connect(self.slot_on_col_filter_changed) self.table_view.setHorizontalHeader(self._header) # remove previous col buttons c = self.layout_col_buttons.takeAt(0) while c and c.widget(): c.widget().setParent(None) del c c = self.layout_col_buttons.takeAt(0) # create new col buttons def create_lambda(icol): return lambda: self.slot_on_col_button_clicked(icol) self.col_buttons = [] for i in range(0, ncol): s = self._model._headers[i] b = QPushButton(s) # , parent=self.layout_col_buttons) b.clicked.connect(create_lambda(i)) b.setFlat(True) b.setVisible(False) self.layout_col_buttons.addWidget(b) self.col_buttons.append(b) h = QSpacerItem(878, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.layout_col_buttons.addItem(h) # create menu col width for i in range(0, ncol): b = QAction(self) b.setText('Toggle adjust width') b.setCheckable(True) b.setChecked(False) self._toggle_width_menus.append(b) # special case for first column ('id') if i == 0: b.setChecked(True) self.slot_on_auto_width_column(i) # make the area invisible first self.scrollArea.setVisible(False) # self.scrollArea.setAutoFillBackground(True) # self.table_view.setAutoFillBackground(True) self.table_view.setAlternatingRowColors(True) # initial nb of elements self.slot_on_col_filter_changed() # double click header self.table_view.horizontalHeader().sectionDoubleClicked. \ connect(self.slot_on_toggle_auto_width_column) # global filter self.edit_filter.textChanged.connect(self.slot_on_filter_changed) self.edit_filter.setClearButtonEnabled(True) # allow sorting self.table_view.setSortingEnabled(True) self._filter_proxy_model.sort(0, Qt.AscendingOrder) self._filter_proxy_model.invalidateFilter() self._header.updateGeometries() def slot_on_column_header_popup(self, pos): idx = self.table_view.horizontalHeader().logicalIndexAt(pos) menu = QMenu(self.table_view) a = QAction(self) name = self._model._col_names[idx] a.setText(f'Hide {name}') a.triggered.connect(lambda col_name=idx: self.slot_on_hide_column(idx)) b = self._toggle_width_menus[idx] b.triggered.connect( lambda col_name=idx: self.slot_on_auto_width_column(idx)) menu.addAction(a) menu.addAction(b) menu.exec_(self.table_view.mapToGlobal(pos)) def slot_on_hide_column(self, idx): # hide the column self.table_view.setColumnHidden(idx, True) # show the button self.scrollArea.setVisible(True) self.col_buttons[idx].setVisible(True) self._header.updateGeometries() def slot_on_col_button_clicked(self, idx): # show the column self.table_view.setColumnHidden(idx, False) # hide the button self.col_buttons[idx].setVisible(False) for b in self.col_buttons: if b.isVisible(): return self.scrollArea.setVisible(False) self._header.updateGeometries() def slot_on_toggle_auto_width_column(self, idx): b = self._toggle_width_menus[idx] b.setChecked(not b.isChecked()) self.slot_on_auto_width_column(idx) def slot_on_auto_width_column(self, idx): b = self._toggle_width_menus[idx] if b.isChecked(): self._header.setSectionResizeMode( idx, QtWidgets.QHeaderView.ResizeToContents) else: self._header.setSectionResizeMode( idx, QtWidgets.QHeaderView.Interactive) self._header.updateGeometries() def slot_on_col_filter_changed(self): n = self._filter_proxy_model.rowCount() t = self._model.rowCount(None) self.label_tablename.setText(f'{self._table_name}') self.label_status.setText(f'{n}/{t}') if self._table_name == 'Image' or self._table_name == 'DicomSeries': self.button_view.show() elif self._table_name == "DicomSeries_default" or self._table_name == "Image_default": self.button_view.show() def slot_on_filter_changed(self): n = self._filter_proxy_model.rowCount() t = self._model.rowCount(None) self.label_status.setText(f'{n}/{t}') f = self.edit_filter self._filter_proxy_model.set_global_filter(f.text()) def slot_on_reload(self): # later -> keep filters if the columns are identical. # not clear why I need to reopen the db here # (not needed for tables, needed for view) self._db = syd.open_db(self._filename) t = self._db.load_table(self._table_name) elements = syd.find_all(t) self.set_data(elements) # indicate that the table has been reloaded self.table_reloaded.emit() n = self._filter_proxy_model.rowCount() t = self._model.rowCount(None) self.label_status.setText(f'{n}/{t}') self.button_view.setText("view in vv") self.button_view.setEnabled(False) def slot_on_view(self): data = [] path = [] rows = set(index.row() for index in self.table_view.selectedIndexes()) for row in rows: data.append(self._data[row]) self.w = SydCTWindow(data, self._filename, self._table_name) self.w.button_ct_on.setEnabled(False) db = syd.open_db(self._filename) for d in data: e = self.w.get_ct_path(db, d) if e is not None and len(rows) == 1 and d['modality'] != 'CT': self.w.button_ct_on.setEnabled(True) self.w.show() else: if self._table_name == 'DicomSeries' or self._table_name == 'DicomSeries_default': db = syd.open_db(self._filename) dicom_file = syd.find_one(db['DicomFile'], dicom_series_id=d['id']) file = syd.find_one(db['File'], id=dicom_file['file_id']) tmp = db.absolute_data_folder + '/' + file[ 'folder'] + '/' + file['filename'] path.append(tmp) elif self._table_name == 'Image' or self._table_name == 'Image_default': db = syd.open_db(self._filename) file = syd.find_one(db['File'], id=d['file_mhd_id']) path.append(db.absolute_data_folder + '/' + file['folder'] + '/' + file['filename']) else: print('La table séléctionnée ne correspond pas') if path != []: path = ' '.join(path) cmd = f'vv {path}' os.system(cmd) else: print('Path to image has no corresponding file') def on_selection_change(self): rows = set(index.row() for index in self.table_view.selectedIndexes()) if len(rows) == 0: self.button_view.setEnabled(False) self.button_view.setText("view in vv") else: t = self._model.rowCount(None) self.button_view.setText(f"view in vv {len(rows)}/{t}") self.button_view.setEnabled(True)
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 DictWidget(QWidget): def __init__(self, parent=None): super().__init__() self.view = QTableView() self.model = DictModel() self.proxy_model = QSortFilterProxyModel() self.search_bar = QLineEdit() self._show_loading = False self.proxy_model.setSourceModel(self.model) self.view.setModel(self.proxy_model) self.view.setAlternatingRowColors(True) self.view.horizontalHeader().setStretchLastSection(True) self.view.setSelectionMode(QAbstractItemView.SingleSelection) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSortingEnabled(True) self.view.verticalHeader().hide() self.search_bar.textChanged.connect( self.proxy_model.setFilterRegularExpression) self.search_bar.setVisible(False) self._show_search_action = QAction("show search bar") self._show_search_action.setCheckable(True) self._show_search_action.setShortcutContext(Qt.WidgetShortcut) self._show_search_action.setShortcut(QKeySequence.Find) self._show_search_action.triggered.connect(self._on_show_search) self._close_search_action = QAction() self._close_search_action.setShortcut(QKeySequence(Qt.Key_Escape)) self._close_search_action.setShortcutContext(Qt.WidgetShortcut) self._close_search_action.triggered.connect(self._on_close_search) self.view.addAction(self._show_search_action) self.search_bar.addAction(self._close_search_action) _layout = QVBoxLayout() _layout.addWidget(self.view) _layout.addWidget(self.search_bar) _layout.setContentsMargins(0, 0, 0, 0) self.setLayout(_layout) print("init") def set_dict(self, data: dict): self.model.set_dict(data) def _on_show_search(self): self.search_bar.setVisible(True) self.search_bar.setFocus(Qt.ShortcutFocusReason) def _on_close_search(self): self.search_bar.hide() self.search_bar.clear() self.view.setFocus(Qt.ShortcutFocusReason) def set_header_visible(self, visible=True): self.view.horizontalHeader().setVisible(visible) def clear(self): self.model.clear() def paintEvent(self, event: QPaintEvent): if self._show_loading: painter = QPainter(self) painter.drawText(self.rect(), Qt.AlignCenter, self.tr("Loading ...")) else: super().paintEvent(event) def set_loading(self, show=True): self._show_loading = True self.view.setVisible(not show) self.update()