def __init__(self, args, parent=None, rows=10): super(EDLManagerApp, self).__init__(parent) self.pyside_app = QtWidgets.QApplication(['EDL Manager']) self.table_model = TableModel(rows) self.qmodel = QModel(self) self.main_window = MainWindow(application=self, model=self.qmodel) self.main_window.saveEvent.connect(self.save_edl) self.main_window.openedFile.connect(self.read_edl)
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) ''' Load our form.ui ''' self.load_ui() ''' Load our widgets ''' self.assign_widgets() # region Populate table '''Create model, pass data (has to be pandas dataframe)''' self.model = TableModel(load_portfolio()) '''Set the model for table ''' self.table.setModel(self.model) '''Set some table properties''' self.table.setSelectionBehavior(QAbstractItemView.SelectRows) # self.table_setData() # self.table.setSortingEnabled(False) # self.table.resizeColumnsToContents() # endregion ''' Generate pool of threads ''' self.threadpool = QThreadPool() print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) # region Timer to update table self.timer = QTimer() self.timer.setInterval(timer_interval) self.timer.timeout.connect(self.assign_worker_fn) self.timer.start()
def label_activated_handler(self, text): self.table = DayDetail(self) self.table_model = TableModel(self.events) self.table.setModel(self.table_model) self.table.table_view.horizontalHeader().hideSection(3) self.table_model.itemChanged.connect(self.table_item_changed_handler) self.table.show()
def __init__(self): QMainWindow.__init__(self) self.resize(700, 700) self.table = QTableView() (data, ids) = self.get_data() data = pd.DataFrame( data, columns=['Model', 'Year', 'Km', 'Color', 'Price', 'City'], index=ids) self.model = TableModel(data) self.table.setModel(self.model) self.setCentralWidget(self.table)
class EDLManagerApp(QtCore.QObject): def __init__(self, args, parent=None, rows=10): super(EDLManagerApp, self).__init__(parent) self.pyside_app = QtWidgets.QApplication(['EDL Manager']) self.table_model = TableModel(rows) self.qmodel = QModel(self) self.main_window = MainWindow(application=self, model=self.qmodel) self.main_window.saveEvent.connect(self.save_edl) self.main_window.openedFile.connect(self.read_edl) def model_info(self): return self.table_model.info() def run(self): self.main_window.show() return (self.pyside_app.exec_()) def read_edl(self, edl): pass #parse raw EDL into function to split it into rows / columns def save_edl(self): table_to_save = self.main_window.export_table() # Save commented EDL --- def setRowCount(self, count): return self.table_model.setRowCount(count) def cell(self, row, column): return self.table_model.data[row][column] def update_cell(self, row, col, val): self.table_model.update_cell(row, col, val)
def _source_model_default(self): return TableModel(editor=self)
class TableEditor(Editor, BaseTableEditor): """ Editor that presents data in a table. Optionally, tables can have a set of filters that reduce the set of data displayed, according to their criteria. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The table view control associated with the editor: table_view = Any # A wrapper around the source model which provides filtering and sorting: model = Instance(SortFilterTableModel) # The table model associated with the editor: source_model = Instance(TableModel) # The set of columns currently defined on the editor: columns = List(TableColumn) # The currently selected row(s), column(s), or cell(s). selected = Any # The current selected row selected_row = Property(Any, depends_on='selected') selected_indices = Property(Any, depends_on='selected') # Current filter object (should be a TableFilter or callable or None): filter = Any # The indices of the table items currently passing the table filter: filtered_indices = List(Int) # Current filter summary message filter_summary = Str('All items') # The event fired when a cell is clicked on: click = Event # The event fired when a cell is double-clicked on: dclick = Event # The Traits UI associated with the table editor toolbar: toolbar_ui = Instance(UI) # The context menu associated with empty space in the table empty_menu = Instance(QtGui.QMenu) # The context menu associated with the vertical header header_menu = Instance(QtGui.QMenu) # The context menu actions for moving rows up and down header_menu_up = Instance(QtGui.QAction) header_menu_down = Instance(QtGui.QAction) # The index of the row that was last right clicked on its vertical header header_row = Int #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """Finishes initializing the editor by creating the underlying toolkit widget.""" factory = self.factory self.columns = factory.columns[:] # Create the table view and model self.table_view = TableView(editor=self) self.source_model = TableModel(editor=self) self.model = SortFilterTableModel(editor=self) self.model.setDynamicSortFilter(True) self.model.setSourceModel(self.source_model) self.table_view.setModel(self.model) # Create the vertical header context menu and connect to its signals self.header_menu = QtGui.QMenu(self.table_view) signal = QtCore.SIGNAL('triggered()') insertable = factory.row_factory is not None and not factory.auto_add if factory.editable: if insertable: action = self.header_menu.addAction('Insert new item') QtCore.QObject.connect(action, signal, self._on_context_insert) if factory.deletable: action = self.header_menu.addAction('Delete item') QtCore.QObject.connect(action, signal, self._on_context_remove) if factory.reorderable: if factory.editable and (insertable or factory.deletable): self.header_menu.addSeparator() self.header_menu_up = self.header_menu.addAction('Move item up') QtCore.QObject.connect(self.header_menu_up, signal, self._on_context_move_up) self.header_menu_down = self.header_menu.addAction('Move item down') QtCore.QObject.connect(self.header_menu_down, signal, self._on_context_move_down) # Create the empty space context menu and connect its signals self.empty_menu = QtGui.QMenu(self.table_view) action = self.empty_menu.addAction('Add new item') QtCore.QObject.connect(action, signal, self._on_context_append) # When sorting is enabled, the first column is initially displayed with # the triangle indicating it is the sort index, even though no sorting # has actually been done. Sort here for UI/model consistency. if self.factory.sortable and not self.factory.reorderable: self.model.sort(0, QtCore.Qt.AscendingOrder) # Connect to the mode specific selection handler and select the first # row/column/cell. Do this before creating the edit_view to make sure # that it has a valid item to use when constructing its view. smodel = self.table_view.selectionModel() signal = QtCore.SIGNAL('selectionChanged(QItemSelection, QItemSelection)') mode_slot = getattr(self, '_on_%s_selection' % factory.selection_mode) QtCore.QObject.connect(smodel, signal, mode_slot) self.table_view.setCurrentIndex(self.model.index(0, 0)) # Create the toolbar if necessary if factory.show_toolbar and len(factory.filters) > 0: main_view = QtGui.QWidget() layout = QtGui.QVBoxLayout(main_view) layout.setMargin(0) self.toolbar_ui = self.edit_traits( parent = parent, kind = 'subpanel', view = View(Group(Item('filter{View}', editor = factory._filter_editor ), Item('filter_summary{Results}', style = 'readonly'), spring, orientation='horizontal'), resizable = True)) self.toolbar_ui.parent = self.ui layout.addWidget(self.toolbar_ui.control) layout.addWidget(self.table_view) else: main_view = self.table_view # Create auxillary editor and encompassing splitter if necessary mode = factory.selection_mode if (factory.edit_view == ' ') or not mode in ('row', 'rows'): self.control = main_view else: self.control = QtGui.QSplitter(QtCore.Qt.Vertical) self.control.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.control.addWidget(main_view) self.control.setStretchFactor(0, 2) # Create the row editor below the table view editor = InstanceEditor(view=factory.edit_view, kind='subpanel') self._ui = self.edit_traits( parent = self.control, kind = 'subpanel', view = View(Item('selected_row', style = 'custom', editor = editor, show_label = False, resizable = True, width = factory.edit_view_width, height = factory.edit_view_height), resizable = True, handler = factory.edit_view_handler)) self._ui.parent = self.ui self.control.addWidget(self._ui.control) self.control.setStretchFactor(1, 1) # Connect to the click and double click handlers signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_dclick) # Make sure we listen for 'items' changes as well as complete list # replacements self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch='ui') # Listen for changes to traits on the objects in the list self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Listen for changes on column definitions self.on_trait_change(self._update_columns, 'columns', dispatch='ui') self.on_trait_change(self._update_columns, 'columns_items', dispatch='ui') # Set up the required externally synchronized traits is_list = (mode in ('rows', 'columns', 'cells')) self.sync_value(factory.click, 'click', 'to') self.sync_value(factory.dclick, 'dclick', 'to') self.sync_value(factory.columns_name, 'columns', is_list=True) self.sync_value(factory.selected, 'selected', is_list=is_list) self.sync_value(factory.selected_indices, 'selected_indices', is_list=is_list) self.sync_value(factory.filter_name, 'filter', 'from') self.sync_value(factory.filtered_indices, 'filtered_indices', 'to') # Initialize the ItemDelegates for each column self._update_columns() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose(self): """ Disposes of the contents of an editor.""" # Disconnect the table view from its model to ensure that they do not # continue to interact (the control won't be deleted until later). self.table_view.setModel(None) # Make sure that the auxillary UIs are properly disposed if self.toolbar_ui is not None: self.toolbar_ui.dispose() if self._ui is not None: self._ui.dispose() # Remove listener for 'items' changes on object trait self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove=True) # Remove listener for changes to traits on the objects in the list self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', remove=True) # Remove listeners for column definition changes self.on_trait_change(self._update_columns, 'columns', remove=True) self.on_trait_change(self._update_columns, 'columns_items', remove=True) super(TableEditor, self).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """Updates the editor when the object trait changes externally to the editor.""" if self._no_notify: return self.table_view.setUpdatesEnabled(False) try: filtering = len(self.factory.filters) > 0 if filtering: self._update_filtering() # invalidate the model, but do not reset it. Resetting the model # may cause problems if the selection sync'ed traits are being used # externally to manage the selections self.model.invalidate() if self.factory.auto_size: self.table_view.resizeColumnsToContents() finally: self.table_view.setUpdatesEnabled(True) #--------------------------------------------------------------------------- # Requests that the underlying table widget to redraw itself: #--------------------------------------------------------------------------- def refresh_editor(self): """Requests that the underlying table widget to redraw itself.""" self.table_view.viewport().update() #--------------------------------------------------------------------------- # Creates a new row object using the provided factory: #--------------------------------------------------------------------------- def create_new_row(self): """Creates a new row object using the provided factory.""" factory = self.factory kw = factory.row_factory_kw.copy() if '__table_editor__' in kw: kw[ '__table_editor__' ] = self return self.ui.evaluate(factory.row_factory, *factory.row_factory_args, **kw) #--------------------------------------------------------------------------- # Returns the raw list of model objects: #--------------------------------------------------------------------------- def items(self): """Returns the raw list of model objects.""" items = self.value if not isinstance(items, SequenceTypes): items = [ items ] if self.factory.reverse: items = ReversedList(items) return items #--------------------------------------------------------------------------- # Perform actions without notifying the underlying table view or model: #--------------------------------------------------------------------------- def callx(self, func, *args, **kw): """Call a function without notifying the underlying table view or model.""" old = self._no_notify self._no_notify = True try: func(*args, **kw) finally: self._no_notify = old def setx(self, **keywords): """Set one or more attributes without notifying the underlying table view or model.""" old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old #--------------------------------------------------------------------------- # Sets the current selection to a set of specified objects: #--------------------------------------------------------------------------- def set_selection(self, objects=[], notify=True): """Sets the current selection to a set of specified objects.""" if not isinstance(objects, SequenceTypes): objects = [ objects ] mode = self.factory.selection_mode indexes = [] flags = QtGui.QItemSelectionModel.ClearAndSelect # In the case of row or column selection, we need a dummy value for the # other dimension that has not been filtered. source_index = self.model.mapToSource(self.model.index(0, 0)) source_row, source_column = source_index.row(), source_index.column() # Selection mode is 'row' or 'rows' if mode.startswith('row'): flags |= QtGui.QItemSelectionModel.Rows items = self.items() for obj in objects: try: row = items.index(obj) except ValueError: continue indexes.append(self.source_model.index(row, source_column)) # Selection mode is 'column' or 'columns' elif mode.startswith('column'): flags |= QtGui.QItemSelectionModel.Columns for name in objects: column = self._column_index_from_name(name) if column != -1: indexes.append(self.source_model.index(source_row, column)) # Selection mode is 'cell' or 'cells' else: items = self.items() for obj, name in objects: try: row = items.index(obj) except ValueError: continue column = self._column_index_from_name(name) if column != -1: indexes.append(self.source_model.index(row, column)) # Perform the selection so that only one signal is emitted selection = QtGui.QItemSelection() for index in indexes: index = self.model.mapFromSource(index) if index.isValid(): self.table_view.setCurrentIndex(index) selection.select(index, index) smodel = self.table_view.selectionModel() try: smodel.blockSignals(not notify) if len(selection.indexes()): smodel.select(selection, flags) else: smodel.clear() finally: smodel.blockSignals(False) #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _column_index_from_name(self, name): """Returns the index of the column with the given name or -1 if no column exists with that name.""" for i, column in enumerate(self.columns): if name == column.name: return i return -1 def _customize_filters(self, filter): """Allows the user to customize the current set of table filters.""" filter_editor = TableFilterEditor(editor=self) ui = filter_editor.edit_traits(parent=self.control) if ui.result: self.factory.filters = filter_editor.templates self.filter = filter_editor.selected_filter else: self.setx(filter = filter) def _update_filtering(self): """Update the filter summary and the filtered indices.""" items = self.items() num_items = len(items) f = self.filter if f is None: self._filtered_cache = None self.filtered_indices = range(num_items) self.filter_summary = 'All %i items' % num_items else: if not callable(f): f = f.filter self._filtered_cache = fc = [ f(item) for item in items ] self.filtered_indices = fi = [ i for i, ok in enumerate(fc) if ok ] self.filter_summary = '%i of %i items' % (len(fi), num_items) #-- Trait Property getters/setters ----------------------------------------- @cached_property def _get_selected_row(self): """Gets the selected row, or the first row if multiple rows are selected.""" mode = self.factory.selection_mode if mode.startswith('column'): return None elif mode == 'row': return self.selected try: if mode == 'rows': return self.selected[0] elif mode == 'cell': return self.selected[0] elif mode == 'cells': return self.selected[0][0] except IndexError: return None @cached_property def _get_selected_indices(self): """Gets the row,column indices which match the selected trait""" if len(self.selected) == 0: return [] selection_items = self.table_view.selectionModel().selection() indices = self.model.mapSelectionFromSource(selection_items).indexes() return [(index.row(), index.column()) for index in indices] def _set_selected_indices(self, indices): selected = [] for row, col in indices: selected.append((self.value[row], self.columns[col].name)) self.selected = selected self.set_selection(self.selected, False) return #-- Trait Change Handlers -------------------------------------------------- def _filter_changed(self, old_filter, new_filter): """Handles the current filter being changed.""" if not self._no_notify: if new_filter is customize_filter: do_later(self._customize_filters, old_filter) else: self._update_filtering() self.model.invalidate() self.set_selection(self.selected) def _update_columns(self): """Handle the column list being changed.""" self.table_view.setItemDelegate(TableDelegate(self.table_view)) for i, column in enumerate(self.columns): if column.renderer: self.table_view.setItemDelegateForColumn(i, column.renderer) self.model.reset() self.table_view.resizeColumnsToContents() def _selected_changed(self, new): """Handle the selected row/column/cell being changed externally.""" if not self._no_notify: self.set_selection(self.selected, notify=False) #-- Event Handlers --------------------------------------------------------- def _on_row_selection(self, added, removed): """Handle the row selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedRows() if len(indexes): index = self.model.mapToSource(indexes[0]) selected = items[index.row()] else: selected = None self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_rows_selection(self, added, removed): """Handle the rows selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedRows() selected = [ items[self.model.mapToSource(index).row()] for index in indexes ] self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_column_selection(self, added, removed): """Handle the column selection being changed.""" indexes = self.table_view.selectionModel().selectedColumns() if len(indexes): index = self.model.mapToSource(indexes[0]) selected = self.columns[index.column()].name else: selected = '' self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_columns_selection(self, added, removed): """Handle the columns selection being changed.""" indexes = self.table_view.selectionModel().selectedColumns() selected = [ self.columns[self.model.mapToSource(index).column()].name for index in indexes ] self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_cell_selection(self, added, removed): """Handle the cell selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedIndexes() if len(indexes): index = self.model.mapToSource(indexes[0]) obj = items[index.row()] column_name = self.columns[index.column()].name else: obj = None column_name = '' selected = (obj, column_name) self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_cells_selection(self, added, removed): """Handle the cells selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedIndexes() selected = [] for index in indexes: index = self.model.mapToSource(index) obj = items[index.row()] column_name = self.columns[index.column()].name selected.append((obj, column_name)) self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_click(self, index): """Handle a cell being clicked.""" index = self.model.mapToSource(index) column = self.columns[index.column()] obj = self.items()[index.row()] # Fire the same event on the editor after mapping it to a model object # and column name: self.click = (obj, column) # Invoke the column's click handler: column.on_click(obj) def _on_dclick(self, index): """Handle a cell being double clicked.""" index = self.model.mapToSource(index) column = self.columns[index.column()] obj = self.items()[index.row()] # Fire the same event on the editor after mapping it to a model object # and column name: self.dclick = (obj, column) # Invoke the column's double-click handler: column.on_dclick(obj) def _on_context_insert(self): """Handle 'insert item' being selected from the header context menu.""" self.model.insertRow(self.header_row) def _on_context_append(self): """Handle 'add item' being selected from the empty space context menu.""" self.model.insertRow(self.model.rowCount()) def _on_context_remove(self): """Handle 'remove item' being selected from the header context menu.""" self.model.removeRow(self.header_row) def _on_context_move_up(self): """Handle 'move up' being selected from the header context menu.""" self.model.moveRow(self.header_row, self.header_row - 1) def _on_context_move_down(self): """Handle 'move down' being selected from the header context menu.""" self.model.moveRow(self.header_row, self.header_row + 1)
def init(self, parent): """Finishes initializing the editor by creating the underlying toolkit widget.""" factory = self.factory self.columns = factory.columns[:] # Create the table view and model self.table_view = TableView(editor=self) self.source_model = TableModel(editor=self) self.model = SortFilterTableModel(editor=self) self.model.setDynamicSortFilter(True) self.model.setSourceModel(self.source_model) self.table_view.setModel(self.model) # Create the vertical header context menu and connect to its signals self.header_menu = QtGui.QMenu(self.table_view) signal = QtCore.SIGNAL('triggered()') insertable = factory.row_factory is not None and not factory.auto_add if factory.editable: if insertable: action = self.header_menu.addAction('Insert new item') QtCore.QObject.connect(action, signal, self._on_context_insert) if factory.deletable: action = self.header_menu.addAction('Delete item') QtCore.QObject.connect(action, signal, self._on_context_remove) if factory.reorderable: if factory.editable and (insertable or factory.deletable): self.header_menu.addSeparator() self.header_menu_up = self.header_menu.addAction('Move item up') QtCore.QObject.connect(self.header_menu_up, signal, self._on_context_move_up) self.header_menu_down = self.header_menu.addAction('Move item down') QtCore.QObject.connect(self.header_menu_down, signal, self._on_context_move_down) # Create the empty space context menu and connect its signals self.empty_menu = QtGui.QMenu(self.table_view) action = self.empty_menu.addAction('Add new item') QtCore.QObject.connect(action, signal, self._on_context_append) # When sorting is enabled, the first column is initially displayed with # the triangle indicating it is the sort index, even though no sorting # has actually been done. Sort here for UI/model consistency. if self.factory.sortable and not self.factory.reorderable: self.model.sort(0, QtCore.Qt.AscendingOrder) # Connect to the mode specific selection handler and select the first # row/column/cell. Do this before creating the edit_view to make sure # that it has a valid item to use when constructing its view. smodel = self.table_view.selectionModel() signal = QtCore.SIGNAL('selectionChanged(QItemSelection, QItemSelection)') mode_slot = getattr(self, '_on_%s_selection' % factory.selection_mode) QtCore.QObject.connect(smodel, signal, mode_slot) self.table_view.setCurrentIndex(self.model.index(0, 0)) # Create the toolbar if necessary if factory.show_toolbar and len(factory.filters) > 0: main_view = QtGui.QWidget() layout = QtGui.QVBoxLayout(main_view) layout.setMargin(0) self.toolbar_ui = self.edit_traits( parent = parent, kind = 'subpanel', view = View(Group(Item('filter{View}', editor = factory._filter_editor ), Item('filter_summary{Results}', style = 'readonly'), spring, orientation='horizontal'), resizable = True)) self.toolbar_ui.parent = self.ui layout.addWidget(self.toolbar_ui.control) layout.addWidget(self.table_view) else: main_view = self.table_view # Create auxillary editor and encompassing splitter if necessary mode = factory.selection_mode if (factory.edit_view == ' ') or not mode in ('row', 'rows'): self.control = main_view else: self.control = QtGui.QSplitter(QtCore.Qt.Vertical) self.control.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.control.addWidget(main_view) self.control.setStretchFactor(0, 2) # Create the row editor below the table view editor = InstanceEditor(view=factory.edit_view, kind='subpanel') self._ui = self.edit_traits( parent = self.control, kind = 'subpanel', view = View(Item('selected_row', style = 'custom', editor = editor, show_label = False, resizable = True, width = factory.edit_view_width, height = factory.edit_view_height), resizable = True, handler = factory.edit_view_handler)) self._ui.parent = self.ui self.control.addWidget(self._ui.control) self.control.setStretchFactor(1, 1) # Connect to the click and double click handlers signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_dclick) # Make sure we listen for 'items' changes as well as complete list # replacements self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch='ui') # Listen for changes to traits on the objects in the list self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Listen for changes on column definitions self.on_trait_change(self._update_columns, 'columns', dispatch='ui') self.on_trait_change(self._update_columns, 'columns_items', dispatch='ui') # Set up the required externally synchronized traits is_list = (mode in ('rows', 'columns', 'cells')) self.sync_value(factory.click, 'click', 'to') self.sync_value(factory.dclick, 'dclick', 'to') self.sync_value(factory.columns_name, 'columns', is_list=True) self.sync_value(factory.selected, 'selected', is_list=is_list) self.sync_value(factory.selected_indices, 'selected_indices', is_list=is_list) self.sync_value(factory.filter_name, 'filter', 'from') self.sync_value(factory.filtered_indices, 'filtered_indices', 'to') # Initialize the ItemDelegates for each column self._update_columns()
def __init__(self, app, ui, config, parent=None): super(MainWindow, self).__init__(parent) print('\n---------- GAVLab RTK Survey ----------') def setupMOOS(): # manual threading is only necessary if reading messages from moos # roslaunch automatically configures threads - ros is superior to moos self.comm_arch = 'moos' try: MainWindow.viz_ip = config['ip'] MainWindow.viz_port = config['port'] except: pass self.thread = MainWindow.VizThread() self.moos_widget = MoosWidget(config['moos']) self.requestPosition.connect(self.moos_widget.onPositionRequested) self.moos_widget.sendPosition.connect(self.receivePosition) print('MOOS setup') def setupROS(): self.comm_arch = 'ros' # ... print('ROS setup') # Determine Comm arch if config['ros']: import rospy, roslib roslib.load_manifest('survey_gui') setupROS() elif config['moos']: from moos_comm import MoosWidget, MOOSPositionWarning, MOOSConnectionWarning setupMOOS() else: raise Exception('Need a config file with comm architecture') self.app = app # reference to the Qt Application self.ui = ui self.ui.setupUi(self) self.config = config # Table self.table_model = TableModel() self.ui.tableView.setModel(self.table_model) self.ui.tableView.horizontalHeader().setStretchLastSection(True) # output self.output_file_dialog = QFileDialog() self.output_file = None self.header = '## GAVLab Survey - Recorded %s\n' + \ '## All data in ECEF (m): X Y Z Description\n' self.manual_dialog = QtGui.QDialog() self.pos_data = array([None] * 3) # latest self.pos_data_good = False self.std_dev_threshold = config["std_dev_threshold"] if not self.std_dev_threshold: # blank string --> accept first position received and record self.std_dev_threshold = inf # Signals/Slots self.ui.actionExit.triggered.connect(self.app.closeAllWindows) self.ui.recordButton.clicked.connect(self.onRecordRequested) self.ui.actionManual_Entry.triggered.connect(self.addManualPoint) self.ui.actionWrite.triggered.connect(self.writeToFile) # Number cruncing states (iterative) self._sum = array([0.0] * 3) self._2sum = array([0.0] * 3)
class MainWindow(QtGui.QMainWindow, QtCore.QObject): """survey mainwindow class""" requestPosition = QtCore.Signal() viz_ip = '127.0.0.1' viz_port = 9001 class VizThread(QtCore.QThread): """Thread for the viz MainWindow""" def run(): """reimplement run()""" socket = QtNetwork.QTcpSocket() socket.connectToHost(MainWindow.viz_ip, MainWindow.viz_port) self.exec_() def __init__(self, app, ui, config, parent=None): super(MainWindow, self).__init__(parent) print('\n---------- GAVLab RTK Survey ----------') def setupMOOS(): # manual threading is only necessary if reading messages from moos # roslaunch automatically configures threads - ros is superior to moos self.comm_arch = 'moos' try: MainWindow.viz_ip = config['ip'] MainWindow.viz_port = config['port'] except: pass self.thread = MainWindow.VizThread() self.moos_widget = MoosWidget(config['moos']) self.requestPosition.connect(self.moos_widget.onPositionRequested) self.moos_widget.sendPosition.connect(self.receivePosition) print('MOOS setup') def setupROS(): self.comm_arch = 'ros' # ... print('ROS setup') # Determine Comm arch if config['ros']: import rospy, roslib roslib.load_manifest('survey_gui') setupROS() elif config['moos']: from moos_comm import MoosWidget, MOOSPositionWarning, MOOSConnectionWarning setupMOOS() else: raise Exception('Need a config file with comm architecture') self.app = app # reference to the Qt Application self.ui = ui self.ui.setupUi(self) self.config = config # Table self.table_model = TableModel() self.ui.tableView.setModel(self.table_model) self.ui.tableView.horizontalHeader().setStretchLastSection(True) # output self.output_file_dialog = QFileDialog() self.output_file = None self.header = '## GAVLab Survey - Recorded %s\n' + \ '## All data in ECEF (m): X Y Z Description\n' self.manual_dialog = QtGui.QDialog() self.pos_data = array([None] * 3) # latest self.pos_data_good = False self.std_dev_threshold = config["std_dev_threshold"] if not self.std_dev_threshold: # blank string --> accept first position received and record self.std_dev_threshold = inf # Signals/Slots self.ui.actionExit.triggered.connect(self.app.closeAllWindows) self.ui.recordButton.clicked.connect(self.onRecordRequested) self.ui.actionManual_Entry.triggered.connect(self.addManualPoint) self.ui.actionWrite.triggered.connect(self.writeToFile) # Number cruncing states (iterative) self._sum = array([0.0] * 3) self._2sum = array([0.0] * 3) ############################################################################ ##### Signals & Slots Stuff ############################################## ############################################################################ @QtCore.Slot(tuple) def receivePosition(self, pos): """connected to moos widget's position sender Assume self.pos_data_good = False at invocation""" ## TODO make indexing better here (check length of pos with length of pos_data) n = 0 while True: try: i = pos.next() self.pos_data[n] = i except StopIteration: break n += 1 if n == len(self.config['moos']['desired_variables'] ): # TODO refer to subscribed vars of either comm set self.pos_data_good = True else: raise MOOSPositionWarning('Not enough values received') @QtCore.Slot() def onRecordRequested(self): """When the record button is pressed, listens to moos until good position acquired for write""" self._sum = array([0.0] * 3) self._2sum = array([0.0] * 3) n = int(0) keep_averaging = True print('\nRecord requested') while keep_averaging: # Get values self.pos_data_good = False try: # put most time consuming procs in a catcher self.requestPosition.emit() sleep(1) except KeyboardInterrupt: # user has requested stop print('Aborting Record') self.ui.recordButton.setChecked(False) break if not self.pos_data_good: print('\tWaiting for good data ...') pass else: print('\tGood data set recieved: (%.2f, %.2f, %.2f) ' % \ (self.pos_data[0], self.pos_data[1], self.pos_data[2])) n += 1 n, _mean, _stddev_mag = self.iterateRecord(n) print('\tStd Dev magnitude = %f' % _stddev_mag) # Check the variance magnitude if n == 1: continue if _stddev_mag < self.std_dev_threshold: x = _mean[0] y = _mean[1] z = _mean[2] description = self.ui.descriptionLineEdit.text() self.addEntry(x=x, y=y, z=z, description=description) # exit stuff print('\t---> Survey Point Added: ( %f , %f , %f ) %s\n' % (x, y, z, description)) keep_averaging = False self.ui.recordButton.setChecked(False) # done recording self.ui.descriptionLineEdit.setText('') else: print('\tWaiting for variance to drop...\n') @QtCore.Slot() def addManualPoint(self): x, x_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input X Coordinate", "(ECEF) X:", 0.0, -1e9, 1e9, 1) if not x_ok: return y, y_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input Y Coordinate", "(ECEF) Y:", 0.0, -1e9, 1e9, 1) if not y_ok: return z, z_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input Z Coordinate", "(ECEF) Z:", 0.0, -1e9, 1e9, 1) if not z_ok: return desc, desc_ok = QtGui.QInputDialog.getText(self.manual_dialog, "Input Point Description", "Description:", QtGui.QLineEdit.Normal) if not desc_ok: return self.addEntry(x=x, y=y, z=z, description=desc) @QtCore.Slot() def writeToFile(self): self.output_file = open( str(self.output_file_dialog.getOpenFileName()[0]), 'w') # Header self.output_file.write(self.header % asctime(localtime(time()))) for line in self.getAllData(): line = (str(line[0]), str(line[1]), str(line[2]), line[3]) for item in line: self.output_file.write('%s\t\t' % item) self.output_file.write('\n') self.output_file.close() print('Output Log File Written!') # @QtCore.Slot() # def onExitRequested(self): ############################################################################ ##### Helper functions #################################################### ############################################################################ def iterateRecord(self, n): # calculate the variance self._sum += self.pos_data self._2sum += self.pos_data**2 _mean = self._sum / n _var = self._2sum / n - _mean**2 _sdev = sqrt(abs(_var)) self.updateLCD(var=_var) _stddev_mag = sqrt(sum(_sdev**2)) return n, _mean, _stddev_mag def updateLCD(self, var=(0, 0, 0), stddev=(0, 0, 0)): """update the variance LCD's while waiting for point to go low""" # print('MainWindow: showVariance') self.ui.xVarianceLcd.display(var[0]) self.ui.yVarianceLcd.display(var[1]) self.ui.zVarianceLcd.display(var[2]) self.ui.xStdDevLcd.display(stddev[0]) self.ui.yStdDevLcd.display(stddev[1]) self.ui.zStdDevLcd.display(stddev[2]) def addEntry(self, x=None, y=None, z=None, description=None): if x is None and y is None and z is None and description is None: raise Exception('something has to go into the entry') point = {"x": x, "y": y, "z": z, "description": description} points = self.table_model.points[:] # TODO check for duplicates by attempting to remove # Assume new point self.table_model.insertRows(0) # at position zero ix = self.table_model.index(0, 0, QtCore.QModelIndex()) self.table_model.setData(ix, point["x"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 1, QtCore.QModelIndex()) self.table_model.setData(ix, point["y"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 2, QtCore.QModelIndex()) self.table_model.setData(ix, point["z"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 3, QtCore.QModelIndex()) self.table_model.setData(ix, point["description"], QtCore.Qt.EditRole) # may need some resizing # self.currentWidget.resizeRowToContents(ix.row()) ##!! AttributeError: 'MainWindow' object has no attribute 'currentWidget' def getAllData(self): data = [] for pt in range(len(self.table_model.points)): data.append([]) for w in range(4): ix = self.table_model.index(pt, w, QtCore.QModelIndex()) data[pt].append(self.table_model.data(ix)) return data
files = [pd.read_csv(fname, sep='\t', header=None) for fname in fnames] paramval = [json.loads(pv) for pv in files[0][0]] intpspec = [] for i in range(len(paramval)): curspec = [] for core in cores: curspec += json.loads(files[core - 1][1][i]) intpspec.append(curspec) spectra_dict = { "PARAMVAL": paramval, "INTPSPEC": intpspec, } for i in range(len(fnames)): try: os.remove(fnames[i]) except FileNotFoundError: pass table = TableModel( pars_dict, energy_dict, spectra_dict, nintpars=len(pars_dict['NAME']), ) table.save_to(c.TableName) print("Done!")
def __init__(self, app, ui, config, parent=None): super(MainWindow, self).__init__(parent) print('\n---------- GAVLab RTK Survey ----------') def setupMOOS(): # manual threading is only necessary if reading messages from moos # roslaunch automatically configures threads - ros is superior to moos self.comm_arch = 'moos' try: MainWindow.viz_ip = config['ip'] MainWindow.viz_port = config['port'] except: pass self.thread = MainWindow.VizThread() self.moos_widget = MoosWidget(config['moos']) self.requestPosition.connect(self.moos_widget.onPositionRequested) self.moos_widget.sendPosition.connect(self.receivePosition) print('MOOS setup') def setupROS(): self.comm_arch = 'ros' # ... print('ROS setup') # Determine Comm arch if config['ros']: import rospy, roslib roslib.load_manifest('survey_gui') setupROS() elif config['moos']: from moos_comm import MoosWidget, MOOSPositionWarning, MOOSConnectionWarning setupMOOS() else: raise Exception('Need a config file with comm architecture') self.app = app # reference to the Qt Application self.ui = ui self.ui.setupUi(self) self.config = config # Table self.table_model = TableModel() self.ui.tableView.setModel(self.table_model) self.ui.tableView.horizontalHeader().setStretchLastSection(True) # output self.output_file_dialog = QFileDialog() self.output_file = None self.header = '## GAVLab Survey - Recorded %s\n' + \ '## All data in ECEF (m): X Y Z Description\n' self.manual_dialog = QtGui.QDialog() self.pos_data = array([None]*3) # latest self.pos_data_good = False self.std_dev_threshold = config["std_dev_threshold"] if not self.std_dev_threshold: # blank string --> accept first position received and record self.std_dev_threshold = inf # Signals/Slots self.ui.actionExit.triggered.connect(self.app.closeAllWindows) self.ui.recordButton.clicked.connect(self.onRecordRequested) self.ui.actionManual_Entry.triggered.connect(self.addManualPoint) self.ui.actionWrite.triggered.connect(self.writeToFile) # Number cruncing states (iterative) self._sum = array([0.0]*3) self._2sum = array([0.0]*3)
class MainWindow(QtGui.QMainWindow, QtCore.QObject): """survey mainwindow class""" requestPosition = QtCore.Signal() viz_ip = '127.0.0.1' viz_port = 9001 class VizThread(QtCore.QThread): """Thread for the viz MainWindow""" def run(): """reimplement run()""" socket = QtNetwork.QTcpSocket() socket.connectToHost(MainWindow.viz_ip, MainWindow.viz_port) self.exec_() def __init__(self, app, ui, config, parent=None): super(MainWindow, self).__init__(parent) print('\n---------- GAVLab RTK Survey ----------') def setupMOOS(): # manual threading is only necessary if reading messages from moos # roslaunch automatically configures threads - ros is superior to moos self.comm_arch = 'moos' try: MainWindow.viz_ip = config['ip'] MainWindow.viz_port = config['port'] except: pass self.thread = MainWindow.VizThread() self.moos_widget = MoosWidget(config['moos']) self.requestPosition.connect(self.moos_widget.onPositionRequested) self.moos_widget.sendPosition.connect(self.receivePosition) print('MOOS setup') def setupROS(): self.comm_arch = 'ros' # ... print('ROS setup') # Determine Comm arch if config['ros']: import rospy, roslib roslib.load_manifest('survey_gui') setupROS() elif config['moos']: from moos_comm import MoosWidget, MOOSPositionWarning, MOOSConnectionWarning setupMOOS() else: raise Exception('Need a config file with comm architecture') self.app = app # reference to the Qt Application self.ui = ui self.ui.setupUi(self) self.config = config # Table self.table_model = TableModel() self.ui.tableView.setModel(self.table_model) self.ui.tableView.horizontalHeader().setStretchLastSection(True) # output self.output_file_dialog = QFileDialog() self.output_file = None self.header = '## GAVLab Survey - Recorded %s\n' + \ '## All data in ECEF (m): X Y Z Description\n' self.manual_dialog = QtGui.QDialog() self.pos_data = array([None]*3) # latest self.pos_data_good = False self.std_dev_threshold = config["std_dev_threshold"] if not self.std_dev_threshold: # blank string --> accept first position received and record self.std_dev_threshold = inf # Signals/Slots self.ui.actionExit.triggered.connect(self.app.closeAllWindows) self.ui.recordButton.clicked.connect(self.onRecordRequested) self.ui.actionManual_Entry.triggered.connect(self.addManualPoint) self.ui.actionWrite.triggered.connect(self.writeToFile) # Number cruncing states (iterative) self._sum = array([0.0]*3) self._2sum = array([0.0]*3) ############################################################################ ##### Signals & Slots Stuff ############################################## ############################################################################ @QtCore.Slot(tuple) def receivePosition(self, pos): """connected to moos widget's position sender Assume self.pos_data_good = False at invocation""" ## TODO make indexing better here (check length of pos with length of pos_data) n = 0 while True: try: i = pos.next() self.pos_data[n] = i except StopIteration: break n += 1 if n == len(self.config['moos']['desired_variables']): # TODO refer to subscribed vars of either comm set self.pos_data_good = True else: raise MOOSPositionWarning('Not enough values received') @QtCore.Slot() def onRecordRequested(self): """When the record button is pressed, listens to moos until good position acquired for write""" self._sum = array([0.0]*3) self._2sum = array([0.0]*3) n = int(0) keep_averaging = True print('\nRecord requested') while keep_averaging: # Get values self.pos_data_good = False try: # put most time consuming procs in a catcher self.requestPosition.emit() sleep(1) except KeyboardInterrupt: # user has requested stop print('Aborting Record') self.ui.recordButton.setChecked(False) break if not self.pos_data_good: print('\tWaiting for good data ...') pass else: print('\tGood data set recieved: (%.2f, %.2f, %.2f) ' % \ (self.pos_data[0], self.pos_data[1], self.pos_data[2])) n += 1 n, _mean, _stddev_mag = self.iterateRecord(n) print('\tStd Dev magnitude = %f' % _stddev_mag) # Check the variance magnitude if n == 1: continue if _stddev_mag < self.std_dev_threshold: x = _mean[0] y = _mean[1] z = _mean[2] description = self.ui.descriptionLineEdit.text() self.addEntry(x=x, y=y, z=z, description=description) # exit stuff print('\t---> Survey Point Added: ( %f , %f , %f ) %s\n' % (x, y, z, description)) keep_averaging = False self.ui.recordButton.setChecked(False) # done recording self.ui.descriptionLineEdit.setText('') else: print('\tWaiting for variance to drop...\n') @QtCore.Slot() def addManualPoint(self): x, x_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input X Coordinate", "(ECEF) X:", 0.0, -1e9, 1e9, 1) if not x_ok: return y, y_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input Y Coordinate", "(ECEF) Y:", 0.0, -1e9, 1e9, 1) if not y_ok: return z, z_ok = QtGui.QInputDialog.getDouble(self.manual_dialog, "Input Z Coordinate", "(ECEF) Z:", 0.0, -1e9, 1e9, 1) if not z_ok: return desc, desc_ok = QtGui.QInputDialog.getText(self.manual_dialog, "Input Point Description", "Description:", QtGui.QLineEdit.Normal) if not desc_ok: return self.addEntry(x=x, y=y, z=z, description=desc) @QtCore.Slot() def writeToFile(self): self.output_file = open( str(self.output_file_dialog.getOpenFileName()[0]), 'w' ) # Header self.output_file.write(self.header % asctime(localtime(time()))) for line in self.getAllData(): line = (str(line[0]), str(line[1]), str(line[2]), line[3]) for item in line: self.output_file.write('%s\t\t' % item) self.output_file.write('\n') self.output_file.close() print('Output Log File Written!') # @QtCore.Slot() # def onExitRequested(self): ############################################################################ ##### Helper functions #################################################### ############################################################################ def iterateRecord(self, n): # calculate the variance self._sum += self.pos_data self._2sum += self.pos_data**2 _mean = self._sum/n _var = self._2sum/n - _mean**2 _sdev = sqrt(abs(_var)) self.updateLCD(var=_var) _stddev_mag = sqrt(sum(_sdev**2)) return n, _mean, _stddev_mag def updateLCD(self, var=(0, 0, 0), stddev=(0, 0, 0)): """update the variance LCD's while waiting for point to go low""" # print('MainWindow: showVariance') self.ui.xVarianceLcd.display(var[0]) self.ui.yVarianceLcd.display(var[1]) self.ui.zVarianceLcd.display(var[2]) self.ui.xStdDevLcd.display(stddev[0]) self.ui.yStdDevLcd.display(stddev[1]) self.ui.zStdDevLcd.display(stddev[2]) def addEntry(self, x=None, y=None, z=None, description=None): if x is None and y is None and z is None and description is None: raise Exception('something has to go into the entry') point = {"x":x, "y":y, "z":z, "description":description} points = self.table_model.points[:] # TODO check for duplicates by attempting to remove # Assume new point self.table_model.insertRows(0) # at position zero ix = self.table_model.index(0, 0, QtCore.QModelIndex()) self.table_model.setData(ix, point["x"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 1, QtCore.QModelIndex()) self.table_model.setData(ix, point["y"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 2, QtCore.QModelIndex()) self.table_model.setData(ix, point["z"], QtCore.Qt.EditRole) ix = self.table_model.index(0, 3, QtCore.QModelIndex()) self.table_model.setData(ix, point["description"], QtCore.Qt.EditRole) # may need some resizing # self.currentWidget.resizeRowToContents(ix.row()) ##!! AttributeError: 'MainWindow' object has no attribute 'currentWidget' def getAllData(self): data = [] for pt in range(len(self.table_model.points)): data.append([]) for w in range(4): ix = self.table_model.index(pt, w, QtCore.QModelIndex()) data[pt].append(self.table_model.data(ix)) return data
def spawnTables(self,file,size,pos,angle): name=self.getNextName() model=TableModel(file) model.spawnModel(pos,angle,size,name) self.models.append(model) return