def __init__(self, parent=None, icon=QIcon(), title="", text="", wordWrap=False, textFormat=Qt.PlainText, standardButtons=NoButton, acceptLabel="Ok", rejectLabel="No", **kwargs): super().__init__(parent, **kwargs) self._title = title self._text = text self._icon = QIcon() self._wordWrap = wordWrap self._standardButtons = NotificationMessageWidget.NoButton self._buttons = [] self._acceptLabel = acceptLabel self._rejectLabel = rejectLabel self._iconlabel = QLabel(objectName="icon-label") self._titlelabel = QLabel(objectName="title-label", text=title, wordWrap=wordWrap, textFormat=textFormat) self._textlabel = QLabel(objectName="text-label", text=text, wordWrap=wordWrap, textFormat=textFormat) self._textlabel.setTextInteractionFlags(Qt.TextBrowserInteraction) self._textlabel.setOpenExternalLinks(True) if sys.platform == "darwin": self._titlelabel.setAttribute(Qt.WA_MacSmallSize) self._textlabel.setAttribute(Qt.WA_MacSmallSize) layout = QHBoxLayout() self._iconlabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self._iconlabel) layout.setAlignment(self._iconlabel, Qt.AlignTop) message_layout = QVBoxLayout() self._titlelabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) if sys.platform == "darwin": self._titlelabel.setContentsMargins(0, 1, 0, 0) else: self._titlelabel.setContentsMargins(0, 0, 0, 0) message_layout.addWidget(self._titlelabel) self._textlabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) message_layout.addWidget(self._textlabel) self.button_layout = QHBoxLayout() self.button_layout.setAlignment(Qt.AlignLeft) message_layout.addLayout(self.button_layout) layout.addLayout(message_layout) layout.setSpacing(7) self.setLayout(layout) self.setIcon(icon) self.setStandardButtons(standardButtons)
class NotificationMessageWidget(QWidget): #: Emitted when a button with the AcceptRole is clicked accepted = Signal() #: Emitted when a button with the RejectRole is clicked rejected = Signal() #: Emitted when a button is clicked clicked = Signal(QAbstractButton) class StandardButton(enum.IntEnum): NoButton, Ok, Close = 0x0, 0x1, 0x2 NoButton, Ok, Close = list(StandardButton) class ButtonRole(enum.IntEnum): InvalidRole, AcceptRole, RejectRole, DismissRole = 0, 1, 2, 3 InvalidRole, AcceptRole, RejectRole, DismissRole = list(ButtonRole) _Button = namedtuple("_Button", ["button", "role", "stdbutton"]) def __init__(self, parent=None, icon=QIcon(), title="", text="", wordWrap=False, textFormat=Qt.PlainText, standardButtons=NoButton, acceptLabel="Ok", rejectLabel="No", **kwargs): super().__init__(parent, **kwargs) self._title = title self._text = text self._icon = QIcon() self._wordWrap = wordWrap self._standardButtons = NotificationMessageWidget.NoButton self._buttons = [] self._acceptLabel = acceptLabel self._rejectLabel = rejectLabel self._iconlabel = QLabel(objectName="icon-label") self._titlelabel = QLabel(objectName="title-label", text=title, wordWrap=wordWrap, textFormat=textFormat) self._textlabel = QLabel(objectName="text-label", text=text, wordWrap=wordWrap, textFormat=textFormat) self._textlabel.setTextInteractionFlags(Qt.TextBrowserInteraction) self._textlabel.setOpenExternalLinks(True) if sys.platform == "darwin": self._titlelabel.setAttribute(Qt.WA_MacSmallSize) self._textlabel.setAttribute(Qt.WA_MacSmallSize) layout = QHBoxLayout() self._iconlabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self._iconlabel) layout.setAlignment(self._iconlabel, Qt.AlignTop) message_layout = QVBoxLayout() self._titlelabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) if sys.platform == "darwin": self._titlelabel.setContentsMargins(0, 1, 0, 0) else: self._titlelabel.setContentsMargins(0, 0, 0, 0) message_layout.addWidget(self._titlelabel) self._textlabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) message_layout.addWidget(self._textlabel) self.button_layout = QHBoxLayout() self.button_layout.setAlignment(Qt.AlignLeft) message_layout.addLayout(self.button_layout) layout.addLayout(message_layout) layout.setSpacing(7) self.setLayout(layout) self.setIcon(icon) self.setStandardButtons(standardButtons) def setText(self, text): """ Set the current message text. :type message: str """ if self._text != text: self._text = text self._textlabel.setText(text) def text(self): """ Return the current message text. :rtype: str """ return self._text def setTitle(self, title): """ Set the current title text. :type title: str """ if self._title != title: self._title = title self._titleLabel.setText(title) def title(self): """ Return the current title text. :rtype: str """ return self._title def setIcon(self, icon): """ Set the message icon. :type icon: QIcon | QPixmap | QString | QStyle.StandardPixmap """ if isinstance(icon, QStyle.StandardPixmap): icon = self.style().standardIcon(icon) else: icon = QIcon(icon) if self._icon != icon: self._icon = QIcon(icon) if not self._icon.isNull(): size = self.style().pixelMetric(QStyle.PM_SmallIconSize, None, self) pm = self._icon.pixmap(QSize(size, size)) else: pm = QPixmap() self._iconlabel.setPixmap(pm) self._iconlabel.setVisible(not pm.isNull()) def icon(self): """ Return the current icon. :rtype: QIcon """ return QIcon(self._icon) def setWordWrap(self, wordWrap): """ Set the message text wrap property :type wordWrap: bool """ if self._wordWrap != wordWrap: self._wordWrap = wordWrap self._textlabel.setWordWrap(wordWrap) def wordWrap(self): """ Return the message text wrap property. :rtype: bool """ return self._wordWrap def setTextFormat(self, textFormat): """ Set message text format :type textFormat: Qt.TextFormat """ self._textlabel.setTextFormat(textFormat) def textFormat(self): """ Return the message text format. :rtype: Qt.TextFormat """ return self._textlabel.textFormat() def setAcceptLabel(self, label): """ Set the accept button label. :type label: str """ self._acceptLabel = label def acceptLabel(self): """ Return the accept button label. :rtype str """ return self._acceptLabel def setRejectLabel(self, label): """ Set the reject button label. :type label: str """ self._rejectLabel = label def rejectLabel(self): """ Return the reject button label. :rtype str """ return self._rejectLabel def setStandardButtons(self, buttons): for button in NotificationMessageWidget.StandardButton: existing = self.button(button) if button & buttons and existing is None: self.addButton(button) elif existing is not None: self.removeButton(existing) def standardButtons(self): return functools.reduce( operator.ior, (slot.stdbutton for slot in self._buttons if slot.stdbutton is not None), NotificationMessageWidget.NoButton) def addButton(self, button, *rolearg): """ addButton(QAbstractButton, ButtonRole) addButton(str, ButtonRole) addButton(StandardButton) Add and return a button """ stdbutton = None if isinstance(button, QAbstractButton): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(QAbstractButton, role)") role = rolearg[0] elif isinstance(button, NotificationMessageWidget.StandardButton): if rolearg: raise TypeError("Wrong number of arguments for " "addButton(StandardButton)") stdbutton = button if button == NotificationMessageWidget.Ok: role = NotificationMessageWidget.AcceptRole button = QPushButton(self._acceptLabel, default=False, autoDefault=False) elif button == NotificationMessageWidget.Close: role = NotificationMessageWidget.RejectRole button = QPushButton(self._rejectLabel, default=False, autoDefault=False) elif isinstance(button, str): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(str, ButtonRole)") role = rolearg[0] button = QPushButton(button, default=False, autoDefault=False) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) self._buttons.append( NotificationMessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self._button_clicked) self._relayout() return button def _relayout(self): for slot in self._buttons: self.button_layout.removeWidget(slot.button) order = { NotificationWidget.AcceptRole: 0, NotificationWidget.RejectRole: 1, } ordered = sorted([ b for b in self._buttons if self.buttonRole(b.button) != NotificationMessageWidget.DismissRole ], key=lambda slot: order.get(slot.role, -1)) prev = self._textlabel for slot in ordered: self.button_layout.addWidget(slot.button) QWidget.setTabOrder(prev, slot.button) def removeButton(self, button): """ Remove a `button`. :type button: QAbstractButton """ slot = [s for s in self._buttons if s.button is button] if slot: slot = slot[0] self._buttons.remove(slot) self.layout().removeWidget(slot.button) slot.button.setParent(None) def buttonRole(self, button): """ Return the ButtonRole for button :type button: QAbstractButton """ for slot in self._buttons: if slot.button is button: return slot.role return NotificationMessageWidget.InvalidRole def button(self, standardButton): """ Return the button for the StandardButton. :type standardButton: StandardButton """ for slot in self._buttons: if slot.stdbutton == standardButton: return slot.button return None def _button_clicked(self): button = self.sender() role = self.buttonRole(button) self.clicked.emit(button) if role == NotificationMessageWidget.AcceptRole: self.accepted.emit() self.close() elif role == NotificationMessageWidget.RejectRole: self.rejected.emit() self.close()
def __init__(self, iterateSettings): nRows = len(iterateSettings["iterableAttrs"]) if not nRows: return nCols = 5 super().__init__() self.css = """ QPushButton {background-color: #1588c5; color: white; height: 20px; border: 1px solid black; border-radius: 2px;} QPushButton:hover {background-color: #1555f5; } QPushButton:hover:pressed { background-color: #1588c5; color: black; border-style: inset; border: 1px solid white} QPushButton:disabled { background-color: lightGray; border: 1px solid gray; } """ self.setMinimumSize(520, 240) self.iterateSettings = iterateSettings self.setWindowTitle("Edit iterate settings") self.table = QTableWidget() self.table.setColumnCount(nCols) for col in range(nCols - 1): self.table.horizontalHeader().setResizeMode( col, QtGui.QHeaderView.ResizeToContents) self.table.horizontalHeader().setResizeMode(nCols - 1, QtGui.QHeaderView.Stretch) self.table.horizontalHeader().setStretchLastSection(True) self.table.setHorizontalHeaderLabels([ "", "Parameter", "Group size", "Threads needed", "Required RAM (MB)" ]) self.settingsCopy = copy.deepcopy(self.iterateSettings) self.table.setRowCount(nRows) rowNum = 0 for parm in self.settingsCopy["iterableAttrs"]: # init values if they are not there if "data" not in self.settingsCopy: self.settingsCopy["data"] = {} if parm not in self.settingsCopy["data"]: self.settingsCopy["data"][parm] = { "groupSize": "1", "threads": "1", "ram": "0", } if ("groupSize" not in self.settingsCopy["data"][parm].keys() or not self.settingsCopy["data"][parm]["groupSize"]): self.settingsCopy["data"][parm]["groupSize"] = "1" if ("threads" not in self.settingsCopy["data"][parm].keys() or not self.settingsCopy["data"][parm]["threads"]): self.settingsCopy["data"][parm]["threads"] = "1" if ("ram" not in self.settingsCopy["data"][parm].keys() or not self.settingsCopy["data"][parm]["ram"]): self.settingsCopy["data"][parm]["ram"] = "0" # make column items cb = QTableWidgetItem() parmItem = QTableWidgetItem(parm) groupSizeItem = QTableWidgetItem( self.settingsCopy["data"][parm]["groupSize"]) threadItem = QTableWidgetItem( self.settingsCopy["data"][parm]["threads"]) ramItem = QTableWidgetItem(self.settingsCopy["data"][parm]["ram"]) self.setSelect(parmItem, False) parmItem.setFlags(parmItem.flags() ^ Qt.ItemIsEditable) parmItem.setFlags(parmItem.flags() ^ Qt.ItemIsSelectable) cb.setFlags(cb.flags() ^ Qt.ItemIsSelectable) if ("iteratedAttrs" in self.settingsCopy and parm in self.settingsCopy["iteratedAttrs"]): cb.setCheckState(QtCore.Qt.Checked) else: cb.setCheckState(QtCore.Qt.Unchecked) self.setEnable(parmItem, False) self.setEnableSelect(groupSizeItem, False) self.setEnableSelect(threadItem, False) self.setEnableSelect(ramItem, False) self.table.setItem(rowNum, 0, cb) self.table.setItem(rowNum, 1, parmItem) self.table.setItem(rowNum, 2, groupSizeItem) self.table.setItem(rowNum, 3, threadItem) self.table.setItem(rowNum, 4, ramItem) rowNum = rowNum + 1 self.table.cellChanged.connect(self.onCheckBoxChanged) # buttons for save and load saveBtn = gui.button(None, self, "Save", callback=self.save) saveBtn.setStyleSheet(self.css) saveBtn.setFixedSize(70, 20) # table tableBox = QGroupBox() scroll_area = QScrollArea(verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn) scroll_area.setWidget(tableBox) scroll_area.setWidgetResizable(True) tableLayout = QHBoxLayout() tableLayout.addWidget(self.table) tableBox.setLayout(tableLayout) # buttons buttonLayout = QHBoxLayout() buttonLayout.setAlignment(Qt.AlignTop) buttonLayout.addWidget(saveBtn) iterateLayout = QVBoxLayout() iterateLayout.addWidget(tableBox) iterateLayout.addLayout(buttonLayout) self.setLayout(iterateLayout)