class FormTabWidget(QWidget): def __init__(self, datalist, comment="", parent=None): QWidget.__init__(self, parent) layout = QHBoxLayout() self.contentsWidget = QListWidget() self.contentsWidget.setViewMode(QListView.ListMode) self.contentsWidget.setMovement(QListView.Static) self.contentsWidget.setMaximumWidth(128) self.pagesWidget = QStackedWidget() layout.addWidget(self.contentsWidget) layout.addWidget(self.pagesWidget) self.setLayout(layout) self.widgetlist = [] for elem in datalist: if len(elem) == 4: data, title, comment, icon = elem else: data, title, comment = elem icon = None if len(data[0]) == 3: widget = FormComboWidget(data, comment=comment, parent=self) else: widget = FormWidget(data, comment=comment, parent=self) #index = self.tabwidget.addTab(widget, title) #self.tabwidget.setTabToolTip(index, comment) self.pagesWidget.addWidget(widget) contentItem = QListWidgetItem(self.contentsWidget) if icon: contentItem.setIcon(icon) contentItem.setText(title) contentItem.setToolTip(comment) contentItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.contentsWidget.addItem(contentItem) self.widgetlist.append(widget) self.contentsWidget.currentRowChanged.connect(self.changePage) def changePage(self, current): if current != -1: self.pagesWidget.setCurrentIndex(current) def setup(self): for widget in self.widgetlist: widget.setup() def get(self): return [ widget.get() for widget in self.widgetlist]
class MiniCalculation(QDialog): AppName = u"迷你计算器" def __init__(self, parent=None): super(MiniCalculation, self).__init__(parent) self.btnHelpState = False self.setWindowTitle(MiniCalculation.AppName) self.txtBrower = QTextBrowser() self.txtLine = QLineEdit() self.txtLine.setPlaceholderText(u"请输入表达式,按回车结束...") self.btnCal = QPushButton(u"计算") self.btnClear = QPushButton(u"清空") self.btnHelp = QPushButton(u"特殊函数表>>") self.btnHelp.setCheckable(True) self.btnHelp.setChecked(True) mathList = [s for s in dir(math) if not s.startswith("__")] self.listWidget = QListWidget() self.listWidget.addItems(mathList) for i in range(len(mathList)): item = self.listWidget.item(i) strFun = item.text() + '.__doc__' item.setToolTip(eval(str(strFun))) self.listWidget.setMaximumWidth(100) midLay = QHBoxLayout() midLay.addWidget(self.btnCal) midLay.addWidget(self.btnClear) midLay.addStretch() midLay.addWidget(self.btnHelp) bottomLay = QHBoxLayout() bottomLay.addWidget(self.txtBrower) bottomLay.addWidget(self.listWidget) lay = QVBoxLayout() lay.addWidget(self.txtLine) lay.addItem(midLay) lay.addItem(bottomLay) self.resize(450, 300) self.setLayout(lay) self.updateUI() self.btnCal.clicked.connect(self.btnCalClicked) self.btnClear.clicked.connect(self.txtLine.clear) self.btnClear.clicked.connect(self.txtBrower.clear) self.btnHelp.clicked.connect(self.updateUI) self.listWidget.itemDoubleClicked.connect(self.listItemDoubleClicked) def updateUI(self): state = not self.btnHelp.isChecked() self.listWidget.setHidden(state) text = u"特殊函数表>>" if state else u"特殊函数表<<" self.btnHelp.setText(text) def btnCalClicked(self): try: txt = str(self.txtLine.text()) self.txtBrower.append("%s = <b>%s</b>" % (txt, eval(txt))) except UnicodeEncodeError: QMessageBox.warning(self,u"QData -- 迷你计算机", u"表达式中存在中文或全角字符\n", QMessageBox.Ok) except: self.txtBrower.append("<font color=red>%s <b>is invalid</b>" % txt) def listItemDoubleClicked(self): item = self.listWidget.currentItem() self.txtLine.insert(item.text()) self.txtLine.setFocus()
class ConfigDialog(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.contents_widget = QListWidget() self.contents_widget.setMovement(QListView.Static) self.contents_widget.setMinimumWidth(120) self.contents_widget.setMaximumWidth(120) self.contents_widget.setSpacing(1) bbox = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Apply |QDialogButtonBox.Cancel) self.apply_btn = bbox.button(QDialogButtonBox.Apply) self.connect(bbox, SIGNAL("accepted()"), SLOT("accept()")) self.connect(bbox, SIGNAL("rejected()"), SLOT("reject()")) self.connect(bbox, SIGNAL("clicked(QAbstractButton*)"), self.button_clicked) self.pages_widget = QStackedWidget() self.connect(self.pages_widget, SIGNAL("currentChanged(int)"), self.current_page_changed) self.connect(self.contents_widget, SIGNAL("currentRowChanged(int)"), self.pages_widget.setCurrentIndex) self.contents_widget.setCurrentRow(0) hlayout = QHBoxLayout() hlayout.addWidget(self.contents_widget) hlayout.addWidget(self.pages_widget) hlayout.setStretch(1,1) btnlayout = QHBoxLayout() btnlayout.addStretch(1) btnlayout.addWidget(bbox) vlayout = QVBoxLayout() vlayout.addLayout(hlayout) vlayout.addLayout(btnlayout) self.setLayout(vlayout) self.setWindowTitle("Preferences") self.setWindowIcon(get_icon("configure.png")) def get_current_index(self): """Return current page index""" return self.contents_widget.currentRow() def set_current_index(self, index): """Set current page index""" self.contents_widget.setCurrentRow(index) def accept(self): """Reimplement Qt method""" for index in range(self.pages_widget.count()): configpage = self.pages_widget.widget(index) if not configpage.is_valid(): return configpage.apply_changes() QDialog.accept(self) def button_clicked(self, button): if button is self.apply_btn: # Apply button was clicked configpage = self.pages_widget.currentWidget() if not configpage.is_valid(): return configpage.apply_changes() def current_page_changed(self, index): widget = self.pages_widget.widget(index) self.apply_btn.setVisible(widget.apply_callback is not None) self.apply_btn.setEnabled(widget.is_modified) def add_page(self, widget): self.connect(self, SIGNAL('check_settings()'), widget.check_settings) self.connect(widget, SIGNAL('show_this_page()'), lambda row=self.contents_widget.count(): self.contents_widget.setCurrentRow(row)) self.connect(widget, SIGNAL("apply_button_enabled(bool)"), self.apply_btn.setEnabled) self.pages_widget.addWidget(widget) item = QListWidgetItem(self.contents_widget) item.setIcon(widget.get_icon()) item.setText(widget.get_name()) item.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) item.setSizeHint(QSize(0, 25)) def check_all_settings(self): """This method is called to check all configuration page settings after configuration dialog has been shown""" self.emit(SIGNAL('check_settings()'))
class MainWindow(QMainWindow): """The main window widget for the program. """ def __init__(self, parent=None): super(MainWindow, self).__init__(parent) #### 1 CREATE AND INITIALIZE DATA STRUCTURES #### self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} # Y selector on Left self.ySelector = QListWidget() ySelectorLabel = QLabel("y axis channel") self.ySelector.setMaximumWidth(ySelectorLabel.sizeHint().width()) # File name and plot in the middle self.sourceFileName = QLabel("None") self.sourceFileName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sourceFileLabel = QLabel("current file") sourceFileLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) # Matplotlib canvas fig = Figure(dpi=100) self.canvas = FigureCanvas(fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) mpl_toolbar = NavigationToolbar(self.canvas, self.canvas) self.axes = fig.add_subplot(111) # X selector on bottom self.xSelector = QListWidget() self.xSelector.addItem("Time") self.xSelector.setFlow(0) xSelectorLabel = QLabel("x axis channel") self.xSelector.setMaximumHeight(self.xSelector.sizeHintForColumn(0)) # Offset and parameter widgets on the right top self.offsetThing = OffsetWidget() self.attributesThing = AttributesWidget() # Save channel on right bottom self.save_chan_chkbx = QCheckBox() save_chan_label = QLabel("Save Channel") # Status bar at the bottom self.fileSizeLabel = QLabel("File Size: {f_size:0>7.3f} MB".format(f_size=0.0)) self.fileSizeLabel.setFixedWidth(self.fileSizeLabel.sizeHint().width()+10) self.fileSizeLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.yChanLength = QLabel("Y Channel Length: {y_len:0>7.0f}".format(y_len=0.0)) self.yChanLength.setFixedWidth(self.yChanLength.sizeHint().width()+10) self.yChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.xChanLength = QLabel("X Channel Length: {x_len:0>7.0f}".format(x_len=0.0)) self.xChanLength.setFixedWidth(self.xChanLength.sizeHint().width()+10) self.xChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.fileSizeLabel) status.addPermanentWidget(self.yChanLength) status.addPermanentWidget(self.xChanLength) status.showMessage("Ready", 5000) #2 Create the central widget self.centralWidget = QWidget() # Left Side selectorLayout = QVBoxLayout() #selectorLayout.addWidget(xSelectorLabel) #selectorLayout.addWidget(self.xSelector) selectorLayout.addWidget(ySelectorLabel) selectorLayout.addWidget(self.ySelector) selectorLayout.addStretch() # Center centralLayout = QVBoxLayout() fileNameLayout = QHBoxLayout() xSelectorLayout = QHBoxLayout() fileNameLayout.addWidget(sourceFileLabel) fileNameLayout.addWidget(self.sourceFileName) xSelectorLayout.addWidget(xSelectorLabel) xSelectorLayout.addWidget(self.xSelector) centralLayout.addLayout(fileNameLayout) centralLayout.addWidget(self.canvas) centralLayout.addWidget(mpl_toolbar) centralLayout.addLayout(xSelectorLayout) # Right bottom save_chan_layout = QHBoxLayout() save_chan_layout.addWidget(self.save_chan_chkbx) save_chan_layout.addWidget(save_chan_label) # Right Side rightLayout = QVBoxLayout() rightLayout.addWidget(self.offsetThing) rightLayout.addWidget(self.attributesThing) rightLayout.addStretch() rightLayout.addLayout(save_chan_layout) layout = QHBoxLayout() layout.addLayout(selectorLayout) layout.addLayout(centralLayout) layout.addLayout(rightLayout) self.centralWidget.setLayout(layout) self.setCentralWidget(self.centralWidget) self.resize(self.sizeHint()) #3 Create and set up any dock windows #4 Create actions and insert them into menus and toolbars fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "exit", "Close the application") fileOpenAction = self.createAction("&Open TDMS File", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing TDMS file") fileExportAction = self.createAction("&Export", self.exprtToHDF5, "Ctrl+E", tip="Export the TDMS data to HDF5") self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileOpenAction, fileExportAction, fileQuitAction) #self.addActions(self.fileMenu, self.fileMenuActions) self.xSelector.itemSelectionChanged.connect(self.make_x_selection) self.ySelector.itemSelectionChanged.connect(self.make_y_selection) self.offsetThing.new_offset.connect(self.subtract_offset) self.fileMenu.triggered.connect(self.update_file_menu) self.save_chan_chkbx.stateChanged.connect(self.toggle_save) #5 Read in application's settings settings = QSettings() # Restore the geometry and state of the main window from last use #self.restoreGeometry(settings.value("MainWindow/Geometry")) #self.restoreState(settings.value("MainWindow/State")) self.setWindowTitle("TDMS to HDF5 Converter") self.recentFiles = settings.value("RecentFiles") if not self.recentFiles: self.recentFiles = [] self.update_file_menu() def update_ui(self): pass def initVariables(self): self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): # Create the action action = QAction(text, self) # Give it its icon if icon is not None: action.setIcon(QIcon(":/{icon}.png".format(icon=icon))) # Give it its shortcut if shortcut is not None: action.setShortcut(shortcut) # Set up its help/tip text if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) # Connect it to a signal if slot is not None: self.connect(action, SIGNAL(signal), slot) # Make it checkable if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def update_file_menu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = self.filename if self.filename is not None else None recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction("&{num} {name}".format(num=i+1, name=QFileInfo(fname).fileName()), self) action.setData(fname) action.triggered.connect(lambda: self.loadFile(fname)) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileOpen(self): # Process 1 self.initVariables() basedir = os.path.dirname(self.filename) if self.filename is not None \ else "~/Documents/PhD/root/raw-data/sio2al149/CryoMeasurement" formats = "TDMS files (*.tdms)" fname = QFileDialog.getOpenFileName(self, "Open a TDMS File", basedir, formats) # Process 1.1 Collect file name if fname and QFile.exists(fname): self.loadFile(fname) def loadFile(self, fname): # Process 1.2 Generate TDMS file object self.add_recent_file(fname) self.tdms_file_object = TdmsFile(fname) self.filename = fname # Process 1.3 Read data into local structure if self.tdms_file_object: # Process 1.3.0 Generate group list group_list = self.tdms_file_object.groups() # Processes 1.3.1 through 1.3.3 Sort TDMS data for group in group_list: self.sortTDMSGroupData(group) message = "Loaded {f_name}".format(f_name=os.path.basename(fname)) self.sourceFileName.setText(os.path.basename(fname)) # Process 2.1 Populate channel selection lists self.update_selectors() else: message = "Failed to load {f_name}".format(f_name=os.path. basename(fname)) self.statusBar().showMessage(message, 5000) fsize = os.path.getsize(self.filename) self.fileSizeLabel.setText("File Size: {file_size:>7.3f} MB".format(file_size=fsize/1E6)) #TODO self.updateStatus(message) # see Rapid GUI ch06.pyw def add_recent_file(self, fname): if fname is None: return if not fname in self.recentFiles: self.recentFiles.insert(0, fname) while len(self.recentFiles) > 9: self.recentFiles.pop() def sortTDMSGroupData(self, group): # Process 1.3 Sort Group data # Process 1.3.1 Get <Group> Channels group_props = self.tdms_file_object.object(group).properties # Process 1.3.2 Get <Group> Properties group_chans = self.tdms_file_object.group_channels(group) # Process 1.3.3 Create a new channel in the registry for each channel # in the group for chan in group_chans: chan_name = chan.path.split('/')[-1].strip("'") # Process 1.3.3.1 Generate new channel object and fill with data # Some of the TDMS channels were created, but never populated with # data. The following weeds those out. try: new_chan = Channel(chan_name, device=group, meas_array=chan.data) except TypeError: self.statusBar().showMessage("Channel {chan} in {dev} has no data" .format(chan=chan_name, dev=group), 5000) try: new_chan.set_start_time(chan.property("wf_start_time")) new_chan.set_delta_time(chan.property("wf_increment")) new_chan.set_location('raw/{c2_name}'.format(c2_name=chan_name)) if chan_name not in ['TCap', 'xMagnet']: new_chan.set_write() # Some of the channel-specific properties were actually # saved in the group object's properties list. # We retrieve those here. # Process 1.3.3.2 Resort the group properties of TDMS ADWin if group == "ADWin": for atr_name in ADWIN_DICT[chan_name]: try: new_chan.attributes[atr_name] = \ group_props[atr_name] except KeyError: #print('The key {a_name} was not found.' # .format(a_name=atr_name)) #print('The keys available are\n') #print(group_props) pass # Process 1.3.3.3 Add new channel to the registry self.channel_registry[chan_name] = new_chan #print('\tChannel name:\t{ch_name}'.format(ch_name=chan_name)) except (KeyError, UnboundLocalError): pass #print('Error: Was unable to load {c3_name}' # .format(c3_name=chan_name)) def update_selectors(self): # Clear the selectors self.xSelector.clear() self.ySelector.clear() # Add the names of the channels in the registry to both selectors for key in self.channel_registry.keys(): self.xSelector.addItem(key) self.ySelector.addItem(key) # Add the time "channel" to the x selector self.xSelector.addItem('Time') # Sort the lists (alphabetically) otherwise the order constantly changes self.xSelector.sortItems() self.ySelector.sortItems() # Set the current x selector default default_x_item = self.xSelector.findItems(DEFAULTX, Qt.MatchExactly) self.xSelector.setCurrentItem(default_x_item[0]) # Set the current y selector default try: default_y_item = self.ySelector.findItems(DEFAULTY, Qt.MatchExactly) self.ySelector.setCurrentItem(default_y_item[0]) except IndexError: self.ySelector.setCurrentRow(0) self.xSelector.setMinimumHeight(self.xSelector.sizeHintForRow(0)*3) self.ySelector.setMinimumWidth(self.ySelector.sizeHintForColumn(0)+10) def exprtToHDF5(self): # Process 5 Save to HDF5 fname = self.filename.split('.')[0] + '.hdf5' basedir = "/home/chris/Documents/PhD/root/data/sio2al149/cryo_measurement" if not os.path.exists(basedir): os.makedirs(basedir) formats = "TDMS files (*.hdf5 *.h5 *.he5 *.hdf)" dialog = QFileDialog() dialog.setFilter(formats) dialog.setDefaultSuffix("*.hdf5") dialog.selectFile(os.path.join(basedir, fname)) dialog.setDirectory(basedir) if dialog.exec_(): fname = dialog.selectedFiles() else: return # Process 5.1 Create HDF5 file object hdf5_file_object = h5py.File(fname[0]) # Process 5.2 Create channels at their locations for chan in self.channel_registry: chan_obj = self.channel_registry[chan] chan_name = chan #print(chan, self.channel_registry[chan].location, # self.channel_registry[chan].write_to_file) # Process 5.2.1 Write channel data if self.channel_registry[chan].write_to_file: dset = hdf5_file_object.create_dataset(chan_obj.location, data=chan_obj.data) # Process 5.2.2 Write channel attributes for attr_name in self.channel_registry[chan].attributes: attr_value = self.channel_registry[chan].attributes[attr_name] # Convert the datetime format to a string if type(attr_value) is datetime: attr_value = attr_value.isoformat() # There's currently a wierd bug when dealing with python3 # strings. # This gets around that if type(attr_value) is str: #attr_value = attr_value.encode('utf-8') #attr_value = np.string_(attr_value, dtype="S10") attr_value = np.string_(attr_value) dset.attrs.create(attr_name, attr_value) # Process 5.3 Write data to file hdf5_file_object.flush() hdf5_file_object.close() def make_x_selection(self): self.x_change = True # Get the name of the newly selected channel self.xSelection = self.xSelector.currentItem().text() # Get the axis label self.xLabel = self.gen_axis_label(self.xSelection) # If the xSelection is time, use the time data instead of measurement # data if self.xSelection == 'Time': try: self.xArray = self.channel_registry[self.ySelection].time except KeyError: self.xArray = np.array([]) else: self.xArray = self.channel_registry[self.xSelection].data if self.yLabel: self.plotData() self.xSelection_old = self.xSelector.currentItem() self.x_change = False self.xChanLength.setText("X Channel Length: {x_len:>7.0f}".format(x_len=len(self.xArray))) def make_y_selection(self, offset=0.0): self.y_change = True # Get the names of the selected channels from the selectors try: self.ySelection = self.ySelector.currentItem().text() except AttributeError: self.ySelection = DEFAULTY # Set save channel checkbox state self.save_chan_chkbx.setChecked(self.channel_registry[self.ySelection] .write_to_file) # Get the axis label self.yLabel = self.gen_axis_label(self.ySelection) # Generate the y-channel array to be plotted self.yArray = self.channel_registry[self.ySelection].data - offset # Update the attributes view self.attributesThing.clear_attributes() self.attributesThing.select_chan(self.channel_registry[self.ySelection]) if self.xSelection == 'Time': self.make_x_selection() else: self.plotData() self.ySelection_old = self.ySelector.currentItem() self.y_change = False self.yChanLength.setText("Y Channel Length: {y_len:>7.0f}".format(y_len=len(self.yArray))) def gen_axis_label(self, chan_name): # Generate the axis labels based on the selected channels # Cycle through the labes in the AXESLABELS dictionary for axlbl in AXESLABELS.keys(): # Cycle through the channel names in each label's dictionary entry for cn in AXESLABELS[axlbl]: # If a channel equals one of the selections, save the label if chan_name == cn: label = axlbl return label def plotData(self): # Clear the plot self.axes.cla() # Turn on the grid self.axes.grid(True) # Set the labels try: self.axes.set_xlabel(self.xLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.xSelection), 5000) try: self.axes.set_ylabel(self.yLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.ySelection), 5000) # Try plotting the data. There are still no checks in place to make sure # the arrays are of the same length. try: # Plot the data and label it self.axes.plot(self.xArray, self.yArray, label=self.ySelection) # Show the legend self.axes.legend(loc=0) # Draw everything self.canvas.draw() except ValueError: QMessageBox.warning(self, "Unequal Arrays", "{y_chan} and {x_chan} " .format(y_chan=self.ySelection, x_chan=self.xSelection) + \ "are not the same length!") if self.x_change: self.xSelector.setCurrentItem(self.xSelection_old) elif self.y_change: self.ySelector.setCurrentItem(self.ySelection_old) def subtract_offset(self): "Subtract the offset entered from the currently selected y channel." offset = self.offsetThing.offset_entry.value() self.make_y_selection(offset=offset) def toggle_save(self): self.channel_registry[self.ySelection].write_to_file = \ self.save_chan_chkbx.isChecked() def create_new_channel(self, ch_name): "Create a new channel in the registry." #print(ch_name) pass def closeEvent(self, event): """Reimplementation of the close even handler. We have to reimplement this because not all close actions, e.g. clicking the X button, call the close() method. We want to catch this so we can give the user the opportunity to save unsaved changes before the program exits. """ settings = QSettings() #settings.setValue("MainWindow/Geometry", QVariant( # self.saveGeometry())) #settings.setValue("MainWindow/State", QVariant( # self.saveState())) if self.recentFiles: recentFiles = self.recentFiles else: recentFiles = [] settings.setValue("RecentFiles", recentFiles)
class ConfigDialog(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.contents_widget = QListWidget() self.contents_widget.setMovement(QListView.Static) self.contents_widget.setMinimumWidth(120) self.contents_widget.setMaximumWidth(120) self.contents_widget.setSpacing(1) bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel) self.apply_btn = bbox.button(QDialogButtonBox.Apply) self.connect(bbox, SIGNAL("accepted()"), SLOT("accept()")) self.connect(bbox, SIGNAL("rejected()"), SLOT("reject()")) self.connect(bbox, SIGNAL("clicked(QAbstractButton*)"), self.button_clicked) self.pages_widget = QStackedWidget() self.connect(self.pages_widget, SIGNAL("currentChanged(int)"), self.current_page_changed) self.connect(self.contents_widget, SIGNAL("currentRowChanged(int)"), self.pages_widget.setCurrentIndex) self.contents_widget.setCurrentRow(0) hlayout = QHBoxLayout() hlayout.addWidget(self.contents_widget) hlayout.addWidget(self.pages_widget) hlayout.setStretch(1, 1) btnlayout = QHBoxLayout() btnlayout.addStretch(1) btnlayout.addWidget(bbox) vlayout = QVBoxLayout() vlayout.addLayout(hlayout) vlayout.addLayout(btnlayout) self.setLayout(vlayout) self.setWindowTitle("Preferences") self.setWindowIcon(get_icon("configure.png")) def get_current_index(self): """Return current page index""" return self.contents_widget.currentRow() def set_current_index(self, index): """Set current page index""" self.contents_widget.setCurrentRow(index) def accept(self): """Reimplement Qt method""" for index in range(self.pages_widget.count()): configpage = self.pages_widget.widget(index) if not configpage.is_valid(): return configpage.apply_changes() QDialog.accept(self) def button_clicked(self, button): if button is self.apply_btn: # Apply button was clicked configpage = self.pages_widget.currentWidget() if not configpage.is_valid(): return configpage.apply_changes() def current_page_changed(self, index): widget = self.pages_widget.widget(index) self.apply_btn.setVisible(widget.apply_callback is not None) self.apply_btn.setEnabled(widget.is_modified) def add_page(self, widget): self.connect(self, SIGNAL('check_settings()'), widget.check_settings) self.connect(widget, SIGNAL('show_this_page()'), lambda row=self.contents_widget.count(): self. contents_widget.setCurrentRow(row)) self.connect(widget, SIGNAL("apply_button_enabled(bool)"), self.apply_btn.setEnabled) self.pages_widget.addWidget(widget) item = QListWidgetItem(self.contents_widget) item.setIcon(widget.get_icon()) item.setText(widget.get_name()) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) item.setSizeHint(QSize(0, 25)) def check_all_settings(self): """This method is called to check all configuration page settings after configuration dialog has been shown""" self.emit(SIGNAL('check_settings()'))
class I2CWidget(QWidget): def __init__(self, status, actions): super (I2CWidget, self).__init__() self.status = status self.actions = actions self.row_add_action = QAction("Add Row", self) self.row_add_action.triggered.connect(self.add_row) self.row_delete_action = QAction("Delete Row", self) self.row_delete_action.triggered.connect(self.remove_row) self.default_script_list = QListWidget() self.default_script_list.setMaximumWidth(150) self.default_script_list.itemDoubleClicked.connect(self.default_script_load_double_clicked) self.setWindowTitle("Standalone I2C Widget") layout = QHBoxLayout() self.load_callback = None self.toolbar = QToolBar() self.toolbar.setMaximumWidth(150) self.toolbar.setSizePolicy(Qt.QSizePolicy.Maximum, Qt.QSizePolicy.Maximum) self.tools_layout= QVBoxLayout() self.save_loader = SaveLoader(extensions = ["csv"], initial_file = "i2c_config_file") self.toolbar.setOrientation(QtCore.Qt.Vertical) self.toolbar.addAction(self.row_add_action) self.toolbar.addAction(self.row_delete_action) self.tools_layout.addWidget(self.toolbar) self.tools_layout.addWidget(QLabel("Default Scripts")) self.tools_layout.addWidget(self.default_script_list) default_script_load = QPushButton("Load") default_script_load.clicked.connect(self.default_script_load_clicked) self.tools_layout.addWidget(default_script_load) self.tab_view = QTabWidget() self.init_table = I2CTable(self.status, self.actions, loop = False) self.loop_table = I2CTable(self.status, self.actions, loop = True) self.tab_view.addTab(self.init_table, "Start") self.tab_view.addTab(self.loop_table, "Loop") self.control_view = I2CControlView(self.status, self.actions) self.actions.i2c_update_view.connect(self.update_i2c_transactions) layout.addLayout(self.tools_layout) io_layout = QVBoxLayout() io_layout.addWidget(self.save_loader) name_desc_layout = QHBoxLayout() self.config_name = QLineEdit("Name") self.config_name.setMinimumWidth(100) self.config_name.setSizePolicy(Qt.QSizePolicy.Preferred, Qt.QSizePolicy.Preferred) self.config_desc = QLineEdit("Description") name_desc_layout.addWidget(self.config_name) name_desc_layout.addWidget(self.config_desc) io_layout.addLayout(name_desc_layout) io_layout.addWidget(self.tab_view) layout.addLayout(io_layout) #layout.addWidget(self.tab_view) layout.addWidget(self.control_view) self.setLayout(layout) self.actions.i2c_update_read_view.connect(self.update_read_view) self.init_read_data = None self.loop_read_data = None self.read_timer = QTimer(self) self.read_timer.setInterval(SINGLE_SHOT_TIMEOUT) self.read_timer.setSingleShot(True) def get_config_name(self): return self.config_name.text() def set_config_name(self, name): self.config_name.setText(name) def get_config_description(self): return self.config_desc.text() def set_config_description(self, description): self.config_desc.setText(description) def add_row(self): if self.tab_view.currentWidget() is self.loop_table: self.actions.i2c_row_add.emit(True) else: self.actions.i2c_row_add.emit(False) def remove_row(self): if self.tab_view.currentWidget() is self.loop_table: self.actions.i2c_row_delete.emit(True) else: self.actions.i2c_row_delete.emit(False) def update_i2c_transactions(self, loop, transactions): if not loop: self.update_i2c_init_transactions(transactions) else: self.update_i2c_loop_transactions(transactions) def update_i2c_init_transactions(self, transactions): self.init_table.update_i2c_transactions(transactions) def update_i2c_loop_transactions(self, transactions): self.loop_table.update_i2c_transactions(transactions) def set_save_callback(self, callback): self.save_loader.set_save_callback(callback) def set_load_callback(self, callback): self.save_loader.set_load_callback(callback) def get_filename(self): return self.save_loader.get_filename() def default_script_load_clicked(self): item = self.default_script_list.currentItem() if item is not None: filename = os.path.join(DEFAULT_SCRIPT_PATH, str(item.text())) if self.load_callback is not None: self.load_callback(filename) #print "Item: %s" % filename def set_load_default_callback(self, callback): self.load_callback = callback def default_script_load_double_clicked(self, item): self.default_script_load_clicked() def load_default_scripts(self): files = os.listdir(DEFAULT_SCRIPT_PATH) self.default_script_list.clear() self.default_script_list.addItems(files) self.default_script_list.setCurrentRow(0) def singleshot_event(self): #print "update I2C Read: in thread: %s" % str(QThread.currentThread().objectName()) if self.init_read_data is not None: self.init_table.update_read_data(self.init_read_data) self.init_read_data = None if self.loop_read_data is not None: self.loop_table.update_read_data(self.loop_read_data) self.loop_read_data = None def update_read_view(self, loop, read_data): #print "read timer active: %s" % str(self.read_timer.isActive()) if loop: self.loop_read_data = read_data else: self.init_read_data = read_data if not self.read_timer.isActive(): self.read_timer.singleShot(SINGLE_SHOT_TIMEOUT, self.singleshot_event) self.read_timer.start()
class ChatTracer(QMainWindow): def __init__(self): super(ChatTracer, self).__init__() self.__initGui() self.__initQeo() self.connect(self, SIGNAL("newLogMsg"), self.__appendLog) def __initGui(self): self.setWindowTitle("ChatTracer") g = QGridLayout() w = QWidget() w.setLayout(g) self.setCentralWidget(w) self.logWindow = QTextEdit() self.logWindow.setReadOnly(True) self.logWindow.setFocusPolicy(Qt.NoFocus) self.logWindow.setMinimumWidth(300) g.addWidget(self.logWindow, 0, 0, 3, 1) l = QLabel("ChatParticipants") g.addWidget(l, 0, 1) self.participants = QListWidget() self.participants.setMaximumWidth(250) self.participants.setFocusPolicy(Qt.NoFocus) g.addWidget(self.participants, 1, 1) pb = QPushButton("Refresh Participants") pb.clicked.connect(self.onRefreshParticipants) g.addWidget(pb, 2, 1) g.setColumnStretch(0, 3) g.setColumnStretch(1, 2) self.show() pb.setFocus() def __initQeo(self): self.participantReader = StateReader( ChatParticipant, onData=self.forwardData, onNoMoreData=lambda cls="ChatParticipant": self.forwardNoMoreData(cls), onDispose=self.forwardDispose) self.msgReader = EventReader(ChatMessage, onData=self.forwardData, onNoMoreData=lambda cls="ChatMessage": self.forwardNoMoreData(cls)) self.connect(self, SIGNAL("onData"), self.onData) self.connect(self, SIGNAL("onNoMoreData"), self.onNoMoreData) self.connect(self, SIGNAL("onDispose"), self.onDispose) def closeApp(self): self.participantReader.close() self.participantReader = None self.msgReader.close() self.msgReader = None def __appendLog(self, msg): self.logWindow.append(msg) def __buildLogMsg(self, prefix, data): msg = [prefix + ": "] if data: msg.append("%s" % data.__class__.__name__) msg.append("{") for k, v in data.__dict__.iteritems(): msg.append("%s='%s'" % (str(k), str(v))) msg.append("}") self.__appendLog(' '.join(msg)) def forwardData(self, s): self.emit(SIGNAL("onData"), s) def forwardDispose(self, s): self.emit(SIGNAL("onDispose"), s) def forwardNoMoreData(self, s): self.emit(SIGNAL("onNoMoreData"), s) def onData(self, sample): self.__buildLogMsg("onData", sample) def onDispose(self, sample): print "onDispose called: %s - %s" % (sample.name, sample.room) def onNoMoreData(self, class_): self.__buildLogMsg("onNoMoreData", None) def onRefreshParticipants(self): self.participants.clear() for s in self.participantReader.states(): self.participants.addItem("%s - %s - %s" % (s.name, s.room, s.state))
class LayerImportBrowser(QDialog): class VectorPage(QWidget): def __init__(self, parent=None, filters="", encodings=[]): QWidget.__init__(self, parent) self.filters = filters self.layerLineEdit = QLineEdit() self.browseToolButton = QToolButton() self.browseToolButton.setAutoRaise(True) self.browseToolButton.setIcon(QIcon(":document-open")) layerLabel = QLabel("&Dataset:") layerLabel.setBuddy(self.layerLineEdit) self.encodingComboBox = QComboBox() self.encodingComboBox.addItems(encodings) encodingLabel = QLabel("&Encoding:") encodingLabel.setBuddy(self.encodingComboBox) hbox = QHBoxLayout() hbox.addWidget(layerLabel) hbox.addWidget(self.layerLineEdit) hbox.addWidget(self.browseToolButton) vbox = QVBoxLayout() vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(encodingLabel) hbox.addWidget(self.encodingComboBox) vbox.addLayout(hbox) self.setLayout(vbox) self.encodingComboBox.setCurrentIndex(self.encodingComboBox.findText("System")) self.connect(self.browseToolButton, SIGNAL("clicked()"), self.browseToFile) self.connect(self.encodingComboBox, SIGNAL("currentIndexChanged(QString)"), self.changeEncoding) def browseToFile(self): dialog = QFileDialog(self, "manageR - Open Vector File", unicode(robjects.r.getwd()[0]), self.filters) if not dialog.exec_() == QDialog.Accepted: return files = dialog.selectedFiles() file = files.first().trimmed() self.layerLineEdit.setText(file) self.emit(SIGNAL("filePathChanged(QString)"), file) def changeEncoding(self, text): self.emit(SIGNAL("encodingChanged(QString)"), text) class RasterPage(QWidget): def __init__(self, parent=None, filters=""): QWidget.__init__(self, parent) self.parent = parent self.filters = filters self.layerLineEdit = QLineEdit() self.browseToolButton = QToolButton() self.browseToolButton.setAutoRaise(True) self.browseToolButton.setIcon(QIcon(":document-open")) layerLabel = QLabel("&Dataset:") layerLabel.setBuddy(self.layerLineEdit) hbox = QHBoxLayout() hbox.addWidget(layerLabel) hbox.addWidget(self.layerLineEdit) hbox.addWidget(self.browseToolButton) vbox = QVBoxLayout() vbox.addLayout(hbox) self.setLayout(vbox) self.connect(self.browseToolButton, SIGNAL("clicked()"), self.browseToFile) def browseToFile(self): dialog = QFileDialog(self, "manageR - Open Raster File", unicode(robjects.r.getwd()[0]), self.filters) if not dialog.exec_() == QDialog.Accepted: return files = dialog.selectedFiles() file = files.first().trimmed() self.layerLineEdit.setText(file) self.emit(SIGNAL("filePathChanged(QString)"), file) def __init__(self, parent=None, vectors="", rasters="", encodings=[]): QDialog.__init__(self, parent) self.contentsWidget = QListWidget() self.setWindowIcon(QIcon(":icon")) self.contentsWidget.setViewMode(QListView.IconMode) self.contentsWidget.setIconSize(QSize(76, 66)) self.contentsWidget.setMovement(QListView.Static) self.contentsWidget.setMaximumWidth(106) self.contentsWidget.setMinimumWidth(106) self.contentsWidget.setMinimumHeight(220) self.contentsWidget.setSpacing(12) self.__filePath = "" self.__encoding = "System" self.__type = 0 self.pagesWidget = QStackedWidget() vectorPage = self.VectorPage(self, vectors, encodings) self.pagesWidget.addWidget(vectorPage) rasterPage = self.RasterPage(self, rasters) self.pagesWidget.addWidget(rasterPage) buttons = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel, Qt.Horizontal, self) self.connect(buttons, SIGNAL("accepted()"), self.accept) self.connect(buttons, SIGNAL("rejected()"), self.reject) self.connect(vectorPage, SIGNAL("filePathChanged(QString)"), self.setFilePath) self.connect(vectorPage, SIGNAL("encodingChanged(QString)"), self.setEncoding) self.connect(rasterPage, SIGNAL("filePathChanged(QString)"), self.setFilePath) self.createIcons() self.contentsWidget.setCurrentRow(0) horizontalLayout = QHBoxLayout() horizontalLayout.addWidget(self.contentsWidget) horizontalLayout.addWidget(self.pagesWidget, 1) mainLayout = QVBoxLayout() mainLayout.addLayout(horizontalLayout) mainLayout.addStretch(1) mainLayout.addSpacing(12) mainLayout.addWidget(buttons) self.setLayout(mainLayout) self.setWindowTitle("manageR - Import Layer") def createIcons(self): vectorButton = QListWidgetItem(self.contentsWidget) vectorButton.setIcon(QIcon(":custom-vector.svg")) vectorButton.setText("Vector Layer") vectorButton.setTextAlignment(Qt.AlignHCenter) vectorButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) rasterButton = QListWidgetItem(self.contentsWidget) rasterButton.setIcon(QIcon(":custom-raster.svg")) rasterButton.setText("Raster Layer") rasterButton.setTextAlignment(Qt.AlignHCenter) rasterButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.connect(self.contentsWidget, SIGNAL("currentItemChanged(QListWidgetItem*, QListWidgetItem*)"), self.changePage) def changePage(self, current, previous): if not current: current = previous self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current)) def filePath(self): return self.__filePath def setFilePath(self, filePath): self.__filePath = filePath def encoding(self): return self.__encoding def setEncoding(self, encoding): self.__encoding = encoding def layerType(self): return self.__type def setLayerType(self, type): self.__type = type def accept(self): self.__type = self.pagesWidget.currentIndex() QDialog.accept(self)
class ChatTracer(QMainWindow): def __init__(self): super(ChatTracer, self).__init__() self.__initGui() self.__initQeo() self.connect(self, SIGNAL("newLogMsg"), self.__appendLog) def __initGui(self): self.setWindowTitle("ChatTracer") g = QGridLayout() w = QWidget() w.setLayout(g) self.setCentralWidget(w) self.logWindow = QTextEdit() self.logWindow.setReadOnly(True) self.logWindow.setFocusPolicy(Qt.NoFocus) self.logWindow.setMinimumWidth(300) g.addWidget(self.logWindow, 0, 0, 3, 1) l = QLabel("ChatParticipants") g.addWidget(l, 0, 1) self.participants = QListWidget() self.participants.setMaximumWidth(250) self.participants.setFocusPolicy(Qt.NoFocus) g.addWidget(self.participants, 1, 1) pb = QPushButton("Refresh Participants") pb.clicked.connect(self.onRefreshParticipants) g.addWidget(pb, 2, 1) g.setColumnStretch(0, 3) g.setColumnStretch(1, 2) self.show() pb.setFocus() def __initQeo(self): self.participantReader = StateReader( ChatParticipant, onData=self.forwardData, onNoMoreData=lambda cls="ChatParticipant": self.forwardNoMoreData( cls), onDispose=self.forwardDispose) self.msgReader = EventReader( ChatMessage, onData=self.forwardData, onNoMoreData=lambda cls="ChatMessage": self.forwardNoMoreData(cls)) self.connect(self, SIGNAL("onData"), self.onData) self.connect(self, SIGNAL("onNoMoreData"), self.onNoMoreData) self.connect(self, SIGNAL("onDispose"), self.onDispose) def closeApp(self): self.participantReader.close() self.participantReader = None self.msgReader.close() self.msgReader = None def __appendLog(self, msg): self.logWindow.append(msg) def __buildLogMsg(self, prefix, data): msg = [prefix + ": "] if data: msg.append("%s" % data.__class__.__name__) msg.append("{") for k, v in data.__dict__.iteritems(): msg.append("%s='%s'" % (str(k), str(v))) msg.append("}") self.__appendLog(' '.join(msg)) def forwardData(self, s): self.emit(SIGNAL("onData"), s) def forwardDispose(self, s): self.emit(SIGNAL("onDispose"), s) def forwardNoMoreData(self, s): self.emit(SIGNAL("onNoMoreData"), s) def onData(self, sample): self.__buildLogMsg("onData", sample) def onDispose(self, sample): print "onDispose called: %s - %s" % (sample.name, sample.room) def onNoMoreData(self, class_): self.__buildLogMsg("onNoMoreData", None) def onRefreshParticipants(self): self.participants.clear() for s in self.participantReader.states(): self.participants.addItem("%s - %s - %s" % (s.name, s.room, s.state))