class FullColorPickerWidget(QWidget): color_changed = Signal(QColor) def __init__(self, title: str, parent=None): super().__init__(parent) self.__color_picker = QColorDialog(self) self.__color_picker.setOption(QColorDialog.ColorDialogOption.DontUseNativeDialog) self.__color_picker.setOption(QColorDialog.ColorDialogOption.NoButtons) self.__color_picker.setWindowFlags(Qt.Widget) self.__group_box = QGroupBox(title) self.__group_box_layout = QVBoxLayout() self.__group_box_layout.addWidget(self.__color_picker) self.__group_box.setLayout(self.__group_box_layout) self.__group_box_layout.setStretch(1, 1) self.__main_layout = QVBoxLayout(self) self.__main_layout.addWidget(self.__group_box) @Slot(QColor) def __on_color_changed(self, color: QColor): self.color_changed.emit(color) def get_current_color(self) -> QColor: return self.__color_picker.currentColor()
def on_color_picker(self): """ Show color-picker dialog to select color. Qt will use the native dialog by default. """ dlg = QColorDialog(self) # We will need an RGBA color value dlg.setOption(QColorDialog.ShowAlphaChannel, True) dlg.setCurrentColor(self.color()) dlg.finished.connect(self.dialog_finished) dlg.open()
class IconColorEditor(QDialog): """An editor to let the user select an icon and a color for an object_class. """ def __init__(self, parent): """Init class.""" super().__init__(parent) # , Qt.Popup) icon_size = QSize(32, 32) self.icon_mngr = IconListManager(icon_size) self.setWindowTitle("Select icon and color") self.icon_widget = QWidget(self) self.icon_list = QListView(self.icon_widget) self.icon_list.setViewMode(QListView.IconMode) self.icon_list.setIconSize(icon_size) self.icon_list.setResizeMode(QListView.Adjust) self.icon_list.setItemDelegate(_IconPainterDelegate(self)) self.icon_list.setMovement(QListView.Static) self.icon_list.setMinimumHeight(400) icon_widget_layout = QVBoxLayout(self.icon_widget) icon_widget_layout.addWidget(QLabel("Font Awesome icons")) self.line_edit = QLineEdit() self.line_edit.setPlaceholderText("Search icons for...") icon_widget_layout.addWidget(self.line_edit) icon_widget_layout.addWidget(self.icon_list) self.color_dialog = QColorDialog(self) self.color_dialog.setWindowFlags(Qt.Widget) self.color_dialog.setOption(QColorDialog.NoButtons, True) self.color_dialog.setOption(QColorDialog.DontUseNativeDialog, True) self.button_box = QDialogButtonBox(self) self.button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) top_widget = QWidget(self) top_layout = QHBoxLayout(top_widget) top_layout.addWidget(self.icon_widget) top_layout.addWidget(self.color_dialog) layout = QVBoxLayout(self) layout.addWidget(top_widget) layout.addWidget(self.button_box) self.proxy_model = QSortFilterProxyModel(self) self.proxy_model.setSourceModel(self.icon_mngr.model) self.proxy_model.filterAcceptsRow = self._proxy_model_filter_accepts_row self.icon_list.setModel(self.proxy_model) self.setAttribute(Qt.WA_DeleteOnClose) self.connect_signals() def _proxy_model_filter_accepts_row(self, source_row, source_parent): """Overridden method to filter icons according to search terms. """ text = self.line_edit.text() if not text: return QSortFilterProxyModel.filterAcceptsRow( self.proxy_model, source_row, source_parent) searchterms = self.icon_mngr.model.index( source_row, 0, source_parent).data(Qt.UserRole + 1) return any([text in term for term in searchterms]) def connect_signals(self): """Connect signals to slots.""" self.line_edit.textEdited.connect(self.proxy_model.invalidateFilter) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) def set_data(self, data): icon_code, color_code = interpret_icon_id(data) self.icon_mngr.init_model() for i in range(self.proxy_model.rowCount()): index = self.proxy_model.index(i, 0) if index.data(Qt.UserRole) == icon_code: self.icon_list.setCurrentIndex(index) break self.color_dialog.setCurrentColor(QColor(color_code)) def data(self): icon_code = self.icon_list.currentIndex().data(Qt.UserRole) color_code = self.color_dialog.currentColor().rgb() return make_icon_id(icon_code, color_code)
class SoundBoard(QDialog): def __init__(self): super(SoundBoard, self).__init__() self.title = '=== SoundBoard ===' # positionnement de la fenêtre à l'ouverture self.left = 50 self.top = 50 # initialisation de la largeur et hauteur par défaut self.width = 500 self.height = 500 self.currFileName = "" self.pbPosToModify = -1 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.windowLayout = QHBoxLayout() self.tableWidget = QTableWidget() self.tableWidget.horizontalHeader().hide() self.tableWidget.verticalHeader().hide() self.initIcons() self.initMenu() self.initColorPicker() self.initButtons() self.windowLayout.setStretch(1, 0) self.setLayout(self.windowLayout) self.show() def initIcons(self): self.iEdit = QIcon() self.iEdit.addPixmap(QPixmap("./icons/edit.png"), QIcon.Normal, QIcon.Off) self.iPlus = QIcon() self.iPlus.addPixmap(QPixmap("./icons/plus.png"), QIcon.Normal, QIcon.Off) self.iMinus = QIcon() self.iMinus.addPixmap(QPixmap("./icons/minus.png"), QIcon.Normal, QIcon.Off) self.iParam = QIcon() self.iParam.addPixmap(QPixmap("./icons/cog.png"), QIcon.Normal, QIcon.Off) def initMenu(self): layout = QVBoxLayout() hlayout = QHBoxLayout() # bouton ajout self.tbPlus = QToolButton() self.tbPlus.setGeometry(QRect(0, 0, 32, 32)) self.tbPlus.setIcon(self.iPlus) self.tbPlus.setObjectName("tbPlus") hlayout.addWidget(self.tbPlus) self.tbPlus.clicked.connect(self.add) # bouton suppression self.tbMinus = QToolButton() self.tbMinus.setGeometry(QRect(0, 0, 32, 32)) self.tbMinus.setIcon(self.iMinus) self.tbMinus.setObjectName("tbMinus") hlayout.addWidget(self.tbMinus) self.tbMinus.clicked.connect(self.delete) # bouton édition self.tbEdit = QToolButton() self.tbEdit.setGeometry(QRect(0, 0, 32, 32)) self.tbEdit.setIcon(self.iEdit) self.tbEdit.setObjectName("tbEdit") hlayout.addWidget(self.tbEdit) self.tbEdit.clicked.connect(self.editBtn) # bouton paramètres self.tbParam = QToolButton() self.tbParam.setGeometry(QRect(0, 0, 32, 32)) self.tbParam.setIcon(self.iParam) self.tbParam.setObjectName("tbParam") hlayout.addWidget(self.tbParam) self.tbParam.clicked.connect(self.settings) layout.addLayout(hlayout) self.pbStop = QPushButton("Don't STOP\n\nthe\n\nSoundBoard") self.pbStop.setStyleSheet("font-weight: bold;") self.pbStop.setMinimumSize(QSize(100, 100)) self.pbStop.setGeometry(QRect(0, 0, 100, 100)) layout.addWidget(self.pbStop) self.pbStop.clicked.connect(self.stop) spacerMenu = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) layout.addItem(spacerMenu) self.windowLayout.addLayout(layout) def startInitButtons(self): self.tableWidget.clear() self.tableWidget.clearSpans() self.tableWidget.setColumnWidth(0, 100) self.tableWidget.setColumnWidth(2, 100) self.cdColorPicker.setVisible(False) self.tableWidget.horizontalHeader().hide() # import des informations boutons contenues dans le json with open('buttons.json', encoding='utf-8') as json_file: self.data_buttons = json.load(json_file) # stockage de la position la plus élevée pour le cadrage self.positions = [p['position'] for p in self.data_buttons['buttons']] self.max_pos = max(self.positions) # calcul du nombre de boutons par hauteur et largeur self.BtnH = self.data_buttons['buttons_grid']['height'] self.BtnW = self.data_buttons['buttons_grid']['width'] self.setGeometry(self.left, self.top, 140 + self.BtnW * 100, 175 if self.BtnH * 31 < 175 else 25 + self.BtnH * 30) self.tableWidget.setColumnCount(self.BtnW) self.tableWidget.setRowCount(self.BtnH) def endInitButtons(self): buttonsLayout = QVBoxLayout() buttonsLayout.setStretch(0, 1) buttonsLayout.addWidget(self.tableWidget) self.windowLayout.addLayout(buttonsLayout) self.setGeometry(self.left, self.top, 140 + self.BtnW * 100, 175 if self.BtnH * 31 < 175 else 25 + self.BtnH * 30) def initButtons(self): self.startInitButtons() # positionnement des boutons en fonction des positions du json for ligne in range(self.BtnH): for colonne in range(self.BtnW): if (ligne * self.BtnW) + (colonne + 1) in self.positions: for b in self.data_buttons['buttons']: if b['position'] == (ligne * self.BtnW) + (colonne + 1): pb = QPushButton(b['name'][:9]) pb.setProperty('pbPos', b['position']) # si fond clair, font noire, si sombre, font blanche if (b['r'] * 0.299 + b['g'] * 0.587 + b['b'] * 0.114) > 186: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #000000;" ) else: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #ffffff;" ) self.tableWidget.setCellWidget(ligne, colonne, pb) pb.clicked.connect(self.play) else: pb = QPushButton('Nouveau') calcPos = self.BtnW * ligne + colonne + 1 pb.setProperty('pbPos', f"nouveau,{calcPos}") pb.clicked.connect(self.add) self.tableWidget.setCellWidget(ligne, colonne, pb) colonne += 1 ligne += 1 self.endInitButtons() def initColorPicker(self): self.lColorPicker = QVBoxLayout() self.cdColorPicker = QColorDialog() self.cdColorPicker.setOption(self.cdColorPicker.NoButtons, True) self.colorSelected = self.cdColorPicker.currentColor() self.lColorPicker.addWidget(self.cdColorPicker) self.cdColorPicker.setVisible(False) self.cdColorPicker.currentColorChanged.connect(self.colorChanged) self.windowLayout.addLayout(self.lColorPicker) def play(self): pb = self.sender() pbPos = pb.property('pbPos') for b in self.data_buttons['buttons']: if pbPos == b['position']: pbFile = b['file'] if (p.get_state() == vlc.State.Playing): p.stop() media = instance.media_new(soundRep + pbFile) if (self.currFileName != pbFile): p.set_media(media) p.play() self.currFileName = pbFile else: media = instance.media_new(soundRep + pbFile) p.set_media(media) p.play() self.currFileName = pbFile def stop(self): p.stop() def add(self): self.cdColorPicker.setVisible(True) self.tableWidget.clear() self.tableWidget.clearSpans() self.tableWidget.setColumnWidth(2, 100) self.tableWidget.setColumnCount(6) self.tableWidget.setRowCount(len(self.data_buttons['buttons']) + 1) self.tableWidget.horizontalHeader().show() self.tableWidget.setHorizontalHeaderItem(0, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(0).setText('Nom') self.tableWidget.setHorizontalHeaderItem(1, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(1).setText('Fichier') self.tableWidget.setHorizontalHeaderItem(2, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(2).setText('') self.tableWidget.setColumnWidth(2, 22) self.tableWidget.setHorizontalHeaderItem(3, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(3).setText('Position') self.tableWidget.setHorizontalHeaderItem(4, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(4).setText('Couleur') self.tableWidget.setHorizontalHeaderItem(5, QTableWidgetItem()) self.tableWidget.horizontalHeaderItem(5).setText('') # nom self.leName = QLineEdit() self.leName.setPlaceholderText('Nom (10 max.)') self.tableWidget.setCellWidget(0, 0, self.leName) # fichier self.leFile = QLineEdit() self.leFile.setPlaceholderText('Fichier') self.tableWidget.setCellWidget(0, 1, self.leFile) # browse pbBrowser = QPushButton('...') pbBrowser.setMinimumSize(QSize(21, 21)) pbBrowser.clicked.connect(self.browseMedia) self.tableWidget.setCellWidget(0, 2, pbBrowser) # position self.lePos = QLineEdit() self.lePos.setPlaceholderText('Position') self.tableWidget.setCellWidget(0, 3, self.lePos) # couleur self.leColor = QLineEdit() self.leColor.setPlaceholderText('255,255,255') self.leColor.setText( str(self.colorSelected.red()) + "," + str(self.colorSelected.green()) + "," + str(self.colorSelected.blue())) self.tableWidget.setCellWidget(0, 4, self.leColor) # validation pbValid = QPushButton('Valider') pbValid.clicked.connect(self.addValid) self.tableWidget.setCellWidget(0, 5, pbValid) pb = self.sender() pbPos = pb.property('pbPos') if pbPos is not None: if str(pbPos)[:8] == 'nouveau,': self.lePos.setText(pbPos[8:]) def sortByPos(val): return val['position'] self.data_buttons['buttons'].sort(key=sortByPos) for ligne, b in enumerate(self.data_buttons['buttons'], start=1): self.tableWidget.setSpan(ligne, 1, 1, 2) self.tableWidget.setCellWidget(ligne, 0, QLabel(b['name'])) self.tableWidget.setCellWidget(ligne, 1, QLabel(b['file'])) self.tableWidget.setCellWidget(ligne, 3, QLabel(str(b['position']))) self.tableWidget.setCellWidget(ligne, 4, QLabel('Couleur')) # 530 color picker width self.setGeometry(self.left, self.top, 690 + 530, 300) def addValid(self): gName = self.leName.text() self.leName.setStyleSheet("color: rgb(0,0,0);") gFile = self.leFile.text() self.leFile.setStyleSheet("color: rgb(0,0,0);") gPos = self.lePos.text() self.lePos.setStyleSheet("color: rgb(0,0,0);") gColor = self.leColor.text() self.leColor.setStyleSheet("color: rgb(0,0,0);") # si champs vides if ((gName == '' or gName == 'Obligatoire !') or (gFile == '' or gFile == 'Obligatoire !') or (gPos == '' or gColor == 'Obligatoire !') or (gColor == '' or gColor == 'Obligatoire !')): if gName == '' or gName == 'Obligatoire !': self.leName.setText('Obligatoire !') self.leName.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") if gFile == '' or gFile == 'Obligatoire !': self.leFile.setText('Obligatoire !') self.leFile.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") if gPos == '' or gColor == 'Obligatoire !': self.lePos.setText('Obligatoire !') self.lePos.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") if gColor == '' or gColor == 'Obligatoire !': self.leColor.setText('Obligatoire !') self.leColor.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") else: # vérif si champ position est un nombre try: flag = 0 flag = int(gPos) except ValueError: self.lePos.setText(f"{str(gPos)} n'est pas un nombre") self.lePos.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") # si position est un nombre if flag != 0: # si position hors grille if int(gPos) < 0 or int(gPos) > self.data_buttons[ 'buttons_grid']['height'] * self.data_buttons[ 'buttons_grid']['width']: self.lePos.setText(f"{str(gPos)} hors grille") self.lePos.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") else: dictToAppend = { "name": gName, "file": gFile, "position": int(gPos), "r": self.colorSelected.red(), "g": self.colorSelected.green(), "b": self.colorSelected.blue() } # si c'est une modification if self.pbPosToModify != -1: for b in self.data_buttons['buttons']: if b['position'] == self.pbPosToModify: self.data_buttons['buttons'].remove(b) self.data_buttons['buttons'].append(dictToAppend) with open('buttons.json', 'w', encoding='utf-8') as outfile: json.dump(self.data_buttons, outfile, indent=4) self.initButtons() else: # si position déjà prise if int(gPos) in self.positions: self.lePos.setText(f"{str(gPos)} déjà prise") self.lePos.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") else: self.data_buttons['buttons'].append(dictToAppend) with open('buttons.json', 'w', encoding='utf-8') as outfile: json.dump(self.data_buttons, outfile, indent=4) self.initButtons() def delete(self): self.startInitButtons() # positionnement des boutons en fonction des positions du json for ligne in range(self.BtnH): for colonne in range(self.BtnW): if (ligne * self.BtnW) + (colonne + 1) in self.positions: for b in self.data_buttons['buttons']: if b['position'] == (ligne * self.BtnW) + (colonne + 1): pb = QPushButton(b['name'][:9]) pb.setProperty('pbPos', b['position']) pb.setIcon(self.iMinus) # si fond clair, font noire, si sombre, font blanche if (b['r'] * 0.299 + b['g'] * 0.587 + b['b'] * 0.114) > 186: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #000000;" ) else: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #ffffff;" ) self.tableWidget.setCellWidget(ligne, colonne, pb) pb.clicked.connect(self.deleteTw) else: pb = QPushButton('Nouveau') calcPos = self.BtnW * ligne + colonne + 1 pb.setProperty('pbPos', f"nouveau,{calcPos}") pb.clicked.connect(self.add) self.tableWidget.setCellWidget(ligne, colonne, pb) colonne += 1 ligne += 1 self.endInitButtons() def deleteTw(self): pb = self.sender() pbPos = pb.property('pbPos') for b in self.data_buttons['buttons']: if b['position'] == pbPos: self.data_buttons['buttons'].remove(b) with open('buttons.json', 'w', encoding='utf-8') as outfile: json.dump(self.data_buttons, outfile, indent=4) self.delete() def editBtn(self): self.startInitButtons() # positionnement des boutons en fonction des positions du json for ligne in range(self.BtnH): for colonne in range(self.BtnW): if (ligne * self.BtnW) + (colonne + 1) in self.positions: for b in self.data_buttons['buttons']: if b['position'] == (ligne * self.BtnW) + (colonne + 1): pb = QPushButton(b['name'][:9]) pb.setProperty('pbPos', b['position']) pb.setIcon(self.iEdit) # si fond clair, font noire, si sombre, font blanche if (b['r'] * 0.299 + b['g'] * 0.587 + b['b'] * 0.114) > 186: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #000000;" ) else: pb.setStyleSheet( f"background-color: rgb({b['r']},{b['g']},{b['b']}); color: #ffffff;" ) self.tableWidget.setCellWidget(ligne, colonne, pb) pb.clicked.connect(self.editTw) else: pb = QPushButton('Nouveau') pb.setIcon(self.iEdit) calcPos = self.BtnW * ligne + colonne + 1 pb.setProperty('pbPos', f"nouveau,{calcPos}") pb.clicked.connect(self.add) self.tableWidget.setCellWidget(ligne, colonne, pb) colonne += 1 ligne += 1 self.endInitButtons() def editTw(self): pb = self.sender() pbPos = pb.property('pbPos') self.pbPosToModify = pbPos self.add() for b in self.data_buttons['buttons']: if b['position'] == pbPos: self.leName.setText(b['name']) self.leFile.setText(b['file']) self.lePos.setText(str(b['position'])) self.cdColorPicker.setCurrentColor( QColor(b['r'], b['g'], b['b'])) def settings(self): self.tableWidget.clear() self.tableWidget.clearSpans() self.tableWidget.setColumnWidth(2, 100) self.cdColorPicker.setVisible(False) self.tableWidget.setColumnCount(2) self.tableWidget.setRowCount(4) self.tableWidget.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.tableWidget.horizontalHeader().hide() # bouton validation pb = QPushButton('Valider') self.tableWidget.setCellWidget(3, 0, pb) pb.clicked.connect(self.saveSettings) # bouton annulation pb = QPushButton('Annuler') self.tableWidget.setCellWidget(3, 1, pb) pb.clicked.connect(self.refreshUI) # parameters self.tableWidget.setSpan(0, 0, 1, 2) self.lAlert = QLabel("La modification de ces valeurs entrainera la " "modification de position des boutons") self.lAlert.setStyleSheet("font-weight: bold;") self.tableWidget.setCellWidget(0, 0, self.lAlert) self.tableWidget.setCellWidget(1, 0, QLabel('Nombre de boutons en Hauteur')) self.leH = QLineEdit(str(self.data_buttons['buttons_grid']['height'])) self.tableWidget.setCellWidget(1, 1, self.leH) self.tableWidget.setCellWidget(2, 0, QLabel('Nombre de boutons en Largeur')) self.leW = QLineEdit(str(self.data_buttons['buttons_grid']['width'])) self.tableWidget.setCellWidget(2, 1, self.leW) settingsLayout = QVBoxLayout() settingsLayout.setStretch(0, 1) settingsLayout.addWidget(self.tableWidget) self.windowLayout.addLayout(settingsLayout) self.setGeometry(self.left, self.top, 600, 300) def saveSettings(self): h = int(self.leH.text()) w = int(self.leW.text()) if h * w < self.max_pos: self.lAlert.setText(f"Le bouton à la position {str(self.max_pos)} " f"est en dehors de la grille {h} x {w}") self.lAlert.setStyleSheet( "color: rgb(255,0,0); font-weight: bold;") else: self.data_buttons['buttons_grid']['height'] = int(self.leH.text()) self.data_buttons['buttons_grid']['width'] = int(self.leW.text()) with open('buttons.json', 'w', encoding='utf-8') as outfile: json.dump(self.data_buttons, outfile, indent=4) self.initButtons() def refreshUI(self): self.initButtons() def browseMedia(self): self.openFile = QFileDialog.getOpenFileName( self, "Sélectionner un média...", "./sons", "Image Files (*.avi *.mp3 *.wav)") filenameSplitted = self.openFile[0].split('/') self.leFile.setText(filenameSplitted[-1]) def colorChanged(self): self.colorSelected = self.cdColorPicker.currentColor() self.leColor.setText( str(self.colorSelected.red()) + "," + str(self.colorSelected.green()) + "," + str(self.colorSelected.blue()))