class Mixin: def createWidgets(self): settings = QSettings() self.searchLabel = QLabel("Search For") self.searchLineEdit = QLineEdit() self.tooltips.append((self.searchLineEdit, """\ <p><b>Search For editor</b></p> <p>The text or regular expression to search for.</p>""")) self.searchLabel.setBuddy(self.searchLineEdit) self.replaceLabel = QLabel("Replace With") self.replaceLineEdit = QLineEdit() self.tooltips.append((self.replaceLineEdit, """\ <p><b>Replace With editor</b></p> <p>The replacement text (which may include backreferences, \\1, \\2, etc., if a regular expression search is being made).</p>""")) self.replaceLabel.setBuddy(self.replaceLineEdit) self.allEntriesRadioButton = QRadioButton("All Entries") self.allEntriesRadioButton.setChecked( bool(int(settings.value("RP/All", 1)))) self.tooltips.append((self.allEntriesRadioButton, """\ <p><b>All Entries</b></p> <p>If checked, the search will consider every entry in the index.</p>""")) self.filteredEntriesRadioButton = QRadioButton("Filtered Entries") self.filteredEntriesRadioButton.setChecked( bool(int(settings.value("RP/Filtered", 0)))) self.tooltips.append((self.filteredEntriesRadioButton, """\ <p><b>Filtered Entries</b></p> <p>If checked, the search will consider only those entries that are in the current filtered view.</p>""")) self.considerLabel = QLabel("Consider") self.scopeGroup = QButtonGroup() self.scopeGroup.addButton(self.allEntriesRadioButton) self.scopeGroup.addButton(self.filteredEntriesRadioButton) self.literalRadioButton = QRadioButton("Literal") self.literalRadioButton.setChecked( bool(int(settings.value("RP/Literal", 1)))) self.tooltips.append((self.literalRadioButton, """<p><b>Literal</b></p> <p>If checked, the <b>Search For</b> text will be searched for literally.</p>""")) self.regexRadioButton = QRadioButton("Regex") self.regexRadioButton.setChecked( bool(int(settings.value("RP/Regex", 0)))) self.tooltips.append((self.regexRadioButton, """<p><b>Regex</b></p> <p>If checked, the <b>Search For</b> text will be searched for as a regular expression pattern.</p>""")) self.matchAsGroup = QButtonGroup() self.matchAsGroup.addButton(self.literalRadioButton) self.matchAsGroup.addButton(self.regexRadioButton) self.ignoreCaseCheckBox = QCheckBox("Ignore Case") self.ignoreCaseCheckBox.setChecked( bool(int(settings.value("RP/ICase", 0)))) self.tooltips.append((self.ignoreCaseCheckBox, """\ <p><b>Ignore Case</b></p> <p>If checked, the <b>Search For</b> text will be searched for case-insensitively.</p>""")) self.wholeWordsCheckBox = QCheckBox("Whole Words") self.wholeWordsCheckBox.setChecked( bool(int(settings.value("RP/WW", 0)))) self.tooltips.append((self.wholeWordsCheckBox, """\ <p><b>Whole Words</b></p> <p>If checked—and when <b>Literal</b> is checked—the <b>Search For</b> text will be matched as whole words.</p> <p>For example, “habit” will not match “habitat” when whole words is checked.</p> <p>(For regular expressions use \\b before and after each word to get whole word matches.)</p>""")) self.replaceInLabel = QLabel("Look In") self.replaceInTermsCheckBox = QCheckBox("Terms") self.replaceInTermsCheckBox.setChecked( bool(int(settings.value("RP/Terms", 1)))) self.tooltips.append((self.replaceInTermsCheckBox, """\ <p><b>Terms</b></p> <p>If checked, the search will look in term texts.</p>""")) self.replaceInPagesCheckBox = QCheckBox("Pages") self.replaceInPagesCheckBox.setChecked( bool(int(settings.value("RP/Pages", 0)))) self.tooltips.append((self.replaceInPagesCheckBox, """\ <p><b>Pages</b></p> <p>If checked, the search will look in pages texts.</p>""")) self.replaceInNotesCheckBox = QCheckBox("Notes") self.replaceInNotesCheckBox.setChecked( bool(int(settings.value("RP/Notes", 0)))) self.tooltips.append((self.replaceInNotesCheckBox, """\ <p><b>Notes</b></p> <p>If checked, the search will look in notes texts.</p>""")) self.startButton = QPushButton(QIcon(":/edit-find.svg"), "Start Search") self.tooltips.append((self.startButton, """<p><b>Start Search</b></p> <p>Start the search from the first entry in the index or the first entry in the filtered view's entries.</p>""")) self.replaceButton = QPushButton(QIcon(":/edit-find-replace.svg"), "Replace") self.tooltips.append((self.replaceButton, """<p><b>Replace</b></p> <p>Replace the highlighted text with the <b>Replace With</b> text (using backreferences if they are in the replacement text and a <b>Regex</b> search is underway), and then try to find the next matching text.</p>""")) self.skipButton = QPushButton(QIcon(":/skip.svg"), "S&kip") self.tooltips.append((self.skipButton, """<p><b>Skip</b></p> <p>Skip the highlighted text and try to find the next matching text.</p>""")) self.stopButton = QPushButton(QIcon(":/process-stop.svg"), "Stop Search") self.tooltips.append((self.stopButton, """<p><b>Stop Search</b></p> <p>Stop the current search. This allows the search options to be changed.</p>""")) self.closeButton = QToolButton() self.closeButton.setIcon(QIcon(":/hide.svg")) self.closeButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.closeButton, """<p><b>Hide</b></p> <p>Hide the Search and Replace panel.</p> <p>Press <b>Ctrl+H</b> or click <img src=":/edit-find-replace.svg" width={0} height={0}> or click <b>Edit→Search and Replace</b> to show it again.</p>""".format(TOOLTIP_IMAGE_SIZE))) self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append( (self.helpButton, "Help on the Search and Replace panel.")) def layoutWidgets(self): form = QFormLayout() hbox = QHBoxLayout() hbox.addWidget(self.searchLineEdit) hbox.addWidget(self.closeButton) form.addRow(self.searchLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.replaceLineEdit) hbox.addWidget(self.helpButton) form.addRow(self.replaceLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.allEntriesRadioButton) hbox.addWidget(self.filteredEntriesRadioButton) hbox.addStretch() form.addRow(self.considerLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.literalRadioButton) hbox.addWidget(self.regexRadioButton) hbox.addStretch(1) hbox.addWidget(self.ignoreCaseCheckBox) hbox.addWidget(self.wholeWordsCheckBox) hbox.addStretch(5) form.addRow(QLabel("Match"), hbox) hbox = QHBoxLayout() hbox.addWidget(self.replaceInTermsCheckBox) hbox.addWidget(self.replaceInPagesCheckBox) hbox.addWidget(self.replaceInNotesCheckBox) hbox.addStretch() form.addRow(self.replaceInLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.startButton) hbox.addWidget(self.replaceButton) hbox.addWidget(self.skipButton) hbox.addWidget(self.stopButton) hbox.addStretch() form.addRow(hbox) self.setLayout(form) def createConnections(self): self.helpButton.clicked.connect(self.help) self.stopButton.clicked.connect(self.stop) self.startButton.clicked.connect(self.start) self.replaceButton.clicked.connect(self.replace) self.skipButton.clicked.connect(self.skip) self.searchLineEdit.textChanged.connect(self.updateUi) self.searchLineEdit.returnPressed.connect(self.doAction) self.replaceLineEdit.textChanged.connect(self.updateUi) self.replaceLineEdit.returnPressed.connect(self.doAction) for button in (self.literalRadioButton, self.regexRadioButton, self.ignoreCaseCheckBox, self.wholeWordsCheckBox, self.replaceInTermsCheckBox, self.replaceInPagesCheckBox, self.replaceInNotesCheckBox): button.clicked.connect(self.updateUi) def doAction(self): button = None if self.skipButton.isEnabled(): button = self.skipButton elif self.startButton.isEnabled(): button = self.startButton if button is not None: button.setFocus() button.click() if self.skipButton.isEnabled(): self.skipButton.setFocus() def help(self): self.state.help("xix_ref_panel_replace.html")
class MainWindow(QMainWindow): '''The main window of the program''' def __init__(self): '''Initialize the main window and it's parents''' super(MainWindow, self).__init__() self._createtWidgets() self._initUI() self._makeMenu() self._makeConnections() self.fileName = None self.pdfName = None self.scriptName = None self.expName = None self.rawName = None self.rawExpName = None # Set initial number of peaks self.exchange.setNumPeaks(2) # Set matrix to symmetric by default self.exchange.setMatrixSymmetry(True) # Set the initial window. self.scale.setValue(1900, 2100, False) # Default to rate in units of THz self.rate.setUnit('THz') # Clear button starts off inactive self.clear.setEnabled(False) def _createtWidgets(self): '''Creates all the widgets''' # Make the views self.plot = Plot(self) self.rate = RateView(parent=self) self.exchange = ExchangeView(parent=self) self.peak = PeakView(parent=self) self.scale = ScaleView(parent=self) # Create the model controller self.control = Controller(self) # Attach models to the views self.rate.setModel(self.control.rate) self.exchange.setModel(self.control.exchange, self.control.numpeaks) self.peak.setModel(self.control.peak) self.scale.setModel(self.control.scale) # Init the UI of all the views self.rate.initUI() self.exchange.initUI() self.peak.initUI() self.scale.initUI() # Last, make inter-view connections self.rate.makeConnections() self.exchange.makeConnections() self.peak.makeConnections() self.scale.makeConnections() self.plot.makeConnections() # The window will own a button to clear raw data self.clear = QPushButton('Clear Raw Data', self) self.clear.setToolTip(ttt('Remove raw data from the plot ' 'if there is any')) def _initUI(self): '''Sets up the layout of the window''' # Define a central widget and a layout for the window self.setCentralWidget(QWidget()) self.mainLayout = QHBoxLayout() self.setWindowTitle('Spectral Exchange') # Make a layout for all the parameter views params = QVBoxLayout() params.addWidget(self.rate) params.addWidget(self.exchange) params.addWidget(self.peak) # Add the parameter dialog self.mainLayout.addLayout(params) # Add the plot plot_lim = QVBoxLayout() plot_lim.addWidget(self.plot) lim_clear = QHBoxLayout() lim_clear.addWidget(self.scale) lim_clear.addWidget(self.clear) plot_lim.addLayout(lim_clear) self.mainLayout.addLayout(plot_lim) # Add the widgets to the central widget self.centralWidget().setLayout(self.mainLayout) def _makeConnections(self): '''Connect the widgets to each other''' # When the controller says plot, plot self.control.plotSpectrum.connect(self.plot.plotCalculatedData) # When the controller says resize x limits, do so self.control.newXLimits.connect(self.plot.changeScale) # Clear raw data if pushed self.clear.clicked.connect(self.clearRawData) # If the plot is clicked, send info to the scale widget self.plot.pointPicked.connect(self.scale.setSelection) def _makeMenu(self): '''Makes the menu bar for this widget''' # Get the menu bar object self.menu = self.menuBar() self.fileMenu = self.menu.addMenu('&File') # Open action open = QAction('&Open', self) open.setShortcuts(QKeySequence.Open) open.triggered.connect(self.openFromInput) open.setToolTip('Open an already made input file') self.fileMenu.addAction(open) # Save action save = QAction('&Save', self) save.setShortcuts(QKeySequence.Save) save.triggered.connect(self.saveToInput) save.setToolTip('Save settings to an input file') self.fileMenu.addAction(save) # Save action saveas = QAction('Save As', self) saveas.triggered.connect(self.saveToInputAs) save.setToolTip('Save settings to an input file of a new name') self.fileMenu.addAction(saveas) # Save action savepdf = QAction('Save as PDF', self) savepdf.triggered.connect(self.saveAsPDF) save.setToolTip('Save image to a PDF') self.fileMenu.addAction(savepdf) # Menu separator self.fileMenu.addSeparator() # Import action imp = QAction('&Import raw XY data', self) imp.setShortcut(QKeySequence('Ctrl+I')) imp.triggered.connect(self.importRawData) imp.setToolTip('Import raw data an plot alongside calculated data') self.fileMenu.addAction(imp) # Export action raw = QAction('Export raw XY data', self) raw.triggered.connect(self.exportRawData) raw.setToolTip('Export raw data to a file for use elsewhere') self.fileMenu.addAction(raw) # Export action exp = QAction('&Export calculated XY data', self) exp.setShortcut(QKeySequence('Ctrl+E')) exp.triggered.connect(self.exportXYData) exp.setToolTip('Export calculated data to a file for use elsewhere') self.fileMenu.addAction(exp) # Make script action scr = QAction('Make Sc&ript', self) scr.setShortcut(QKeySequence('Ctrl+R')) scr.triggered.connect(self.makeScript) scr.setToolTip('Create a python script that directly recreates this ' 'spectrum') self.fileMenu.addAction(scr) # Menu separator self.fileMenu.addSeparator() # Quit action quit = QAction('&Quit', self) quit.setShortcuts(QKeySequence.Quit) quit.triggered.connect(QApplication.instance().quit) self.fileMenu.addAction(quit) ####### # SLOTS ####### def clearRawData(self): '''Clear the raw data from the plot''' self.plot.clearRawData() self.clear.setEnabled(False) def openFromInput(self): '''Open parameters from an input file''' filter = 'Input Files (*.inp);;All (*)' s = QFileDialog.getOpenFileName(self, 'Input File Name', '', filter) # Continue unless the user hit cancel if not s[0]: return fileName = s[0] # Read given input file try: args = read_input(fileName) except ReaderError as r: # Error reading the input file error.showMessage(str(r)) # Set the number of peaks npeaks = len(args.num) if npeaks < 2: error.showMessage('Need at least 2 peaks for exchange') return elif npeaks > 4: error.showMessage('This GUI can only handle up to 4 peaks. ' 'Use the command-line version for an arbitrary ' 'number of peaks') return self.exchange.setNumPeaks(npeaks) # Set the exchange matrix = ZMat(npeaks, args.exchanges, args.exchange_rates, args.symmetric_exchange) self.exchange.setMatrixSymmetry(args.symmetric_exchange) self.exchange.setMatrix(matrix) # Set the rate if 'lifetime' in args: self.rate.setUnit(args.lifetime[1]) self.rate.setRate(args.lifetime[0]) else: self.rate.setUnit(args.rate[1]) self.rate.setRate(args.rate[0]) # Set the peak data self.peak.setPeaks(args.vib, args.Gamma_Lorentz, args.Gamma_Gauss, args.heights) # Plot this data self.control.setDataForPlot() # Plot raw data if it exists if args.raw is not None: self.rawName = args.rawName self.plot.setRawData(args.raw) self.plot.plotRawData() self.clear.setEnabled(True) # Set the limits self.scale.setValue(args.xlim[0], args.xlim[1], args.reverse) def saveToInput(self): '''Save current settings to current input file if available''' if not self.control.hasPlot: error.showMessage('Cannot save.. there is no data to save yet') return if self.fileName is None: self.saveToInputAs() else: self.inputGen(self.fileName) def saveToInputAs(self): '''Save current settings to an input file of specified name''' if not self.control.hasPlot: error.showMessage('Cannot save.. there is no data to save yet') return filter = 'Input Files (*.inp);;All (*)' d = '' if self.fileName is None else self.fileName s = QFileDialog.getSaveFileName(self, 'Input File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.fileName = s[0] # Generate the input file self.inputGen(self.fileName) def saveAsPDF(self): '''Save plot as a PDF''' if not self.control.hasPlot: error.showMessage('Cannot save.. there is no data to save yet') return filter = 'PDF Documents (*.pdf);;All (*)' d = '' if self.pdfName is None else self.pdfName s = QFileDialog.getSaveFileName(self, 'PDF File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.pdfName = s[0] # Set up the PDF printer printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setOrientation(QPrinter.Landscape) printer.setOutputFileName(self.pdfName) printer.setCreator('RAPID') # Send to the plot for printing p = QPainter() p.begin(printer) x, y = self.plot.calculatedData() plt = pgplot(x, y, antialias=True, connect='all', pen={'color': 'b', 'width': 0}) plt.setLabel('bottom', "Frequency (Wavenumbers, cm<sup>-1</sup>)") plt.getAxis('bottom').setPen('k') plt.setLabel('left', "Intensity (Normalized)") plt.getAxis('left').setPen('k') plt.setYRange(0, 1.1, padding=0) plt.invertX(self.plot.reversed) plt.setBackground('w') # White # The raw (experimental) data, if any if self.plot.rawData is not None: data = self.plot.getRawData() x, y = data[:,0], data[:,1] curve2 = PlotCurveItem(x, y, antialias=True, connect='all', pen={'color': 'g', 'width': 0}) plt.addItem(curve2) plt.render(p) p.end() def exportXYData(self): '''Export current spectrum to XY data''' if not self.control.hasPlot: error.showMessage('Cannot export.. there is no data to export yet') return filter = 'Data Files (*.txt *.data);;All (*)' d = '' if self.expName is None else self.expName s = QFileDialog.getSaveFileName(self, 'Calculated XY Data File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.expName = s[0] # Grab the XY data from the plot x, y = self.plot.calculatedData() # Save in a standard format try: write_data(x, y, self.expName) except (IOError, OSError) as e: error.showMessage(str(e)) def exportRawData(self): '''Export current raw data to XY data''' if self.plot.rawData is None: error.showMessage('Cannot export.. there is no raw data to export yet') return filter = 'Data Files (*.txt *.data);;All (*)' d = '' if self.rawExpName is None else self.rawExpName s = QFileDialog.getSaveFileName(self, 'Raw XY Data File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.rawExpName = s[0] # Grab the raw XY data from the plot data = self.plot.getRawData() # Save in a standard format try: write_data(data[:,0], data[:,1], self.rawExpName) except (IOError, OSError) as e: error.showMessage(str(e)) def importRawData(self): '''Import data from an XY file''' filter = 'Data Files (*.txt *.data);;All (*)' d = '' if self.rawName is None else self.rawName s = QFileDialog.getOpenFileName(self, 'Raw XY Data File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.rawName = s[0] # Load raw data and plot in a second curve rawData = loadtxt(str(self.rawName)) self.plot.setRawData(rawData) self.plot.plotRawData() self.clear.setEnabled(True) def makeScript(self): '''Open parameters from an input file''' if not self.control.hasPlot: error.showMessage('Cannot save.. there is no data to save yet') return filter = 'Python Scripts (*.py)' d = '' if self.scriptName is None else self.scriptName s = QFileDialog.getSaveFileName(self, 'Python Script File Name', d, filter) # Continue unless the user hit cancel if not s[0]: return self.scriptName = s[0] # Get parameters needed xlim, rev, oldp, newp = self.control.getParametersForScript() x, y = self.plot.calculatedData() if self.clear.isEnabled(): raw = self.plot.rawData else: raw = None save_script(x, y, raw, xlim, rev, oldp, newp, self.scriptName) def inputGen(self, fileName): '''Generate an input file''' # Open file for writing try: fl = open(fileName, 'w') except (IOError, OSError) as e: error.showError(str(e)) # Generate a template string to print s = dedent('''\ # The rate or lifetime of the reaction {rate} # The exchange matrix {exchange} # The peak data {peaks} # The plot limits {limits} # Raw input file, if any {raw} ''') # Get the parameters from the underlying data xlim, rev, rate, exchange, peaks = self.control.getParametersForInput() # Create the rate string if rate[1] in ('s', 'ns', 'ps', 'fs'): lr = 'lifetime' else: lr = 'rate' ratestr = '{0} {1[0]:.3G} {1[1]}'.format(lr, rate) # Create exchange string exstr = [] if not exchange[2]: exstr.append('nosym') f = 'exchange {0:d} {1:d} {2:.3f}' for indx, r in zip(exchange[1], exchange[0]): exstr.append(f.format(indx[0]+1, indx[1]+1, r)) exstr = '\n'.join(exstr) # Create peak string peakstr = [] f = 'peak {0:.2f} {1:.3f} L={2:.3f} G={3:.3f}' for p, l, g, h in zip(peaks[0], peaks[1], peaks[2], peaks[3]): peakstr.append(f.format(p, h, l, g)) peakstr = '\n'.join(peakstr) # Create the limits string limitstr = 'xlim {0[0]:d} {0[1]:d}'.format(xlim) if rev: limitstr += '\nreverse' # Create the IO string if self.rawName is not None: rawstr = 'raw {0}'.format(self.rawName) else: rawstr = '' # Write the string to file fl.write(s.format(rate=ratestr, peaks=peakstr, limits=limitstr, exchange=exstr, raw=rawstr)) # Close file fl.close()
class CompareSequences(QMainWindow): def __init__(self): super(CompareSequences, self).__init__() self.setWindowTitle('Compare Sequences') self.setFixedHeight(125) self._ledit1 = QLineEdit() self._btn_pick_1 = QPushButton('...') self._ledit2 = QLineEdit() self._btn_pick_2 = QPushButton('...') self._btn_compare = QPushButton('Compare') self._progress_bar = QProgressBar(self.statusBar()) self._setup_ui() self._set_connections() def _compare(self): self._toggle_ui() src_one = self._ledit1.text() src_two = self._ledit2.text() # TODO: put in some checks for valid sequences if not (src_one and src_two): msg = 'Please pick proper sequences.' print msg nuke.message(msg) else: read1 = nuke.createNode('Read', inpanel=False) read1.knob('file').fromUserText(src_one) read2 = nuke.createNode('Read', inpanel=False) read2.knob('file').fromUserText(src_two) read2.setXYpos(read1.xpos() + 100, read1.ypos()) if not (read1.width() == read2.width() and read1.height() == read2.height()): msg = 'Sequences are not the same resolution.' print msg nuke.message(msg) else: # TODO: check for same resolution m = nuke.createNode('Merge2', inpanel=False) m.knob('operation').setValue(6) m.setXYpos(read1.xpos(), read2.ypos() + 100) m.setInput(0, read1) m.setInput(1, read2) c = nuke.createNode('CurveTool', inpanel=False) c.knob('operation').setValue(3) c.knob('ROI').fromDict( { 'x': 0, 'y': 0, 'r': read1.width(), 't': read1.height() } ) v = nuke.createNode('Viewer') check = False frame = None first = read1.knob('first').value() last = read1.knob('last').value() self._progress_bar.setRange(first, last) for i in range(first, last + 1): self._progress_bar.setValue(i) nuke.execute(c, i, i) data = c.knob('maxlumapixvalue').animations() check = False for curve in data: if not curve.constant(): check = True frame = i break if check: break if not check: msg = 'There is no difference.' else: msg = 'There is a difference at frame %d.' % frame nuke.message(msg) self._progress_bar.reset() self._toggle_ui() def _pick_sequence(self): btn = self.sender() le_btn_pair = { self._btn_pick_1: self._ledit1, self._btn_pick_2: self._ledit2 } clip_path = nuke.getClipname('Pick Sequence to compare') le_btn_pair[btn].setText(clip_path) def _set_connections(self): self._btn_pick_1.released.connect(self._pick_sequence) self._btn_pick_2.released.connect(self._pick_sequence) self._btn_compare.released.connect(self._compare) def _setup_ui(self): self._btn_pick_1.setFixedWidth(25) self._btn_pick_1.setToolTip('Pick first sequence.') self._btn_pick_2.setFixedWidth(25) self._btn_pick_2.setToolTip('Pick second sequence.') self._btn_compare.setToolTip('Compare sequences.') self._progress_bar.setFixedHeight(10) lyt_seq1 = QHBoxLayout() lyt_seq1.addWidget(self._ledit1) lyt_seq1.addWidget(self._btn_pick_1) lyt_seq2 = QHBoxLayout() lyt_seq2.addWidget(self._ledit2) lyt_seq2.addWidget(self._btn_pick_2) lyt_main = QVBoxLayout() lyt_main.addLayout(lyt_seq1) lyt_main.addLayout(lyt_seq2) lyt_main.addWidget(self._btn_compare) main_widget = QWidget() main_widget.setLayout(lyt_main) self.setCentralWidget(main_widget) def _toggle_ui(self): self._ledit1.setEnabled(not self._ledit1.isEnabled()) self._ledit2.setEnabled(not self._ledit2.isEnabled()) self._btn_pick_1.setEnabled(not self._btn_pick_1.isEnabled()) self._btn_pick_2.setEnabled(not self._btn_pick_2.isEnabled()) self._btn_compare.setEnabled(not self._btn_compare.isEnabled())
class FindReplaceDialog(QDialog): """A find and replace dialog that has a search-as-I-type option The caller should keep a reference to this dialog, or delete it explicitly""" find_text_changed = Signal(str) replace_committed = Signal(str, str) find_cancelled = Signal() def __init__(self, parent=None): super(FindReplaceDialog, self).__init__(parent) layout = QGridLayout() # prepare the widgets label_find = QLabel(self.tr("Find")) self.lineedit_find = QLineEdit() label_replace = QLabel(self.tr("Replace")) self.lineedit_replace = QLineEdit() self.checkbox_dynamic_find = QCheckBox(self.tr("Search as I type")) self.button_find = QPushButton(self.tr("Find")) self.button_replace = QPushButton(self.tr("Replace")) button_cancel = QPushButton(self.tr("Cancel")) # connect the signals self.lineedit_find.textEdited.connect(self._findEdited) self.button_find.clicked.connect(self._emitFind) self.checkbox_dynamic_find.stateChanged.connect(self._dynamicFindChanged) self.button_replace.clicked.connect(self._emitReplacement) button_cancel.clicked.connect(self._cancel) # setup the layout row = 0; col = 0; layout.addWidget(label_find, row, col) col += 1; layout.addWidget(self.lineedit_find, row, col) row += 1; col -= 1 layout.addWidget(label_replace, row, col) col += 1 layout.addWidget(self.lineedit_replace, row, col) row += 1; col -= 1; layout.addWidget(self.checkbox_dynamic_find, row, col, 1, 2) row += 1 layout.addWidget(self.button_find, row, col) col += 1 layout.addWidget(self.button_replace, row, col) row += 1; col -= 1 layout.addWidget(button_cancel, row, col, 1, 2) self.setLayout(layout) self.setWindowTitle(self.tr("Find/Replace")) def keyPressEvent(self, kpe): if kpe.key() == Qt.Key.Key_Enter: self._emitFind() else: super(FindReplaceDialog, self).keyPressEvent(kpe) def _findEdited(self, text): if self.checkbox_dynamic_find.isChecked(): self.find_text_changed.emit(text) else: pass def _emitFind(self): self.find_text_changed.emit(self.lineedit_find.text()) def _dynamicFindChanged(self, state): print state if self.button_find.isEnabled(): self.button_find.setEnabled(False) else: self.button_find.setEnabled(True) def _emitReplacement(self): # don't emit a replacement with empty fields if not self.lineedit_find.text() or not self.lineedit_replace.text(): QApplication.beep() else: self.replace_committed.emit(self.lineedit_find.text(), self.lineedit_replace.text()) def _cancel(self): self.find_cancelled.emit() self.hide() def closeEvent(self, ce): self._cancel()