class Window(QWidget): def __init__(self): super().__init__() self.title = "PyQt ButtonGroup" self.top = 100 self.left = 100 self.width = 400 self.height = 300 self.buttongroup = QButtonGroup() self.hbox = QHBoxLayout() self.label = QLabel(self) self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon("home.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) #self.buttongroup.buttonClicked[int].connect(self.onButtonClicked) self.buttongroup.buttonPressed[int].connect(self.onButtonPressed) self.buttongroup.buttonReleased[int].connect(self.onButtonReleased) self.buttonGroup() self.hbox.addWidget(self.label) self.setLayout(self.hbox) self.show() def buttonGroup(self): button = QPushButton('Python') self.buttongroup.addButton(button, 1) self.hbox.addWidget(button) button2 = QPushButton('Java') self.buttongroup.addButton(button2, 2) self.hbox.addWidget(button2) button3 = QPushButton('C++') self.buttongroup.addButton(button3, 3) self.hbox.addWidget(button3) def onButtonClicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + ' was clicked') def onButtonPressed(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + ' was pressed!') def onButtonReleased(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + ' was released!')
class LocalButtonsConf(OptionsDialogGroupBox): def __init__(self, name, main): self.main = main OptionsDialogGroupBox.__init__(self, name, main) self.buttonBox = QGroupBox("Pins") self.buttonBoxLayout = QVBoxLayout() self.buttonBox.setLayout(self.buttonBoxLayout) def initUI(self): vbox = QVBoxLayout() self.polBox = QCheckBox("Invert") vbox.addWidget(self.polBox) self.buttongroup = QButtonGroup() self.buttongroup.setExclusive(False) vbox.addWidget(self.buttonBox) self.setLayout(vbox) def initButtons(self, num): #delete buttons self.num = num # Remove buttons for i in range(self.buttonBoxLayout.count()): b = self.buttonBoxLayout.takeAt(0) self.buttonBoxLayout.removeItem(b) b.widget().deleteLater() for b in self.buttongroup.buttons(): self.buttongroup.removeButton(b) self.buttonBox.update() for i in range(self.num): cb = QCheckBox(str(i + 1)) self.buttongroup.addButton(cb, i) self.buttonBoxLayout.addWidget(cb) def localcb(mask): for i in range(self.num): self.buttongroup.button(i).setChecked(mask & (1 << i)) self.main.comms.serialGetAsync("local_btnmask?", localcb, int) def apply(self): mask = 0 for i in range(self.num): if (self.buttongroup.button(i).isChecked()): mask |= 1 << i self.main.comms.serialWrite("local_btnmask=" + str(mask)) self.main.comms.serialWrite("local_btnpol=" + ("1" if self.polBox.isChecked() else "0")) def readValues(self): self.main.comms.serialGetAsync("local_btnpins?", self.initButtons, int) self.main.comms.serialGetAsync("local_btnpol?", self.polBox.setChecked, int)
class PaletteList(QListWidget): def __init__(self, window=None): super(PaletteList, self).__init__(window) self.window = window self.uniformItemSizes = True self.list = [] self.current_index = 0 self.radio_button_group = QButtonGroup() def add_palette_from_image(self, image_filename, image_map): print(image_filename) item = QListWidgetItem(self) self.addItem(item) pf = PaletteFrame(len(self.list), image_filename, image_map, self) self.list.append(pf) item.setSizeHint(pf.minimumSizeHint()) self.setItemWidget(item, pf) # Try and make it the right size self.setMinimumWidth(self.sizeHintForColumn(0)) return pf def remove_last_palette(self): print('Removing last palette!') self.takeItem(len(self.list) - 1) self.list.pop() def duplicate(self, idx): command = CommandDuplicate(self, idx, "Duplicate Palette %d" % idx) self.window.undo_stack.push(command) def set_current_palette(self, idx): self.current_index = idx self.radio_button_group.button(idx).setChecked(True) self.window.palette_text.setText(self.get_current_palette().name) self.window.update_view() def get_current_palette(self): return self.list[self.current_index] def get_last_palette(self): return self.list[-1] def get_palette(self, idx): return self.list[idx] def clear(self): print('PaletteList clear') # Need to remove things in reverse order, duh for idx, l in reversed(list(enumerate(self.list))): print(idx) self.takeItem(idx) l.deleteLater() self.list = [] self.current_index = 0
class RecordWindow(QDialog): def __init__(self): super().__init__() self.setWindowTitle("Рекорды") self.setFixedSize(400, 300) self.init_ui() def init_ui(self): font = QFont() font.setPointSize(12) self.tableWidget = QTableWidget(self) self.tableWidget.setGeometry(QtCore.QRect(140, 0, 260, 300)) self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableWidget.setColumnCount(2) self.tableWidget.setRowCount(0) self.buttonGroup = QButtonGroup(self) for n, text in enumerate(['Новичок', 'Эксперт', 'Бывалый']): rb = QRadioButton(self) rb.setGeometry(QtCore.QRect(30, 100 + 30 * n, 91, 17)) rb.setText(text) rb.setFont(font) self.buttonGroup.addButton(rb) self.buttonGroup.setId(rb, n) self.buttonGroup.buttonClicked.connect(self.choose_table) self.tableWidget.setHorizontalHeaderLabels(["Имя", "Время"]) self.tableWidget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.game_stat = GameStat() self.buttonGroup.button(0).click() def choose_table(self): res = self.game_stat.get_records(self.sender().checkedButton().text()) self.tableWidget.setRowCount(len(res)) for i in range(len(res)): name = QTableWidgetItem(res[i]["name"]) name.setTextAlignment(QtCore.Qt.AlignCenter) time = QTableWidgetItem(str(res[i]["time"])) time.setTextAlignment(QtCore.Qt.AlignCenter) self.tableWidget.setItem(i, 0, name) self.tableWidget.setItem(i, 1, time) # self.tableWidget.resizeColumnsToContents() def show(self): self.exec()
class RadioButtons(WidgetBridge, Choices): _qttype = QGroupBox def customize(self, widget): assert self.choices, "RadioButtons: Cannot build widget bridge without choices" # We give the GroupBox a container so we can add stretch at the end. self.container = QWidget(self.parent) hbox = QHBoxLayout(self.container) self.buttongroup = QButtonGroup(self.parent) if "direction" in self.config and \ self.config["direction"].lower() == "vertical": box = QVBoxLayout() else: box = QHBoxLayout() ix = 1 for text in self.choicesdict().values(): rb = QRadioButton(text, self.parent) box.addWidget(rb) self.buttongroup.addButton(rb, ix) ix += 1 widget.setLayout(box) hbox.addWidget(widget) hbox.addStretch(1) hbox.setContentsMargins(QMargins(0, 0, 0, 0)) def apply(self, value): for b in self.buttongroup.buttons(): b.setChecked(False) b = self.buttongroup.button(self.index(value) + 1) if b: b.setChecked(True) def retrieve(self): ix = self.buttongroup.checkedId() return self.at(ix - 1) if ix > 0 else None
class ButtonGroup(QWidget): def __init__(self): super().__init__() self.grid = QGridLayout() self.btn_group = QButtonGroup() self.initUI() def initUI(self): pos = [(x, y) for x in range(3) for y in range(3)] btn_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] for pos, num in zip(pos, btn_list): btn = QPushButton(num) self.grid.addWidget(btn, *pos) self.btn_group.addButton(btn, int(num)) self.btn_group.buttonClicked[int].connect(self.button_group_clicked) self.setLayout(self.grid) self.setWindowTitle("Button Group") self.resize(400, 250) self.center() self.show() def button_group_clicked(self, id): btn = self.btn_group.button(id) btn.setText(str(randint(1, 100))) def center(self): geom = self.frameGeometry() cnt = QDesktopWidget().availableGeometry().center() geom.moveCenter(cnt) self.move(geom.topLeft())
class Window(QWidget): def __init__(self): super().__init__() self.title = "PyQt5 QButton Group" self.top = 200 self.left = 500 self.width = 400 self.height = 300 self.setWindowTitle(self.title) self.setWindowIcon(QtGui.QIcon("icon.png")) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() self.label = QLabel(self) self.label.setFont(QtGui.QFont("Sanserif", 15)) hbox.addWidget(self.label) self.buttongroup = QButtonGroup() #self.buttongroup.setExclusive(False) self.buttongroup.buttonClicked[int].connect(self.on_button_clicked) button = QPushButton("Python") self.buttongroup.addButton(button, 0) button.setFont(QtGui.QFont("Sanserif", 15)) button.setIcon(QtGui.QIcon("pythonicon.png")) button.setIconSize(QtCore.QSize(40, 40)) hbox.addWidget(button) button = QPushButton("Java") self.buttongroup.addButton(button, 1) button.setFont(QtGui.QFont("Sanserif", 15)) button.setIcon(QtGui.QIcon("java.png")) button.setIconSize(QtCore.QSize(40, 40)) hbox.addWidget(button) button = QPushButton("C++") self.buttongroup.addButton(button, 2) button.setFont(QtGui.QFont("Sanserif", 15)) button.setIcon(QtGui.QIcon("cpp.png")) button.setIconSize(QtCore.QSize(40, 40)) hbox.addWidget(button) self.setLayout(hbox) self.show() def on_button_clicked(self, id): print(id) for button in self.buttongroup.buttons(): print(type(button)) if button is self.buttongroup.button(id): self.label.setText(button.text() + " Was Clicked ") self.setWindowTitle("andy") button.setIconSize(QtCore.QSize(60, 60)) print(button.text()) button.setText("andy")
class Window(QWidget): def __init__(self): super().__init__() self.title = 'Button Group' self.top = 200 self.left = 400 self.width = 400 self.height = 200 self.initWindow() def initWindow(self): self.setWindowTitle(self.title) self.setWindowIcon(QtGui.QIcon('avatar.png')) self.setGeometry(self.left, self.top, self.width, self.height) vbox = QVBoxLayout() hbox = QHBoxLayout() self.label = QLabel('This is label', self) self.label.setFont(QtGui.QFont('Sanserif', 13)) vbox.addWidget(self.label) self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.on_button_clicked) button = QPushButton('Python') self.buttongroup.addButton(button, 1) self.buttongroup.addButton(button, 1) button.setFont(QtGui.QFont("Sanserif", 13)) button.setIcon(QtGui.QIcon("avatar.png")) button.setIconSize(QtCore.QSize(15, 15)) hbox.addWidget(button) button = QPushButton("Java") self.buttongroup.addButton(button, 2) button.setFont(QtGui.QFont("Sanserif", 13)) button.setIcon(QtGui.QIcon("avatar.png")) button.setIconSize(QtCore.QSize(15, 15)) hbox.addWidget(button) button = QPushButton("C++") self.buttongroup.addButton(button, 3) button.setFont(QtGui.QFont("Sanserif", 13)) button.setIcon(QtGui.QIcon("avatar.png")) button.setIconSize(QtCore.QSize(15, 15)) hbox.addWidget(button) vbox.addLayout(hbox) self.setLayout(vbox) self.show() def on_button_clicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + ' Was Clicked')
class Window(QWidget): def __init__(self): super().__init__() self.title = "PyQt5 QButton Group" self.left = 500 self.top = 200 self.width = 300 self.height = 250 self.iconName = "icon.png" self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hqbox = QHBoxLayout() self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.on_button_clicked) self.label = QLabel(self) self.label.setFont(QtGui.QFont("Sanserif", 14)) hqbox.addWidget(self.label) button = QPushButton("Python") button.setFont(QtGui.QFont("Sanserif", 14)) button.setIcon(QtGui.QIcon("python.png")) button.setIconSize(QtCore.QSize(40, 40)) self.buttongroup.addButton(button, 1) hqbox.addWidget(button) button2 = QPushButton("Java") button2.setFont(QtGui.QFont("Sanserif", 14)) button2.setIcon(QtGui.QIcon("java.png")) button2.setIconSize(QtCore.QSize(40, 40)) self.buttongroup.addButton(button2, 2) hqbox.addWidget(button2) button3 = QPushButton("PHP") button3.setFont(QtGui.QFont("Sanserif", 14)) button3.setIcon(QtGui.QIcon("php.png")) button3.setIconSize(QtCore.QSize(40, 40)) self.buttongroup.addButton(button3, 3) hqbox.addWidget(button3) self.setLayout(hqbox) self.show() def on_button_clicked(self, id): # 原始範例 for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + " Was clicked.")
class MainWidow(QWidget): def __init__(self): super().__init__() self.Window_Properties() self.Window_Properties_Apply() self.Interface() def Window_Properties(self): self.title = "PyQt5 Button Group" self.top = 200 self.left = 500 self.width = 500 self.height = 500 self.iconName = "icon.png" def Window_Properties_Apply(self): self.setWindowTitle(self.title) self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setGeometry(self.top , self.left ,self.width ,self.height) def Interface(self): self.label = QLabel() button_twelfth = QPushButton("Twelfth") button_twelfth.setFont(QtGui.QFont("Sanserif" ,15)) button_twelfth.setIcon(QtGui.QIcon("icon.png")) button_twelfth.setIconSize(QtCore.QSize(40 ,40)) button_thirteenth = QPushButton("Thirteenth") button_fourteenth = QPushButton("Fourteeth") self.buttonGroup = QButtonGroup() self.buttonGroup.addButton(button_twelfth ,1) self.buttonGroup.addButton(button_thirteenth ,2) self.buttonGroup.addButton(button_fourteenth , 3) h_box = QHBoxLayout() h_box.addWidget(self.label) h_box.addWidget(button_twelfth) h_box.addWidget(button_thirteenth) h_box.addWidget(button_fourteenth) self.buttonGroup.buttonClicked[int].connect(self.On_Button_Clicked) self.setLayout(h_box) def On_Button_Clicked(self ,id): for button in self.buttonGroup.buttons(): if button is self.buttonGroup.button(id): self.label.setText(button.text() + " Was Clicked")
class ButtonBar(QFrame): buttonClicked = pyqtSignal( str, int ) # Indicates the iteration number and iteration name of the button that was clicked def __init__(self, items: t_.Sequence[str], parent=None): super().__init__(parent=parent) # self.setFrameStyle(QFrame.Panel) self._bGroup = QButtonGroup(self) l = QHBoxLayout(self) for i, itemName in enumerate(items): b = QPushButton(itemName, parent=self) b.setCheckable(True) # Toggleable self._bGroup.addButton(b, id=i) l.addWidget(b) self._selectedButtonId = self._bGroup.id(self._bGroup.buttons()[0]) self._bGroup.buttons()[0].click( ) # Make sure at least one button is selected. self._bGroup.buttonClicked.connect(self._buttonSelected) l.setSpacing(1) # Move buttons close together l.setContentsMargins(0, 0, 0, 0) w = QFrame(self) w.setFrameStyle(QFrame.Box) w.setLayout(l) scrollArea = QScrollArea(parent=self) scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) scrollArea.setStyleSheet("""QScrollBar:horizontal { height:10px; }""") scrollArea.setWidget(w) scrollArea.setFixedHeight(10 + w.height()) ll = QHBoxLayout() ll.setContentsMargins(0, 0, 0, 0) ll.addWidget(scrollArea) self.setLayout(ll) def _buttonSelected(self, btn): self._selectedButtonId = self._bGroup.id(btn) self.buttonClicked.emit(btn.text(), self._bGroup.id(btn)) def getSelectedButtonId(self): return self._selectedButtonId def selectNextButton(self): id = self._selectedButtonId + 1 if id >= len(self._bGroup.buttons()): id = 0 self.setButtonSelected(id) def setButtonSelected(self, ID: int): btn = self._bGroup.button(ID) btn.click()
class Window(QDialog): def __init__(self): super().__init__() self.title = "Line Edit" self.left = 300 self.top = 100 self.width = 500 self.height = 500 self.IconName = "Icon/python.png" self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon(self.IconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() self.buttonGroup = QButtonGroup() buttonOne = QPushButton("Python") buttonTwo = QPushButton("Java") buttonOne.setIcon(QtGui.QIcon(self.IconName)) buttonOne.setIconSize(QtCore.QSize(40, 40)) buttonTwo.setIcon(QtGui.QIcon(self.IconName)) buttonTwo.setIconSize(QtCore.QSize(40, 40)) self.buttonGroup.addButton(buttonOne) self.buttonGroup.addButton(buttonTwo) self.buttonGroup.buttonClicked[int].connect(self.OnButtonClick) self.label = QLabel(self) hbox.addWidget(buttonOne) hbox.addWidget(buttonTwo) hbox.addWidget(self.label) self.setLayout(hbox) self.show() def OnButtonClick(self, id): for button in self.buttonGroup.buttons(): if button is self.buttonGroup.button(id): self.label.setText(button.text() + " is clicked!")
class Window(QWidget): def __init__(self): super().__init__() self.title = "PyQt5 QButton Group @ stu_dados" self.top = 500 self.left = 500 self.width = 500 self.height = 500 self.iconName = "_imagens/stuart.ico" self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() self.label = QLabel(self) self.label.setFont(QtGui.QFont("Sanserif", 15)) hbox.addWidget(self.label) self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.on_button_clicked) button = QPushButton("Python") self.buttongroup.addButton(button, 1) button.setFont(QtGui.QFont("Sanserif", 13)) hbox.addWidget(button) button = QPushButton("Java") self.buttongroup.addButton(button, 2) button.setFont(QtGui.QFont("Sanserif", 13)) hbox.addWidget(button) button = QPushButton("C++") self.buttongroup.addButton(button, 3) button.setFont(QtGui.QFont("Sanserif", 13)) hbox.addWidget(button) self.setLayout(hbox) self.show() def on_button_clicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + " foi clicado.")
class Window(QWidget): def __init__(self): super().__init__() self.title = "QLine Edit" self.top = 100 self.left = 100 self.width = 400 self.height = 120 self.iconName = "logo.png" self.setWindowTitle(self.title) self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() self.label = QLabel("Hello") hbox.addWidget(self.label) self.label.setFont(QtGui.QFont("Algerian", 14)) self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.onButtonClicked) btn1 = QPushButton("Python") btn1.setIcon(QtGui.QIcon("python.png")) self.buttongroup.addButton(btn1, 1) hbox.addWidget(btn1) btn2 = QPushButton("Java") btn2.setIcon(QtGui.QIcon("java.png")) self.buttongroup.addButton(btn2, 2) hbox.addWidget(btn2) btn3 = QPushButton("C++") btn3.setIcon(QtGui.QIcon("Cpp.png")) self.buttongroup.addButton(btn3, 3) hbox.addWidget(btn3) self.setLayout(hbox) self.show() def onButtonClicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + " Clicked!")
class window(QWidget): def __init__(self): super().__init__() self.title = "Pyqt5 Qbutton group" self.top = 500 self.left = 500 self.width = 100 self.height = 200 self.iconName = "transistor.jpg" self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QVBoxLayout() self.label = QLabel("Hello") self.label.setFont(QtGui.QFont("Sanserif", 10)) hbox.addWidget(self.label) self.buttongroup = QButtonGroup() self.buttongroup.buttonClicked[int].connect(self.onButton_clicked) button = QPushButton("Python") self.buttongroup.addButton(button, 1) button.setMinimumHeight(70) hbox.addWidget(button) button1 = QPushButton("Java") self.buttongroup.addButton(button1, 2) button1.setMinimumHeight(70) button1.setIcon(QtGui.QIcon(self.iconName)) button1.setIconSize(QtCore.QSize(60, 60)) button1.setFont(QtGui.QFont("Sanserif", 15)) hbox.addWidget(button1) button2 = QPushButton("JOSE") self.buttongroup.addButton(button2, 3) button2.setMinimumHeight(70) hbox.addWidget(button2) self.setLayout(hbox) self.show() def onButton_clicked(self, id): for button in self.buttongroup.buttons(): if button is self.buttongroup.button(id): self.label.setText(button.text() + " was Clicked")
class MyWindow(QWidget): def __init__(self): super(MyWindow, self).__init__() self.icon = QtGui.QIcon("home.ico") self.rect = QtCore.QRect(100,200,800,600) self.title = "PyQt5 BuggonGroup" self.setWindowIcon(self.icon) self.setWindowTitle(self.title) self.setGeometry(self.rect) self.label = QLabel(self) self.label.setText('label') self.button_group = QButtonGroup() self.InitWindow() self.show() def InitWindow(self): ''' QButtonGroup的signal再使用的时候要注意如何使用[int]不要忘记了,否则会出错 :return: ''' self.button_group.buttonClicked[int].connect(self.OnButtonGroupPressed) vbox = QVBoxLayout() for i in range(1,10): button = QPushButton('Button %d'%i) button.setIcon(self.icon) button.setIconSize(QtCore.QSize(40,40)) button.setFont(QtGui.QFont('lisu',20)) self.button_group.addButton(button,i) vbox.addWidget(button) self.label.setFont(QtGui.QFont('lisu',20)) vbox.addWidget(self.label) self.setLayout(vbox) def OnButtonGroupPressed(self,id): self.label.setText(self.button_group.button(id).text())
class EnumBase(Option): values = () def get_value(self): if self.__as_radio_buttons: return self.values[self.__button_group.checkedId()] button_text = self.widget.text() if isinstance(self, SymbolicEnumOption): return self.values[self.labels.index(button_text)] return button_text def set_value(self, value): if self.__as_radio_buttons: self.__button_group.button( self.values.index(value)).setChecked(True) elif isinstance(self, SymbolicEnumOption): self.widget.setText(self.labels[self.values.index(value)]) else: self.widget.setText(value) value = property(get_value, set_value) def set_multiple(self): if not self.__as_radio_buttons: self.widget.setText(self.multiple_value) def remake_menu(self): from PyQt5.QtWidgets import QAction, QRadioButton from PyQt5.QtCore import Qt if isinstance(self, SymbolicEnumOption): labels = self.labels else: labels = self.values if self.__as_radio_buttons: for b in self.__button_group.buttons(): self.__button_group.removeButton(b) b.hide() b.destroy() layout = self.widget.layout() for i, l in enumerate(labels): b = QRadioButton(l) layout.addWidget(b, alignment=Qt.AlignLeft) self.__button_group.addButton(b, id=i) else: menu = self.widget.menu() menu.clear() for label, value in zip(labels, self.values): menu_label = label.replace('&', '&&') action = QAction(menu_label, self.widget) action.triggered.connect( lambda arg, s=self, val=value: s._menu_cb(val)) menu.addAction(action) if self.values and self.value not in self.values and self.value != self.multiple_value: self.value = labels[0] self.make_callback() remake_buttons = remake_menu def _make_widget(self, *, as_radio_buttons=False, display_value=None, **kw): from PyQt5.QtWidgets import QPushButton, QMenu, QWidget, QButtonGroup, QVBoxLayout self.__as_radio_buttons = as_radio_buttons if as_radio_buttons: self.widget = QWidget() layout = QVBoxLayout() self.widget.setLayout(layout) self.__button_group = QButtonGroup() self.remake_buttons() self.__button_group.button(self.values.index( self.default)).setChecked(True) self.__button_group.buttonClicked[int].connect( lambda arg: self.make_callback()) else: if display_value is not None: button_label = display_value elif isinstance(self, SymbolicEnumOption): button_label = self.labels[self.values.index(self.default)] else: button_label = self.default self.widget = QPushButton(button_label, **kw) self.widget.setAutoDefault(False) menu = QMenu(self.widget) self.widget.setMenu(menu) self.remake_menu() return self.widget def _menu_cb(self, value): self.value = value self.make_callback()
class TimersDialog(QDialog): sendCommand = pyqtSignal(str, str) def __init__(self, device, *args, **kwargs): super(TimersDialog, self).__init__(*args, **kwargs) self.device = device self.timers = {} self.setWindowTitle("Timers [{}]".format( self.device.p['FriendlyName1'])) vl = VLayout() self.gbTimers = GroupBoxV("Enabled", spacing=5) self.gbTimers.setCheckable(True) self.gbTimers.toggled.connect(self.toggleTimers) self.cbTimer = QComboBox() self.cbTimer.addItems(["Timer{}".format(nr + 1) for nr in range(16)]) self.cbTimer.currentTextChanged.connect(self.loadTimer) hl_tmr_arm_rpt = HLayout(0) self.cbTimerArm = QCheckBox("Arm") self.cbTimerArm.clicked.connect(lambda x: self.describeTimer()) self.cbTimerRpt = QCheckBox("Repeat") self.cbTimerRpt.clicked.connect(lambda x: self.describeTimer()) hl_tmr_arm_rpt.addWidgets([self.cbTimerArm, self.cbTimerRpt]) hl_tmr_out_act = HLayout(0) self.cbxTimerOut = QComboBox() self.cbxTimerOut.addItems(self.device.power().keys()) self.cbxTimerOut.currentIndexChanged.connect( lambda x: self.describeTimer()) self.cbxTimerAction = QComboBox() self.cbxTimerAction.addItems(["Off", "On", "Toggle", "Rule"]) self.cbxTimerAction.currentIndexChanged.connect( lambda x: self.describeTimer()) hl_tmr_out_act.addWidgets([self.cbxTimerOut, self.cbxTimerAction]) self.TimerMode = QButtonGroup() rbTime = QRadioButton("Time") rbSunrise = QRadioButton("Sunrise ({})".format( self.device.p['Sunrise'])) rbSunset = QRadioButton("Sunset ({})".format(self.device.p['Sunset'])) self.TimerMode.addButton(rbTime, 0) self.TimerMode.addButton(rbSunrise, 1) self.TimerMode.addButton(rbSunset, 2) self.TimerMode.buttonClicked.connect(lambda x: self.describeTimer()) gbTimerMode = GroupBoxH("Mode") gbTimerMode.addWidgets(self.TimerMode.buttons()) hl_tmr_time = HLayout(0) self.cbxTimerPM = QComboBox() self.cbxTimerPM.addItems(["+", "-"]) self.cbxTimerPM.currentIndexChanged.connect( lambda x: self.describeTimer()) self.TimerMode.buttonClicked[int].connect( lambda x: self.cbxTimerPM.setEnabled(x != 0)) self.teTimerTime = QTimeEdit() self.teTimerTime.setButtonSymbols(QTimeEdit.NoButtons) self.teTimerTime.setAlignment(Qt.AlignCenter) self.teTimerTime.timeChanged.connect(lambda x: self.describeTimer()) lbWnd = QLabel("Window:") lbWnd.setAlignment(Qt.AlignVCenter | Qt.AlignRight) self.cbxTimerWnd = QComboBox() self.cbxTimerWnd.addItems([str(x).zfill(2) for x in range(0, 16)]) self.cbxTimerWnd.currentIndexChanged.connect( lambda x: self.describeTimer()) hl_tmr_days = HLayout(0) self.TimerWeekday = QButtonGroup() self.TimerWeekday.setExclusive(False) for i, wd in enumerate( ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]): cb = QCheckBox(wd) cb.clicked.connect(lambda x: self.describeTimer()) hl_tmr_days.addWidget(cb) self.TimerWeekday.addButton(cb, i) gbTimerDesc = GroupBoxV("Timer description", 5) gbTimerDesc.setMinimumHeight(200) self.lbTimerDesc = QLabel() self.lbTimerDesc.setAlignment(Qt.AlignCenter) self.lbTimerDesc.setWordWrap(True) gbTimerDesc.layout().addWidget(self.lbTimerDesc) hl_tmr_time.addWidgets( [self.cbxTimerPM, self.teTimerTime, lbWnd, self.cbxTimerWnd]) self.gbTimers.layout().addWidget(self.cbTimer) self.gbTimers.layout().addLayout(hl_tmr_arm_rpt) self.gbTimers.layout().addLayout(hl_tmr_out_act) self.gbTimers.layout().addWidget(gbTimerMode) self.gbTimers.layout().addLayout(hl_tmr_time) self.gbTimers.layout().addLayout(hl_tmr_days) btns = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close) reload = btns.addButton("Reload", QDialogButtonBox.ResetRole) btns.accepted.connect(self.saveTimer) btns.rejected.connect(self.reject) reload.clicked.connect( lambda: self.loadTimer(self.cbTimer.currentText())) vl.addWidgets([self.gbTimers, gbTimerDesc, btns]) self.setLayout(vl) def toggleTimers(self, state): self.sendCommand.emit(self.device.cmnd_topic('timers'), "ON" if state else "OFF") def loadTimer(self, timer=""): if not timer: timer = self.cbTimer.currentText() payload = self.timers[timer] if payload: self.blockSignals(True) self.cbTimerArm.setChecked(payload['Arm']) self.cbTimerRpt.setChecked(payload['Repeat']) self.cbxTimerAction.setCurrentIndex(payload['Action']) output = payload.get('Output') if output: self.cbxTimerOut.setEnabled(True) self.cbxTimerOut.setCurrentIndex(output - 1) else: self.cbxTimerOut.setEnabled(False) mode = payload.get('Mode', 0) self.TimerMode.button(mode).setChecked(True) h, m = map(int, payload["Time"].split(":")) if h < 0: self.cbxTimerPM.setCurrentText("-") h *= -1 self.teTimerTime.setTime(QTime(h, m)) self.cbxTimerWnd.setCurrentText(str(payload['Window']).zfill(2)) for wd, v in enumerate(payload['Days']): self.TimerWeekday.button(wd).setChecked(int(v)) self.blockSignals(False) self.describeTimer() def describeTimer(self): if self.cbTimerArm.isChecked(): desc = { 'days': '', 'repeat': '', 'timer': self.cbTimer.currentText().upper() } repeat = self.cbTimerRpt.isChecked() out = self.cbxTimerOut.currentText() act = self.cbxTimerAction.currentText() mode = self.TimerMode.checkedId() pm = self.cbxTimerPM.currentText() time = self.teTimerTime.time() wnd = int(self.cbxTimerWnd.currentText()) * 60 if mode == 0: if wnd == 0: desc['time'] = "at {}".format(time.toString("hh:mm")) else: desc['time'] = "somewhere between {} and {}".format( time.addSecs(wnd * -1).toString("hh:mm"), time.addSecs(wnd).toString("hh:mm")) else: prefix = "before" if pm == "-" else "after" mode_desc = "sunrise" if mode == 1 else "sunset" window = "somewhere in a {} minute window centered around ".format( wnd // 30) desc['time'] = "{}h{}m {} {}".format(time.hour(), time.minute(), prefix, mode_desc) if wnd > 0: desc['time'] = window + desc['time'] if repeat: day_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] days = [cb.isChecked() for cb in self.TimerWeekday.buttons()] if days.count(True) == 7: desc['days'] = "everyday" else: days_list = [day_names[d] for d in range(7) if days[d]] desc['days'] = "on every {}".format(", ".join(days_list)) else: desc['repeat'] = "only ONCE" if act == "Rule": desc['action'] = "trigger clock#Timer={}".format( self.cbTimer.currentIndex() + 1) text = "{timer} will {action} {time} {days} {repeat}".format( **desc) elif self.cbxTimerOut.count() > 0: if act == "Toggle": desc['action'] = "TOGGLE {}".format(out.upper()) else: desc['action'] = "set {} to {}".format( out.upper(), act.upper()) text = "{timer} will {action} {time} {days} {repeat}".format( **desc) else: text = "{timer} will do nothing because there are no relays configured.".format( **desc) self.lbTimerDesc.setText(text) else: self.lbTimerDesc.setText( "{} is not armed, it will do nothing.".format( self.cbTimer.currentText().upper())) def saveTimer(self): payload = { "Arm": int(self.cbTimerArm.isChecked()), "Mode": self.TimerMode.checkedId(), "Time": self.teTimerTime.time().toString("hh:mm"), "Window": self.cbxTimerWnd.currentIndex(), "Days": "".join([ str(int(cb.isChecked())) for cb in self.TimerWeekday.buttons() ]), "Repeat": int(self.cbTimerRpt.isChecked()), "Output": self.cbxTimerOut.currentIndex() + 1, "Action": self.cbxTimerAction.currentIndex() } self.sendCommand.emit( self.device.cmnd_topic(self.cbTimer.currentText()), dumps(payload)) QMessageBox.information( self, "Timer saved", "{} data sent to device.".format(self.cbTimer.currentText())) @pyqtSlot(str, str) def parseMessage(self, topic, msg): if self.device.matches(topic): if self.device.reply == "RESULT" or self.device.reply == "TIMERS": try: payload = loads(msg) first = list(payload)[0] except JSONDecodeError as e: error = "Timer loading error", "Can't load the timer from device.\n{}".format( e) logging.critical(error) QMessageBox.critical(self, error) else: if first == 'Timers': self.gbTimers.setChecked(payload[first] == "ON") elif first.startswith('Timers'): self.timers.update(payload[first]) if first == 'Timers4': self.loadTimer(self.cbTimer.currentText())
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText( app.settings.get("account", "username")) self.lineEdit_loginPassword.setText( app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked( app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked(app.autoStart) # Xwared Management managedBySystemd = app.xwaredpy.managedBySystemd managedByUpstart = app.xwaredpy.managedByUpstart managedByAutostart = app.xwaredpy.managedByAutostart self.radio_managedBySystemd.setChecked(managedBySystemd) self.radio_managedByUpstart.setChecked(managedByUpstart) self.radio_managedByAutostart.setChecked(managedByAutostart) self.radio_managedByNothing.setChecked(not ( managedBySystemd or managedByUpstart or managedByAutostart)) initType = getInitType() self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD) self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART) # frontend self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked( app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect( self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked( app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled( self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText( app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) startEtmWhen = app.xwaredpy.startEtmWhen if startEtmWhen: self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) else: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @pyqtSlot(int) def slotWatchClipboardToggled(self, state): self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): self.table_mounts.insertRow(i) # drive1: the drive letter it should map to, by alphabetical order drive1 = app.mountsFaker.driveIndexToLetter(i) self.table_mounts.setItem( i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD")) # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.setItem(i, 1, QTableWidgetItem(mount)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") errors = [] # check: mapping if drive1 != drive2: errors.append("错误:盘符映射在'{actual}',而不是'{should}'。\n" "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。".format( actual=drive2, should=drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem( row, 0, QTableWidgetItem( app.mountsFaker.driveIndexToLetter(row) + "\\TDDOWNLOAD")) self.table_mounts.setItem(row, 1, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) app.autoStart = self.checkBox_autoStartFrontend.isChecked() app.xwaredpy.managedBySystemd = self.radio_managedBySystemd.isChecked() app.xwaredpy.managedByUpstart = self.radio_managedByUpstart.isChecked() app.xwaredpy.managedByAutostart = self.radio_managedByAutostart.isChecked( ) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) app.settings.set("frontend", "watchpattern", self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id( self.btngrp_etmStartWhen.checkedButton()) try: app.xwaredpy.startEtmWhen = startEtmWhen except InvalidSocket: QMessageBox.warning( None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list( map(lambda row: self.table_mounts.item(row, 1).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue( etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting( dLimit=self.spinBox_dSpeedLimit.value(), uLimit=self.spinBox_uSpeedLimit.value(), maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class parameter(): def __init__(self, const, vary): self.const = const self.vary = vary self.constPara = [] self.varyPara = [] self.pp = [] for i in range(vary): self.pp.append(property.property()) def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1200, 800) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(40, 30, 171, 16)) self.label.setText("Parameter Setting") self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.gridLayoutWidget.setGeometry(QtCore.QRect(40, 80, 1000, 700)) self.gridLayoutWidget.setObjectName("gridLayoutWidget") self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") # list for vary paramter label self.name = [] self.combo = [] self.range = [] self.rfield = [] self.check = [] self.add = [] self.other = [] self.othername = [] # list for const paramter label self.cname = [] self.ccombo = [] self.cvalue = [] self.crfield = [] self.cadd = [] self.cother = [] self.cothername = [] self.btn_grp = QButtonGroup() self.btn_grp.buttonClicked[int].connect(self.addSession) for i in range(self.vary): self.name.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.name[i].setText("Varying parameter" + str(i + 1)) self.gridLayout.addWidget(self.name[i], i, 0, 1, 1) self.name[i].adjustSize() self.combo.append(QtWidgets.QComboBox(self.gridLayoutWidget)) self.combo[i].setObjectName("comboBox") self.combo[i].addItem("Keithley 2440 cur (A)") self.combo[i].addItem("Keithley 2440 com (V)") self.combo[i].addItem("Keithley 6221 cur (A)") self.combo[i].addItem("Keithley 6221 com (V)") self.combo[i].addItem("Keithley 6221 amp (A)") self.combo[i].addItem("Keithley 6221 fre (Hz)") self.combo[i].addItem("Keithley 6221 duration") self.combo[i].addItem("Angle") self.combo[i].addItem("Other") self.gridLayout.addWidget(self.combo[i], i, 1, 1, 1) self.combo[i].adjustSize() self.pp[i].savename = "Keithley 2440 cur (A)" self.combo[i].currentTextChanged.connect(partial(self.changetoother, i, True)) self.other.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.other[i].setText("Other: ") self.gridLayout.addWidget(self.other[i], i, 2, 1, 1) self.other[i].adjustSize() self.othername.append(QtWidgets.QLineEdit(self.gridLayoutWidget)) self.gridLayout.addWidget(self.othername[i], i, 3, 1, 1) self.othername[i].textChanged.connect(partial(self.savename, i)) self.range.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.range[i].setText("Range") self.gridLayout.addWidget(self.range[i], i, 4, 1, 1) self.range[i].adjustSize() self.rfield.append(QtWidgets.QLineEdit(self.gridLayoutWidget)) self.rfield[i].setText(self.pp[i].saverange[0]) self.gridLayout.addWidget(self.rfield[i], i, 5, 1, 1) # save range property whenever text changed self.rfield[i].textChanged.connect(partial(self.saverfield, i)) self.check.append(QtWidgets.QCheckBox(self.gridLayoutWidget)) self.check[i].setText("sweep") self.check[i].setChecked(self.pp[i].savesweep[0]) self.gridLayout.addWidget(self.check[i], i, 6, 1, 1) self.check[i].clicked.connect(partial(self.savescheck, i)) self.add.append(QtWidgets.QPushButton(self.gridLayoutWidget)) self.add[i].setText("Add") self.add[i].setObjectName(str(i)) self.gridLayout.addWidget(self.add[i], i, 7, 1, 1) self.btn_grp.addButton(self.add[i], i) for i in range(self.const): self.cname.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.cname[i].setText("Constant parameter" + str(i + 1)) self.gridLayout.addWidget(self.cname[i], i + self.vary, 0, 1, 1) self.cname[i].adjustSize() self.ccombo.append(QtWidgets.QComboBox(self.gridLayoutWidget)) self.ccombo[i].setObjectName("comboBox") self.ccombo[i].addItem("Keithley 2440 cur (A)") self.ccombo[i].addItem("Keithley 2440 com (V)") self.ccombo[i].addItem("Keithley 6221 cur (A)") self.ccombo[i].addItem("Keithley 6221 com (V)") self.ccombo[i].addItem("Keithley 6221 amp (A)") self.ccombo[i].addItem("Keithley 6221 fre (Hz)") self.ccombo[i].addItem("Keithley 6221 duration") self.ccombo[i].addItem("Angle") self.ccombo[i].addItem("Other") self.gridLayout.addWidget(self.ccombo[i], i + self.vary, 1, 1, 1) self.ccombo[i].adjustSize() self.cother.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.cother[i].setText("Other:") self.gridLayout.addWidget(self.cother[i], i + self.vary, 2, 1, 1) self.cother[i].adjustSize() self.cothername.append(QtWidgets.QLineEdit(self.gridLayoutWidget)) self.gridLayout.addWidget(self.cothername[i], i + self.vary, 3, 1, 1) self.cothername[i].textChanged.connect(partial(self.changetoother, i, False)) self.cvalue.append(QtWidgets.QLabel(self.gridLayoutWidget)) self.cvalue[i].setText("Constant Value") self.gridLayout.addWidget(self.cvalue[i], i + self.vary, 4, 1, 1) self.cvalue[i].adjustSize() self.crfield.append(QtWidgets.QLineEdit(self.gridLayoutWidget)) self.crfield[i].setText("const") self.gridLayout.addWidget(self.crfield[i], i + self.vary, 5, 1, 1) self.genBtn = QtWidgets.QPushButton(self.gridLayoutWidget) self.genBtn.setText("Generate") self.gridLayout.addWidget(self.genBtn, i + self.vary + 1, 4, 1, 1) self.genBtn.clicked.connect(lambda: self.generate_handler()) for i in range(self.vary): self.pp[i].bind_to(self.update) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 422, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) QtCore.QMetaObject.connectSlotsByName(MainWindow) def generate_handler(self): # varying for i in range(self.vary): slist = self.pp[i].savesweep name = self.pp[i].savename list = self.pp[i].saverange check = self.checkrange(self.rfield[i].text(), i) if not check: return self.varyPara.append(varyPara.VaryPara(name, list, slist)) # const for i in range(self.const): const = self.crfield[i].text() check = self.checknum(const, i, False) if not check: return checkbound = self.checkboundary(const, i, False) if not checkbound: return if self.ccombo[i].currentText() == "Other": name = self.cothername[i].text() else: name = self.ccombo[i].currentText() self.constPara.append(constPara.ConstPara(name, const)) file = WriteFile.inputFile(self.varyPara, self.constPara) def saverfield(self, i, text): self.pp[i].saverange[0] = text def savescheck(self, i, text): self.pp[i].savesweep[0] = text def savename(self, i, text): if self.combo[i].currentText() != "Other": self.combo[i].setCurrentText("Other") self.pp[i].savename = text self.pp[i].setname(text) print(self.pp[i].savename) def addSession(self, button_id): for btn in self.btn_grp.buttons(): if btn is self.btn_grp.button(button_id): self.openwindow(self.pp[button_id]) def changetoother(self, i, vary): if vary: if self.othername[i].text() != "": self.combo[i].setCurrentText("Other") self.pp[i].savename = self.othername[i].text() self.pp[i].setname(self.combo[i].currentText()) else: if self.cothername[i].text() != "": self.ccombo[i].setCurrentText("Other") def openwindow(self, status): self.window = QtWidgets.QMainWindow() self.ui = add(status) self.ui.setupUi(self.window) self.window.show() def update(self): for i in range(self.vary): self.rfield[i].setText(self.pp[i].saverange[0]) self.check[i].setChecked(self.pp[i].savesweep[0]) def checkrange(self, text, i): try: numbers = text.split(",") num1 = numbers[0] num2 = numbers[1] check1 = self.checknum(num1, i, True) check2 = self.checknum(num2, i, True) check3 = numbers[2].isdigit() num3 = int(numbers[2]) check4 = num3 >= 0 if not (check1 and check2 and check3 and check4): self.popErrorWindow("Wrong input range format at " + str(i + 1) + "th vary item.") return checkbound1 = self.checkboundary(num1, i, True) checkbound2 = self.checkboundary(num2, i, True) return check1 and check2 and check3 and checkbound1 and checkbound2 except: self.popErrorWindow("Wrong input range format at " + str(i + 1) + "th vary item hh.") return False def checkboundary(self, num, index, vary): try: cur_path = os.path.dirname(__file__) new_path = os.path.join(cur_path, '..', 'input', 'boundary.txt') file1 = open(new_path, "r+") text = file1.readlines() for i in range(len(text)): text[i] = text[i].replace('\n', '') x = re.split("<=|>=|<|>", text[i]) y = re.findall("<=|>=|<|>", text[i]) y = y[0] if vary: name = self.pp[index].savename if name == x[0]: if y == ">": if not float(num) > float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th vary item should > " + str(x[1])) return False if y == "<": if not float(num) < float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th vary item should < " + str(x[1])) return False if y == ">=": if not float(num) >= float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th vary item should >= " + str(x[1])) return False if y == "<=": if not float(num) <= float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th vary item should <= " + str(x[1])) return False else: if self.ccombo[index].currentText() == "Other": name = self.cothername[index].text() else: name = self.ccombo[index].currentText() if name == x[0]: if y == ">": if not float(num) > float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th const item should > " + str(x[1])) return False if y == "<": if not float(num) < float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th const item should < " + str(x[1])) return False if y == ">=": if not float(num) >= float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th const item should >= " + str(x[1])) return False if y == "<=": if not float(num) <= float(x[1]): file1.close() self.popErrorWindow( "Warning: Value at " + str(index + 1) + "th const item should <= " + str(x[1])) return False file1.close() return True except: self.popErrorWindow("Fail to read boundary.txt") return False def checknum(self, text, i, vary): y = re.fullmatch("[0-9]*[.][0-9]*|[-][0-9]*[.][0-9]*|[0-9]*|[-][0-9]*", text) if y is None: if vary: self.popErrorWindow("Range must be integers/float at " + str(i + 1) + "th vary item.") if not vary: self.popErrorWindow("Constant value must be integers/float at " + str(i + 1) + "th const item.") return False return True def popErrorWindow(self, msg): self.window = QtWidgets.QMainWindow() self.ui = ErrorPane.error(msg) self.ui.setupUi(self.window) self.window.show()
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText(app.settings.get("adapter-legacy", "username")) self.lineEdit_loginPassword.setText(app.settings.get("adapter-legacy", "password")) self.checkBox_autoLogin.setChecked(app.settings.getbool("legacy", "autologin")) self.checkBox_autoStartFrontend.setChecked(app.autoStart) if sys.platform == "linux": self.checkBox_autoStartFrontend.setEnabled(True) adapter = app.adapterManager[0] # Xwared Management managedBySystemd = adapter.daemonManagedBySystemd managedByUpstart = adapter.daemonManagedByUpstart managedByAutostart = adapter.daemonManagedByAutostart self.radio_managedBySystemd.setChecked(managedBySystemd) self.radio_managedByUpstart.setChecked(managedByUpstart) self.radio_managedByAutostart.setChecked(managedByAutostart) self.radio_managedByNothing.setChecked( not (managedBySystemd or managedByUpstart or managedByAutostart)) initType = getInitType() self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD) self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART) if not adapter.useXwared: self.group_etmStartWhen.setEnabled(False) self.group_initManaged.setEnabled(False) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) if adapter.useXwared: startEtmWhen = adapter.startEtmWhen self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) # frontend self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("legacy", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(app.settings.getbool("legacy", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern")) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @pyqtSlot(int) def slotWatchClipboardToggled(self, state): self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): adapter = app.adapterManager[0] if not adapter.useXwared: self.tab_mount.setEnabled(False) return self.table_mounts.setRowCount(0) self.table_mounts.clearContents() mountsMapping = app.adapterManager[0].mountsFaker.getMountsMapping() for i, mount in enumerate(app.adapterManager[0].mountsFaker.mounts): self.table_mounts.insertRow(i) # drive1: the drive letter it should map to, by alphabetical order drive1 = app.adapterManager[0].mountsFaker.driveIndexToLetter(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD")) # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.setItem(i, 1, QTableWidgetItem(mount)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") errors = [] # check: mapping if drive1 != drive2: errors.append( "错误:盘符映射在'{actual}',而不是'{should}'。\n" "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。" .format(actual = drive2, should = drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem( row, 0, QTableWidgetItem(app.adapterManager[0].mountsFaker.driveIndexToLetter(row) + "\\TDDOWNLOAD")) self.table_mounts.setItem(row, 1, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("adapter-legacy", "username", self.lineEdit_loginUsername.text()) app.settings.set("adapter-legacy", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("legacy", "autologin", self.checkBox_autoLogin.isChecked()) app.autoStart = self.checkBox_autoStartFrontend.isChecked() app.adapterManager[0].daemonManagedBySystemd = self.radio_managedBySystemd.isChecked() app.adapterManager[0].daemonManagedByUpstart = self.radio_managedByUpstart.isChecked() app.adapterManager[0].daemonManagedByAutostart = self.radio_managedByAutostart.isChecked() app.settings.setbool("legacy", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("legacy", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) app.settings.set("frontend", "watchpattern", self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton()) app.adapterManager[0].startEtmWhen = startEtmWhen app.settings.save() if self.tab_mount.isEnabled(): app.adapterManager[0].mountsFaker.mounts = self.newMounts app.applySettings.emit() super().accept() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 1).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values adapter = app.adapterManager[0] settings = adapter.backendSettings etmRunning = adapter.etmPid != 0 if etmRunning and settings.initialized: self.spinBox_dSpeedLimit.setValue(settings.downloadSpeedLimit) self.spinBox_uSpeedLimit.setValue(settings.uploadSpeedLimit) self.spinBox_maxRunningTasksNum.setValue(settings.maxRunTaskNumber) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): adapter = app.adapterManager[0] adapter.do_applySettings({ "downloadSpeedLimit": self.spinBox_dSpeedLimit.value(), "uploadSpeedLimit": self.spinBox_uSpeedLimit.value(), "maxRunTaskNumber": self.spinBox_maxRunningTasksNum.value(), })
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setWindowModality(Qt.WindowModal) self.setAttribute(Qt.WA_DeleteOnClose) self.mainWin = parent self.setupUi(self) self.lineEdit_loginUsername.setText(self.settings.get("account", "username")) self.lineEdit_loginPassword.setText(self.settings.get("account", "password")) self.checkBox_autoLogin.setChecked(self.settings.getbool("account", "autologin")) self.checkBox_enableDevelopersTools.setChecked( self.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(self.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked(self.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked(self.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked(self.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked(self.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked(self.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue(self.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(self.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(self.settings.get("frontend", "watchpattern")) from PyQt5.QtWidgets import QButtonGroup self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) self.btngrp_etmStartWhen.button(self.settings.getint("xwared", "startetmwhen")).setChecked(True) self.accepted.connect(self.writeSettings) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() # shorthand @property def settings(self): return self.mainWin.settings # shorthand ends @staticmethod def permissionCheck(): import re ansiEscape = re.compile(r'\x1b[^m]*m') import subprocess with subprocess.Popen([constants.PERMISSIONCHECK], stdout = subprocess.PIPE, stderr = subprocess.PIPE) as proc: output = proc.stdout.read().decode("utf-8") output = ansiEscape.sub('', output) lines = output.split("\n") prevLine = None currMount = None result = {} for line in lines: if len(line.strip()) == 0: continue if all(map(lambda c: c == '=', line)): if currMount: result[currMount] = result[currMount][:-1] result[prevLine] = [] currMount = prevLine continue if currMount: if line != "正常。": result[currMount].append(line) prevLine = line return result @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() PermissionError = self.permissionCheck() mountsMapping = self.mainWin.mountsFaker.getMountsMapping() for i, mount in enumerate(self.mainWin.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) drive1 = chr(ord('C') + i) + ":" # the drive letter it should map to, by alphabetical order self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) drive2 = mountsMapping.get(mount, "无") # the drive letter it actually is assigned to # check 1: permission errors = PermissionError.get(mount, ["无法获得检测权限。运行/opt/xware_desktop/permissioncheck查看原因。"]) # check 2: mapping if drive1 != drive2: errors.append("警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format(actual = drive2, should = drive1)) from PyQt5.Qt import Qt from PyQt5.QtGui import QBrush brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): import os from PyQt5.QtWidgets import QFileDialog from PyQt5.Qt import Qt fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if (fileDialog.exec()): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def writeSettings(self): self.settings.set("account", "username", self.lineEdit_loginUsername.text()) self.settings.set("account", "password", self.lineEdit_loginPassword.text()) self.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) self.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) self.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) self.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 self.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) self.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) self.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) self.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) self.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) self.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # self.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) self.settings.setint("xwared", "startetmwhen", self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton())) startETMWhen = self.settings.getint("xwared", "startetmwhen") if startETMWhen == 1: self.settings.setbool("xwared", "startetm", True) self.settings.save() self.mainWin.mountsFaker.setMounts(self.newMounts) self.settings.applySettings.emit() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): etmpy = self.mainWin.etmpy # fill values self.lineEdit_lcport.setText(etmpy.cfg.get("local_control.listen_port", "不可用")) etmSettings = etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): import etmpy newsettings = etmpy.EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(), uLimit = self.spinBox_uSpeedLimit.value(), maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value()) self.mainWin.etmpy.saveSettings(newsettings)
class SpectraModuleUI(QWidget): monoStartup = pyqtSignal() def __init__(self, cam_wi, status_bar, hardware_conf): super().__init__() self.CameraWI = cam_wi self.statusBar = status_bar self.ui_construct(hardware_conf) def init_parameters(self, param_set): frame = param_set['frameSet'] stage = param_set['stagePos'] laser = param_set['Laser'] mono = param_set['MDR-3'] andor = param_set['Andor'] # Hardware parameter set self.x_pos.setText(str(stage['x'])) self.y_pos.setText(str(stage['y'])) self.z_pos.setText(str(stage['z'])) self.step_val.setCurrentText(str(stage['step'])) self.WLStart.setValue(mono['WL-start']) self.monoGridPos.setValue(mono['WL-pos']) self.monoCurrentPos.setText(str(mono['WL-pos']) + ' nm') self.monoGridSelect.setCurrentIndex(mono['grating-select']) self.monoStartup.emit() self.laserSelect.setCurrentIndex(laser['source-id']) # Frame parameter set self.frameRowSelect.setValue(frame['row']) self.frameColSelect.setValue(frame['column']) self.frameColSelect.setValue(frame['column']) self.rowBinning.setValue(frame['binning']) if frame['binningAvg']: self.avgBinning.setChecked(True) # self.XUnits.button(frame['x-axis']).setChecked(True) self.XUnits.button(frame['x-axis']).click() # self.YUnits.button(frame['y-axis']).setChecked(True) self.YUnits.button(frame['y-axis']).click() # Andor parameter set self.exposureTime.setValue(andor['exposure']) self.acquisitionMode.setCurrentIndex(andor['AcqMode']['mode']) self.mode_prm_enable(andor['AcqMode']['mode']) self.accumulationFrames.setValue(andor['AcqMode']['accumFrames']) self.accumulationCycle.setValue(andor['AcqMode']['accumCycle']) self.kineticSeries.setValue(andor['AcqMode']['kSeries']) self.kineticCycle.setValue(andor['AcqMode']['kCycle']) self.triggeringMode.setCurrentIndex(andor['trigMode']) self.readoutMode.setCurrentIndex(andor['readMode']) self.VSSpeed.setCurrentIndex(andor['VSSpeed']) self.VSAVoltage.setCurrentIndex(andor['VSAVoltage']) self.readoutRate.setCurrentIndex(andor['ADCRate']) self.preAmpGain.setCurrentIndex(andor['gain']) def mode_prm_enable(self, acq_mode): if acq_mode == 0: self.accumulationFrames.setEnabled(False) self.accumulationCycle.setEnabled(False) self.kineticSeries.setEnabled(False) self.kineticCycle.setEnabled(False) elif acq_mode == 1: self.accumulationFrames.setEnabled(True) self.accumulationCycle.setEnabled(True) self.kineticSeries.setEnabled(False) self.kineticCycle.setEnabled(False) elif acq_mode == 2: self.accumulationFrames.setEnabled(True) self.accumulationCycle.setEnabled(True) self.kineticSeries.setEnabled(True) self.kineticCycle.setEnabled(True) elif acq_mode == 4: self.accumulationFrames.setEnabled(False) self.accumulationCycle.setEnabled(True) self.kineticSeries.setEnabled(True) self.kineticCycle.setEnabled(False) def ui_construct(self, conf): # Main splitters topleft_frame = QFrame(self) topleft_frame.setFrameShape(QFrame.StyledPanel) topright_frame = QFrame(self) topright_frame.setFrameShape(QFrame.StyledPanel) bottom_frame = QFrame(self) bottom_frame.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(topleft_frame) splitter1.addWidget(topright_frame) splitter1.setSizes((250, 100)) splitter1.setStretchFactor(0, 0) splitter1.setStretchFactor(1, 1) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom_frame) splitter2.setSizes((100, 200)) splitter2.setStretchFactor(0, 1) splitter2.setStretchFactor(1, 0) main_lay = QVBoxLayout(self) main_lay.addWidget(splitter2) view_area = QTabWidget(self) view_area.setTabPosition(QTabWidget.West) ccd = QFrame(self) view_area.addTab(ccd, "Spectra acquisition") view_area.addTab(self.CameraWI, "Camera") view_area_lay = QVBoxLayout(topright_frame) view_area_lay.addWidget(view_area) # --- Controls frame --- self.monoGridPos = QDoubleSpinBox(self) self.monoGridPos.setRange(200.0, 1000.0) self.monoGridPos.setSingleStep(0.1) self.monoGridPos.setDecimals(1) self.monoSetPos = QPushButton('Set') self.monoSetPos.setMinimumSize(90, 30) self.monoCalibrate = QPushButton('Calibration') self.monoCalibrate.setMinimumSize(90, 30) self.monoStop = QPushButton('Stop') self.monoStop.setMinimumSize(90, 30) self.monoCurrentPos = QLabel('500.00 nm') mono_pos_lbl = QLabel('Current position: ') self.monoGridSelect = QComboBox(self) self.monoGridSelect.addItems(['300 g/mm', '600 g/mm']) mono_grid_lbl = QLabel('Grating: ') self.laserSelect = QComboBox(self) self.laserSelect.addItems( ['Laser 405 nm', 'Laser 450 nm', 'LED 370 nm', 'LED 430 nm']) self.laserOn = QPushButton('Connect') self.laserOff = QPushButton('Disconnect') self.laserOn.setMinimumSize(110, 30) self.laserOff.setMinimumSize(110, 30) self.laserConn = QLabel('Off', self) self.laserStat = QLabel('0 mW', self) self.laserPower = QSlider(Qt.Vertical) laser_select_lbl = QLabel('Source: ', self) laser_conn_lbl = QLabel('Connection: ', self) laser_stat_lbl = QLabel('Power: ', self) self.x_up = QPushButton('X+') self.x_down = QPushButton('X-') self.y_up = QPushButton('Y+') self.y_down = QPushButton('Y-') self.z_up = QPushButton('Z+') self.z_down = QPushButton('Z-') self.stop_move = QPushButton('Stop') self.step_val = QComboBox(self) self.step_val.setEditable(True) self.step_val.addItems([ '1', '2', '5', '10', '20', '50', '100', '200', '500', '1000', '2000', '5000' ]) self.step_val.setValidator(QIntValidator(1, 10000)) step_lbl = QLabel('Step size: ', self) self.distance_lbl = QLabel('Distance: 0.05um', self) self.x_up.setMinimumSize(85, 30) self.x_down.setMinimumSize(85, 30) self.x_down.setMinimumSize(85, 30) self.y_up.setMinimumSize(85, 30) self.y_down.setMinimumSize(85, 30) self.z_up.setMinimumSize(85, 30) self.z_down.setMinimumSize(85, 30) self.stop_move.setMinimumSize(85, 30) self.x_pos = QTableWidgetItem() self.x_pos.setTextAlignment(Qt.AlignCenter) self.y_pos = QTableWidgetItem() self.y_pos.setTextAlignment(Qt.AlignCenter) self.z_pos = QTableWidgetItem() self.z_pos.setTextAlignment(Qt.AlignCenter) self.acquire_btn = QPushButton('Acquire') self.acquire_btn.setFixedSize(120, 60) stage_coordinates = QTableWidget(3, 1) stage_coordinates.setEditTriggers(QAbstractItemView.NoEditTriggers) stage_coordinates.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) stage_coordinates.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) stage_coordinates.setStyleSheet("border: 0") stage_coordinates.setHorizontalHeaderLabels(['Position']) stage_coordinates.setVerticalHeaderLabels(['X', 'Y', 'Z']) stage_coordinates.setItem(0, 0, self.x_pos) stage_coordinates.setItem(1, 0, self.y_pos) stage_coordinates.setItem(2, 0, self.z_pos) mono_control_group = QGroupBox('Monochromator') mono_control_group.setAlignment(Qt.AlignCenter) mono_control_lay = QGridLayout(mono_control_group) mono_control_lay.addWidget(self.monoGridPos, 0, 0) mono_control_lay.addWidget(self.monoSetPos, 0, 1) mono_control_lay.addWidget(self.monoCalibrate, 1, 0) mono_control_lay.addWidget(self.monoStop, 1, 1) mono_control_lay.addWidget(mono_pos_lbl, 2, 0) mono_control_lay.addWidget(self.monoCurrentPos, 2, 1) mono_control_lay.addWidget(mono_grid_lbl, 3, 0) mono_control_lay.addWidget(self.monoGridSelect, 3, 1) light_source_group = QGroupBox('Light source') light_source_group.setAlignment(Qt.AlignCenter) light_source_lay = QGridLayout(light_source_group) light_source_lay.addWidget(laser_select_lbl, 0, 0) light_source_lay.addWidget(self.laserSelect, 0, 1) light_source_lay.addWidget(self.laserOn, 1, 0) light_source_lay.addWidget(self.laserOff, 1, 1) light_source_lay.addWidget(laser_conn_lbl, 2, 0) light_source_lay.addWidget(self.laserConn, 2, 1) light_source_lay.addWidget(laser_stat_lbl, 3, 0) light_source_lay.addWidget(self.laserStat, 3, 1) light_source_lay.addWidget(self.laserPower, 0, 3, 4, 1) light_source_lay.setColumnMinimumWidth(2, 20) stage_pos_group = QGroupBox('Stage position') stage_pos_group.setAlignment(Qt.AlignCenter) stage_pos_lay = QGridLayout(stage_pos_group) stage_pos_lay.addWidget(self.x_up, 1, 2) stage_pos_lay.addWidget(self.x_down, 1, 0) stage_pos_lay.addWidget(self.y_up, 0, 1) stage_pos_lay.addWidget(self.y_down, 2, 1) stage_pos_lay.addWidget(self.z_up, 0, 3) stage_pos_lay.addWidget(self.z_down, 2, 3) stage_pos_lay.addWidget(self.stop_move, 1, 1) stage_pos_lay.addWidget(step_lbl, 3, 0) stage_pos_lay.addWidget(self.step_val, 3, 1) stage_pos_lay.addWidget(self.distance_lbl, 3, 2, 1, 2) stage_pos_lay.setColumnMinimumWidth(4, 20) stage_pos_lay.addWidget(stage_coordinates, 0, 5, 4, 1) acquire_btns_group = QFrame(self) acquire_btns_lay = QHBoxLayout(acquire_btns_group) acquire_btns_lay.addWidget(self.acquire_btn) action_btns_lay = QHBoxLayout(bottom_frame) action_btns_lay.addWidget(mono_control_group, 3) action_btns_lay.addWidget(light_source_group, 3) action_btns_lay.addWidget(stage_pos_group, 6) action_btns_lay.addWidget(acquire_btns_group, 3) action_btns_lay.setSpacing(20) # --- CCD Frame Layout --- self.CCDFrame = PgGraphicsView(self, aspect_locked=False) self.CCDFrame.setMinimumSize(512, 128) self.CCDFrame.vb.setLimits(xMin=0, xMax=conf['CCD-w'] - 1, yMin=0, yMax=conf['CCD-h'] - 1) self.vLine = CrossLine(angle=90, bounds=(0.5, 1023.5)) self.hLine = CrossLine(angle=0, bounds=(0.5, 255.5)) self.CCDFrame.vb.addItem(self.vLine) self.CCDFrame.vb.addItem(self.hLine) self.spectrum = PgPlotWidget(self, w='row') self.spectrum.plotItem.setLabels(left='Intensity') self.spectrum.vb.setYRange(0, 40000) self.spectrumCursor = CrossCursor() self.cursorPosLbl = pg.TextItem(text="X = 0, Y = 0", anchor=(-5, -1), color=pg.mkColor("#99999988")) self.cursorPosLbl.setParentItem(self.spectrum.vb) self.spectrum.vb.addItem(self.spectrumCursor) self.frameSection = PgPlotWidget(self, w='col') # self.frameSection.setLabels(right='Row') self.frameSection.vb.setYRange(0, conf['CCD-h'] - 1) self.frameSection.vb.setLimits(yMin=0, yMax=conf['CCD-h'] - 1) # self.frameSectionCurve = self.frameSection.plot(pen='y') self.frameSectionCursor = CrossCursor() self.frameSection.addItem(self.frameSectionCursor) self.frameRowSelect = QSpinBox(self) self.frameRowSelect.setRange(1, conf['CCD-h']) self.frameColSelect = QSpinBox(self) self.frameColSelect.setRange(1, conf['CCD-w']) y_radio0 = QRadioButton('Counts') y_radio0.setChecked(True) y_radio1 = QRadioButton('Counts norm.') self.YUnits = QButtonGroup(self) self.YUnits.addButton(y_radio0, id=0) self.YUnits.addButton(y_radio1, id=1) x_radio0 = QRadioButton('nm') x_radio0.setChecked(True) x_radio1 = QRadioButton('eV') x_radio2 = QRadioButton('pixel number') self.XUnits = QButtonGroup(self) self.XUnits.addButton(x_radio0, id=0) self.XUnits.addButton(x_radio1, id=1) self.XUnits.addButton(x_radio2, id=2) self.XUnits.button(0).setChecked(True) self.rowBinning = QSpinBox(self) self.rowBinning.setRange(1, 256) self.avgBinning = QCheckBox('Average value') row_binning_lbl = QLabel('Binning', self) row_select_group = QGroupBox('Row/Column') row_select_group.setAlignment(Qt.AlignCenter) row_select_lay = QHBoxLayout(row_select_group) row_select_lay.addWidget(self.frameRowSelect) row_select_lay.addWidget(self.frameColSelect) y_units_group = QGroupBox("Y-axis") y_units_group.setAlignment(Qt.AlignCenter) y_units_lay = QVBoxLayout(y_units_group) y_units_lay.addWidget(y_radio0) y_units_lay.addWidget(y_radio1) x_units_group = QGroupBox("X-axis") x_units_group.setAlignment(Qt.AlignCenter) x_units_lay = QVBoxLayout(x_units_group) x_units_lay.addWidget(x_radio0) x_units_lay.addWidget(x_radio1) x_units_lay.addWidget(x_radio2) row_binning_group = QGroupBox() row_binning_group.setAlignment(Qt.AlignCenter) row_binning_lay = QGridLayout(row_binning_group) row_binning_lay.addWidget(row_binning_lbl, 0, 0) row_binning_lay.addWidget(self.rowBinning, 0, 1) row_binning_lay.addWidget(self.avgBinning, 1, 0, 1, 2) frame_param = QFrame() frame_param_lay = QVBoxLayout(frame_param) frame_param_lay.setSpacing(0) frame_param_lay.addWidget(row_select_group) frame_param_lay.addWidget(y_units_group) frame_param_lay.addWidget(x_units_group) frame_param_lay.addWidget(row_binning_group) ccd_lay = QGridLayout(ccd) ccd_lay.setRowStretch(0, 2) ccd_lay.setRowStretch(1, 3) ccd_lay.setColumnStretch(0, 1) ccd_lay.setColumnStretch(1, 6) ccd_lay.addWidget(self.CCDFrame, 0, 1) ccd_lay.addWidget(self.spectrum, 1, 1) ccd_lay.addWidget(self.frameSection, 0, 0) ccd_lay.addWidget(frame_param, 1, 0) # --- Experiment Details, Andor Camera Settings --- self.WLStart = QDoubleSpinBox(self) self.WLStart.setRange(200.0, 1000.0) self.WLStart.setSingleStep(0.1) self.WLStart.setDecimals(1) self.WLEnd = QLineEdit(self) self.WLEnd.setReadOnly(True) self.WLEnd_dec = QPushButton('<') self.WLEnd_inc = QPushButton('>') self.WLEnd_dec.setStyleSheet('QPushButton {min-width: 20px;}') self.WLEnd_inc.setStyleSheet('QPushButton {min-width: 20px;}') WL_range_lbl = QLabel('—') WL_range_group = QGroupBox("Wavelength range") WL_range_lay = QHBoxLayout(WL_range_group) WL_range_lay.addWidget(self.WLStart, 5) WL_range_lay.addWidget(WL_range_lbl, 1) WL_range_lay.addWidget(self.WLEnd, 5) WL_range_lay.addWidget(self.WLEnd_dec, 1) WL_range_lay.addWidget(self.WLEnd_inc, 1) self.exposureTime = QDoubleSpinBox(self) self.exposureTime.setRange(0.01, 1000.0) self.exposureTime.setDecimals(2) # self.exposureTime.setStepType(QDoubleSpinBox.AdaptiveDecimalStepType) exp_time_lbl = QLabel('Exposure time (sec)') self.acquisitionMode = QComboBox(self) self.acquisitionMode.addItems([ 'Single', 'Accumulate', 'Kinetic', 'Photon Count', 'Fast Kinetic' ]) self.acquisitionMode.model().item(3).setEnabled(False) self.accumulationFrames = QSpinBox(self) self.accumulationFrames.setRange(1, 50) self.accumulationCycle = QDoubleSpinBox(self) self.accumulationCycle.setRange(0.01, 1000.0) self.accumulationCycle.setSingleStep(1) self.accumulationCycle.setDecimals(2) self.kineticSeries = QSpinBox(self) self.kineticSeries.setRange(1, 50) self.kineticCycle = QDoubleSpinBox(self) self.kineticCycle.setRange(0.01, 1000.0) self.kineticCycle.setSingleStep(1) self.kineticCycle.setDecimals(2) acq_mode_lbl = QLabel('Acquisition Mode', self) accum_frames_lbl = QLabel('Accumulation Frames') accum_cycle_lbl = QLabel('Accumulation Cycle') kinetic_series_lbl = QLabel('Kinetic Series') kinetic_cycle_lbl = QLabel('Kinetic Cycle Time') self.triggeringMode = QComboBox(self) self.triggeringMode.addItems( ['Internal', 'External', 'Fast External', 'External Start']) self.triggeringMode.model().item(2).setEnabled(False) self.readoutMode = QComboBox(self) self.readoutMode.addItems( ['Image', 'Single-Track', 'Multi-Track', 'FVB']) self.readoutMode.model().item(1).setEnabled(False) self.readoutMode.model().item(2).setEnabled(False) self.readoutMode.model().item(3).setEnabled(False) trig_mode_lbl = QLabel('Triggering Mode', self) read_mode_lbl = QLabel('Readout Mode', self) self.readoutRate = QComboBox(self) self.readoutRate.addItems( ['50kHz at 16-bit', '1MHz at 16-bit', '3MHz at 16-bit']) self.preAmpGain = QComboBox(self) self.preAmpGain.addItems(['1x', '2x', '4x']) readout_rate_lbl = QLabel('Readout Rate') preamp_gain_lbl = QLabel('Pre-Amp Gain') self.VSSpeed = QComboBox(self) self.VSSpeed.addItems([ '12.9', '25.7', '51.3', '76.9', '102.5', '128.1', '153.7', '179.3' ]) self.VSAVoltage = QComboBox(self) self.VSAVoltage.addItems(['Normal', '+1']) self.VSAVoltage.model().item(1).setEnabled(False) vs_speed_lbl = QLabel('VShift speed (usec)') vsa_voltage_lbl = QLabel('VShift Amp Voltage') cam_settings_lay = QVBoxLayout(topleft_frame) cam_settings_lay.setSpacing(10) cam_exposure_group = QGroupBox("Exposition") cam_exposure_lay = QGridLayout(cam_exposure_group) cam_exposure_lay.addWidget(exp_time_lbl, 0, 0) cam_exposure_lay.addWidget(self.exposureTime, 0, 1) cam_timing_group = QGroupBox("Acquisition timings") cam_timing_lay = QGridLayout(cam_timing_group) cam_timing_lay.addWidget(acq_mode_lbl, 0, 0) cam_timing_lay.addWidget(self.acquisitionMode, 0, 1) cam_timing_lay.addWidget(accum_frames_lbl, 1, 0) cam_timing_lay.addWidget(self.accumulationFrames, 1, 1) cam_timing_lay.addWidget(accum_cycle_lbl, 2, 0) cam_timing_lay.addWidget(self.accumulationCycle, 2, 1) cam_timing_lay.addWidget(kinetic_series_lbl, 3, 0) cam_timing_lay.addWidget(self.kineticSeries, 3, 1) cam_timing_lay.addWidget(kinetic_cycle_lbl, 4, 0) cam_timing_lay.addWidget(self.kineticCycle, 4, 1) cam_mode_group = QGroupBox("Mode") cam_mode_lay = QGridLayout(cam_mode_group) cam_mode_lay.addWidget(trig_mode_lbl, 0, 0) cam_mode_lay.addWidget(self.triggeringMode, 0, 1) cam_mode_lay.addWidget(read_mode_lbl, 1, 0) cam_mode_lay.addWidget(self.readoutMode, 1, 1) cam_readout_group = QGroupBox("Readout") cam_readout_lay = QGridLayout(cam_readout_group) cam_readout_lay.addWidget(readout_rate_lbl, 0, 0) cam_readout_lay.addWidget(self.readoutRate, 0, 1) cam_readout_lay.addWidget(preamp_gain_lbl, 1, 0) cam_readout_lay.addWidget(self.preAmpGain, 1, 1) cam_readout_lay.addWidget(vs_speed_lbl, 2, 0) cam_readout_lay.addWidget(self.VSSpeed, 2, 1) cam_readout_lay.addWidget(vsa_voltage_lbl, 3, 0) cam_readout_lay.addWidget(self.VSAVoltage, 3, 1) cam_settings_lay.addWidget(WL_range_group) cam_settings_lay.addWidget(cam_exposure_group) cam_settings_lay.addWidget(cam_timing_group) cam_settings_lay.addWidget(cam_mode_group) cam_settings_lay.addWidget(cam_readout_group)
def create_rows(self, layout, sarea): u"""Build the rows of the dialog box""" play_button_group = QButtonGroup(sarea) old_play_button_group = QButtonGroup(sarea) for num, entry in enumerate(self.entries_list, 2): tt_text = self.build_text_help_label(entry) ico_label = QLabel('', sarea) ico_label.setToolTip(tt_text) if entry.icon: ico_label.setPixmap(QPixmap.fromImage(entry.icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(entry.display_word, sarea) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(sarea) play_button_group.addButton(t_play_button, num-2) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[entry.audio_field_name]: t_play_old_button = QPushButton(sarea) old_play_button_group.addButton(t_play_old_button, num-2) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip( self.note[entry.audio_field_name]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', sarea) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(sarea) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(sarea) t_add_button.setCheckable(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, Action.Add) t_keep_button = QPushButton(sarea) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, Action.Keep) t_delete_button = QPushButton(sarea) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon( QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, Action.Delete) t_blacklist_button = QPushButton(sarea) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon( QIcon(os.path.join(icons_dir, 'blacklist.png'))) if entry.entry_hash: layout.addWidget( t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() dummy_label_bl = QLabel('', sarea) dummy_label_bl.setToolTip(self.blacklist_empty_line_help) layout.addWidget(dummy_label_bl, num, self.blacklist_column) t_button_group.button(entry.action).setChecked(True) # New: check a button based on how good the downloader is. t_button_group.addButton(t_blacklist_button, Action.Blacklist) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play( self.entries_list[play_button_group.id(button)].file_path)) # N.B.: anki.sound.play() plays files from anywhere, not just # from the colection.media folder. We should be good, # here. (This behaviour may be a security risk, idk.) old_play_button_group.buttonClicked.connect( lambda button: playFromText( self.note[ self.entries_list[ old_play_button_group.id(button)].audio_field_name]))
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText( app.settings.get("account", "username")) self.lineEdit_loginPassword.setText( app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked( app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked( self.doesAutoStartFileExists()) self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked( app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect( self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked( app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled( self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText( app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) try: startEtmWhen = callXwaredInterface("getStartEtmWhen") self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) except SocketDoesntExist: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @staticmethod def doesAutoStartFileExists(): return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE) @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() permissionCheckResult = app.mountsFaker.permissionCheck() permissionCheckFailed = [ "无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK) ] mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) # drive1: the drive letter it should map to, by alphabetical order drive1 = chr(ord('C') + i) + ":" self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") # check 1: permission errors = permissionCheckResult.get(mount, permissionCheckFailed) # check 2: mapping if drive1 != drive2: errors.append( "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format( actual=drive2, should=drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) doesAutoStartFileExists = self.doesAutoStartFileExists() if self.checkBox_autoStartFrontend.isChecked( ) and not doesAutoStartFileExists: # mkdir if autostart dir doesn't exist try: os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE)) except OSError: pass # already exists os.symlink(constants.DESKTOP_FILE_LOCATION, constants.FRONTEND_AUTOSTART_FILE) elif (not self.checkBox_autoStartFrontend.isChecked() ) and doesAutoStartFileExists: os.remove(constants.FRONTEND_AUTOSTART_FILE) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # app.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id( self.btngrp_etmStartWhen.checkedButton()) try: callXwaredInterface("setStartEtmWhen", startEtmWhen) except SocketDoesntExist: QMessageBox.warning( None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list( map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue( etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting( dLimit=self.spinBox_dSpeedLimit.value(), uLimit=self.spinBox_uSpeedLimit.value(), maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class ToolBar(QWidget): mouseEntered = pyqtSignal() mouseLeft = pyqtSignal() toolChanged = pyqtSignal(str) primaryInkChanged = pyqtSignal(str) secondaryInkChanged = pyqtSignal(str) def __init__(self): super(ToolBar, self).__init__() self.setAttribute(Qt.WA_StaticContents) self.setAttribute(Qt.WA_NoSystemBackground) self.setFont(ResourcesCache.get("BigFont")) self._registeredTools = {} self._registeredInks = {} self._toolSlots = [] self._inkSlots = [] self._currentActiveToolSlot = None self._previousActiveToolSlot = None self._currentEditedInkSlot = None self._previousEditedInkSlot = None self._editMode = False self._backgroundColor = QColor(40, 40, 40) self._toolLabelColor = QColor(112, 231, 255) self._layout = QVBoxLayout() self._layout.setAlignment(Qt.AlignTop) self._layout.setContentsMargins(4, 4, 4, 4) top_layout = QHBoxLayout() self._layout.addLayout(top_layout) self._toolsLayout = QHBoxLayout() self._inksLayout = QHBoxLayout() self._toolsLayout.setContentsMargins(0, 0, 0, 0) self._toolsLayout.setAlignment(Qt.AlignLeft) self._inksLayout.setContentsMargins(0, 0, 0, 0) self._inksLayout.setAlignment(Qt.AlignRight) top_layout.addLayout(self._toolsLayout) top_layout.addLayout(self._inksLayout) self._toolsButtonGroup = QButtonGroup() self._toolsButtonGroup.buttonClicked.connect( self._on_tool_slot_triggered) self._inksButtonGroup = QButtonGroup() self._inksButtonGroup.setExclusive(False) self._inksButtonGroup.buttonClicked.connect( self._on_ink_slot_triggered) self.setLayout(self._layout) self._toolbarSubPanel = None self._toolsListWidget = None self._toolsOptionsPanel = None self._init_edit_panel() self._add_ink_slot(0) self._add_ink_slot(1) self.resize(0, 50) # ------------------------------------------------------------------------- def get_tool_by_name(self, name): return self._registeredTools[name] def register_tool(self, tool, is_default=None): if tool.name not in self._registeredTools: self._registeredTools[tool.name] = tool self._toolsListWidget.addItem(tool.name) if is_default is True: self._toolsListWidget.setCurrentRow(0) self._build_tool_options_pane(tool) if len(self._toolSlots) < 4: slot_index = self._add_tool_slot(is_default) self._assign_tool_to_slot(tool, slot_index) def register_ink(self, ink, slot): if not ink.name in self._registeredInks: self._registeredInks[ink.name] = ink self._inksListWidget.addItem(ink.name) self._build_ink_options_pane(ink) if self._inkSlots[slot]['id'] is None: self._assign_ink_to_slot(ink, slot) def switch_tool_slot(self, slot): self._previousActiveToolSlot = self._currentActiveToolSlot self._currentActiveToolSlot = slot if self._currentActiveToolSlot == self._previousActiveToolSlot: return tool_name = self._toolSlots[slot]['id'] self._toolSlots[slot]['button'].setChecked(True) self.toolChanged.emit(tool_name) self._select_tool_on_list(tool_name) # ------------------------------------------------------------------------- def _go_back_to_last_tool(self): self.switch_tool_slot(self._previousActiveToolSlot) def _add_tool_slot(self, selected=None): slot_button = QPushButton() slot_button.setCheckable(True) index = len(self._toolSlots) if selected is not None and selected is True: slot_button.setChecked(True) slot = {'id': None, 'button': slot_button} if selected: self._currentActiveToolSlot = index self._toolSlots.append(slot) self._toolsButtonGroup.addButton(slot_button, index) self._toolsLayout.addWidget(slot_button) return index def _add_ink_slot(self, slot_number): slot_button = QPushButton() slot_button.setFont(self.font()) slot_button.setStyleSheet( "border-color: rgb(56,56,56); background-color: rgb(17,17," "17); font-size: 12pt;") index = len(self._inkSlots) if slot_number == 0: icon = QIcon() icon.addPixmap(QPixmap(":/icons/ico_mouse_button1"), QIcon.Normal, QIcon.Off) slot_button.setIcon(icon) slot_button.setIconSize(QSize(18, 23)) elif slot_number == 1: icon = QIcon() icon.addPixmap(QPixmap(":/icons/ico_mouse_button2"), QIcon.Normal, QIcon.Off) slot_button.setIcon(icon) slot_button.setIconSize(QSize(18, 23)) slot = {'id': None, 'button': slot_button} self._inkSlots.append(slot) self._inksButtonGroup.addButton(slot_button) self._inksButtonGroup.setId(slot_button, index) self._inksLayout.addWidget(slot_button) return index def _assign_tool_to_slot(self, tool, slot): if slot < 0 or slot > len(self._toolSlots) - 1: raise Exception( '[ToolBar] > _assignToolToSlot : invalid slot parameter') self._toolSlots[slot]['id'] = tool.name icon = tool.icon if icon is not None: tool_button = self._toolSlots[slot]['button'] tool_button.setIcon(tool.icon) tool_button.setIconSize(QSize(24, 24)) def _assign_ink_to_slot(self, ink, slot): if slot != 0 and slot != 1: raise Exception( '[ToolBar] > _assignInkToSlot : invalid slot parameter') ink_name = ink.name self._inkSlots[slot]['id'] = ink_name self._inkSlots[slot]['button'].setText(ink_name) if slot == 0: self.primaryInkChanged.emit(ink_name) elif slot == 1: self.secondaryInkChanged.emit(ink_name) def _init_edit_panel(self): self._toolbarSubPanel = QStackedWidget() # 1. Initialize Tools Control Panel ----------------------------------- self._toolsListWidget = QListWidget() self._toolsListWidget.currentRowChanged.connect( lambda v: self._toolsOptionsPanel.setCurrentIndex(v)) self._toolsListWidget.setMaximumSize(QSize(150, 200)) self._toolsListWidget.itemClicked.connect( self._on_tool_list_item_clicked) # Tools Subpanel ------------------------------------------------------ tools_control_panel = QWidget() tools_control_panel_layout = QHBoxLayout() tools_control_panel.setLayout(tools_control_panel_layout) tools_control_panel_layout.setAlignment(Qt.AlignLeft) # Tools List ---------------------------------------------------------- tools_list_sublayout = QVBoxLayout() tools_list_sublayout.setAlignment(Qt.AlignTop) tools_list_sublayout.setContentsMargins(0, 0, 0, 0) tools_list_sublayout.addWidget(QLabel("Tools")) tools_list_sublayout.addWidget(self._toolsListWidget) tools_control_panel_layout.addLayout(tools_list_sublayout) # Tools Options ------------------------------------------------------- tools_options_sublayout = QVBoxLayout() tools_options_sublayout.setAlignment(Qt.AlignTop) tools_control_panel_layout.addLayout(tools_options_sublayout) self._toolsOptionsPanel = QStackedWidget() tools_options_sublayout.addWidget(QLabel("Tools Options")) tools_options_sublayout.addWidget(self._toolsOptionsPanel) self._toolbarSubPanel.addWidget(tools_control_panel) # 2. Initialize Inks Control Panel ------------------------------------ self._inksListWidget = QListWidget() self._inksListWidget.currentRowChanged.connect( lambda v: self._inksOptionsPanel.setCurrentIndex(v)) self._inksListWidget.setMaximumSize(QSize(150, 200)) self._inksListWidget.itemClicked.connect( self._on_ink_list_item_clicked) # Inks Subpanel ------------------------------------------------------- inks_control_panel = QWidget() inks_control_panel_layout = QHBoxLayout() inks_control_panel.setLayout(inks_control_panel_layout) inks_control_panel_layout.setAlignment(Qt.AlignLeft) # Inks List ----------------------------------------------------------- inks_list_sublayout = QVBoxLayout() inks_list_sublayout.setAlignment(Qt.AlignTop) inks_list_sublayout.setContentsMargins(0, 0, 0, 0) inks_list_sublayout.addWidget(QLabel("Inks")) inks_list_sublayout.addWidget(self._inksListWidget) inks_control_panel_layout.addLayout(inks_list_sublayout) # Inks Options -------------------------------------------------------- inks_options_sublayout = QVBoxLayout() inks_options_sublayout.setAlignment(Qt.AlignTop) inks_control_panel_layout.addLayout(inks_options_sublayout) self._inksOptionsPanel = QStackedWidget() inks_options_sublayout.addWidget(QLabel("Ink Options")) inks_options_sublayout.addWidget(self._inksOptionsPanel) self._toolbarSubPanel.addWidget(inks_control_panel) # --------------------------------------------------------------------- self._layout.addWidget(self._toolbarSubPanel) self._toolbarSubPanel.setVisible(False) def _build_tool_options_pane(self, tool): pane = QWidget() pane_layout = QVBoxLayout() pane_layout.setAlignment(Qt.AlignTop) pane.setLayout(pane_layout) for prop in tool.properties.values(): field_layout = QHBoxLayout() field_layout.addWidget(QLabel(prop.description)) prop_widget = prop.build_property_widget() field_layout.addWidget(prop_widget) pane_layout.addLayout(field_layout) self._toolsOptionsPanel.addWidget(pane) def _build_ink_options_pane(self, ink): pane = QWidget() pane_layout = QVBoxLayout() pane_layout.setAlignment(Qt.AlignTop) pane.setLayout(pane_layout) for prop in ink.properties.values(): field_layout = QHBoxLayout() field_layout.addWidget(QLabel(prop.description)) prop_widget = prop.build_property_widget() field_layout.addWidget(prop_widget) pane_layout.addLayout(field_layout) self._inksOptionsPanel.addWidget(pane) def _select_tool_on_list(self, tool_name): tool_list_item = \ self._toolsListWidget.findItems(tool_name, Qt.MatchExactly)[0] if tool_list_item is not None: self._toolsListWidget.setCurrentItem(tool_list_item) def _select_ink_on_list(self, ink_name): ink_list_item = \ self._inksListWidget.findItems(ink_name, Qt.MatchExactly)[0] if ink_list_item is not None: self._inksListWidget.setCurrentItem(ink_list_item) def _toggle_edit_mode(self): if not self._editMode: self._show_sub_panel() else: self._hide_sub_panel() self.update() def _show_sub_panel(self): self._editMode = True self.resize(self.width(), 300) self._toolbarSubPanel.setVisible(True) def _hide_sub_panel(self): self._editMode = False self.resize(self.width(), 50) self._toolbarSubPanel.setVisible(False) self._finish_ink_edit_mode() def _finish_ink_edit_mode(self): if self._currentEditedInkSlot is not None: self._inksButtonGroup.button(self._currentEditedInkSlot). \ setStyleSheet("border-color: rgb(56,56,56);") self._currentEditedInkSlot = None self._previousEditedInkSlot = None self._inksListWidget.setCurrentRow(0) self._toolbarSubPanel.setCurrentIndex(0) # ------------------------------------------------------------------------- def mousePressEvent(self, e): self._toggle_edit_mode() e.accept() def wheelEvent(self, e): e.accept() def enterEvent(self, e): self.mouseEntered.emit() self.setCursor(Qt.PointingHandCursor) def leaveEvent(self, e): self.mouseLeft.emit() def _on_tool_slot_triggered(self): self._toolbarSubPanel.setCurrentIndex(0) triggered_slot = self._toolsButtonGroup.checkedId() if self._currentEditedInkSlot is not None: self._finish_ink_edit_mode() self.switch_tool_slot(triggered_slot) self.update() def _on_ink_slot_triggered(self, slot_button): if not self._editMode: self._show_sub_panel() triggered_slot_id = self._inksButtonGroup.id(slot_button) if triggered_slot_id != self._currentEditedInkSlot: self._previousEditedInkSlot = self._currentEditedInkSlot self._currentEditedInkSlot = triggered_slot_id if self._previousEditedInkSlot is not None: self._inksButtonGroup. \ button(self._previousEditedInkSlot). \ setStyleSheet("border-color: rgb(56,56,56);") slot_button.setStyleSheet("border-color: rgb(255,0,0);") self._toolbarSubPanel.setCurrentIndex(1) ink_name = self._inkSlots[triggered_slot_id]['id'] self._select_ink_on_list(ink_name) if triggered_slot_id == 0: self.primaryInkChanged.emit(ink_name) elif triggered_slot_id == 1: self.secondaryInkChanged.emit(ink_name) else: self._hide_sub_panel() def _on_tool_list_item_clicked(self, new_item): new_item_name = new_item.text() self._assign_tool_to_slot(self.get_tool_by_name(new_item_name), self._currentActiveToolSlot) self.toolChanged.emit(new_item_name) self._toolbarSubPanel.update() def _on_ink_list_item_clicked(self, item): item_name = item.text() ink = self._registeredInks[item_name] if ink is not None: self._assign_ink_to_slot(ink, self._currentEditedInkSlot)
class TimekeeperUi(QtWidgets.QMainWindow): """User interface for the timekeeper""" def __init__(self): super().__init__() uic.loadUi('src/UI/timekeeper.ui', self) self.pause_button = self.findChild(QtWidgets.QPushButton, 'pause_button') self.pause_button.clicked.connect(timekeeper.pause_time) self.start_button = self.findChild(QtWidgets.QPushButton, 'start_button') self.start_button.clicked.connect(timekeeper.resume_time) signals.timer_expired.connect(self.update_time) self.update_time(timekeeper.current_day, timekeeper.current_time_hour, timekeeper.current_time_min, timekeeper.current_time_sec) self.button_group = QButtonGroup() self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'one_times_button')) self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'two_times_button')) self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'five_times_button')) self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'ten_times_button')) self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'fifty_times_button')) self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'one_hundred_times_button')) # Set the correct button according to the time factor self.button_group.button(PERIODS.index(timekeeper.time_factor)*-1 - 2) \ .setChecked(True) self.button_group.buttonClicked.connect(self.update_speed) self.show() def update_time(self, day, hours, mins, secs): """Updates the time label :param int day: Current day :param int hours: Current hours :param int mins: Current minutes :param int secs: Current seconds """ days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] period = 'am' if hours in range(12, 24): period = 'pm' if hours == 0: hours = 12 elif hours > 12: hours -= 12 time_text = "{} {:02}:{:02}:{:02} {}".format(days[day], hours, mins, secs, period) time_label = self.findChild(QtWidgets.QLabel, 'time_label') time_label.setText(time_text) def update_speed(self): """Method called when a new speed factor is selected Note: Button ids start at -2 and go down for some god awful reason """ # We don't need the lock here because this variable is only being used for the sleep time timekeeper.time_factor = PERIODS[abs(self.button_group.checkedId()) - 2]
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText(app.settings.get("account", "username")) self.lineEdit_loginPassword.setText(app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked(app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked(self.doesAutoStartFileExists()) self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) try: startEtmWhen = callXwaredInterface("getStartEtmWhen") self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) except SocketDoesntExist: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @staticmethod def doesAutoStartFileExists(): return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE) @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() permissionCheckResult = app.mountsFaker.permissionCheck() permissionCheckFailed = ["无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK)] mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) # drive1: the drive letter it should map to, by alphabetical order drive1 = chr(ord('C') + i) + ":" self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") # check 1: permission errors = permissionCheckResult.get(mount, permissionCheckFailed) # check 2: mapping if drive1 != drive2: errors.append( "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format( actual = drive2, should = drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) doesAutoStartFileExists = self.doesAutoStartFileExists() if self.checkBox_autoStartFrontend.isChecked() and not doesAutoStartFileExists: # mkdir if autostart dir doesn't exist try: os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE)) except OSError: pass # already exists os.symlink(constants.DESKTOP_FILE_LOCATION, constants.FRONTEND_AUTOSTART_FILE) elif (not self.checkBox_autoStartFrontend.isChecked()) and doesAutoStartFileExists: os.remove(constants.FRONTEND_AUTOSTART_FILE) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # app.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton()) try: callXwaredInterface("setStartEtmWhen", startEtmWhen) except SocketDoesntExist: QMessageBox.warning(None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(), uLimit = self.spinBox_uSpeedLimit.value(), maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class MyWindow(QWidget): def __init__(self): super(MyWindow, self).__init__() self.initGUI("PyQt5 学习 ButtonGroup") # 设定窗口的布局管理器为 QGridLayout layout = QGridLayout() self.setLayout(layout) self.buttonGroup = QButtonGroup() # # 按钮不是互斥的,即可以同时选中多个按钮 # self.buttonGroup.setExclusive(False) # 按钮是互斥的,即同一时刻只能选中1个按钮 self.buttonGroup.setExclusive(True) # NOTE: 绑定信号与槽函数,信号是 buttonGroup.buttonClicked(id),槽函数是 on_button_clicked(id) self.buttonGroup.buttonClicked[int].connect(self.on_button_clicked) button = QPushButton("PushButton 1") self.buttonGroup.addButton(button, 1) layout.addWidget(button, 0, 0) button = QPushButton("PushButton 2") self.buttonGroup.addButton(button, 2) layout.addWidget(button, 0, 1) rdBtn = QRadioButton("单选按钮1") self.buttonGroup.addButton(rdBtn, 3) layout.addWidget(rdBtn, 1, 0) rdBtn = QRadioButton("单选按钮2") self.buttonGroup.addButton(rdBtn, 4) layout.addWidget(rdBtn, 1, 1) # 添加了复选框到同一个分组,四个按钮同时只能选择一个。 checkbox = QCheckBox("复选框1") self.buttonGroup.addButton(checkbox, 5) layout.addWidget(checkbox, 2, 0) checkbox = QCheckBox("复选框2") self.buttonGroup.addButton(checkbox, 6) layout.addWidget(checkbox, 2, 1) # layout.setVerticalSpacing(5) # layout.setHorizontalSpacing(5) boxlayout = QBoxLayout(QBoxLayout.LeftToRight) label = QLabel("------分割线------") boxlayout.addWidget(label, 1, Qt.AlignHCenter) layout.addLayout(boxlayout, 3, 0, 1, 2, Qt.AlignJustify) layout2 = QGridLayout() layout.addLayout(layout2, 4, 0, 1, 2, Qt.AlignJustify) self.btn_group2 = QButtonGroup() self.btn_group2.setExclusive(False) self.btn_group2.buttonClicked[int].connect(self.on_btn_group2_clicked) radio = QRadioButton("神仙?") self.btn_group2.addButton(radio, 1) layout2.addWidget(radio, 0, 0, 2, 2, Qt.AlignJustify) layout2.setHorizontalSpacing(10) radio = QRadioButton("妖怪?") self.btn_group2.addButton(radio, 2) layout2.addWidget(radio, 0, 2, 2, 2, Qt.AlignJustify) def on_button_clicked(self, id): """ 遍历按钮组,找到这个按钮 """ for button in self.buttonGroup.buttons(): if button is self.buttonGroup.button(id): print("%s was clicked" % (button.text())) def on_btn_group2_clicked(self, id): """ 第二个按钮分组有按钮被单击 """ for button in self.btn_group2.buttons(): if button is self.btn_group2.button(id): print("%s was clicked" % (button.text())) def initGUI(self, title): """ 设置窗口大小和位置,以及标题 """ startx = 800 starty = 400 width = 480 height = 320 self.setGeometry(startx, starty, width, height) self.setWindowTitle(title)
class SummaryTab(QWidget): def __init__(self, leak, updateFlagIcon, notifyUnsavedChanges): super(SummaryTab, self).__init__() assert isinstance(leak, Leak) assert isinstance(leak.meta, LeakMetaInfo) self.leak = leak self.user_comment = QTextEdit("") self.leak_details = QLabel(str(self.leak.status)) self.updateFlagIcon = updateFlagIcon self.notifyUnsavedChanges = notifyUnsavedChanges self.setupUI() def setupUI(self): summary_layout = QGridLayout() self.user_comment.textChanged.connect(self.commentChanged) comment = self.leak.meta.comment if comment == "": self.user_comment.setPlaceholderText("User comments") else: self.user_comment.setText(comment) # # # # # flags_group_box = QGroupBox("Rating") #icon_size = QSize(20, 20) font_size = QFontMetrics(self.user_comment.currentFont()).size(0,"A").height() font_size *= 1.1 icon_size = QSize(font_size, font_size) flag_0 = createIconButton(icon_size, LeakFlags.NOLEAK) flag_1 = createIconButton(icon_size, LeakFlags.INVESTIGATE) flag_2 = createIconButton(icon_size, LeakFlags.LEAK) flag_3 = createIconButton(icon_size, LeakFlags.DONTCARE) flag_0.setCheckable(True) flag_1.setCheckable(True) flag_2.setCheckable(True) flag_3.setCheckable(True) self.flags_button_group = QButtonGroup() self.flags_button_group.buttonClicked[int].connect(self.bgClicked) self.flags_button_group.setExclusive(True) self.flags_button_group.addButton(flag_0, 0) self.flags_button_group.addButton(flag_1, 1) self.flags_button_group.addButton(flag_2, 2) self.flags_button_group.addButton(flag_3, 3) btn_id = flag_to_btn[self.leak.meta.flag] self.flags_button_group.button(btn_id).setChecked(True) # # # # # flags_hbox = QHBoxLayout() flags_hbox.addWidget(flag_0) flags_hbox.addWidget(flag_1) flags_hbox.addWidget(flag_2) flags_hbox.addWidget(flag_3) flags_group_box.setLayout(flags_hbox) flags_group_box.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # statistic_group_box = QGroupBox("Statistics") statistic_grid = QGridLayout() rowid = 0 if self.leak.status is not None: if self.leak.status.nsperformed: # Only show the highest value for generic leaks l = max(self.leak.status.nsleak, key=lambda l: l.normalized()) lbl_circle = QLabel() lbl_circle.setPixmap(getCircle(getColor(l.normalized(), l.threshold()))) lbl_circle.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) lbl_text = QLabel("%s: %0.1f%%" % ("generic", l.normalized() * 100.0)) statistic_grid.addWidget(lbl_circle, rowid, 0) statistic_grid.addWidget(lbl_text, rowid, 1) rowid += 1 if len(self.leak.status.spperformed) > 0: # Filter leaks: only keep the highest value spleaks = dict() for l in self.leak.status.spleak: key = (l.target, l.property) if key in spleaks and spleaks[key].normalized() >= l.normalized(): continue spleaks[key] = l for key, l in sorted(spleaks.items()): lbl_circle = QLabel() lbl_circle.setPixmap(getCircle(getColor(l.normalized(), l.threshold()))) lbl_circle.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) lbl_text = QLabel("%s[%s]: %0.1f%%" % (l.target, l.property, l.normalized() * 100.0)) statistic_grid.addWidget(lbl_circle, rowid, 0) statistic_grid.addWidget(lbl_text, rowid, 1) rowid += 1 statistic_group_box.setLayout(statistic_grid) statistic_group_box.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.leak_details.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) summary_layout.addWidget(flags_group_box, 0, 0) if rowid > 0: summary_layout.addWidget(statistic_group_box, 1, 0) summary_layout.addWidget(self.leak_details, 2, 0) summary_layout.addWidget(self.user_comment, 0, 1, 3, 1) self.setLayout(summary_layout) def bgClicked(self, btn_id): debug(5, "[bgClicked] flag_%d clicked", btn_id) flag_id = btn_to_flag[btn_id] self.leak.meta.flag = flag_id self.updateFlagIcon(self.leak.ip, flag_id) self.notifyUnsavedChanges() def commentChanged(self): comment = self.user_comment.toPlainText() debug(5, "[usrComment]: %s", comment) self.leak.meta.comment = comment self.notifyUnsavedChanges()
class AltBaseDialog(QWidget): """Displays edit boxes for other number bases. """ baseCode = {'X': 16, 'O': 8, 'B': 2, 'D': 10} def __init__(self, dlgRef, parent=None): QWidget.__init__(self, parent) self.dlgRef = dlgRef self.prevBase = None # revert to prevBase after temp base change self.setAttribute(Qt.WA_QuitOnClose, False) self.setWindowTitle('rpCalc Alternate Bases') if self.dlgRef.calc.option.boolData('KeepOnTop'): self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(Qt.Window) topLay = QVBoxLayout(self) self.setLayout(topLay) mainLay = QGridLayout() topLay.addLayout(mainLay) self.buttons = QButtonGroup(self) self.baseBoxes = {} hexButton = QPushButton('He&x') self.buttons.addButton(hexButton, 16) mainLay.addWidget(hexButton, 0, 0, Qt.AlignRight) self.baseBoxes[16] = AltBaseBox(16, self.dlgRef.calc) mainLay.addWidget(self.baseBoxes[16], 0, 1) octalButton = QPushButton('&Octal') self.buttons.addButton(octalButton, 8) mainLay.addWidget(octalButton, 1, 0, Qt.AlignRight) self.baseBoxes[8] = AltBaseBox(8, self.dlgRef.calc) mainLay.addWidget(self.baseBoxes[8], 1, 1) binaryButton = QPushButton('&Binary') self.buttons.addButton(binaryButton, 2) mainLay.addWidget(binaryButton, 2, 0, Qt.AlignRight) self.baseBoxes[2] = AltBaseBox(2, self.dlgRef.calc) mainLay.addWidget(self.baseBoxes[2], 2, 1) decimalButton = QPushButton('&Decimal') self.buttons.addButton(decimalButton, 10) mainLay.addWidget(decimalButton, 3, 0, Qt.AlignRight) self.baseBoxes[10] = AltBaseBox(10, self.dlgRef.calc) mainLay.addWidget(self.baseBoxes[10], 3, 1) for button in self.buttons.buttons(): button.setCheckable(True) self.buttons.buttonClicked[int].connect(self.changeBase) self.bitsLabel = QLabel() self.bitsLabel.setAlignment(Qt.AlignHCenter) self.bitsLabel.setFrameStyle(QFrame.Box | QFrame.Plain) topLay.addSpacing(3) topLay.addWidget(self.bitsLabel) topLay.addSpacing(3) buttonLay = QHBoxLayout() topLay.addLayout(buttonLay) copyButton = QPushButton('Copy &Value') buttonLay.addWidget(copyButton) copyButton.clicked.connect(self.copyValue) closeButton = QPushButton('&Close') buttonLay.addWidget(closeButton) closeButton.clicked.connect(self.close) self.changeBase(self.dlgRef.calc.base, False) self.updateOptions() option = self.dlgRef.calc.option self.move(option.intData('AltBaseXPos', 0, 10000), option.intData('AltBaseYPos', 0, 10000)) def updateData(self): """Update edit box contents for current registers. """ if self.prevBase and self.dlgRef.calc.flag != calccore.Mode.entryMode: self.changeBase(self.prevBase, False) self.prevBase = None for box in self.baseBoxes.values(): box.setValue(self.dlgRef.calc.stack[0]) def changeBase(self, base, endEntryMode=True): """Change core's base, button depression and label highlighting. """ self.baseBoxes[self.dlgRef.calc.base].setHighlight(False) self.baseBoxes[base].setHighlight(True) self.buttons.button(base).setChecked(True) if endEntryMode and self.dlgRef.calc.base != base and \ self.dlgRef.calc.flag == calccore.Mode.entryMode: self.dlgRef.calc.flag = calccore.Mode.saveMode self.dlgRef.calc.base = base def setCodedBase(self, baseCode, temp=True): """Set new base from letter code, temporarily if temp is true. """ if temp: self.prevBase = self.dlgRef.calc.base else: self.prevBase = None try: self.changeBase(AltBaseDialog.baseCode[baseCode], not temp) except KeyError: pass def updateOptions(self): """Update bit limit and two's complement use. """ self.dlgRef.calc.setAltBaseOptions() if self.dlgRef.calc.useTwosComplement: text = '{0} bit, two\'s complement'.format( self.dlgRef.calc.numBits) else: text = '{0} bit, no two\'s complement'.format( self.dlgRef.calc.numBits) self.bitsLabel.setText(text) def copyValue(self): """Copy the value in the current base to the clipboard. """ text = str(self.baseBoxes[self.dlgRef.calc.base].text()) clip = QApplication.clipboard() if clip.supportsSelection(): clip.setText(text, QClipboard.Selection) clip.setText(text) def keyPressEvent(self, keyEvent): """Pass all keypresses to main dialog. """ self.dlgRef.keyPressEvent(keyEvent) def keyReleaseEvent(self, keyEvent): """Pass all key releases to main dialog. """ self.dlgRef.keyReleaseEvent(keyEvent) def closeEvent(self, closeEvent): """Change back to base 10 before closing. """ self.changeBase(10) QWidget.closeEvent(self, closeEvent)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.create_main_window_actions([ QActionProperties( name=main_window_constants.EXPORT_ACTION_NAME, icon=QIcon(':/icons/export'), text='&Export', shortcut='Ctrl+E', status_tip='Export to Python code', triggered=self.export_diagram, ), QActionProperties( name=main_window_constants.DELETE_ACTON_NAME, icon=QIcon(':/icons/delete'), text='&Delete', shortcut='Delete', status_tip='Delete item from diagram', triggered=self.delete_item, ), QActionProperties( name=main_window_constants.TO_FRONT_ACTION_NAME, icon=QIcon(':/icons/bring_to_front'), text='Bring to &Front', shortcut='Ctrl+F', status_tip='Bring item to front', triggered=self.bring_to_front, ), QActionProperties( name=main_window_constants.TO_BACK_ACTION_NAME, icon=QIcon(':/icons/send_to_back'), text='Send to &Back', shortcut='Ctrl+B', status_tip='Send item to back', triggered=self.send_to_back, ), ]) self.create_file_menu() self.create_edit_menu() self.create_frameworks_toolbar() self.create_edit_diagram_toolbar() self.create_pointer_toolbar() self.create_diagram_scene_and_view() self.create_framework_toolbox() self.layout = QHBoxLayout() self.layout.addWidget(self.framework_toolbox) self.layout.addWidget(self.view) self.widget = QWidget() self.widget.setLayout(self.layout) self.setWindowTitle(main_window_constants.MAIN_WINDOW_TITLE) self.setCentralWidget(self.widget) # Create methods. def create_main_window_actions( self, main_window_actions: List[QActionProperties]): self.main_window_actions = dict() for main_window_action in main_window_actions: self.main_window_actions[main_window_action.name] = QAction( main_window_action.icon, main_window_action.text, self, shortcut=main_window_action.shortcut, statusTip=main_window_action.status_tip, triggered=main_window_action.triggered, ) def create_file_menu(self): self.file_menu = self.menuBar().addMenu( main_window_constants.FILE_MENU_NAME) self.file_menu.addAction( self.main_window_actions[main_window_constants.EXPORT_ACTION_NAME]) def create_edit_menu(self): self.edit_menu = self.menuBar().addMenu( main_window_constants.EDIT_MENU_NAME) self.edit_menu.addAction( self.main_window_actions[main_window_constants.DELETE_ACTON_NAME]) self.edit_menu.addSeparator() self.edit_menu.addAction(self.main_window_actions[ main_window_constants.TO_FRONT_ACTION_NAME]) self.edit_menu.addAction(self.main_window_actions[ main_window_constants.TO_BACK_ACTION_NAME]) def create_frameworks_toolbar(self): self.frameworks_label = QLabel(main_window_constants.FRAMEWORKS_LABEL) self.frameworks_combobox = QComboBox() self.frameworks_combobox.setEditable(False) for framework in frameworks_utils.get_sorted_frameworks_list(): self.frameworks_combobox.addItem(framework) self.frameworks_toolbar = self.addToolBar( main_window_constants.FRAMEWORKS_TOOLBAR_NAME) self.frameworks_toolbar.addWidget(self.frameworks_label) self.frameworks_toolbar.addWidget(self.frameworks_combobox) def create_edit_diagram_toolbar(self): self.edit_diagram_toolbar = self.addToolBar( main_window_constants.DIAGRAM_EDIT_TOOLBAR_NAME) self.edit_diagram_toolbar.addAction( self.main_window_actions[main_window_constants.DELETE_ACTON_NAME]) self.edit_diagram_toolbar.addAction(self.main_window_actions[ main_window_constants.TO_FRONT_ACTION_NAME]) self.edit_diagram_toolbar.addAction(self.main_window_actions[ main_window_constants.TO_BACK_ACTION_NAME]) def create_pointer_toolbar(self): pointer_button = QToolButton() pointer_button.setCheckable(True) pointer_button.setChecked(True) pointer_button.setIcon(QIcon(':/icons/pointer')) line_pointer_button = QToolButton() line_pointer_button.setCheckable(True) line_pointer_button.setIcon(QIcon(':/icons/line_pointer')) self.pointer_type_group = QButtonGroup() self.pointer_type_group.addButton(pointer_button, DiagramScene.move_item) self.pointer_type_group.addButton(line_pointer_button, DiagramScene.insert_line) self.pointer_type_group.buttonClicked[int].connect( self.pointer_group_clicked) scene_scale_combo = QComboBox() scene_scale_combo.addItems(main_window_constants.DIAGRAM_SCENE_SCALES) scene_scale_combo.setCurrentIndex( main_window_constants.DIAGRAM_SCENE_SCALES.index( main_window_constants.DIAGRAM_SCENE_DEFAULT_SCALE)) scene_scale_combo.currentIndexChanged[str].connect( self.scene_scale_changed) self.pointer_toolbar = self.addToolBar( main_window_constants.POINTER_TYPE_TOOLBAR_NAME) self.pointer_toolbar.addWidget(pointer_button) self.pointer_toolbar.addWidget(line_pointer_button) self.pointer_toolbar.addWidget(scene_scale_combo) def create_diagram_scene_and_view(self): self.scene = DiagramScene(self.edit_menu) self.scene.setSceneRect( QRectF(0, 0, main_window_constants.DIAGRAM_SCENE_SIZE, main_window_constants.DIAGRAM_SCENE_SIZE)) self.scene.item_inserted.connect(self.item_inserted) self.view = QGraphicsView(self.scene) def create_framework_toolbox(self): framework_layers = frameworks_utils.get_framework_layers( self.get_selected_framework()) self.framework_layers_button_group = QButtonGroup() self.framework_layers_button_group.setExclusive(False) self.framework_layers_button_group.buttonClicked[int].connect( self.framework_layers_button_group_clicked) layout = QGridLayout() for framework_layer in framework_layers: layout.addWidget( self.create_framework_layer_widget(framework_layer())) layout.setRowStretch(3, 10) layout.setColumnStretch(2, 10) item_widget = QWidget() item_widget.setLayout(layout) self.framework_toolbox = QToolBox() self.framework_toolbox.setSizePolicy( QSizePolicy( QSizePolicy.Maximum, QSizePolicy.Ignored, ), ) self.framework_toolbox.setMinimumWidth(item_widget.sizeHint().width()) self.framework_toolbox.addItem(item_widget, main_window_constants.LAYERS) # Callback methods. def export_diagram(self): nodes = self.get_nodes_from_scene() if len(nodes) == 0: return edges = self.get_edges_from_scene() nodes_mapping = self.create_nodes_mapping(nodes) uni_graph = graph_utils.create_graph_from_qt_elements( nodes, edges, nodes_mapping) bi_graph = graph_utils.create_graph_from_qt_elements( nodes, edges, nodes_mapping, is_bi_directional=True) is_one_connected_component = graph_utils.is_one_connected_component( bi_graph) graph_topological_sort = graph_utils.create_graph_topological_sort( uni_graph) root_nodes = graph_utils.get_root_nodes(uni_graph) is_all_root_nodes_are_input_layers = graph_utils.is_all_root_nodes_are_input_layers( nodes, root_nodes) if not is_one_connected_component: self.show_model_graph_eval_error_msg( main_window_constants.MODEL_GRAPH_MULTIPLE_COMPONENTS_ERROR_MSG ) elif graph_topological_sort is None: self.show_model_graph_eval_error_msg( main_window_constants.MODEL_GRAPH_CYCLE_ERROR_MSG) elif not is_all_root_nodes_are_input_layers: self.show_model_graph_eval_error_msg( main_window_constants. MODEL_GRAPH_ROOT_NODE_IS_NOT_INPUT_ERROR_MSG) else: input_definitions = self.build_input_definitions( map(nodes.__getitem__, root_nodes)) layer_definitions = self.build_layer_definitions( nodes, graph_topological_sort, root_nodes) model_connections = self.build_model_connections( nodes, uni_graph, graph_topological_sort, root_nodes) framework_template = frameworks_utils.get_formatted_framework_template( self.get_selected_framework(), input_definitions, layer_definitions, model_connections, ) file_path, _ = QFileDialog.getSaveFileName( self, 'Export Model As', 'talzeeq.py', 'Python Language (*.py);;' 'All files (*.*)', ) if file_path: with open(file_path, 'w') as fp: fp.write(framework_template) def delete_item(self): for item in self.scene.selectedItems(): if isinstance(item, DiagramItem): item.remove_arrows() self.scene.removeItem(item) def bring_to_front(self): for selected_item in self.scene.selectedItems(): z_value = 0 for item in selected_item.collidingItems(): if item.zValue() >= z_value and isinstance(item, DiagramItem): z_value = item.zValue() + 0.1 selected_item.setZValue(z_value) def send_to_back(self): for selected_item in self.scene.selectedItems(): z_value = 0 for item in selected_item.collidingItems(): if item.zValue() <= z_value and isinstance(item, DiagramItem): z_value = item.zValue() - 0.1 selected_item.setZValue(z_value) def pointer_group_clicked(self, index: int): self.scene.set_mode(self.pointer_type_group.checkedId()) def scene_scale_changed(self, scale: str): new_scale = int( scale[:scale.index(main_window_constants. DIAGRAM_SCENE_SCALE_PERCENT)]) / 100.0 old_transform = self.view.transform() self.view.resetTransform() self.view.translate(old_transform.dx(), old_transform.dy()) self.view.scale(new_scale, new_scale) def item_inserted(self, item: DiagramItem): self.pointer_type_group.button(DiagramScene.move_item).setChecked(True) self.scene.set_mode(self.pointer_type_group.checkedId()) layer_index = frameworks_utils.get_framework_layer_index( self.get_selected_framework(), item.framework_layer.__class__, ) self.framework_layers_button_group.button(layer_index).setChecked( False) def framework_layers_button_group_clicked(self, id: int): buttons = self.framework_layers_button_group.buttons() for button in buttons: if self.framework_layers_button_group.button(id) != button: button.setChecked(False) if self.framework_layers_button_group.button(id).isChecked(): self.scene.set_item_type(id) self.scene.set_framework_name(self.get_selected_framework()) self.scene.set_mode(DiagramScene.insert_item) else: self.scene.set_mode(DiagramScene.move_item) # Helper methods. def get_selected_framework(self) -> str: return str(self.frameworks_combobox.currentText()) def get_nodes_from_scene(self) -> List[DiagramItem]: return list( filter(lambda item: isinstance(item, DiagramItem), self.scene.items())) def get_edges_from_scene(self) -> List[Arrow]: return list( filter(lambda item: isinstance(item, Arrow), self.scene.items())) def create_nodes_mapping( self, nodes: List[DiagramItem]) -> Dict[DiagramItem, int]: return {node: index for index, node in enumerate(nodes)} def show_model_graph_eval_error_msg(self, message: str): msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText(main_window_constants.MODEL_GRAPH_EVAL_ERROR_MSG_TEXT) msg.setInformativeText(message) msg.setWindowTitle( main_window_constants.MODEL_GRAPH_EVAL_ERROR_MSG_TEXT) msg.exec_() def build_input_definitions(self, root_nodes: List[DiagramItem]) -> str: input_definitions = list() for node in root_nodes: input_definitions.append( node.get_framework_layer().layer_definition()) return ', '.join(input_definitions) def build_layer_definitions( self, nodes: List[DiagramItem], graph_topological_sort: List[int], root_nodes: List[int], ) -> str: layer_definitions = list() for element in graph_topological_sort: if element not in root_nodes: layer_definitions.append( nodes[element].get_framework_layer().layer_definition()) return '\n'.join(layer_definitions) def build_model_connections( self, nodes: List[DiagramItem], graph: List[List[int]], graph_topological_sort: List[int], root_nodes: List[int], ) -> str: model_connections = list() for element in graph_topological_sort: parents = list() is_root = list() for node in range(len(graph)): if element in graph[node]: parents.append(nodes[node].get_framework_layer()) is_root.append(node in root_nodes) layer_connections = nodes[element].get_framework_layer( ).layer_connections(parents, is_root) if layer_connections: model_connections.append(layer_connections) return '\n'.join(model_connections) def create_framework_layer_widget( self, framework_layer: LayerInterface) -> QWidget: button = QToolButton() button.setText(framework_layer.layer_name()) button.setCheckable(True) self.framework_layers_button_group.addButton( button, frameworks_utils.get_framework_layer_index( self.get_selected_framework(), framework_layer.__class__, ), ) layout = QVBoxLayout() layout.addWidget(button) widget = QWidget() widget.setLayout(layout) return widget
class PochaPlayerInputWidget(QFrame): winnerSet = QtCore.pyqtSignal(str) newExpected = QtCore.pyqtSignal() handsClicked = QtCore.pyqtSignal(str, str) def __init__(self, player, engine, colour=None, parent=None): super(PochaPlayerInputWidget, self).__init__(parent) self.player = player self.engine = engine self.winner = False self.pcolour = colour self.mainLayout = QVBoxLayout(self) self.mainLayout.setSpacing(0) self.label = QLabel(self) self.label.setText(self.player) self.mainLayout.addWidget(self.label) self.label.setAutoFillBackground(False) self.setFrameShape(QFrame.Panel) self.setFrameShadow(QFrame.Raised) self.label.setScaledContents(True) self.label.setAlignment(QtCore.Qt.AlignCenter) self.label.setWordWrap(False) css = ("QLabel {{ font-size: 24px; font-weight: bold; " "color:rgb({},{},{});}}") self.label.setStyleSheet(css.format(self.pcolour.red(), self.pcolour.green(), self.pcolour.blue())) self.expectedGroupBox = QFrame(self) self.mainLayout.addWidget(self.expectedGroupBox) self.ebLayout = QHBoxLayout(self.expectedGroupBox) self.ebLayout.setSpacing(0) self.ebLayout.setContentsMargins(2, 2, 2, 2) self.expectedGroup = QButtonGroup(self) self.expectedGroup.buttonReleased.connect(self.expectedClickedAction) self.expectedButtons = [] self.wonGroupBox = QFrame(self) self.mainLayout.addWidget(self.wonGroupBox) self.wbLayout = QHBoxLayout(self.wonGroupBox) self.wbLayout.setSpacing(0) self.wbLayout.setContentsMargins(2, 2, 2, 2) self.wonGroup = QButtonGroup(self) self.wonGroup.buttonReleased.connect(self.wonClickedAction) self.wonButtons = [] for i in range(-1, 9): button = PochaHandsButton(str(i), self) self.expectedGroup.addButton(button, i) self.expectedButtons.append(button) button.toggled.connect(self.enableWonGroup) if i < 0: button.hide() else: self.ebLayout.addWidget(button) button = PochaHandsButton(str(i), self) self.wonGroup.addButton(button, i) self.wonButtons.append(button) if i < 0: button.hide() else: self.wbLayout.addWidget(button) self.reset() def reset(self): self.expectedButtons[0].setChecked(True) self.wonButtons[0].setChecked(True) self.refreshButtons() self.disableWonRow() def refreshButtons(self, forbidden=-1): hands = self.engine.getHands() for eb, wb in zip(self.expectedButtons, self.wonButtons): eb.setDisabled(int(eb.text()) > hands) if int(eb.text()) == forbidden: eb.setDisabled(True) wb.setDisabled(int(wb.text()) > hands) def disableWonRow(self, disable=True): if self.getExpectedHands() < 0: self.wonGroupBox.setDisabled(True) else: self.wonGroupBox.setDisabled(disable) def enableWonGroup(self, button): self.newExpected.emit() def isWinner(self): return False def getPlayer(self): return self.player def getScore(self): expected = self.expectedGroup.checkedId() won = self.wonGroup.checkedId() if expected < 0 or won < 0: return 0 if expected == won: return 10 + 3 * won return -3 * abs(expected - won) def getWonHands(self): return self.wonGroup.checkedId() def getExpectedHands(self): return self.expectedGroup.checkedId() def setExpectedHands(self, number): if number < 0: self.expectedButtons[0].toggle() return True button = self.expectedGroup.button(number) if button.isEnabled(): button.toggle() return True return False def setWonHands(self, number): if number < 0: self.wonButtons[0].toggle() return True button = self.wonGroup.button(number) if button.isEnabled(): button.toggle() return True return False def expectedClickedAction(self, _): self.handsClicked.emit('expected', self.player) def wonClickedAction(self, _): self.handsClicked.emit('won', self.player) def setColour(self, colour): self.pcolour = colour css = ("QLabel {{ font-size: 24px; font-weight: bold; " "color:rgb({},{},{});}}") self.label.setStyleSheet(css.format(self.pcolour.red(), self.pcolour.green(), self.pcolour.blue()))
class ColormapDialog(QDialog): sigColormapChanged = pyqtSignal(object) def __init__(self, parent=None, name="Colormap Dialog"): QDialog.__init__(self, parent) self.setWindowTitle(name) self.title = name self.colormapList = [ 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn' ] # histogramData is tupel(bins, counts) self.histogramData = None # default values self.dataMin = -10 self.dataMax = 10 self.minValue = 0 self.maxValue = 1 self.colormapIndex = 2 self.colormapType = 0 self.autoscale = False self.autoscale90 = False # main layout vlayout = QVBoxLayout(self) vlayout.setContentsMargins(10, 10, 10, 10) vlayout.setSpacing(0) # layout 1 : -combo to choose colormap # -autoscale button # -autoscale 90% button hbox1 = QWidget(self) hlayout1 = QHBoxLayout(hbox1) vlayout.addWidget(hbox1) hlayout1.setContentsMargins(0, 0, 0, 0) hlayout1.setSpacing(10) # combo self.combo = QComboBox(hbox1) for colormap in self.colormapList: self.combo.addItem(colormap) self.combo.activated[int].connect(self.colormapChange) hlayout1.addWidget(self.combo) # autoscale self.autoScaleButton = QPushButton("Autoscale", hbox1) self.autoScaleButton.setCheckable(True) self.autoScaleButton.setAutoDefault(False) self.autoScaleButton.toggled[bool].connect(self.autoscaleChange) hlayout1.addWidget(self.autoScaleButton) # autoscale 90% self.autoScale90Button = QPushButton("Autoscale 90%", hbox1) self.autoScale90Button.setCheckable(True) self.autoScale90Button.setAutoDefault(False) self.autoScale90Button.toggled[bool].connect(self.autoscale90Change) hlayout1.addWidget(self.autoScale90Button) # hlayout hbox0 = QWidget(self) self.__hbox0 = hbox0 hlayout0 = QHBoxLayout(hbox0) hlayout0.setContentsMargins(0, 0, 0, 0) hlayout0.setSpacing(0) vlayout.addWidget(hbox0) #hlayout0.addStretch(10) self.buttonGroup = QButtonGroup() g1 = QCheckBox(hbox0) g1.setText("Linear") g2 = QCheckBox(hbox0) g2.setText("Logarithmic") g3 = QCheckBox(hbox0) g3.setText("Gamma") self.buttonGroup.addButton(g1, 0) self.buttonGroup.addButton(g2, 1) self.buttonGroup.addButton(g3, 2) self.buttonGroup.setExclusive(True) if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.buttonGroup.button(0).setChecked(True) hlayout0.addWidget(g1) hlayout0.addWidget(g2) hlayout0.addWidget(g3) vlayout.addWidget(hbox0) self.buttonGroup.buttonClicked[int].connect(self.buttonGroupChange) vlayout.addSpacing(20) hboxlimits = QWidget(self) hboxlimitslayout = QHBoxLayout(hboxlimits) hboxlimitslayout.setContentsMargins(0, 0, 0, 0) hboxlimitslayout.setSpacing(0) self.slider = None vlayout.addWidget(hboxlimits) vboxlimits = QWidget(hboxlimits) vboxlimitslayout = QVBoxLayout(vboxlimits) vboxlimitslayout.setContentsMargins(0, 0, 0, 0) vboxlimitslayout.setSpacing(0) hboxlimitslayout.addWidget(vboxlimits) # hlayout 2 : - min label # - min texte hbox2 = QWidget(vboxlimits) self.__hbox2 = hbox2 hlayout2 = QHBoxLayout(hbox2) hlayout2.setContentsMargins(0, 0, 0, 0) hlayout2.setSpacing(0) #vlayout.addWidget(hbox2) vboxlimitslayout.addWidget(hbox2) hlayout2.addStretch(10) self.minLabel = QLabel(hbox2) self.minLabel.setText("Minimum") hlayout2.addWidget(self.minLabel) hlayout2.addSpacing(5) hlayout2.addStretch(1) self.minText = MyQLineEdit(hbox2) self.minText.setFixedWidth(150) self.minText.setAlignment(QtCore.Qt.AlignRight) self.minText.returnPressed[()].connect(self.minTextChanged) hlayout2.addWidget(self.minText) # hlayout 3 : - min label # - min text hbox3 = QWidget(vboxlimits) self.__hbox3 = hbox3 hlayout3 = QHBoxLayout(hbox3) hlayout3.setContentsMargins(0, 0, 0, 0) hlayout3.setSpacing(0) #vlayout.addWidget(hbox3) vboxlimitslayout.addWidget(hbox3) hlayout3.addStretch(10) self.maxLabel = QLabel(hbox3) self.maxLabel.setText("Maximum") hlayout3.addWidget(self.maxLabel) hlayout3.addSpacing(5) hlayout3.addStretch(1) self.maxText = MyQLineEdit(hbox3) self.maxText.setFixedWidth(150) self.maxText.setAlignment(QtCore.Qt.AlignRight) self.maxText.returnPressed[()].connect(self.maxTextChanged) hlayout3.addWidget(self.maxText) # Graph widget for color curve... self.c = PlotWidget(self, backend=None) self.c.setGraphXLabel("Data Values") self.c.setInteractiveMode('select') self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits(-11.5, 11.5) x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] y = [-10, -10, 10, 10] self.c.addCurve(x, y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.markers = [] self.__x = x self.__y = y labelList = ["", "Min", "Max", ""] for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" #TODO symbol legend = "%d" % i self.c.addXMarker(x[i], legend=legend, text=labelList[i], draggable=draggable, color=color) self.markers.append((legend, "")) self.c.setMinimumSize(QSize(250, 200)) vlayout.addWidget(self.c) self.c.sigPlotSignal.connect(self.chval) # colormap window can not be resized self.setFixedSize(vlayout.minimumSize()) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") vlayout.addWidget(self.buttonBox) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def plotHistogram(self, data=None): if data is not None: self.histogramData = data if self.histogramData is None: return False bins, counts = self.histogramData self.c.addCurve(bins, counts, "Histogram", color='darkYellow', histogram='center', yaxis='right', fill=True) def _update(self): _logger.debug("colormap _update called") self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0 self.minmd = self.dataMin - self.marge self.maxpd = self.dataMax + self.marge self.c.setGraphXLimits(self.minmd, self.maxpd) self.c.setGraphYLimits(-11.5, 11.5) self.__x = [self.minmd, self.dataMin, self.dataMax, self.maxpd] self.__y = [-10, -10, 10, 10] self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.c.clearMarkers() for i in range(4): if i in [1, 2]: draggable = True color = "blue" else: draggable = False color = "black" key = self.markers[i][0] label = self.markers[i][1] self.c.addXMarker(self.__x[i], legend=key, text=label, draggable=draggable, color=color) self.sendColormap() def buttonGroupChange(self, val): _logger.debug("buttonGroup asking to update colormap") self.setColormapType(val, update=True) self._update() def setColormapType(self, val, update=False): self.colormapType = val if self.colormapType == 1: self.buttonGroup.button(1).setChecked(True) elif self.colormapType == 2: self.buttonGroup.button(2).setChecked(True) else: self.colormapType = 0 self.buttonGroup.button(0).setChecked(True) if update: self._update() def chval(self, ddict): _logger.debug("Received %s", ddict) if ddict['event'] == 'markerMoving': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setDisplayedMinValue(x) elif diam == 2: self.setDisplayedMaxValue(x) elif ddict['event'] == 'markerMoved': diam = int(ddict['label']) x = ddict['x'] if diam == 1: self.setMinValue(x) if diam == 2: self.setMaxValue(x) """ Colormap """ def setColormap(self, colormap): self.colormapIndex = colormap if QTVERSION < '4.0.0': self.combo.setCurrentItem(colormap) else: self.combo.setCurrentIndex(colormap) def colormapChange(self, colormap): self.colormapIndex = colormap self.sendColormap() # AUTOSCALE """ Autoscale """ def autoscaleChange(self, val): self.autoscale = val self.setAutoscale(val) self.sendColormap() def setAutoscale(self, val): _logger.debug("setAutoscale called %s", val) if val: self.autoScaleButton.setChecked(True) self.autoScale90Button.setChecked(False) #self.autoScale90Button.setDown(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax) self.maxText.setEnabled(0) self.minText.setEnabled(0) self.c.setEnabled(False) #self.c.disablemarkermode() else: self.autoScaleButton.setChecked(False) self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) #self.c.enablemarkermode() """ set rangeValues to dataMin ; dataMax-10% """ def autoscale90Change(self, val): self.autoscale90 = val self.setAutoscale90(val) self.sendColormap() def setAutoscale90(self, val): if val: self.autoScaleButton.setChecked(False) self.setMinValue(self.dataMin) self.setMaxValue(self.dataMax - abs(self.dataMax / 10)) self.minText.setEnabled(0) self.maxText.setEnabled(0) self.c.setEnabled(False) else: self.autoScale90Button.setChecked(False) self.minText.setEnabled(1) self.maxText.setEnabled(1) self.c.setEnabled(True) self.c.setFocus() # MINIMUM """ change min value and update colormap """ def setMinValue(self, val): v = float(str(val)) self.minValue = v self.minText.setText("%g" % v) self.__x[1] = v key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ min value changed by text """ def minTextChanged(self): text = str(self.minText.text()) if not len(text): return val = float(text) self.setMinValue(val) if self.minText.hasFocus(): self.c.setFocus() """ change only the displayed min value """ def setDisplayedMinValue(self, val): val = float(val) self.minValue = val self.minText.setText("%g" % val) self.__x[1] = val key = self.markers[1][0] label = self.markers[1][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # MAXIMUM """ change max value and update colormap """ def setMaxValue(self, val): v = float(str(val)) self.maxValue = v self.maxText.setText("%g" % v) self.__x[2] = v key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') self.sendColormap() """ max value changed by text """ def maxTextChanged(self): text = str(self.maxText.text()) if not len(text): return val = float(text) self.setMaxValue(val) if self.maxText.hasFocus(): self.c.setFocus() """ change only the displayed max value """ def setDisplayedMaxValue(self, val): val = float(val) self.maxValue = val self.maxText.setText("%g" % val) self.__x[2] = val key = self.markers[2][0] label = self.markers[2][1] self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True) self.c.addCurve(self.__x, self.__y, legend="ConstrainedCurve", color='black', symbol='o', linestyle='-') # DATA values """ set min/max value of data source """ def setDataMinMax(self, minVal, maxVal, update=True): if minVal is not None: vmin = float(str(minVal)) self.dataMin = vmin if maxVal is not None: vmax = float(str(maxVal)) self.dataMax = vmax if update: # are current values in the good range ? self._update() def getColormap(self): if self.minValue > self.maxValue: vmax = self.minValue vmin = self.maxValue else: vmax = self.maxValue vmin = self.minValue cmap = [ self.colormapIndex, self.autoscale, vmin, vmax, self.dataMin, self.dataMax, self.colormapType ] return cmap if self.exec_() else None """ send 'ColormapChanged' signal """ def sendColormap(self): _logger.debug("sending colormap") try: cmap = self.getColormap() self.sigColormapChanged.emit(cmap) except: sys.excepthook(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]) def colormapListToDict(colormapList): """Convert colormap from this dialog to :class:`PlotBackend`. :param colormapList: Colormap as returned by :meth:`getColormap`. :type colormapList: list or tuple :return: Colormap as used in :class:`PlotBackend`. :rtype: dict """ index, autoscale, vMin, vMax, dataMin, dataMax, cmapType = colormapList # Warning, gamma cmapType is not supported in plot backend # Here it is silently replaced by linear as the default colormap return { 'name': _COLORMAP_NAMES[index], 'autoscale': autoscale, 'vmin': vMin, 'vmax': vMax, 'normalization': 'log' if cmapType == 1 else 'linear', 'colors': 256 } def getColormap_name(self): self.getColormap() return _COLORMAP_NAMES[self.colormapIndex] def getColor(self): return _COLOR_NAMES[self.colormapIndex] def colormapDictToList(colormapDict): """Convert colormap from :class:`PlotBackend` to this dialog. :param dict colormapDict: Colormap as used in :class:`PlotBackend`. :return: Colormap as returned by :meth:`getColormap`. :rtype: list """ cmapIndex = _COLORMAP_NAMES.index(colormapDict['name']) cmapType = 1 if colormapDict['normalization'].startswith('log') else 0 return [ cmapIndex, colormapDict['autoscale'], colormapDict['vmin'], colormapDict['vmax'], 0, # dataMin is not defined in PlotBackend colormap 0, # dataMax is not defined in PlotBackend colormap cmapType ]
class MainWindow(QMainWindow): InsertTextButton = 10 items = {-2: "source", -3: "channel", -4: "sink"} def __init__(self): import _diagramscene_rc super(MainWindow, self).__init__() self.config_manipulations = FlumeConfig(self) properties_generator.dump_props() self.create_actions() self.create_menus() self.create_tool_box() self.clicked_button_id = 0 self.scene = DiagramScene(self.item_menu) self.scene.setSceneRect(QRectF(0, 0, 5000, 5000)) self.scene.itemInserted.connect(self.item_inserted) self.scene.textInserted.connect(self.text_inserted) self.scene.itemSelected.connect(self.item_selected) self.create_tool_bars() # self.scene.enable_grid() layout = QHBoxLayout() layout.addWidget(self.tool_box) self.view = QGraphicsView(self.scene) self.view.centerOn(0, 0) layout.addWidget(self.view) self.widget = QWidget() self.widget.setLayout(layout) self.setCentralWidget(self.widget) self.setWindowTitle("The Flume Illustrator") # noinspection PyAttributeOutsideInit,PyArgumentList def create_actions(self): self.to_front_action = QAction(QIcon(':/images/bringtofront.png'), "Bring to &Front", self, shortcut="Ctrl+F", statusTip="Bring item to front", triggered=self.bring_to_front) self.send_back_action = QAction(QIcon(':/images/sendtoback.png'), "Send to &Back", self, shortcut="Ctrl+B", statusTip="Send item to back", triggered=self.send_to_back) self.bold_action = QAction(QIcon(':/images/bold.png'), "Bold", self, checkable=True, shortcut="Ctrl+B", triggered=self.handle_font_change) self.italic_action = QAction(QIcon(':/images/italic.png'), "Italic", self, checkable=True, shortcut="Ctrl+I", triggered=self.handle_font_change) self.underline_action = QAction(QIcon(':/images/underline.png'), "Underline", self, checkable=True, shortcut="Ctrl+U", triggered=self.handle_font_change) self.delete_action = QAction(QIcon(':/images/delete.png'), "Delete", self, shortcut="Delete", statusTip='Delete item from diagram', triggered=self.delete_item) self.exit_action = QAction("Exit", self, shortcut="Ctrl+X", statusTip="Quit program", triggered=self.close) self.about_action = QAction("About", self, shortcut="Ctrl+B", triggered=self.about) self.load_config_action = QAction("Load", self, shortcut="Ctrl+O", statusTip="Load config file", triggered=self.config_manipulations.load_config) self.enable_grid_action = QAction("Enable grid", self, checkable=True, triggered=self.enable_grid) # noinspection PyAttributeOutsideInit def create_menus(self): self.file_menu = self.menuBar().addMenu("File") self.file_menu.addAction(self.load_config_action) self.file_menu.addAction(self.exit_action) self.item_menu = self.menuBar().addMenu("Item") self.item_menu.addAction(self.delete_action) self.item_menu.addSeparator() self.item_menu.addAction(self.to_front_action) self.item_menu.addAction(self.send_back_action) self.about_menu = self.menuBar().addMenu("Help") self.about_menu.addAction(self.about_action) # noinspection PyAttributeOutsideInit,PyUnresolvedReferences def create_tool_box(self): self.button_group = QButtonGroup() self.button_group.setExclusive(False) self.button_group.buttonClicked[int].connect(self.button_group_clicked) layout = QGridLayout() layout.addWidget(self.create_cell_widget("Source", "source"), 0, 0) layout.addWidget(self.create_cell_widget("Channel", "channel"), 0, 1) layout.addWidget(self.create_cell_widget("Sink", "sink"), 1, 0) text_button = QToolButton() text_button.setCheckable(True) self.button_group.addButton(text_button, self.InsertTextButton) text_button.setIcon(QIcon(QPixmap(':/images/textpointer.png').scaled(30, 30))) text_button.setIconSize(QSize(50, 50)) text_layout = QGridLayout() text_layout.addWidget(text_button, 0, 0, Qt.AlignHCenter) text_layout.addWidget(QLabel("Text"), 1, 0, Qt.AlignCenter) text_widget = QWidget() text_widget.setLayout(text_layout) layout.addWidget(text_widget, 1, 1) layout.setRowStretch(3, 10) layout.setColumnStretch(2, 10) item_widget = QWidget() item_widget.setLayout(layout) self.tool_box = QToolBox() self.tool_box.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored)) self.tool_box.setMinimumWidth(item_widget.sizeHint().width()) self.tool_box.addItem(item_widget, "Basic Flume Items") # noinspection PyAttributeOutsideInit,PyUnresolvedReferences def create_tool_bars(self): self.edit_tool_bar = self.addToolBar("Edit") self.edit_tool_bar.addAction(self.delete_action) self.edit_tool_bar.addAction(self.to_front_action) self.edit_tool_bar.addAction(self.send_back_action) self.edit_tool_bar.addAction(self.enable_grid_action) self.font_combo = QFontComboBox() self.font_combo.currentFontChanged.connect(self.current_font_changed) self.font_size_combo = QComboBox() self.font_size_combo.setEditable(True) for i in range(8, 30, 2): self.font_size_combo.addItem(str(i)) validator = QIntValidator(2, 64, self) self.font_size_combo.setValidator(validator) self.font_size_combo.currentIndexChanged.connect(self.font_size_changed) self.font_color_tool_button = QToolButton() self.font_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup) self.font_color_tool_button.setMenu( self.create_color_menu(self.text_color_changed, Qt.black)) self.text_action = self.font_color_tool_button.menu().defaultAction() self.font_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/textpointer.png', Qt.black)) self.font_color_tool_button.setAutoFillBackground(True) self.font_color_tool_button.clicked.connect(self.text_button_triggered) self.fill_color_tool_button = QToolButton() self.fill_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup) self.fill_color_tool_button.setMenu( self.create_color_menu(self.item_color_changed, Qt.white)) self.fillAction = self.fill_color_tool_button.menu().defaultAction() self.fill_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/floodfill.png', Qt.white)) self.fill_color_tool_button.clicked.connect(self.fill_button_triggered) self.line_color_tool_button = QToolButton() self.line_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup) self.line_color_tool_button.setMenu( self.create_color_menu(self.line_color_changed, Qt.black)) self.lineAction = self.line_color_tool_button.menu().defaultAction() self.line_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/linecolor.png', Qt.black)) self.line_color_tool_button.clicked.connect(self.line_button_triggered) self.text_tool_bar = self.addToolBar("Font") self.text_tool_bar.addWidget(self.font_combo) self.text_tool_bar.addWidget(self.font_size_combo) self.text_tool_bar.addAction(self.bold_action) self.text_tool_bar.addAction(self.italic_action) self.text_tool_bar.addAction(self.underline_action) self.color_tool_bar = self.addToolBar("Color") self.color_tool_bar.addWidget(self.font_color_tool_button) self.color_tool_bar.addWidget(self.fill_color_tool_button) self.color_tool_bar.addWidget(self.line_color_tool_button) self.loading_tool_bar = self.addToolBar("Load") self.loading_tool_bar.addAction(self.load_config_action) pointer_button = QToolButton() pointer_button.setCheckable(True) pointer_button.setChecked(True) pointer_button.setIcon(QIcon(":/images/pointer.png")) line_pointer_button = QToolButton() line_pointer_button.setCheckable(True) line_pointer_button.setIcon(QIcon(":/images/linepointer.png")) self.pointer_type_group = QButtonGroup() self.pointer_type_group.addButton(pointer_button, DiagramScene.MoveItem) self.pointer_type_group.addButton(line_pointer_button, DiagramScene.InsertLine) self.pointer_type_group.buttonClicked[int].connect(self.pointer_group_clicked) self.scene_scale_combo = QComboBox() self.scene_scale_combo.addItems(["50%", "75%", "100%", "125%", "150%"]) self.scene_scale_combo.setCurrentIndex(2) self.scene_scale_combo.currentIndexChanged[str].connect(self.scene_scale_changed) self.pointer_tool_bar = self.addToolBar("Pointer type") self.pointer_tool_bar.addWidget(pointer_button) self.pointer_tool_bar.addWidget(line_pointer_button) self.pointer_tool_bar.addWidget(self.scene_scale_combo) def button_group_clicked(self, button_id): buttons = self.button_group.buttons() self.clicked_button_id = button_id for button in buttons: if self.button_group.button(button_id) != button: button.setChecked(False) if button_id == self.InsertTextButton: self.scene.set_mode(DiagramScene.InsertText) else: self.scene.set_item_type(self.items[button_id]) self.scene.set_mode(DiagramScene.InsertItem) def delete_item(self): for item in self.scene.selectedItems(): if isinstance(item, FlumeDiagramItem): item.remove_arrows() self.scene.removeItem(item) # noinspection PyTypeChecker,PyCallByClass def about(self): # noinspection PyArgumentList QMessageBox.about(self, "About Flume Illustrator", "The Flume illustrator shows config-file details") def pointer_group_clicked(self): self.scene.set_mode(self.pointer_type_group.checkedId()) def bring_to_front(self): if not self.scene.selectedItems(): return selected_item = self.scene.selectedItems()[0] overlap_items = selected_item.collidingItems() z_value = 0 for item in overlap_items: if item.zValue() >= z_value and isinstance(item, FlumeDiagramItem): z_value = item.zValue() + 0.1 selected_item.setZValue(z_value) def send_to_back(self): if not self.scene.selectedItems(): return selected_item = self.scene.selectedItems()[0] overlap_items = selected_item.collidingItems() z_value = 0 for item in overlap_items: if item.zValue() <= z_value and isinstance(item, FlumeDiagramItem): z_value = item.zValue() - 0.1 selected_item.setZValue(z_value) def scene_scale_changed(self, scale): new_scale = float(scale[:scale.index("%")]) / 100 old_transform = self.view.transform() self.view.resetTransform() self.view.translate(old_transform.dx(), old_transform.dy()) self.view.scale(new_scale, new_scale) def item_inserted(self, diagram_type): self.pointer_type_group.button(DiagramScene.MoveItem).setChecked(True) self.scene.set_mode(self.scene.DefaultMode) self.button_group.button(self.clicked_button_id).setChecked(False) def text_inserted(self, item): self.button_group.button(self.InsertTextButton).setChecked(False) self.scene.set_mode(self.pointer_type_group.checkedId()) def current_font_changed(self, font): self.handle_font_change() def font_size_changed(self, font=None): self.handle_font_change() def text_color_changed(self): self.text_action = self.sender() self.font_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/textpointer.png', QColor(self.text_action.data()))) self.text_button_triggered() def item_color_changed(self): self.fillAction = self.sender() self.fill_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/floodfill.png', QColor(self.fillAction.data()))) self.fill_button_triggered() def line_color_changed(self): self.lineAction = self.sender() self.line_color_tool_button.setIcon( self.create_color_tool_button_icon(':/images/linecolor.png', QColor(self.lineAction.data()))) self.line_button_triggered() def text_button_triggered(self): self.scene.set_text_color(QColor(self.text_action.data())) def fill_button_triggered(self): self.scene.set_item_color(QColor(self.fillAction.data())) def line_button_triggered(self): self.scene.set_line_color(QColor(self.lineAction.data())) def handle_font_change(self): font = self.font_combo.currentFont() font.setPointSize(int(self.font_size_combo.currentText())) if self.bold_action.isChecked(): font.setWeight(QFont.Bold) else: font.setWeight(QFont.Normal) font.setItalic(self.italic_action.isChecked()) font.setUnderline(self.underline_action.isChecked()) self.scene.setFont(font) def item_selected(self, item): font = item.font() self.font_combo.setCurrentFont(font) self.font_size_combo.setEditText(str(font.pointSize())) self.bold_action.setChecked(font.weight() == QFont.Bold) self.italic_action.setChecked(font.italic()) self.underline_action.setChecked(font.underline()) def create_cell_widget(self, text, diagram_type): item = FlumeObject(diagram_type, "") icon = QIcon(item.pictogram.image()) button = QToolButton() button.setIcon(icon) button.setIconSize(QSize(50, 50)) button.setCheckable(True) self.button_group.addButton(button) # , diagram_type layout = QGridLayout() layout.addWidget(button, 0, 0, Qt.AlignHCenter) layout.addWidget(QLabel(text), 1, 0, Qt.AlignHCenter) widget = QWidget() widget.setLayout(layout) return widget # noinspection PyArgumentList def create_color_menu(self, slot, default_color): colors = [Qt.black, Qt.white, Qt.red, Qt.blue, Qt.yellow] names = ["black", "white", "red", "blue", "yellow"] color_menu = QMenu(self) for color, name in zip(colors, names): action = QAction(self.create_color_icon(color), name, self, triggered=slot) action.setData(QColor(color)) color_menu.addAction(action) if color == default_color: color_menu.setDefaultAction(action) return color_menu @staticmethod def create_color_tool_button_icon(image_file, color): pixmap = QPixmap(50, 80) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) image = QPixmap(image_file) target = QRect(0, 0, 50, 60) source = QRect(0, 0, 42, 42) painter.fillRect(QRect(0, 60, 50, 80), color) painter.drawPixmap(target, image, source) painter.end() return QIcon(pixmap) @staticmethod def create_color_icon(color): pixmap = QPixmap(20, 20) painter = QPainter(pixmap) painter.setPen(Qt.NoPen) painter.fillRect(QRect(0, 0, 20, 20), color) painter.end() return QIcon(pixmap) def enable_grid(self): if self.enable_grid_action.isChecked(): color = Qt.black else: color = Qt.white for i in range(50): for j in range(50): self.scene.addEllipse(i * 100, j * 100, 2, 2, QPen(color))