class QTimeInputDialog(QDialog): def __init__(self, title='', description='', initial=QtCore.QTime(), minValue=QtCore.QTime(), maxValue=QtCore.QTime(), dformat='mm.ss', parent=None): super().__init__(parent) self.setWindowTitle(title) self.setWindowModality(QtCore.Qt.ApplicationModal) self.setMaximumSize(300, 110) self.setMinimumSize(300, 110) self.resize(300, 130) self.label = QLabel(description, self) self.label.setGeometry(10, 0, 280, 20) self.label.setAlignment(QtCore.Qt.AlignCenter) self.time = QTimeEdit(self) self.time.setDisplayFormat(dformat) self.time.setMaximumTime(maxValue) self.time.setMinimumTime(minValue) self.time.setTime(initial) self.time.setGeometry(10, 30, 280, 25) self.acceptButton = QPushButton(self) self.acceptButton.setGeometry(QtCore.QRect(180, 80, 100, 25)) self.acceptButton.setText("Ok") self.rejectButton = QPushButton(self) self.rejectButton.setGeometry(QtCore.QRect(60, 80, 100, 25)) self.rejectButton.setText("Cancel") self.rejectButton.clicked.connect(self.reject) self.acceptButton.clicked.connect(self.accept)
def createEditor(self, parent, option, index): editor = QTimeEdit(parent=parent) editor.setMinimumTime(datetime.time(hour=8, minute=30, second=30)) editor.setMaximumTime(datetime.time(hour=23, minute=30, second=30)) editor.setDisplayFormat("HH:mm:ss") # setFrame(): tell whether the line edit draws itself with a frame. # If enabled (the default) the line edit draws itself inside a frame, otherwise the line edit draws itself without any frame. editor.setFrame(False) return editor
class Window(QWidget): def __init__(self): super().__init__() # Make widgets ################# self.edit1 = QTimeEdit() self.edit2 = QTimeEdit() self.edit3 = QTimeEdit() self.edit1.setMinimumTime(datetime.time(hour=8, minute=30, second=30)) self.edit2.setMinimumTime(datetime.time(hour=8, minute=30, second=30)) self.edit3.setMinimumTime(datetime.time(hour=8, minute=30, second=30)) self.edit1.setMaximumTime(datetime.time(hour=18, minute=30, second=30)) self.edit2.setMaximumTime(datetime.time(hour=18, minute=30, second=30)) self.edit3.setMaximumTime(datetime.time(hour=18, minute=30, second=30)) self.edit1.setTime(datetime.datetime.now().time()) self.edit2.setTime(datetime.datetime.now().time()) self.edit3.setTime(datetime.datetime.now().time()) # Format: see http://doc.qt.io/qt-5/qdatetime.html#toString-2 self.edit1.setDisplayFormat("HH:mm") self.edit2.setDisplayFormat("HH:mm:ss t") self.edit3.setDisplayFormat("h m AP") self.btn = QPushButton("Print") # Set button slot ############## self.btn.clicked.connect(self.printText) # Set the layout ############### vbox = QVBoxLayout() vbox.addWidget(self.edit1) vbox.addWidget(self.edit2) vbox.addWidget(self.edit3) vbox.addWidget(self.btn) self.setLayout(vbox) def printText(self): print(self.edit1.text()) print(self.edit2.text()) print(self.edit3.text())
class VCTimeCounter(QWidget): timeChanged = pyqtSignal(QTime) def __init__(self, parent=None): super(VCTimeCounter, self).__init__(parent) self.parent = parent self.timeedit = QTimeEdit(QTime(0, 0)) self.timeedit.setObjectName('timeCounter') self.timeedit.setStyle(QStyleFactory.create('Fusion')) self.timeedit.setFrame(False) self.timeedit.setDisplayFormat('hh:mm:ss.zzz') self.timeedit.timeChanged.connect(self.timeChangeHandler) separator = QLabel('/') separator.setObjectName('timeSeparator') self.duration = QLabel('00:00:00.000') self.duration.setObjectName('timeDuration') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) layout.addWidget(self.timeedit) layout.addWidget(separator) layout.addWidget(self.duration) self.setLayout(layout) def setRange(self, minval: str, maxval: str) -> None: self.timeedit.setTimeRange(QTime.fromString(minval, 'hh:mm:ss.zzz'), QTime.fromString(maxval, 'hh:mm:ss.zzz')) def setMinimum(self, val: str = None) -> None: if val is None: self.timeedit.setMinimumTime(QTime(0, 0)) else: self.timeedit.setMinimumTime(QTime.fromString(val, 'hh:mm:ss.zzz')) def setMaximum(self, val: str) -> None: self.timeedit.setMaximumTime(QTime.fromString(val, 'hh:mm:ss.zzz')) def setTime(self, time: str) -> None: self.timeedit.setTime(QTime.fromString(time, 'hh:mm:ss.zzz')) def setDuration(self, time: str) -> None: self.duration.setText(time) self.setMaximum(time) def clearFocus(self) -> None: self.timeedit.clearFocus() def hasFocus(self) -> bool: if self.timeedit.hasFocus(): return True return super(VCTimeCounter, self).hasFocus() def reset(self) -> None: self.timeedit.setTime(QTime(0, 0)) self.setDuration('00:00:00.000') def setReadOnly(self, readonly: bool) -> None: self.timeedit.setReadOnly(readonly) if readonly: self.timeedit.setButtonSymbols(QAbstractSpinBox.NoButtons) else: self.timeedit.setButtonSymbols(QAbstractSpinBox.UpDownArrows) @pyqtSlot(QTime) def timeChangeHandler(self, newtime: QTime) -> None: if self.timeedit.hasFocus(): self.timeChanged.emit(newtime)
class WindowEmployeeUpdate(QDialog): def __init__(self): super(WindowEmployeeUpdate, self).__init__() self.setWindowTitle("Update Employee Details") self.set_layout() def set_layout(self): #Set up basic Stuff here vbox = QVBoxLayout() group1 = QGroupBox("Employee Update") form1 = QFormLayout() group1.setLayout(form1) #Set Nane self.namelabel = QLabel("Name") self.nameLineEdit = QLineEdit("") self.nameLineEdit.setEnabled(False) form1.setWidget(0, QFormLayout.LabelRole, self.namelabel) form1.setWidget(0, QFormLayout.FieldRole, self.nameLineEdit) #Set Date Label self.datelabel = QLabel("Date Started") self.dateLineEdit = QDateEdit() self.dateLineEdit.setDate(QDate(2021, 1, 1)) self.dateLineEdit.setCalendarPopup(True) form1.setWidget(1, QFormLayout.LabelRole, self.datelabel) form1.setWidget(1, QFormLayout.FieldRole, self.dateLineEdit) # set Time Started self.timestartlabel = QLabel("Time Started") self.updatestartLineEdit = QTimeEdit() # Set time constrain self.updatestartLineEdit.timeChanged.connect(self.connect_start_end) #Add to form Widget form1.setWidget(2, QFormLayout.LabelRole, self.timestartlabel) form1.setWidget(2, QFormLayout.FieldRole, self.updatestartLineEdit) # set Time Ended self.timeendedlabel = QLabel("Time Ended") self.updateendeLineEdit = QTimeEdit() # connect min time of endtime as starttime self.updateendeLineEdit.timeChanged.connect( self.connect_min_time) #you can use lambda function to get 1 line # Add to form Widget form1.setWidget(3, QFormLayout.LabelRole, self.timeendedlabel) form1.setWidget(3, QFormLayout.FieldRole, self.updateendeLineEdit) ##ADD BUTTON self.updatebtn = QPushButton("Update Employee") self.updatebtn.clicked.connect(self.saved_messagebox) ## ADD ITEMS TO LAYOUT vbox.addWidget(group1) vbox.addWidget(self.updatebtn, 0, Qt.AlignHCenter) self.setLayout(vbox) def connect_start_end(self): self.updateendeLineEdit.setTime(self.updatestartLineEdit.time()) def connect_min_time(self): self.updateendeLineEdit.setMinimumTime(self.updateendeLineEdit.time()) def saved_messagebox(self): if self.nameLineEdit.text() != "": QMessageBox.information(self, "Information", "Details Updated Successfully") self.accept() elif self.nameLineEdit.text() == "": QMessageBox.warning(self, "Warning", "All Boxes Must be Filled")
class WindowEmployeeAdd(QDialog): def __init__(self): super(WindowEmployeeAdd, self).__init__() self.setWindowTitle("Add Employee") self.set_layout() def set_layout(self): # Set up basic Stuff here vbox = QVBoxLayout() group1 = QGroupBox("Employee") form1 = QFormLayout() group1.setLayout(form1) self.namelabel = QLabel("Name") self.nameLineEdit = QLineEdit("") self.nameLineEdit.setPlaceholderText("Enter Employee Name") form1.setWidget(0, QFormLayout.LabelRole, self.namelabel) form1.setWidget(0, QFormLayout.FieldRole, self.nameLineEdit) datelabel = QLabel("Date Started") self.dateLineEdit = QDateEdit() self.dateLineEdit.setDate(QDate(2021, 1, 1)) self.dateLineEdit.setCalendarPopup(True) form1.setWidget(1, QFormLayout.LabelRole, datelabel) form1.setWidget(1, QFormLayout.FieldRole, self.dateLineEdit) self.timestartlabel = QLabel("Time Started") self.timestartLineEdit = QTimeEdit() self.timestartLineEdit.setTime(QTime(7, 0, 0)) # Set time constrain self.timestartLineEdit.timeChanged.connect(self.connect_start_end) form1.setWidget(2, QFormLayout.LabelRole, self.timestartlabel) form1.setWidget(2, QFormLayout.FieldRole, self.timestartLineEdit) timeendedlabel = QLabel("Time Ended") self.timeendeLineEdit = QTimeEdit() self.timeendeLineEdit.setTime(QTime(self.timestartLineEdit.time())) # connect min time of endtime as starttime self.timeendeLineEdit.timeChanged.connect( self.set_min_time) # you can use lambda function to get 1 line form1.setWidget(3, QFormLayout.LabelRole, timeendedlabel) form1.setWidget(3, QFormLayout.FieldRole, self.timeendeLineEdit) ##Group 2 (Employer) group2 = QGroupBox("Employer") form2 = QFormLayout() group2.setLayout(form2) # Add items to form amountlabel = QLabel("Amount Paid Per Hour") self.amountLine = QLineEdit("$5.00") self.amountLine.setEnabled(False) form2.setWidget(0, QFormLayout.LabelRole, amountlabel) form2.setWidget(0, QFormLayout.FieldRole, self.amountLine) ##ADD BUTTON self.addbtn = QPushButton("Add Emmployee") self.addbtn.clicked.connect(self.saved_messagebox) ## ADD ITEMS TO LAYOUT vbox.addWidget(group1) vbox.addWidget(group2) vbox.addWidget(self.addbtn, 0, Qt.AlignHCenter) self.setLayout(vbox) def connect_start_end(self): self.timeendeLineEdit.setTime(self.timestartLineEdit.time()) def set_min_time(self): self.timeendeLineEdit.setMinimumTime(self.timestartLineEdit.time()) def saved_messagebox(self): if self.nameLineEdit.text() != "": QMessageBox.information(self, "Information", "Details Saved Successfully") self.accept() elif self.nameLineEdit.text() == "": QMessageBox.warning(self, "Warning", "All Boxes Must be Filled")
class VideoWindow(QWidget): def __init__(self, vidPath): super().__init__() self.fullPath = vidPath self.startTime = 0 self.endTime = 0 self.init_ui() def init_ui(self): layout = QVBoxLayout() self.setLayout(layout) self.setWindowTitle(self.fullPath) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoWidget = QVideoWidget() self.playButton = QPushButton() self.playButton.setEnabled(True) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.setFixedWidth(100) self.playButton.setFixedHeight(50) self.playButton.clicked.connect(self.play) self.trimButton = QPushButton("Trim") self.trimButton.setFixedWidth(150) self.trimButton.setFixedHeight(50) self.trimButton.clicked.connect(self.trimVid) self.positionSlider = QSlider(QtCore.Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.rangeSlider = qrangeslider.QRangeSlider() self.rangeSlider.setRange(0, 0) self.rangeSlider.endValueChanged.connect(self.adjustForEnd) self.rangeSlider.startValueChanged.connect(self.adjustForStart) self.rangeSlider.setFixedHeight(15) self.startTimeInput = QTimeEdit() self.endTimeInput = QTimeEdit() self.startTimeInput.setDisplayFormat('hh:mm:ss.zzz') self.endTimeInput.setDisplayFormat('hh:mm:ss.zzz') self.startTimeInput.timeChanged.connect(self.startInputChanged) self.endTimeInput.timeChanged.connect(self.endInputChanged) self.mediaPlayer.setMedia( QMediaContent(QtCore.QUrl.fromLocalFile(self.fullPath))) layout.addWidget(self.videoWidget) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.setNotifyInterval(10) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) controlLayout = QVBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.rangeSlider) controlLayout.addWidget(self.positionSlider) timeInputLayout = QHBoxLayout() timeInputLayout.addWidget(self.playButton) timeInputLayout.addWidget(self.startTimeInput) timeInputLayout.addWidget(self.endTimeInput) timeInputLayout.addWidget(self.trimButton) controlLayout.addLayout(timeInputLayout) layout.addLayout(controlLayout) self.mediaPlayer.play() self.resize(1024, 700) self.show() def closeEvent(self, event): self.mediaPlayer.stop() self.videoWidget.setParent(None) self.mediaPlayer.setParent(None) self.mediaPlayer.deleteLater() self.videoWidget.deleteLater() def trimVid(self): self.trimButton.setEnabled(False) outName = mytools.getAvailableName(self.fullPath, 'Trim') print(outName) trimStartTime = self.startTimeInput.time().toString('hh:mm:ss.zzz') trimEndTime = self.endTimeInput.time().toString('hh:mm:ss.zzz') try: ff = FFmpeg(inputs={self.fullPath: None}, outputs={ outName: [ '-ss', trimStartTime, '-to', trimEndTime, '-c:v', 'copy', '-c:a', 'copy', ] }) ff.run() except Exception as e: msg = QMessageBox() msg.setWindowTitle("Trim Failed") msg.setText(str(e)) msg.setIcon(QMessageBox.Critical) showMsg = msg.exec_() self.trimButton.setEnabled(True) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) if position > self.endTime: self.mediaPlayer.setPosition(self.startTime) def adjustForStart(self, startPos): self.startTime = startPos self.mediaPlayer.setPosition(startPos) self.startTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(startPos)) self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0).addMSecs(startPos)) def adjustForEnd(self, endPos): self.endTime = endPos if self.positionSlider.value() > endPos: self.mediaPlayer.setPosition(endPos) self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(endPos)) self.startTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(endPos)) def startInputChanged(self, inputTime): self.rangeSlider.setStart(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime)) def endInputChanged(self, inputTime): self.rangeSlider.setEnd(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime)) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) self.rangeSlider.setMax(duration) self.rangeSlider.setEnd(duration) self.startTimeInput.setMinimumTime(QtCore.QTime(0, 0)) self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0)) self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(duration)) self.startTimeInput.setMaximumTime( QtCore.QTime(0, 0).addMSecs(duration)) self.endTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(duration)) def setPosition(self, position): self.mediaPlayer.setPosition(position)
class QFrameSelect(QWidget): frameSelectionChanged = pyqtSignal(int, QTime) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() self.setLayout(layout) self.slider = Slider(self) self.slider.setOrientation(Qt.Horizontal) self.slider.valueChanged.connect(self._handleSliderChange) self.slider.setTickInterval(1) layout.addWidget(self.slider) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.leftLabel = QLabel(self) self.spinBox = QSpinBox(self) self.spinBox.valueChanged.connect(self._handleSpinboxChange) self.currentTime = QTimeEdit(self) self.currentTime.setDisplayFormat("H:mm:ss.zzz") self.currentTime.timeChanged.connect(self._handleTimeEditChange) self.currentTime.editingFinished.connect(self._handleTimeEditFinished) self.rightLabel = QLabel(self) hlayout.addWidget(self.leftLabel) hlayout.addStretch() hlayout.addWidget(QLabel("Frame index:", self)) hlayout.addWidget(self.spinBox) hlayout.addWidget(QLabel("Timestamp:", self)) hlayout.addWidget(self.currentTime) hlayout.addStretch() hlayout.addWidget(self.rightLabel) self.setPtsTimeArray(None) def setValue(self, n): self.slider.setValue(n) def setMinimum(self, n=0): self.slider.setMinimum(n) self.spinBox.setMinimum(n) ms = int(self.pts_time[n] * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.setMinimumTime(QTime(h, m, s, ms)) self.leftLabel.setText(f"{n} ({h}:{m:02d}:{s:02d}.{ms:03d})") def setMaximum(self, n=None): if n is None: n = len(self.pts_time) - 1 self.slider.setMaximum(n) self.spinBox.setMaximum(n) ms = int(self.pts_time[n] * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.setMaximumTime(QTime(h, m, s, ms)) self.rightLabel.setText(f"{n} ({h}:{m:02d}:{s:02d}.{ms:03d})") def setStartEndVisible(self, value): self.leftLabel.setHidden(not bool(value)) self.rightLabel.setHidden(not bool(value)) def setPtsTimeArray(self, pts_time=None): self.pts_time = pts_time if pts_time is not None: N = len(pts_time) self.setMinimum(0) self.setMaximum(N - 1) self.slider.setValue(0) self.slider.setSnapValues(None) self.slider.setDisabled(False) self.spinBox.setDisabled(False) self.currentTime.setDisabled(False) else: self.slider.setMinimum(0) self.slider.setMaximum(0) self.slider.setSnapValues(None) self.slider.setDisabled(True) self.spinBox.setDisabled(True) self.currentTime.setDisabled(True) def _handleSliderChange(self, n): self.spinBox.blockSignals(True) self.spinBox.setValue(n) self.spinBox.blockSignals(False) pts_time = self.pts_time[n] ms = int(pts_time * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.blockSignals(True) self.currentTime.setTime(QTime(h, m, s, ms)) self.currentTime.blockSignals(False) self.frameSelectionChanged.emit(n, QTime(h, m, s, ms)) def _handleSpinboxChange(self, n): self.slider.blockSignals(True) self.slider.setValue(n) self.slider.blockSignals(False) pts_time = self.pts_time[n] ms = int(pts_time * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.blockSignals(True) self.currentTime.setTime(QTime(h, m, s, ms)) self.currentTime.blockSignals(False) self.frameSelectionChanged.emit(n, QTime(h, m, s, ms)) def _handleTimeEditChange(self, t): pts = t.msecsSinceStartOfDay() / 1000 try: n = search(self.pts_time, pts + 0.0005, dir="-") except IndexError: n = 0 if n != self.slider.value(): self.slider.blockSignals(True) self.slider.setValue(n) self.slider.blockSignals(False) self.spinBox.blockSignals(True) self.spinBox.setValue(n) self.spinBox.blockSignals(False) pts_time = self.pts_time[n] ms = int(pts_time * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.frameSelectionChanged.emit(n, QTime(h, m, s, ms)) def _handleTimeEditFinished(self): t = self.currentTime.time() pts = t.msecsSinceStartOfDay() / 1000 n = search(self.pts_time, pts + 0.0005, dir="-") pts_time = self.pts_time[n] ms = int(pts_time * 1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) T = QTime(h, m, s, ms) if t != T: self.currentTime.setTime(T)
class SettingsWindow(QMainWindow): def __init__(self, screens): super().__init__() self._init_ui() self.addButton.clicked.connect(self.on_add) self.deleteButton.clicked.connect(self.on_delete) self.upButton.clicked.connect(self.on_up) self.downButton.clicked.connect(self.on_down) self.startButton.clicked.connect(self.on_start) self.saveButton.clicked.connect(self.on_save) self.loadButton.clicked.connect(self.on_load) self.gradientWindowController = GradientWindowController(screens) self._load_settings() def _create_color_tab(self): self.colorWidget = QWidget() self.colorWidget.setAutoFillBackground(True) self.colorsLayout = QHBoxLayout() self.colorTable = QTableWidget() self.colorTable.setRowCount(0) self.colorTable.setColumnCount(1) self.colorTable.verticalHeader().hide() self.colorTable.horizontalHeader().hide() self.colorTable.setMaximumWidth(40) self.colorTable.setColumnWidth(20, 30) self.colorButtonsLayout = QVBoxLayout() self.addButton = QPushButton('Добавить') self.upButton = QPushButton('Вверх') self.downButton = QPushButton('Вниз') self.deleteButton = QPushButton('Удалить') self.colorButtonsLayout.addWidget(self.addButton) self.colorButtonsLayout.addWidget(self.upButton) self.colorButtonsLayout.addWidget(self.downButton) self.colorButtonsLayout.addWidget(self.deleteButton) self.colorButtonsLayout.addStretch() self.colorsLayout.addWidget(self.colorTable) self.colorsLayout.addStretch() self.colorsLayout.addLayout(self.colorButtonsLayout) self.colorWidget.setLayout(self.colorsLayout) return self.colorWidget def _create_intervals_tab(self): self.intervalsWidget = QWidget() self.intervalsWidget.setAutoFillBackground(True) self.intervalsLayout = QVBoxLayout() self.delayInput = QTimeEdit() self.delayInput.setDisplayFormat('hh:mm:ss') self.delayInput.setMinimumTime(QTime(0, 0, 1)) self.repeatInput = QTimeEdit() self.repeatInput.setDisplayFormat('hh:mm:ss') self.repeatInput.setMinimumTime(QTime(0, 0, 1)) self.intervalsLayout.addWidget(QLabel('Первый цвет')) self.intervalsLayout.addWidget(self.delayInput) self.intervalsLayout.addWidget(QLabel('Интервал')) self.intervalsLayout.addWidget(self.repeatInput) self.intervalsLayout.addStretch() self.intervalsWidget.setLayout(self.intervalsLayout) return self.intervalsWidget def _init_ui(self): self.central = QWidget() self.centralLayout = QVBoxLayout() self.tabWidget = QTabWidget() self.tabWidget.addTab(self._create_color_tab(), 'Цвета') self.tabWidget.addTab(self._create_intervals_tab(), 'Интервалы') self.centralLayout.addWidget(self.tabWidget) self.errorLabel = QLabel() self.centralLayout.addWidget(self.errorLabel) self.settingsButtonsLayout = QHBoxLayout() self.saveButton = QPushButton('Сохранить') self.loadButton = QPushButton('Загрузить') self.startButton = QPushButton('Запустить') self.settingsButtonsLayout.addWidget(self.saveButton) self.settingsButtonsLayout.addWidget(self.loadButton) self.settingsButtonsLayout.addWidget(self.startButton) self.centralLayout.addLayout(self.settingsButtonsLayout) self.central.setLayout(self.centralLayout) self.setCentralWidget(self.central) @pyqtSlot() def on_add(self): color = QColorDialog.getColor() item = QTableWidgetItem() item.setBackground(color) table: QTableWidget = self.colorTable table.insertRow(table.rowCount()) table.setItem(table.rowCount() - 1, 0, item) @pyqtSlot() def on_delete(self): table: QTableWidget = self.colorTable selected = table.selectedIndexes() rows = [index.row() for index in selected] for row in rows: table.removeRow(row) @staticmethod def _swap_items(table: QTableWidget, row1, col1, row2, col2): item1 = table.takeItem(row1, col1) item2 = table.takeItem(row2, col2) table.setItem(row1, col1, item2) table.setItem(row2, col2, item1) @pyqtSlot() def on_up(self): table: QTableWidget = self.colorTable selected = table.selectedIndexes() if selected: rows = [index.row() for index in selected] prev_row = 0 for row in sorted(rows): if row > prev_row: SettingsWindow._swap_items(table, row, 0, row - 1, 0) else: prev_row += 1 table.clearSelection() table.setRangeSelected( QTableWidgetSelectionRange(min(rows) - 1, 0, max(rows) - 1, 0), True) @pyqtSlot() def on_down(self): table: QTableWidget = self.colorTable selected = table.selectedIndexes() if selected: rows = [index.row() for index in selected] next_row = table.rowCount() - 1 for row in sorted(rows, reverse=True): if row < next_row: SettingsWindow._swap_items(table, row, 0, row + 1, 0) else: next_row -= 1 table.clearSelection() table.setRangeSelected( QTableWidgetSelectionRange(min(rows) + 1, 0, max(rows) + 1, 0), True) @pyqtSlot() def on_start(self): table: QTableWidget = self.colorTable items = [table.item(row, 0) for row in range(table.rowCount())] colors = [item.background().color() for item in items] if not colors: self.errorLabel.setText('цвета добавь') return if len(colors) < 2: self.errorLabel.setText('давай побольше цветов') return if self.errorLabel.text(): self.errorLabel.setText('молодец') delay = QTime(0, 0).secsTo(self.delayInput.time()) repeat_interval = QTime(0, 0).secsTo(self.repeatInput.time()) self.gradientWindowController.set_colors(colors) self.gradientWindowController.set_timers(delay, repeat_interval) self.gradientWindowController.run() @pyqtSlot() def on_save(self): table: QTableWidget = self.colorTable settings = dict() items = [table.item(row, 0) for row in range(table.rowCount())] colors = [item.background().color() for item in items] rgb_colors = [color.getRgb() for color in colors] settings['colors'] = rgb_colors settings['delay'] = QTime(0, 0).secsTo(self.delayInput.time()) settings['repeat_interval'] = QTime(0, 0).secsTo(self.repeatInput.time()) filename = QFileDialog.getSaveFileName(directory='settings.json')[0] if filename: with open(filename, 'w') as f: json.dump(settings, f) self.errorLabel.setText(f'настройки сохранены в {filename}') def _load_settings(self, filename='settings.json'): try: with open(filename) as f: settings = json.load(f) table: QTableWidget = self.colorTable table.setRowCount(0) for rgb_color in settings['colors']: color = QColor.fromRgb(*rgb_color) item = QTableWidgetItem() item.setBackground(color) table.insertRow(table.rowCount()) table.setItem(table.rowCount() - 1, 0, item) self.delayInput.setTime(QTime(0, 0).addSecs(settings['delay'])) self.repeatInput.setTime( QTime(0, 0).addSecs(settings['repeat_interval'])) self.errorLabel.setText(f'настройки загружены из {filename}') except FileNotFoundError: pass except json.JSONDecodeError or KeyError or TypeError: self.errorLabel.setText(f'в {filename} ошибка') @pyqtSlot() def on_load(self): filename = QFileDialog.getOpenFileName()[0] if filename: self._load_settings(filename)