class QSeadTargetInfoView(QGroupBox): """ UI Component to display info about a sead target """ def __init__(self, sead_target_infos: SEADTargetInfo): if sead_target_infos is None: sead_target_infos = SEADTargetInfo() super(QSeadTargetInfoView, self).__init__("Target : " + sead_target_infos.name) self.sead_target_infos = sead_target_infos self.radar_list = QListView() self.init_ui() def init_ui(self): layout = QVBoxLayout(self) layout.setSpacing(0) layout.addWidget(self.radar_list) self.setLayout(layout) def setTarget(self, target: SEADTargetInfo): self.setTitle(target.name) self.sead_target_infos = target radar_list_model = QStandardItemModel() self.radar_list.setSelectionMode(QAbstractItemView.NoSelection) for r in self.sead_target_infos.radars: radar_list_model.appendRow(QStandardItem(r.type)) self.radar_list.setModel(radar_list_model)
class QStrikeTargetInfoView(QGroupBox): """ UI Component to display info about a strike target """ def __init__(self, strike_target_infos: StrikeTargetInfo): if strike_target_infos is None: strike_target_infos = StrikeTargetInfo() super(QStrikeTargetInfoView, self).__init__( "Target : " + strike_target_infos.name ) self.strike_target_infos = strike_target_infos self.listView = QListView() self.init_ui() def init_ui(self): layout = QVBoxLayout(self) layout.setSpacing(0) layout.addWidget(self.listView) self.setLayout(layout) def setTarget(self, target): self.setTitle(target.name) self.strike_target_infos = target model = QStandardItemModel() self.listView.setSelectionMode(QAbstractItemView.NoSelection) if len(self.strike_target_infos.units) > 0: dic = {} for u in self.strike_target_infos.units: if u.type in dic.keys(): dic[u.type] = dic[u.type] + 1 else: dic[u.type] = 1 for k, v in dic.items(): model.appendRow(QStandardItem(k + " x " + str(v))) print(k + " x " + str(v)) else: dic = {} for b in self.strike_target_infos.buildings: id = b.dcs_identifier if b.is_dead: id = id + "[Destroyed]" if id in dic.keys(): dic[id] = dic[id] + 1 else: dic[id] = 1 for k, v in dic.items(): model.appendRow(QStandardItem(k + " x " + str(v))) print(k + " x " + str(v)) self.listView.setModel(model)
def getView(self): """Get a new QListView suitable for displaying the toolbox.""" v = QListView() v.setModel(self) v.setSelectionMode(v.SingleSelection) v.setDragEnabled(True) v.setDragDropMode(v.DragOnly) return v
class Shell(QMainWindow): def __init__(self): # constructor super().__init__() # call the parent's constructor # Test data in a model self.users = ['User 1', 'User 2', 'User 3'] self.lv_model = QStringListModel() self.lv_model.setStringList(self.users) # Create the main window content widget w = QWidget() # Setup the rest of the main window appearance self.setGeometry(300, 300, 640, 480) self.setWindowTitle('PySide2 Listview Experiments') self.setWindowIcon(QIcon('assets/icons/moon_64x64.png')) # Create and set the main layout layout = QVBoxLayout() w.setLayout(layout) # Set the layout of the main window content widget self.setCentralWidget(w) # Create and add components to the layout self.lv_label = QLabel('QListView with QStringListModel') layout.addWidget(self.lv_label) self.lv = QListView() self.lv.setSelectionMode( QListView.MultiSelection) # single selection is the default self.lv.setModel(self.lv_model) self.lv.selectionModel().selectionChanged.connect(self.item_selected) layout.addWidget(self.lv) self.button = QPushButton('Update model') self.button.clicked.connect(self.change_model) layout.addWidget(self.button) self.selected_label = QLabel('Selected item: none') layout.addWidget(self.selected_label) layout.addStretch(1) self.show() # display the UI def change_model(self): the_list = self.lv_model.stringList() the_list.append('Another User') self.lv_model.setStringList(the_list) def item_selected(self): # Get the current index (a QModelIndex object) from the QListView # From the index, get the data (a QVariant) that you can convert to a QString index = self.lv.currentIndex() # returns the primary QModelIndex indices = self.lv.selectedIndexes() # returns a list of QModelIndex selected_text = '' for i in indices: selected_text += i.data( ) + '\n' # use .data() to get the value from QModelIndex self.selected_label.setText(selected_text)
class WordListDialog(QDialog): """Window to handle the edition of words in a word set""" def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle(self.tr("Edit Word set")) self.setWindowIcon(QIcon(cm.DIR_ICONS + "app.png")) box = QVBoxLayout() self.add_button = QPushButton(self.tr("Add")) self.add_file_button = QPushButton(self.tr("Add from file...")) self.del_button = QPushButton(self.tr("Remove")) self.del_button.setDisabled(True) self.save_button = QPushButton(self.tr("Save")) self.save_button.setDisabled(True) self.cancel_button = QPushButton(self.tr("Cancel")) box.addWidget(self.add_button) box.addWidget(self.del_button) box.addWidget(self.add_file_button) box.addStretch() box.addWidget(self.save_button) box.addWidget(self.cancel_button) self.view = QListView() self.model = QStringListModel() self.view.setModel(self.model) self.view.setSelectionMode(QAbstractItemView.ExtendedSelection) hlayout = QHBoxLayout() hlayout.addWidget(self.view) hlayout.addLayout(box) self.setLayout(hlayout) self.add_button.pressed.connect(self.on_add) self.del_button.pressed.connect(self.on_remove) self.add_file_button.pressed.connect(self.on_load_file) self.cancel_button.pressed.connect(self.reject) self.save_button.pressed.connect(self.accept) # Item selected in view self.view.selectionModel().selectionChanged.connect( self.on_item_selected) # Data changed in model self.model.dataChanged.connect(self.on_data_changed) self.model.rowsInserted.connect(self.on_data_changed) self.model.rowsRemoved.connect(self.on_data_changed) def on_item_selected(self, *args): """Enable the remove button when an item is selected""" self.del_button.setEnabled(True) def on_data_changed(self, *args): """Enable the save button when data in model is changed""" self.save_button.setEnabled(True) def on_add(self): """Allow to manually add a word to the list Notes: A user must click on save for the changes to take effect. """ data = self.model.stringList() data.append(self.tr("<double click to edit>")) self.model.setStringList(data) def on_remove(self): """Remove the selected rows of the list Notes: A user must click on save for the changes to take effect. """ indexes = self.view.selectionModel().selectedRows() while indexes: self.model.removeRows(indexes[0].row(), 1) indexes = self.view.selectionModel().selectedRows() self.del_button.setDisabled(True) def on_load_file(self): """Allow to automatically add words from a file See Also: :meth:`load_file` """ # Reload last directory used last_directory = QSettings().value("last_directory", QDir.homePath()) filepath, _ = QFileDialog.getOpenFileName(self, self.tr("Open Word set"), last_directory, self.tr("Text file (*.txt)")) if filepath: self.load_file(filepath) def load_file(self, filename: str): """Load file into the view Args: filename(str): A simple file with a list of words (1 per line) Current data filtering: - Strip trailing spaces and EOL characters - Skip empty lines - Skip lines with whitespaces characters (`[ \t\n\r\f\v]`) Examples: - The following line will be skipped: `"abc def\tghi\t \r\n"` - The following line will be cleaned: `"abc\r\n"` """ if not os.path.exists(filename): return # Sanitize words with open(filename, "r") as f_h: data = sanitize_words(f_h) data.update(self.model.stringList()) self.model.setStringList(list(data)) # Simulate signal... TODO: check the syntax... self.model.rowsInserted.emit(0, 0, 0)
class SymbolViewFrame(QWidget): # --- Init methods --- def __init__(self, config): """ Symbols and Labels view frame :param config: application configuration file """ QWidget.__init__(self) self.setFixedSize(QSize(320, 330)) self.setWindowTitle("DigiQt - Symbols") self.config = config self.lab_label = QLabel("Labels") self.lab_label.setAlignment(Qt.AlignCenter) self.lab_symbols = QLabel("Symbols") self.lab_symbols.setAlignment(Qt.AlignCenter) self.sig_symbol_goto = None # pushed by the controler # Initialization of the lists self.labels_view = QListView() self.labels_view.setFixedSize(QSize(150, 300)) self.labels_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.labels_view.setSelectionMode(QAbstractItemView.SingleSelection) self.dm_labels = QStandardItemModel(self.labels_view) self.symbols_view = QListView() self.symbols_view.setFixedSize(QSize(150, 300)) self.symbols_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.symbols_view.setSelectionMode(QAbstractItemView.SingleSelection) self.dm_symbols = QStandardItemModel(self.symbols_view) self.init_labels([]) self.init_symbols([]) self.labels_view.clicked.connect(self.on_label_changed) self.symbols_view.clicked.connect(self.on_symbol_changed) self.__set_layout() self.setStyleSheet(style.get_stylesheet("listviews_frame")) def init_labels(self, list_labels): """ Initiates the data model for the labels :param list_labels: list of labels """ self.__init_view(self.labels_view, self.dm_labels, list_labels) def init_symbols(self, list_symbols): """ Initiates the data model for the symbols :param list_symbols: list of symbols """ self.__init_view(self.symbols_view, self.dm_symbols, list_symbols) def __init_view(self, list_view, data_model, objects_list): """ Initiates the view given the data_model and the objects to add in it. :type list_view: QListView :type data_model: QStandardItemModel :type objects_list: list """ data_model.clear() for l in objects_list: data_model.appendRow(QStandardItem(l)) list_view.setModel(data_model) def __set_layout(self): """ Creates this Widget's Layout """ box = QGridLayout() box.setContentsMargins(0, 0, 0, 0) box.addWidget(self.lab_label, 0, 0) box.addWidget(self.labels_view, 1, 0) box.addWidget(self.lab_symbols, 0, 1) box.addWidget(self.symbols_view, 1, 1) self.setLayout(box) def on_label_changed(self, item): """ Callback method for the label change signal :param item: new item selected :type item: QItemSelection """ text = item.data() if text: self.sig_symbol_goto.emit(text) self.place_search_text(text) def on_symbol_changed(self, item): """ Callback method for the symbol change signal :param item: new item selected :type item: QItemSelection """ text = item.data() if text: self.sig_symbol_goto.emit(text) self.place_search_text(text) def place_search_text(self, text): """ Updates the searched value in the editor search field. :param text: label or symbol to place as search text """ pass def __retrieve_text(self, data_model, item): """ Gets the text with the specified data model from a QItemSelection :type item: QItemSelection :type data_model: QStandardItemModel :rtype: str """ selection = item.indexes() if selection: return data_model.item(QModelIndex(selection[0]).row()).text() # --- Close handler --- def closeEvent(self, event): """ Event called upon a red-cross click. """ self.on_close() def on_close(self): """ Reroot this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip :return: """ pass
class Completer(QWidget): """docstring for ClassName Attributes: delegate (CompleterDelegate): the delegate use by the view model (CompleterModel): the model proxy_model (QSortFilterProxyModel ): the proxy model used to filter model panel (QLabel): The description widget view (QListView): the view Signals: activated (str): return the keyword selected """ activated = Signal(str) def __init__(self, parent=None): super().__init__(parent) self._target = None self._completion_prefix = "" self.setWindowFlag(Qt.Popup) self.setFocusPolicy(Qt.NoFocus) # create model self.model = CompleterModel() self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) # create delegate self.delegate = CompleterDelegate() # create view self.view = QListView() self.view.setSelectionMode(QAbstractItemView.SingleSelection) self.view.setFocusPolicy(Qt.NoFocus) self.view.installEventFilter(self) self.view.setModel(self.proxy_model) self.view.setItemDelegate(self.delegate) self.view.setMinimumWidth(200) self.view.setUniformItemSizes(True) self.view.setSpacing(0) self.view.selectionModel().currentRowChanged.connect( self._on_row_changed) self.setFocusProxy(self.view) # create panel info self.panel = QLabel() self.panel.setAlignment(Qt.AlignTop) self.panel.setMinimumWidth(300) self.panel.setWordWrap(True) self.panel.setFrameShape(QFrame.StyledPanel) # Create layout vlayout = QHBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) vlayout.setSpacing(0) vlayout.addWidget(self.view) vlayout.addWidget(self.panel) self.setLayout(vlayout) def set_target(self, target): """Set CodeEdit Args: target (CodeEdit): The CodeEdit """ self._target = target self.installEventFilter(self._target) def eventFilter(self, obj: QObject, event: QEvent) -> bool: """Filter event from CodeEdit and QListView Args: obj (QObject): Description event (QEvent): Description Returns: bool """ # Intercept CodeEdit event if obj == self._target: if event.type() == QEvent.FocusOut: # Ignore lost focus! return True else: obj.event(event) return True # Intercept QListView event if obj == self.view: # Redirect event to QTextExit if event.type() == QEvent.KeyPress and self._target: current = self.view.selectionModel().currentIndex() # emit signal when user press return if event.key() == Qt.Key_Return: word = current.data() self.activated.emit(word) self.hide() event.ignore() return True # use tab to move down/up in the list if event.key() == Qt.Key_Tab: if current.row() < self.proxy_model.rowCount() - 1: self.view.setCurrentIndex( self.proxy_model.index(current.row() + 1, 0)) if event.key() == Qt.Key_Backtab: if current.row() > 0: self.view.setCurrentIndex( self.proxy_model.index(current.row() - 1, 0)) # Route other key event to the target ! This make possible to write text when completer is visible self._target.event(event) return super().eventFilter(obj, event) def complete(self, rect: QRect): """Show completer as popup Args: rect (QRect): the area where to display the completer """ if self.proxy_model.rowCount() == 0: self.hide() return if self._target: pos = self._target.mapToGlobal(rect.bottomRight()) self.move(pos) self.setFocus() if not self.isVisible(): width = 400 #height = self.view.sizeHintForRow(0) * self.proxy_model.rowCount() + 3 # HACK.. TODO better ! #height = min(self._target.height() / 2, height) #self.resize(width, height) self.adjustSize() self.show() def set_completion_prefix(self, prefix: str): """Set prefix and filter model Args: prefix (str): A prefix keyword used to filter model """ self.view.clearSelection() self._completion_prefix = prefix self.proxy_model.setFilterRegularExpression( QRegularExpression(f"^{prefix}.*", QRegularExpression.CaseInsensitiveOption)) if self.proxy_model.rowCount() > 0: self.select_row(0) def select_row(self, row: int): """Select a row in the model Args: row (int): a row number """ index = self.proxy_model.index(row, 0) self.view.selectionModel().setCurrentIndex(index, QItemSelectionModel.Select) def completion_prefix(self) -> str: """getter of completion_prefix TODO: use getter / setter Returns: str: Return the completion_prefix """ return self._completion_prefix def hide(self): """Override from QWidget Hide the completer """ self.set_completion_prefix("") super().hide() def _on_row_changed(self, current: QModelIndex, previous: QModelIndex): """Slot received when user select a new item in the list. This is used to update the panel Args: current (QModelIndex): the selection index previous (QModelIndex): UNUSED """ description = current.data(Qt.ToolTipRole) self.panel.setText(description)