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)
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 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)
class ObjListWindow(PBDialog): """Create a window managing a list (of bibtexs or of experiments)""" def __init__(self, parent=None, gridLayout=False): """Init using parent class and create common definitions Parameters: parent: the parent object gridLayout (boolean, default False): if True, use a QGridLayout, otherwise a QVBoxLayout """ super(ObjListWindow, self).__init__(parent) self.tableWidth = None self.proxyModel = None self.gridLayout = gridLayout self.filterInput = None self.proxyModel = None self.tableview = None if gridLayout: self.currLayout = QGridLayout() else: self.currLayout = QVBoxLayout() self.setLayout(self.currLayout) def triggeredContextMenuEvent(self, row, col, event): """Not implemented: requires a subclass""" raise NotImplementedError() def handleItemEntered(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellDoubleClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def createTable(self, *args, **kwargs): """Not implemented: requires a subclass""" raise NotImplementedError() def changeFilter(self, string): """Change the filter of the current view. Parameter: string: the filter string to be matched """ self.proxyModel.setFilterRegExp(str(string)) def addFilterInput(self, placeholderText, gridPos=(1, 0)): """Add a `QLineEdit` to change the filter of the list. Parameter: placeholderText: the text to be shown when no filter is present gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.filterInput = QLineEdit("", self) self.filterInput.setPlaceholderText(placeholderText) self.filterInput.textChanged.connect(self.changeFilter) if self.gridLayout: self.currLayout.addWidget(self.filterInput, *gridPos) else: self.currLayout.addWidget(self.filterInput) self.filterInput.setFocus() def setProxyStuff(self, sortColumn, sortOrder): """Prepare the proxy model to filter and sort the view. Parameter: sortColumn: the index of the column to use for sorting at the beginning sortOrder: the order for sorting (`Qt.AscendingOrder` or `Qt.DescendingOrder`) """ self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setSourceModel(self.tableModel) self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setFilterKeyColumn(-1) self.tableview = PBTableView(self) self.tableview.setModel(self.proxyModel) self.tableview.setSortingEnabled(True) self.tableview.setMouseTracking(True) self.tableview.setSelectionBehavior(QAbstractItemView.SelectRows) try: self.tableview.sortByColumn(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.tableview.sortByColumn(sortColumn, sortOrder) try: self.proxyModel.sort(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.proxyModel.sort(sortColumn, sortOrder) self.currLayout.addWidget(self.tableview) def finalizeTable(self, gridPos=(1, 0)): """Resize the table to fit the contents, connect functions, add to layout Parameter: gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.tableview.resizeColumnsToContents() maxh = QDesktopWidget().availableGeometry().height() maxw = QDesktopWidget().availableGeometry().width() self.setMaximumHeight(maxh) self.setMaximumWidth(maxw) hwidth = self.tableview.horizontalHeader().length() swidth = self.tableview.style().pixelMetric(QStyle.PM_ScrollBarExtent) fwidth = self.tableview.frameWidth() * 2 if self.tableWidth is None: if hwidth > maxw - (swidth + fwidth): self.tableWidth = maxw - (swidth + fwidth) else: self.tableWidth = hwidth + swidth + fwidth self.tableview.setFixedWidth(self.tableWidth) self.setMinimumHeight(600) self.tableview.resizeColumnsToContents() self.tableview.resizeRowsToContents() self.tableview.entered.connect(self.handleItemEntered) self.tableview.clicked.connect(self.cellClick) self.tableview.doubleClicked.connect(self.cellDoubleClick) if self.gridLayout: self.currLayout.addWidget(self.tableview, *gridPos) else: self.currLayout.addWidget(self.tableview) def recreateTable(self): """Delete the previous table widget and other layout items, then create new ones """ self.cleanLayout() self.createTable()
class MainWindow(QMainWindow): def __init__(self): super().__init__() hlayout = QHBoxLayout() layout = QVBoxLayout() self.filtert = QLineEdit() self.filtert.setPlaceholderText("Search...") self.table = QTableView() vlayout = QVBoxLayout() vlayout.addWidget(self.filtert) vlayout.addWidget(self.table) # Left/right pane. hlayout.addLayout(vlayout) hlayout.addLayout(layout) form = QFormLayout() self.track_id = QSpinBox() self.track_id.setDisabled(True) self.track_id.setRange(0, 2147483647) self.name = QLineEdit() self.album = QComboBox() self.media_type = QComboBox() self.genre = QComboBox() self.composer = QLineEdit() self.milliseconds = QSpinBox() self.milliseconds.setRange(0, 2147483647) self.milliseconds.setSingleStep(1) self.bytes = QSpinBox() self.bytes.setRange(0, 2147483647) self.bytes.setSingleStep(1) self.unit_price = QDoubleSpinBox() self.unit_price.setRange(0, 999) self.unit_price.setSingleStep(0.01) self.unit_price.setPrefix("$") form.addRow(QLabel("Track ID"), self.track_id) form.addRow(QLabel("Track name"), self.name) form.addRow(QLabel("Composer"), self.composer) form.addRow(QLabel("Milliseconds"), self.milliseconds) form.addRow(QLabel("Bytes"), self.bytes) form.addRow(QLabel("Unit Price"), self.unit_price) self.model = QSqlTableModel(db=db) self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self.model) self.proxy_model.sort(1, Qt.AscendingOrder) self.proxy_model.setFilterKeyColumn(-1) # all columns self.table.setModel(self.proxy_model) # Update search when filter changes. self.filtert.textChanged.connect(self.proxy_model.setFilterFixedString) self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy_model) self.mapper.addMapping(self.track_id, 0) self.mapper.addMapping(self.name, 1) self.mapper.addMapping(self.composer, 5) self.mapper.addMapping(self.milliseconds, 6) self.mapper.addMapping(self.bytes, 7) self.mapper.addMapping(self.unit_price, 8) self.model.setTable("Track") self.model.select() # Change the mapper selection using the table. self.table.selectionModel().currentRowChanged.connect( self.mapper.setCurrentModelIndex) self.mapper.toFirst() # tag::controls[] self.setMinimumSize(QSize(800, 400)) controls = QHBoxLayout() prev_rec = QPushButton("Previous") prev_rec.clicked.connect(self.mapper.toPrevious) next_rec = QPushButton("Next") next_rec.clicked.connect(self.mapper.toNext) save_rec = QPushButton("Save Changes") save_rec.clicked.connect(self.mapper.submit) controls.addWidget(prev_rec) controls.addWidget(next_rec) controls.addWidget(save_rec) layout.addLayout(form) layout.addLayout(controls) widget = QWidget() widget.setLayout(hlayout) self.setCentralWidget(widget)
class SmartSyncDialog(object): def __init__(self, parent): self._dialog = QDialog(parent) self._dialog.setWindowIcon(QIcon(':/images/icon.png')) self._ui = Ui_Dialog() self._ui.setupUi(self._dialog) self._ui.centralWidget.setFrameShape(QFrame.NoFrame) self._ui.centralWidget.setLineWidth(1) self._model = None self._proxy_model = QSortFilterProxyModel() self._view = self._ui.folder_list_view self._view.setModel(self._proxy_model) self._view.expanded.connect(self.on_item_expanded) self._offline_paths = None # for frameless window moving self._x_coord = 0 self._y_coord = 0 self._dialog.mousePressEvent = self.on_mouse_press_event self._dialog.mouseMoveEvent = self.on_mouse_move_event self._loader_movie = QMovie(":/images/loader.gif") self._ui.loader_label.setMovie(self._loader_movie) def on_mouse_press_event(self, ev): self._x_coord = ev.x() self._y_coord = ev.y() def on_mouse_move_event(self, ev): self._dialog.move( ev.globalX() - self._x_coord, ev.globalY() - self._y_coord) def on_item_expanded(self, index): if self._model: self._model.on_item_expanded(self._proxy_model.mapToSource(index)) def show(self, root_path, hide_dotted=False): if LOGGING_ENABLED: logger.info( "Opening smart sync dialog for path '%s'...", root_path) self._model = TreeModel( root_path, hide_dotted=hide_dotted) self._proxy_model.setSourceModel(self._model) self.show_cursor_loading(show_movie=True) # Execute dialog result = self._dialog.exec_() if result == QDialog.Accepted: offline_dirs = self._model.get_added_to_offline_paths() new_online = list(self._model.get_removed_from_offline_paths()) new_offline = list(offline_dirs - self._offline_paths) if LOGGING_ENABLED: logger.debug("new offline dirs %s, new online dirs %s", new_offline, new_online) return new_offline, new_online else: return [], [] def set_offline_paths(self, offline_paths): self._offline_paths = offline_paths logger.debug("offline paths %s", offline_paths) self._model.set_offline_dirs(offline_paths) self.show_cursor_normal() self._view.expand(self._proxy_model.mapFromSource( self._model.get_root_path_index())) self._proxy_model.sort(0, Qt.AscendingOrder) def show_cursor_loading(self, show_movie=False): if show_movie: self._ui.stackedWidget.setCurrentIndex(1) self._loader_movie.start() else: self._dialog.setCursor(Qt.WaitCursor) def show_cursor_normal(self): self._dialog.setCursor(Qt.ArrowCursor) if self._loader_movie.state() == QMovie.Running: self._loader_movie.stop() self._ui.stackedWidget.setCurrentIndex(0)