class MyWidget(QWidget): # Constructor function def __init__(self): QWidget.__init__(self) self.setWindowTitle("Reimplementing Events") self.setGeometry(300, 250, 300, 100) self.myLayout = QVBoxLayout() self.myLabel1 = QLabel("Text 1") self.myLineEdit1 = QLineEdit() self.myLabel2 = QLabel("Text 2") self.myLineEdit2 = QLineEdit() self.myLabel3 = QLabel("Text 3") self.myLineEdit3 = QLineEdit() self.myLayout.addWidget(self.myLabel1) self.myLayout.addWidget(self.myLineEdit1) self.myLayout.addWidget(self.myLabel2) self.myLayout.addWidget(self.myLineEdit2) self.myLayout.addWidget(self.myLabel3) self.myLayout.addWidget(self.myLineEdit3) self.setLayout(self.myLayout) # Function reimplementing event() function def event(self, event): if event.type() == QEvent.KeyRelease and event.key() == Qt.Key_Tab: self.myLineEdit3.setFocus() return True return QWidget.event(self, event)
class PopupEdit(QDialog): send = Signal(str) def __init__(self, parent=None): super().__init__(parent) self.setWindowFlags(Qt.Popup) self.setAttribute(Qt.WA_TranslucentBackground) layout = QVBoxLayout(self) self.edit = QLineEdit(self) layout.addWidget(self.edit) self.setLayout(layout) # 現在のマウス位置にGUIを出す size_x = 200 size_y = 50 pos = QCursor().pos() self.setGeometry(pos.x() - size_x, pos.y() - size_y, size_x, size_y) self.edit.returnPressed.connect(self.Submit) self.edit.setFocus() def Submit(self): # Enterしたら文字をEmitして閉じる self.send.emit(self.edit.text()) self.close()
class Logon(QWidget): ok = Signal() # 생성자 (self 는 걍 써줌 기본으로) def __init__(self, ids, pws, parent=None): # 보통 Qwidget 을 만들때, parent 를 넣어주는데, 없으면 default = None 임 QWidget.__init__(self, parent) self.listIds = ids # 클래스 생성자에다가 변수 걍 선언해도됨 self.listPWs = pws self.labelId = QLabel('&Id :') self.labelId.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.labelPW = QLabel('&Password :'******'&Ok') self.buttonOk.setIcon(QIcon(':/images/ok.png')) layout1 = QGridLayout() layout1.addWidget(self.labelId, 0, 0) layout1.addWidget(self.lineEditId, 0, 1) layout1.addWidget(self.labelPW, 1, 0) layout1.addWidget(self.lineEditPW, 1, 1) layout2 = QHBoxLayout() layout2.addStretch() layout2.addWidget(self.buttonOk) mainLayout = QVBoxLayout() mainLayout.addLayout(layout1) mainLayout.addLayout(layout2) self.setLayout(mainLayout) # 되는 이유는 Qwidget 클래스를 상속했기 때문임 self.setWindowTitle('Log on') self.setWindowIcon(QIcon(":/images/ok.png")) self.buttonOk.clicked.connect(self.onOk) # 밑에 함수 연결 def onOk(self): if (self.lineEditId.text() not in self.listIds): QMessageBox.critical(self, 'Logon Error', 'You are not my member.') self.lineEditId.setFocus() else: idx = self.listIds.index(self.lineEditId.text()) if (self.lineEditPW.text() != self.listPWs[idx]): QMessageBox.critical(self, 'Logon Error', 'Wrong Number') self.lineEditPW.setFocus() else: self.ok.emit() # ok 시그널 보냄
class AutoFilterMenu(QMenu): """A widget to show the auto filter 'menu'. Attributes: parent (QTableView): the parent widget. """ asc_sort_triggered = Signal() desc_sort_triggered = Signal() filter_triggered = Signal(dict) def __init__(self, parent): """Initialize class.""" super().__init__(parent) self.auto_filter = dict() # Layout self.all_item_model = AutoFilterMenuAllItemModel(self) self.value_item_model = AutoFilterMenuValueItemModel(self) self.text_filter = QLineEdit(self) self.text_filter.setPlaceholderText("Search...") self.text_filter.setClearButtonEnabled(True) self.all_item_view = AutoFilterMenuView(self) self.value_item_view = AutoFilterMenuView(self) self.all_item_view.setModel(self.all_item_model) self.value_item_view.setModel(self.value_item_model) text_filter_action = QWidgetAction(self) text_filter_action.setDefaultWidget(self.text_filter) all_item_view_action = QWidgetAction(self) all_item_view_action.setDefaultWidget(self.all_item_view) value_item_view_action = QWidgetAction(self) value_item_view_action.setDefaultWidget(self.value_item_view) self.addAction(text_filter_action) self.addAction(all_item_view_action) self.addAction(value_item_view_action) ok_action = self.addAction("Ok") self.text_filter.textEdited.connect(self.value_item_model.set_filter_reg_exp) ok_action.triggered.connect(self._handle_ok_action_triggered) self.all_item_model.checked_state_changed.connect(self.value_item_model.set_all_items_checked_state) self.value_item_model.all_checked_state_changed.connect(self.all_item_model.set_checked_state) self.aboutToShow.connect(self._fix_geometry) def set_data(self, data): """Set data to show in the menu.""" self.value_item_model.reset_model(data) @Slot(name="_fix_geometry") def _fix_geometry(self): """Fix geometry, shrink views as possible.""" all_item_view_height = self.all_item_view.sizeHintForRow(0) self.all_item_view.setMaximumHeight(all_item_view_height) self.text_filter.clear() self.text_filter.setFocus() @Slot("bool", name="_handle_ok_action_triggered") def _handle_ok_action_triggered(self, checked=False): """Called when user presses Ok. Collect selections and emit signal. """ auto_filter = self.value_item_model.get_auto_filter() self.filter_triggered.emit(auto_filter)
class AdvancedImportDialog(PBDialog): """create a window for the advanced import""" def __init__(self, parent=None): """Simple extension of `PBDialog.__init__`""" super(AdvancedImportDialog, self).__init__(parent) self.result = False self.grid = None self.searchStr = None self.comboMethod = None self.acceptButton = None self.cancelButton = None self.initUI() def onCancel(self): """Reject the output (set self.result to False and close)""" self.result = False self.close() def onOk(self): """Accept the output (set self.result to True and close)""" self.result = True self.close() def initUI(self): """Create and fill the `QGridLayout`""" self.setWindowTitle(dwstr.advImpTitle) grid = QGridLayout() self.grid = grid grid.setSpacing(1) ##search grid.addWidget(PBLabel(dwstr.advImpSearch), 0, 0) self.searchStr = QLineEdit("") grid.addWidget(self.searchStr, 0, 1) grid.addWidget(PBLabel(dwstr.advImpMethod), 1, 0) self.comboMethod = PBComboBox( self, ["INSPIRE-HEP", "ADS-NASA", "arXiv", "DOI", "ISBN"], current="INSPIRE-HEP", ) grid.addWidget(self.comboMethod, 1, 1) # OK button self.acceptButton = QPushButton(dwstr.ok, self) self.acceptButton.clicked.connect(self.onOk) grid.addWidget(self.acceptButton, 2, 0) # cancel button self.cancelButton = QPushButton(dwstr.cancel, self) self.cancelButton.clicked.connect(self.onCancel) self.cancelButton.setAutoDefault(True) grid.addWidget(self.cancelButton, 2, 1) self.setGeometry(100, 100, 400, 100) self.setLayout(grid) self.searchStr.setFocus() self.centerWindow()
class TextInput(): def __init__(self, suggestion='', input_valid_callback = None): self.input_valid_callback = input_valid_callback self.menu = QMenu() self.lb = QWidgetAction(None) self.widget = QWidget(None) self.layout = QHBoxLayout() self.button = QPushButton() self.button.setText("Ok") self.le = QLineEdit() self.layout.addWidget(self.le) self.layout.addWidget(self.button) self.widget.setLayout(self.layout) self.button.pressed.connect(self.done) self.le.textEdited.connect(self.check_input) self.eventFilter = EnterKeyPressFilter() self.eventFilter.callback = self.done self.le.installEventFilter(self.eventFilter) self.lb.setDefaultWidget(self.widget) self.menu.addAction(self.lb) self.le.setText(suggestion) self.le.setFocus() self.le.selectAll() self.result = None def show(self, pos): self.menu.exec_(pos) return self.result def done(self): self.result = self.le.text() self.menu.close() def check_input(self): if self.input_valid_callback is not None: result = self.input_valid_callback(self.le.text()) if result: self.le.setStyleSheet('') else: self.le.setStyleSheet('background: pink') return None
class Logon(QWidget): ok = Signal() def __init__(self, ids, pws, parent=None): QWidget.__init__(self, parent) self.listIds = ids self.listPWs = pws self.labelId = QLabel('&Id :') self.labelId.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.labelPW = QLabel('&Password:'******'Log on') self.setWindowIcon(QIcon(":/images/ok.png")) self.buttonOk.clicked.connect(self.onOk) def onOk(self): if (self.lineEditId.text() not in self.listIds): QMessageBox.critical(self, "Logon error", "Unregistered user") self.lineEditId.setFocus() else: idx = self.listIds.index(self.lineEditId.text()) if self.lineEditPW.text() != self.listPWs[idx]: QMessageBox.critical(self, "Logon error", "Incroreect password") self.lineEditPW.setFocus() else: self.ok.emit()
class Form(QFrame): def __init__(self, master=None, *campos, **kwargs): super().__init__(master) self.formlayout = QFormLayout() self.formulario = self.form() self.mainLayout = QVBoxLayout() self.mainLayout.addLayout(self.formlayout) self.setLayout(self.mainLayout) self.setWindowTitle(self.tr("Agenda")) self.rowid = 0 def form(self): self.nameEdit = QLineEdit() self.emailEdit = QLineEdit() self.phoneEdit = QLineEdit() self.phoneEdit.setInputMask("(00)0000-0000") self.dtanascEdit = QDateEdit() self.formlayout.addRow("&Nome",self.nameEdit) self.formlayout.addRow("&Email", self.emailEdit) self.formlayout.addRow("&Celular", self.phoneEdit) self.formlayout.addRow("&Data Nasc.", self.dtanascEdit) def lerdetalhes(self, index): records = dataset.selectbyid(model, index) for row in records: self.rowid = row.id self.nameEdit.setText(row.nomeperson) self.emailEdit.setText(row.emailperson) self.phoneEdit.setText(row.telefoneperson) self.dtanascEdit.setDate(row.dtanascimentoperson) def limparformulario(self): self.rowid = 0 self.nameEdit.setText('') self.nameEdit.setFocus() self.emailEdit.setText('') self.phoneEdit.setText('') self.dtanascEdit.setDate(QDate.currentDate()) def cancel(self): self.newBtn.setEnabled(True) def pegavalores(self): nnome = self.nameEdit.text() eemail = self.emailEdit.text() pphone = self.phoneEdit.text() ddtanascimento = self.dtanascEdit.text() if self.rowid == 0: values = {'nomeperson': nnome, 'emailperson': eemail, 'telefoneperson': pphone, 'dtanascimentoperson': ddtanascimento} else: values = {'id': self.rowid,'nomeperson': nnome, 'emailperson': eemail, 'telefoneperson': pphone, 'dtanascimentoperson': ddtanascimento} return values
class ClientRegister(QDialog): def __init__(self): super(ClientRegister, self).__init__() self.setFixedSize(300, 150) self.setWindowIcon(QIcon('icons/auth.png')) self.setWindowTitle('客户端注册') client = DbHelper.query_client() lbl_app_id = QLabel('APP ID', self) lbl_app_id.setGeometry(10, 20, 50, 26) lbl_app_id.setAlignment(Qt.AlignCenter) self.le_app_id = QLineEdit(self) self.le_app_id.setText(client[0] if client is not None else '') self.le_app_id.setGeometry(70, 20, 200, 26) self.le_app_id.setDisabled(True if client is not None else False) lbl_security = QLabel('密钥', self) lbl_security.setGeometry(10, 66, 50, 26) lbl_security.setAlignment(Qt.AlignCenter) self.le_security = QLineEdit(self) self.le_security.setEchoMode(QLineEdit.Password) self.le_security.setText(client[1] if client is not None else '') self.le_security.setGeometry(70, 66, 200, 26) self.le_security.setDisabled(True if client is not None else False) self.btn_save = QPushButton(self) self.btn_save.setText('已注册' if client is not None else '注册') self.btn_save.setDisabled(True if client is not None else False) self.btn_save.setGeometry(10, 110, 280, 30) self.btn_save.clicked.connect(self.register) def register(self): app_id = self.le_app_id.text().strip(' ') if app_id == '': self.btn_save.setText('请输入APP ID') self.le_app_id.setFocus() return security = self.le_security.text().strip(' ') if security == '': self.btn_save.setText('请输入密钥') self.le_security.setFocus() return self.btn_save.setDisabled(True) result, data = Tool.client_register(app_id, Tool.get_md5(security)) if result: DbHelper.insert_client(data, app_id, security) self.le_app_id.setDisabled(True) self.le_security.setDisabled(True) self.btn_save.setText("注册成功") elif data is not None: self.btn_save.setDisabled(False) self.btn_save.setText(data) else: self.btn_save.setDisabled(False) self.btn_save.setText("注册失败")
class FindToolBar(QToolBar): find = QtCore.Signal(str, QWebEnginePage.FindFlags) def __init__(self): super(FindToolBar, self).__init__() self._line_edit = QLineEdit() self._line_edit.setClearButtonEnabled(True) self._line_edit.setPlaceholderText("Find...") self._line_edit.setMaximumWidth(300) self._line_edit.returnPressed.connect(self._find_next) self.addWidget(self._line_edit) self._previous_button = QToolButton() self._previous_button.setIcon( QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png')) self._previous_button.clicked.connect(self._find_previous) self.addWidget(self._previous_button) self._next_button = QToolButton() self._next_button.setIcon( QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png')) self._next_button.clicked.connect(self._find_next) self.addWidget(self._next_button) self._case_sensitive_checkbox = QCheckBox('Case Sensitive') self.addWidget(self._case_sensitive_checkbox) self._hideButton = QToolButton() self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape)) self._hideButton.setIcon( QIcon(':/qt-project.org/styles/macstyle/images/closedock-16.png')) self._hideButton.clicked.connect(self.hide) self.addWidget(self._hideButton) def focus_find(self): self._line_edit.setFocus() def _emit_find(self, backward): needle = self._line_edit.text().strip() if needle: flags = QWebEnginePage.FindFlags() if self._case_sensitive_checkbox.isChecked(): flags |= QWebEnginePage.FindCaseSensitively if backward: flags |= QWebEnginePage.FindBackward self.find.emit(needle, flags) def _find_next(self): self._emit_find(False) def _find_previous(self): self._emit_find(True)
class MainWindow(QDialog): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.layout_ = QVBoxLayout() self.setLayout(self.layout_) # override Escape key behavior self.reject = self.reset self.entry = None def show_(self): self.update_title() self.adjustSize() self.show() def reset(self): self.clear() self.hide() def clear(self): for i in reversed(range(self.layout_.count())): self.layout_.takeAt(i).widget().deleteLater() def move_(self, x, y): try: self.move(x, y) except OverflowError: pass def show_entry(self, callback): def on_return(): entry = self.entry.text() self.reset() callback(entry) self.entry = QLineEdit() self.entry.returnPressed.connect(on_return) self.layout_.addWidget(self.entry) self.entry.setFocus() def add_label(self, text, sunken=False, raised=False): label = QLabel(text, self) if sunken: label.setFrameStyle(QFrame.Panel | QFrame.Sunken) elif raised: label.setFrameStyle(QFrame.Panel | QFrame.Raised) label.setLineWidth(2) self.layout_.addWidget(label) def update_title(self): time_ = time.asctime(time.localtime()) self.setWindowTitle(time_)
class SearchRouteList(QWidget): def __init__(self, routes): super().__init__() self.route_list = RouteList(routes) self.scroll_area = QScrollArea() self.scroll_area.setWidget(self.route_list) self.scroll_area.setWidgetResizable(False) self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.search_line = QLineEdit() self.search_line.setPlaceholderText('Search') self.search_line.textChanged.connect(self.search) self.search_line.returnPressed.connect(self.select_first_visible) layout = QVBoxLayout() layout.addWidget(self.search_line) layout.addWidget(self.scroll_area) self.setLayout(layout) def search(self): text_elements = self.search_line.text().lower().split(' ') for button in self.route_list.buttons: visible = all(text_element in button.text().lower() for text_element in text_elements) button.setVisible(visible) def select_first_visible(self): for button in self.route_list.buttons: if button.isVisible(): button.animateClick() return def select_route_with_name(self, name): for route, button in self.route_list.route_per_button.items(): if route.name == name: button.animateClick() return def set_search(self, text): self.search_line.setText(text) def current_search(self): return self.search_line.text() def focus(self): self.search_line.setFocus() self.search_line.selectAll()
class FindToolBar(QToolBar): find = QtCore.Signal(str, QWebEnginePage.FindFlags) def __init__(self): super(FindToolBar, self).__init__() self._line_edit = QLineEdit() self._line_edit.setClearButtonEnabled(True) self._line_edit.setPlaceholderText("Find...") self._line_edit.setMaximumWidth(300) self._line_edit.returnPressed.connect(self._find_next) self.addWidget(self._line_edit) self._previous_button = QToolButton() self._previous_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png')) self._previous_button.clicked.connect(self._find_previous) self.addWidget(self._previous_button) self._next_button = QToolButton() self._next_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png')) self._next_button.clicked.connect(self._find_next) self.addWidget(self._next_button) self._case_sensitive_checkbox = QCheckBox('Case Sensitive') self.addWidget(self._case_sensitive_checkbox) self._hideButton = QToolButton() self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape)) self._hideButton.setIcon(QIcon(':/qt-project.org/styles/macstyle/images/closedock-16.png')) self._hideButton.clicked.connect(self.hide) self.addWidget(self._hideButton) def focus_find(self): self._line_edit.setFocus() def _emit_find(self, backward): needle = self._line_edit.text().strip() if needle: flags = QWebEnginePage.FindFlags() if self._case_sensitive_checkbox.isChecked(): flags |= QWebEnginePage.FindCaseSensitively if backward: flags |= QWebEnginePage.FindBackward self.find.emit(needle, flags) def _find_next(self): self._emit_find(False) def _find_previous(self): self._emit_find(True)
class CellBase(Observation, QWidget): def __init__(self, subject, index): Observation.__init__(self, subject) QWidget.__init__(self) self.index = index self.selected = False self._initNameLabel() def _initNameLabel(self): self.nameLabel = QLineEdit(self) self.nameLabel.setWindowFlags(Qt.FramelessWindowHint) self.nameLabel.setStyleSheet("background: transparent; border: none;") self.nameLabel.setMaxLength(30) self.nameLabel.setContextMenuPolicy(Qt.NoContextMenu) self.nameLabel.textChanged.connect(self.onNameChanged) self.nameLabel.editingFinished.connect(self.onEditingNameFinished) def editNameResponder(self, e): if self.selected: self.nameLabel.setFocus() self.nameLabel.selectAll() def onNameChanged(self, name): pass def onEditingNameFinished(self): self.nameLabel.clearFocus() def setSelected(self, value): self.selected = value self.updateStyle() def updateStyle(self): pass def setName(self, name): self.nameLabel.setText(name) def name(self): return self.nameLabel.text() def delete(self): self.unregister() self.setParent(None) self.deleteLater()
class TextFieldDialog(QDialog): PRE = "PRE" APPEND = "APPEND" REPLACE = "REPLACE" def __init__(self, plugin_manager): super(TextFieldDialog, self).__init__() self.plugin_manager = plugin_manager self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.edit_line = QLineEdit() self.layout = QVBoxLayout() self.layout.addWidget(self.edit_line) self.layout.addWidget(self.buttonBox) self.setWindowIcon( QIcon(os.path.join(c.ICON_PATH, c.THEME_NEUTRAL, "quote.png"))) self.setWindowTitle("Word") self.setLayout(self.layout) def set_values(self, word, word_pos, action): self.edit_line.clear() self.edit_line.setFocus() self.word = word self.word_pos = word_pos self.action = action self.exec_() def accept(self): replace = False if self.action == self.REPLACE: replace = True if self.action == self.APPEND: self.word_pos = self.word_pos + 1 self.plugin_manager.set_word_at(self.edit_line.text(), self.word_pos, replace) super(TextFieldDialog, self).accept()
class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.num = randint(1, 100) def initUI(self): self.setGeometry(300, 300, 300, 300) self.setWindowTitle("guess") self.setWindowIcon(QIcon('icon.jpg')) self.bt1 = QPushButton("我猜", self) self.bt1.setGeometry(115, 150, 70, 30) self.bt1.setToolTip('<b>点击这里猜游戏</b>') self.bt1.clicked.connect(self.showMessage) self.text = QLineEdit('在这里输入数字', self) self.text.selectAll() self.text.setFocus() self.text.setGeometry(80, 50, 150, 30) self.show() def showMessage(self): guessnumber = int(self.text.text()) print(self.num) if guessnumber > self.num: QMessageBox.about(self, '看结果', '猜大了!') self.text.setFocus() elif guessnumber < self.num: QMessageBox.about(self, '看结果', '猜小了!') self.text.setFocus() else: QMessageBox.about(self, '看结果', '答对了!进入下一轮!') self.num = randint(1, 100) self.text.clear() self.text.setFocus() def closeEvent(self, event): reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore()
class ServerSetting(QDialog): def __init__(self): super(ServerSetting, self).__init__() self.setFixedSize(300, 150) self.setWindowIcon(QIcon('icons/server.png')) self.setWindowTitle('服务器配置') lbl_host = QLabel('域名/IP', self) lbl_host.setGeometry(10, 20, 50, 26) lbl_host.setAlignment(Qt.AlignCenter) self.le_host = QLineEdit(self) self.le_host.setText(Config.host) self.le_host.setGeometry(70, 20, 200, 26) lbl_port = QLabel('端口', self) lbl_port.setGeometry(10, 66, 50, 26) lbl_port.setAlignment(Qt.AlignCenter) self.le_port = QLineEdit(self) self.le_port.setText(Config.port) self.le_port.setGeometry(70, 66, 200, 26) self.btn_save = QPushButton(self) self.btn_save.setText('保存') self.btn_save.setGeometry(10, 110, 280, 30) self.btn_save.clicked.connect(self.save) def save(self): host = self.le_host.text().strip(' ') if host == '' or not (host.startswith("http://") or host.startswith("https://")): self.btn_save.setText('域名/IP必须以http://或https://开头') self.le_host.setFocus() return port = self.le_port.text().strip(' ') if port == '' or not port.isdigit(): self.btn_save.setText('请输入数字端口') self.le_port.setFocus() return if Config.save_server({'host': host, 'port': port}): self.close()
class DimensionSetting(QDialog): def __init__(self): super(DimensionSetting, self).__init__() self.setFixedSize(300, 150) self.setWindowIcon(QIcon('icons/server.png')) self.setWindowTitle('窗口设置') lbl_width = QLabel('宽度', self) lbl_width.setGeometry(10, 20, 50, 26) lbl_width.setAlignment(Qt.AlignCenter) self.le_width = QLineEdit(self) self.le_width.setText(str(Config.width)) self.le_width.setGeometry(70, 20, 200, 26) lbl_height = QLabel('高度', self) lbl_height.setGeometry(10, 66, 50, 26) lbl_height.setAlignment(Qt.AlignCenter) self.le_height = QLineEdit(self) self.le_height.setText(str(Config.height)) self.le_height.setGeometry(70, 66, 200, 26) self.btn_save = QPushButton(self) self.btn_save.setText('保存') self.btn_save.setGeometry(10, 110, 280, 30) self.btn_save.clicked.connect(self.save) def save(self): width = self.le_width.text().strip(' ') if width == '' or not width.isdigit(): self.btn_save.setText('请输入宽度') self.le_width.setFocus() return height = self.le_height.text().strip(' ') if height == '' or not height.isdigit(): self.btn_save.setText('请输入高度') self.le_height.setFocus() return if Config.save_dimension({'width': width, 'height': height}): self.close()
class SporeItem(TreeItemWidget): clicked = Signal(QObject, QEvent) double_clicked = Signal() context_requested = Signal(QObject, QAction) view_toggled = Signal(QObject, int) name_changed = Signal(QObject, str) view_solo = Signal(QObject, bool) def __init__(self, name, parent=None): super(SporeItem, self).__init__(name, parent) self.node_name = name self.build_spore_ui() self.connect_signals() if name in cmds.ls(sl=1, typ='sporeNode'): self.select() def build_spore_ui(self): self.item_wdg.setFrameStyle(QFrame.Raised | QFrame.StyledPanel) self.setStyleSheet("background-color: rgb(68,68,68);") pixmap = QPixmap(':/out_particle.png') icon_lbl = QLabel() icon_lbl.setMaximumWidth(18) icon_lbl.setPixmap(pixmap) self.item_lay.addWidget(icon_lbl, 0, 1, 1, 1) self.target_lbl = QLabel(self.name) self.item_lay.addWidget(self.target_lbl, 0, 2, 1, 1) self.target_edt = QLineEdit(self.item_wdg) self.target_edt.setStyleSheet("background-color: rgb(68,68,68);") self.target_edt.setMinimumWidth(180) self.target_edt.setVisible(False) self.item_lay.addWidget(self.target_edt, 0, 2, 1, 1) self.item_lay.setColumnStretch(2, 1) self.view_buttons = DisplayButtons(self) self.item_lay.addWidget(self.view_buttons, 0, 3, 1, 1) def connect_signals(self): self.view_buttons.view_instancer.connect( lambda: self.view_toggled.emit(self, 0)) self.view_buttons.view_bounding_box.connect( lambda: self.view_toggled.emit(self, 2)) self.view_buttons.view_bounding_boxes.connect( lambda: self.view_toggled.emit(self, 1)) self.view_buttons.view_solo.connect(self.toggle_solo) # self.view_toggled.emit(self, state) # self.target_edt.returnPressed.connect(self.change_name) self.target_edt.editingFinished.connect(self.change_name) def mousePressEvent(self, event): """ click event to select / deselect widgets """ if event.button() == Qt.LeftButton: if self.is_selected: self.deselect() else: self.select() self.clicked.emit(self, event) def mouseDoubleClickEvent(self, event): """ double click event to enter rename context """ self.target_lbl.setVisible(False) self.target_edt.setVisible(True) self.target_edt.setFocus() def contextMenuEvent(self, event): if not self.is_selected: self.select() # build context menu menu = QMenu(self) menu.setStyleSheet("background-color: rgb(68,68,68);") # instance_displ_act = menu.addAction("Display Instances") # bb_displ_act = menu.addAction("Display Bounding Box") # bbs_displ_act = menu.addAction("Display Bounding Boxes") # hide_act = menu.addAction("Hide Selected Setup(s)") # menu.addSeparator() # convert_particle_act = menu.addAction("Convert to Particles") # convert_particle_act = menu.addAction("Write to Alembic") # convert_particle_act = menu.addAction("Write to Katana Live Group") # convert_particle_act = menu.addAction("Combine Selected Setups") menu.addSeparator() remove_act = menu.addAction("Delete") action = menu.exec_(self.mapToGlobal(event.pos())) self.context_requested.emit(self, action) def deselect(self): """ deselect widget """ self.is_selected = False self.setStyleSheet("background-color: rgb(68,68,68);") def select(self): """ select widget """ self.is_selected = True self.setStyleSheet("background-color: rgb(21,60,97);") def set_select(self, select=False): if select: self.select() else: self.deselect() return self.is_selected # def toggle_view(self, state): # self.view_toggled.emit(self, state) def toggle_solo(self): """ check if widget is soloed and emit the view_solo signal """ solo = self.view_buttons.solo_btn.isChecked() self.view_solo.emit(self, solo) def change_name(self): """ trigger for name changed event """ name = self.target_edt.text() if name: self.name_changed.emit(self, name) self.target_edt.setVisible(False) self.target_lbl.setVisible(True)
class BlockingClient(QWidget): def __init__(self, parent=None): super(BlockingClient, self).__init__(parent) self.thread = FortuneThread() self.currentFortune = '' hostLabel = QLabel("&Server name:") portLabel = QLabel("S&erver port:") for ipAddress in QNetworkInterface.allAddresses(): if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address( ) != 0: break else: ipAddress = QHostAddress(QHostAddress.LocalHost) ipAddress = ipAddress.toString() self.hostLineEdit = QLineEdit(ipAddress) self.portLineEdit = QLineEdit() self.portLineEdit.setValidator(QIntValidator(1, 65535, self)) hostLabel.setBuddy(self.hostLineEdit) portLabel.setBuddy(self.portLineEdit) self.statusLabel = QLabel( "This example requires that you run the Fortune Server example as well." ) self.statusLabel.setWordWrap(True) self.getFortuneButton = QPushButton("Get Fortune") self.getFortuneButton.setDefault(True) self.getFortuneButton.setEnabled(False) quitButton = QPushButton("Quit") buttonBox = QDialogButtonBox() buttonBox.addButton(self.getFortuneButton, QDialogButtonBox.ActionRole) buttonBox.addButton(quitButton, QDialogButtonBox.RejectRole) self.getFortuneButton.clicked.connect(self.requestNewFortune) quitButton.clicked.connect(self.close) self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton) self.portLineEdit.textChanged.connect(self.enableGetFortuneButton) self.thread.newFortune.connect(self.showFortune) self.thread.error.connect(self.displayError) mainLayout = QGridLayout() mainLayout.addWidget(hostLabel, 0, 0) mainLayout.addWidget(self.hostLineEdit, 0, 1) mainLayout.addWidget(portLabel, 1, 0) mainLayout.addWidget(self.portLineEdit, 1, 1) mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2) mainLayout.addWidget(buttonBox, 3, 0, 1, 2) self.setLayout(mainLayout) self.setWindowTitle("Blocking Fortune Client") self.portLineEdit.setFocus() def requestNewFortune(self): self.getFortuneButton.setEnabled(False) self.thread.requestNewFortune(self.hostLineEdit.text(), int(self.portLineEdit.text())) def showFortune(self, nextFortune): if nextFortune == self.currentFortune: self.requestNewFortune() return self.currentFortune = nextFortune self.statusLabel.setText(self.currentFortune) self.getFortuneButton.setEnabled(True) def displayError(self, socketError, message): if socketError == QAbstractSocket.HostNotFoundError: QMessageBox.information( self, "Blocking Fortune Client", "The host was not found. Please check the host and port " "settings.") elif socketError == QAbstractSocket.ConnectionRefusedError: QMessageBox.information( self, "Blocking Fortune Client", "The connection was refused by the peer. Make sure the " "fortune server is running, and check that the host name " "and port settings are correct.") else: QMessageBox.information( self, "Blocking Fortune Client", "The following error occurred: %s." % message) self.getFortuneButton.setEnabled(True) def enableGetFortuneButton(self): self.getFortuneButton.setEnabled(self.hostLineEdit.text() != '' and self.portLineEdit.text() != '')
class BlockingClient(QWidget): def __init__(self, parent=None): super(BlockingClient, self).__init__(parent) self.thread = FortuneThread() self.currentFortune = '' hostLabel = QLabel("&Server name:") portLabel = QLabel("S&erver port:") for ipAddress in QNetworkInterface.allAddresses(): if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address() != 0: break else: ipAddress = QHostAddress(QHostAddress.LocalHost) ipAddress = ipAddress.toString() self.hostLineEdit = QLineEdit(ipAddress) self.portLineEdit = QLineEdit() self.portLineEdit.setValidator(QIntValidator(1, 65535, self)) hostLabel.setBuddy(self.hostLineEdit) portLabel.setBuddy(self.portLineEdit) self.statusLabel = QLabel( "This example requires that you run the Fortune Server example as well.") self.statusLabel.setWordWrap(True) self.getFortuneButton = QPushButton("Get Fortune") self.getFortuneButton.setDefault(True) self.getFortuneButton.setEnabled(False) quitButton = QPushButton("Quit") buttonBox = QDialogButtonBox() buttonBox.addButton(self.getFortuneButton, QDialogButtonBox.ActionRole) buttonBox.addButton(quitButton, QDialogButtonBox.RejectRole) self.getFortuneButton.clicked.connect(self.requestNewFortune) quitButton.clicked.connect(self.close) self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton) self.portLineEdit.textChanged.connect(self.enableGetFortuneButton) self.thread.newFortune.connect(self.showFortune) self.thread.error.connect(self.displayError) mainLayout = QGridLayout() mainLayout.addWidget(hostLabel, 0, 0) mainLayout.addWidget(self.hostLineEdit, 0, 1) mainLayout.addWidget(portLabel, 1, 0) mainLayout.addWidget(self.portLineEdit, 1, 1) mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2) mainLayout.addWidget(buttonBox, 3, 0, 1, 2) self.setLayout(mainLayout) self.setWindowTitle("Blocking Fortune Client") self.portLineEdit.setFocus() def requestNewFortune(self): self.getFortuneButton.setEnabled(False) self.thread.requestNewFortune(self.hostLineEdit.text(), int(self.portLineEdit.text())) def showFortune(self, nextFortune): if nextFortune == self.currentFortune: self.requestNewFortune() return self.currentFortune = nextFortune self.statusLabel.setText(self.currentFortune) self.getFortuneButton.setEnabled(True) def displayError(self, socketError, message): if socketError == QAbstractSocket.HostNotFoundError: QMessageBox.information(self, "Blocking Fortune Client", "The host was not found. Please check the host and port " "settings.") elif socketError == QAbstractSocket.ConnectionRefusedError: QMessageBox.information(self, "Blocking Fortune Client", "The connection was refused by the peer. Make sure the " "fortune server is running, and check that the host name " "and port settings are correct.") else: QMessageBox.information(self, "Blocking Fortune Client", "The following error occurred: %s." % message) self.getFortuneButton.setEnabled(True) def enableGetFortuneButton(self): self.getFortuneButton.setEnabled(self.hostLineEdit.text() != '' and self.portLineEdit.text() != '')
class ConsoleDialog(QDialog): def __init__(self, title: str, program: str, args: List[str], commands: List[str]): super().__init__() self.setWindowTitle(title) self.program = program self.args = args self.layout = QGridLayout() self.output = QTextEdit() self.output.acceptRichText = True self.input = QLineEdit() self.completer = QCompleter(commands, self) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.input.setCompleter(self.completer) self.input.setFocus() self.layout.addWidget(self.output) self.layout.addWidget(self.input) self.setLayout(self.layout) self.connect(self.input, SIGNAL("returnPressed(void)"), self.execute_user_command) self.connect(self.completer, SIGNAL("activated(const QString&)"), self.input.clear, Qt.QueuedConnection) def execute_user_command(self): cmd = str(self.input.text()) self.run_command(cmd) def run_command(self, cmd: str): log.info( 'run_command', program=self.program, args=self.args, cmd=cmd ) self.output.append(f'> {cmd}\n') self.input.clear() process = QProcess() process.setProgram(self.program) process.setCurrentReadChannel(0) # noinspection PyUnresolvedReferences process.readyReadStandardError.connect( lambda: self.handle_error(process) ) # noinspection PyUnresolvedReferences process.readyReadStandardOutput.connect( lambda: self.handle_output(process) ) connect_args = list(self.args) args = cmd.split(' ') if args[0] == self.program.split('/')[-1]: args.pop(0) process.setArguments(connect_args + args) process.start() def handle_error(self, process: QProcess): output: QByteArray = process.readAllStandardError() message = output.data().decode('utf-8').strip() self.output.append(message) def handle_output(self, process: QProcess): output: QByteArray = process.readAllStandardOutput() message = output.data().decode('utf-8').strip() if message.startswith('{') or message.startswith('['): formatter = HtmlFormatter() formatter.noclasses = True formatter.linenos = False formatter.nobackground = True message = highlight(message, JsonLexer(), formatter) self.output.insertHtml(message) else: self.output.append(message) # This is just for generating the command lists in constants # commands = None # if '== Blockchain ==' in message: # commands = self.parse_litecoin_cli_commands(message) # elif 'lncli [global options] command [command options]' in message: # commands = self.parse_lncli_commands(message) # if commands is not None: # log.debug('commands', commands=commands) max_scroll = self.output.verticalScrollBar().maximum() self.output.verticalScrollBar().setValue(max_scroll) @staticmethod def parse_litecoin_cli_commands(message: str): log.debug('parse_litecoin_cli_commands') commands = [] for line in message.split(sep='\n'): line = line.strip() if not line or line.startswith('=='): continue command = line.split()[0] command = command.strip() commands.append(command) return commands @staticmethod def parse_lncli_commands(message: str): log.debug('parse_lncli_commands') at_commands = False commands = [] for line in message.split(sep='\n'): line = line.strip() if not at_commands: if 'COMMANDS:' in line: at_commands = True log.debug('commands line', line=line) continue elif 'GLOBAL OPTIONS' in line: return commands elif line.endswith(':') or not line: continue command = line.split()[0] command = command.strip().replace(',', '') commands.append(command) return commands def show(self): self.showMaximized() self.raise_() self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) self.activateWindow() self.input.setFocus() self.run_command('help')
class PropertyTreeDelegateEditor(QFrame): """A special editor that handles renaming blocks and groups.""" sizeHintChanged = Signal(object) """Emitted when the widget changes sizeHint. Delegate should update it's geometry.""" def __init__(self, parent=None): super().__init__(parent) layout = QVBoxLayout() self.setLayout(layout) self.setContentsMargins(0, 0, 0, 0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setAutoFillBackground(True) self.setFocusPolicy(Qt.StrongFocus) self.setFrameStyle(QFrame.Panel | QFrame.Plain) self._fallback_text = None self._experiment = None self.line_edit = QLineEdit() self.line_edit.setFrame(False) self.message_label = QLabel() self.message_label.hide() # Divider line self.divider_line = QFrame() self.divider_line.setFrameShape(QFrame.HLine) self.divider_line.setFrameShadow(QFrame.Plain) self.divider_line.setLineWidth(1) layout.addWidget(self.line_edit) layout.addWidget(self.divider_line) layout.addWidget(self.message_label) self.line_edit.textChanged.connect(self._updateMessage) def experiment(self): return self._experiment def setExperiment(self, ex): self._experiment = ex def fallbackText(self): return self._fallback_text def text(self): """Get the current text value of the editor widget. If editing has not been finished succesfully, returns fallbackText(). """ (text_ok, _) = self.experiment().checkName(self.line_edit.text()) if text_ok: return self.line_edit.text() else: return self.fallbackText() def setFallbackText(self, text): """Set the fallback text value to be used if the editing was not succesfully finished. The text() method returns this value or the line_edit text. """ self._fallback_text = text def setText(self, text): """Set currently editable text. Equivalent to self.line_edit.setText.""" self.line_edit.setText(text) def _updateMessage(self): """Update the displayed message in response to changed text.""" if self.line_edit.text() == self.fallbackText(): # Perform no check text_ok = True else: (text_ok, reason) = self.experiment().checkName(self.line_edit.text()) if text_ok: self.message_label.hide() self.divider_line.hide() else: self.message_label.setText(reason) self.message_label.show() self.divider_line.show() self.sizeHintChanged.emit(self) def focusInEvent(self, event): super().focusInEvent(event) self.line_edit.setFocus()
class SearchBar(QWidget): def __init__(self): super(SearchBar, self).__init__() self.layout = QVBoxLayout() self.layout.setMargin(0) self.setStyleSheet( css('border: 1px solid {{color}};', color=colors.SECONDARY_COLOR)) self.searchbar = QLineEdit() self.searchbar.setPlaceholderText( 'Try searching for an artist or album') self.searchbar.textChanged.connect(self.set_keywords) self.searchbar.returnPressed.connect(self.search) self.searchbar.setStyleSheet( css(''' QLineEdit { padding: 10px; border-radius: 8px; background: {{backgroundColor}}; } ''', backgroundColor=colors.PLACEHOLDER_COLOR)) self.layout.addWidget(self.searchbar) self.setLayout(self.layout) def set_keywords(self, keywords): self.keywords = keywords def search(self): if self.searchbar.completer() and self.searchbar.completer().popup( ).isVisible(): # User did select an option from the dropdown menu. selected_suggestion = [ s for s in self.suggestions if s['label'] == self.keywords ] if len(selected_suggestion) > 0: self.searchbar.setCompleter(None) PageSignal.changed.emit( SongDetailPage(url=selected_suggestion[0]['url'])) else: # User did type something and then hit ENTER to search. self.thread = RunThread(self.get_search_suggestions, self.on_search_suggestions) def get_search_suggestions(self): if self.keywords: self.searchbar.setEnabled(False) logging.info( 'Getting search suggestions for keywords: "{}"'.format( self.keywords)) spider = CoreRadioSpider() self.suggestions = spider.get_search_suggestions(self.keywords) def on_search_suggestions(self): logging.info('Received search suggestions for keywords: "{}"'.format( self.keywords)) self.searchbar.setEnabled(True) self.searchbar.setFocus() if self.suggestions: suggestions = [ suggestion['label'] for suggestion in self.suggestions ] completer = QCompleter(suggestions) completer.setCaseSensitivity(Qt.CaseInsensitive) self.searchbar.setCompleter(completer) self.searchbar.completer().complete() self.searchbar.completer().popup().setStyleSheet( css( """ QListView { border: 1px solid {{borderColor}}; padding: 10px; background: {{backgroundColor}}; } QItemSelection { padding: 10px; } """, borderColor=colors.SECONDARY_COLOR, backgroundColor=colors.PLACEHOLDER_COLOR, ))
class LoginDialog(QDialog): def __init__(self, parent=None): super(LoginDialog, self).__init__(parent) # formatting self.setWindowTitle("Login") # validator regexp = QtCore.QRegExp('[A-Za-z0-9_]+') validator = QtGui.QRegExpValidator(regexp) # widgets self.usernameInput = QLineEdit() self.usernameInput.setValidator(validator) self.passwordInput = QLineEdit() self.passwordInput.setValidator(validator) self.passwordInput.setEchoMode(QLineEdit.Password) # OK and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.buttons.button(QDialogButtonBox.Ok).setText('Login') self.buttons.button(QDialogButtonBox.Cancel).setText('Quit') self.buttons.setCenterButtons(True) # signals self.usernameInput.textChanged.connect(self.check_input) self.usernameInput.textChanged.emit(self.usernameInput.text()) self.passwordInput.textChanged.connect(self.check_input) self.passwordInput.textChanged.emit(self.passwordInput.text()) # layout self.mainLayout = QVBoxLayout(self) self.mainLayout.addWidget(self.usernameInput) self.mainLayout.addWidget(self.passwordInput) self.mainLayout.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) # self.buttons.setEnabled(False) self.usernameInput.setFocus() def check_input(self, *args, **kwargs): sender = self.sender() validator = sender.validator() state = validator.validate(sender.text(), 0)[0] if state == QtGui.QValidator.Acceptable: color = '#ffffff' elif state == QtGui.QValidator.Intermediate: color = '#ffffff' else: color = '#f6989d' # red sender.setStyleSheet('QLineEdit { background-color: %s }' % color) # get current data from the dialog def getUsernameInput(self): return self.usernameInput.text() # get current data from the dialog def getPasswordInput(self): return self.passwordInput.text() # static method to create the dialog and return (date, time, accepted) @staticmethod def run(parent=None): dialog = LoginDialog(parent) result = dialog.exec_() username = dialog.getUsernameInput() password = dialog.getPasswordInput() return username, password, result == QDialog.Accepted
class PyCalcUi(QMainWindow): """PyCalc's View (GUI).""" def __init__(self, win_title: str = 'PyCalc', win_size: Tuple[int, int] = (235, 235), icon_path: Union[Path, str, None] = Path(R'.\coffeebean.ico') ) -> None: """View initializer.""" super().__init__() # Set some main window's properties self.setWindowTitle(win_title) self.setFixedSize(win_size[0], win_size[1]) if isinstance(icon_path, Path): icon_path = str(icon_path.resolve()) self.setWindowIcon(QIcon(icon_path)) # Set the central widget self._centralWidget = QWidget(self) self.setCentralWidget(self._centralWidget) self.generalLayout = QVBoxLayout() self._centralWidget.setLayout(self.generalLayout) # Create the display and the buttons self._createDisplay() self._createButtons() def _createDisplay(self) -> None: """Create the display.""" # Create the display widget self.display = QLineEdit() # Set some display's properties self.display.setFixedHeight(35) self.display.setAlignment(Qt.AlignRight) self.display.setReadOnly(True) # Add the display to the general layout self.generalLayout.addWidget(self.display) def _createButtons(self) -> None: """Create the buttons.""" self.buttons: Dict[str, QPushButton] = {} buttonsLayout = QGridLayout() # Button text | position on the QGridLayout buttons: Dict[str, Tuple[int, int]] = {'7': (0, 0), '8': (0, 1), '9': (0, 2), '/': (0, 3), 'C': (0, 4), '4': (1, 0), '5': (1, 1), '6': (1, 2), '*': (1, 3), '(': (1, 4), '1': (2, 0), '2': (2, 1), '3': (2, 2), '-': (2, 3), ')': (2, 4), '0': (3, 0), '00': (3, 1), '.': (3, 2), '+': (3, 3), '=': (3, 4), } # Create the buttons and add them to the grid layout for btnText, pos in buttons.items(): self.buttons[btnText] = QPushButton(btnText) self.buttons[btnText].setFixedSize(40, 40) buttonsLayout.addWidget(self.buttons[btnText], pos[0], pos[1]) # Add buttonsLayout to the general layout self.generalLayout.addLayout(buttonsLayout) def setDisplayText(self, text: str) -> None: """Set display's text.""" self.display.setText(text) self.display.setFocus() def displayText(self) -> str: """Get display's text.""" return cast(str, self.display.text()) def clearDisplay(self) -> None: """Clear the display.""" self.setDisplayText('')
class QTagWidget(QWidget): def __init__(self, parent, items): super(QTagWidget, self).__init__() self.parent = parent self.items = items self.tags = [] self.mainFrame = QFrame() self.mainFrame.setStyleSheet( 'border:1px solid #76797C; border-radius: 1px;') self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.mainLayout) self.mainLayout.addWidget(self.mainFrame) self.hLayout = QHBoxLayout() self.hLayout.setSpacing(4) self.lineEdit = QLineEdit() self.lineEdit.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) completer = QPartialMatchCompleter(self.lineEdit) completer.setCompletionMode(QCompleter.PopupCompletion) self.lineEdit.setCompleter(completer) model = QStringListModel() completer.setModel(model) model.setStringList(self.items) self.mainFrame.setLayout(self.hLayout) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.hLayout.setContentsMargins(2, 2, 2, 2) self.refresh() self.setup_ui() def show(self): self.show() def setup_ui(self): self.lineEdit.returnPressed.connect(self.create_tags) def create_tags(self): new_tags = self.lineEdit.text().split(', ') self.lineEdit.setText('') self.tags.extend(new_tags) self.tags = list(set(self.tags)) self.tags.sort(key=lambda x: x.lower()) self.refresh() def refresh(self): for i in reversed(range(self.hLayout.count())): self.hLayout.itemAt(i).widget().setParent(None) for tag in self.tags: self.add_tag_to_bar(tag) self.hLayout.addWidget(self.lineEdit) self.lineEdit.setFocus() # Accept to add only 5 tags if len(self.tags) >= 5: self.lineEdit.setDisabled(True) return def add_tag_to_bar(self, text): tag = QFrame() tag.setStyleSheet( 'border:1px solid rgb(192, 192, 192); border-radius: 4px;') tag.setContentsMargins(2, 2, 2, 2) tag.setFixedHeight(28) hbox = QHBoxLayout() hbox.setContentsMargins(4, 4, 4, 4) hbox.setSpacing(10) tag.setLayout(hbox) label = QLabel(text) label.setStyleSheet('border:0px') label.setFixedHeight(16) hbox.addWidget(label) x_button = QPushButton('x') x_button.setFixedSize(20, 20) x_button.setStyleSheet('border:0px; font-weight:bold') x_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) x_button.clicked.connect(partial(self.delete_tag, text)) hbox.addWidget(x_button) tag.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) self.hLayout.addWidget(tag) def delete_tag(self, tag_name): self.tags.remove(tag_name) # Make input available if tags count is less than 5 if len(self.tags) < 5: self.lineEdit.setDisabled(False) self.refresh()
class MainWidget(QWidget): def __init__(self, parent: QWidget, model: Model) -> None: super().__init__(parent) logger.add(self.log) self.mainlayout = QVBoxLayout() self.setLayout(self.mainlayout) self.splitter = QSplitter(Qt.Vertical) self.stack = QStackedWidget() self.splitter.addWidget(self.stack) # mod list widget self.modlistwidget = QWidget() self.modlistlayout = QVBoxLayout() self.modlistlayout.setContentsMargins(0, 0, 0, 0) self.modlistwidget.setLayout(self.modlistlayout) self.stack.addWidget(self.modlistwidget) # search bar self.searchbar = QLineEdit() self.searchbar.setPlaceholderText('Search...') self.modlistlayout.addWidget(self.searchbar) # mod list self.modlist = ModList(self, model) self.modlistlayout.addWidget(self.modlist) self.searchbar.textChanged.connect(lambda e: self.modlist.setFilter(e)) # welcome message welcomelayout = QVBoxLayout() welcomelayout.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) welcomewidget = QWidget() welcomewidget.setLayout(welcomelayout) welcomewidget.dragEnterEvent = self.modlist.dragEnterEvent # type: ignore welcomewidget.dragMoveEvent = self.modlist.dragMoveEvent # type: ignore welcomewidget.dragLeaveEvent = self.modlist.dragLeaveEvent # type: ignore welcomewidget.dropEvent = self.modlist.dropEvent # type: ignore welcomewidget.setAcceptDrops(True) icon = QIcon(str(getRuntimePath('resources/icons/open-folder.ico'))) iconpixmap = icon.pixmap(32, 32) icon = QLabel() icon.setPixmap(iconpixmap) icon.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) icon.setContentsMargins(4, 4, 4, 4) welcomelayout.addWidget(icon) welcome = QLabel('''<p><font> No mod installed yet. Drag a mod into this area to get started! </font></p>''') welcome.setAttribute(Qt.WA_TransparentForMouseEvents) welcome.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) welcomelayout.addWidget(welcome) self.stack.addWidget(welcomewidget) # output log self.output = QTextEdit(self) self.output.setTextInteractionFlags(Qt.NoTextInteraction) self.output.setReadOnly(True) self.output.setContextMenuPolicy(Qt.NoContextMenu) self.output.setPlaceholderText('Program output...') self.splitter.addWidget(self.output) # TODO: enhancement: add a launch game icon # TODO: enhancement: show indicator if scripts have to be merged self.splitter.setStretchFactor(0, 1) self.splitter.setStretchFactor(1, 0) self.mainlayout.addWidget(self.splitter) if len(model): self.stack.setCurrentIndex(0) self.splitter.setSizes([self.splitter.size().height(), 50]) else: self.stack.setCurrentIndex(1) self.splitter.setSizes([self.splitter.size().height(), 0]) model.updateCallbacks.append(self.modelUpdateEvent) def keyPressEvent(self, event: QKeyEvent) -> None: if event.key() == Qt.Key_Escape: self.modlist.setFocus() self.searchbar.setText('') elif event.matches(QKeySequence.Find): self.searchbar.setFocus() elif event.matches(QKeySequence.Paste): self.pasteEvent() super().keyPressEvent(event) def pasteEvent(self) -> None: clipboard = QApplication.clipboard().text().splitlines() if len(clipboard) == 1 and isValidNexusModsUrl(clipboard[0]): self.parentWidget().showDownloadModDialog() else: urls = [ url for url in QApplication.clipboard().text().splitlines() if len(str(url.strip())) ] if all( isValidModDownloadUrl(url) or isValidFileUrl(url) for url in urls): asyncio.create_task(self.modlist.checkInstallFromURLs(urls)) def modelUpdateEvent(self, model: Model) -> None: if len(model) > 0: if self.stack.currentIndex() != 0: self.stack.setCurrentIndex(0) self.repaint() else: if self.stack.currentIndex() != 1: self.stack.setCurrentIndex(1) self.repaint() def unhideOutput(self) -> None: if self.splitter.sizes()[1] < 10: self.splitter.setSizes([self.splitter.size().height(), 50]) def unhideModList(self) -> None: if self.splitter.sizes()[0] < 10: self.splitter.setSizes([50, self.splitter.size().height()]) def log(self, message: Any) -> None: # format log messages to user readable output settings = QSettings() record = message.record message = record['message'] extra = record['extra'] level = record['level'].name.lower() name = str(extra['name'] ) if 'name' in extra and extra['name'] is not None else '' path = str(extra['path'] ) if 'path' in extra and extra['path'] is not None else '' dots = bool( extra['dots'] ) if 'dots' in extra and extra['dots'] is not None else False newline = bool( extra['newline'] ) if 'newline' in extra and extra['newline'] is not None else False output = bool( extra['output'] ) if 'output' in extra and extra['output'] is not None else bool( message) modlist = bool( extra['modlist'] ) if 'modlist' in extra and extra['modlist'] is not None else False if level in ['debug' ] and settings.value('debugOutput', 'False') != 'True': if newline: self.output.append(f'') return n = '<br>' if newline else '' d = '...' if dots else '' if len(name) and len(path): path = f' ({path})' if output: message = html.escape(message, quote=True) if level in ['success', 'error', 'warning']: message = f'<strong>{message}</strong>' if level in ['success']: message = f'<font color="#04c45e">{message}</font>' if level in ['error', 'critical']: message = f'<font color="#ee3b3b">{message}</font>' if level in ['warning']: message = f'<font color="#ff6500">{message}</font>' if level in ['debug', 'trace']: message = f'<font color="#aaa">{message}</font>' path = f'<font color="#aaa">{path}</font>' if path else '' d = f'<font color="#aaa">{d}</font>' if d else '' time = record['time'].astimezone( tz=None).strftime('%Y-%m-%d %H:%M:%S') message = f'<font color="#aaa">{time}</font> {message}' self.output.append( f'{n}{message.strip()}{" " if name or path else ""}{name}{path}{d}' ) else: self.output.append(f'') self.output.verticalScrollBar().setValue( self.output.verticalScrollBar().maximum()) self.output.repaint() if modlist: self.unhideModList() if settings.value('unhideOutput', 'True') == 'True' and output: self.unhideOutput()
def unpackList(self): key = self.mainWindow.detailTree.selectedKey() # Create dialog dialog = QDialog(self.mainWindow) dialog.setMinimumWidth(400) dialog.setWindowTitle("Extract data") layout = QFormLayout() dialog.setLayout(layout) # Extract key input input_extract = QLineEdit() input_extract.setFocus() input_extract.setText(key) layout.addRow("Key to extract:", input_extract) # Object ID key input input_id = QLineEdit() layout.addRow("Key for Object ID:", input_id) # Buttons buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addRow(buttons) def createNodes(): key_nodes = input_extract.text() key_objectid = input_id.text() if key_nodes == '': dialog.close() return False try: progress = ProgressBar("Extracting data...", self.mainWindow) selected = self.mainWindow.tree.selectionModel().selectedRows() progress.setMaximum(len(selected)) for item in selected: progress.step() if progress.wasCanceled: break if not item.isValid(): continue treenode = item.internalPointer() treenode.unpackList(key_nodes, key_objectid, delaycommit = True) except Exception as e: self.mainWindow.logmessage(e) finally: self.mainWindow.tree.treemodel.commitNewNodes() progress.close() dialog.close() return True def close(): dialog.close() # Connect the nested functions to the buttons buttons buttons.accepted.connect(createNodes) buttons.rejected.connect(close) # Open dialog dialog.exec_()
class UpdatePrompt(QDialog): def __init__(self): super().__init__() self.makeView() return def makeView(self): layout = QVBoxLayout() btnLayout = QHBoxLayout() self.centStack = QStackedWidget() self.updateButton = QPushButton('Update') self.cancelButton = QPushButton('Cancel') notifyLabel = QLabel('There are upgrades scheduled') self.inputBox = QLineEdit() self.outputBox = QTextBrowser() #refreshIcon = QIcon.fromTheme('process-working') self.refreshIcon = QMovie('assets/spin3.gif') refreshAnimation = QLabel() layout.addWidget(notifyLabel) layout.addWidget(self.centStack) layout.addWidget(self.inputBox) layout.addLayout(btnLayout) btnLayout.addWidget(self.cancelButton) btnLayout.addWidget(self.updateButton) self.centStack.addWidget(refreshAnimation) self.centStack.addWidget(self.outputBox) refreshAnimation.setMovie(self.refreshIcon) refreshAnimation.setAlignment(Qt.AlignCenter) self.refreshIcon.start() self.inputBox.setEchoMode(QLineEdit.Password) self.inputBox.setFocus() self.inputBox.returnPressed.connect(self.pkgUpdates) self.updateButton.clicked.connect(self.pkgUpdates) self.cancelButton.clicked.connect(self.cancelUpdates) self.updateButton.setDefault(True) self.centStack.setCurrentIndex(1) notifyLabel.setAlignment(Qt.AlignTop) self.outputBox.setReadOnly(True) #self.outputBox.setAlignment(Qt.AlignTop) self.setWindowTitle('Package Upgrades') self.setLayout(layout) self.resize(450, 250) return async def asetup(self, password): async with trio.open_nursery() as nursery: finishedState = trio.Event() nursery.start_soon(self.upProc, password, 'update', finishedState) #nursery.start_soon(self.KEAlive, finishedState) return async def upProc(self, password, cmd, finishedState): proc = await trio.open_process(['sudo', '-S', 'apt-get', cmd, '-y'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) await proc.stdin.send_all((password + '\n').encode()) while (proc.poll() == None): QCoreApplication.processEvents() await trio.sleep(0.1) result = '' result = await self.pullOutput(proc) self.appendToOutput(result) proc.terminate() if (cmd == 'update'): await self.upProc(password, 'upgrade', finishedState) finishedState.set() return async def pullOutput(self, proc): x = await proc.stdout.receive_some() x = x.decode() result = '' while (x != ''): QCoreApplication.processEvents() result = result + x x = await proc.stdout.receive_some() x = x.decode() return result async def KEAlive(self, finishedState): while finishedState.is_set(): QCoreApplication.processEvents() trio.sleep(0.1) return return def appendToOutput(self, add): currentText = self.outputBox.toPlainText() self.outputBox.setText(currentText + 'Running updates\n' + add + '\n') print(add) return def pkgUpdates(self): self.centStack.setCurrentIndex(0) self.refreshIcon.start() QCoreApplication.processEvents() password = self.inputBox.text() if (password == ''): self.passError('The password field cannot be empty') return self.inputBox.clear() self.inputBox.setDisabled(True) self.updateButton.setDisabled(True) trio.run(self.asetup, password) self.centStack.setCurrentIndex(1) self.refreshIcon.stop() self.updateButton.setDisabled(False) self.inputBox.setDisabled(False) return def passError(self, s): passError = QDialog(self) msg = QLabel(s) layout = QVBoxLayout() layout.addWidget(msg) passError.setLayout(layout) okBtn = QPushButton('OK') okBtn.clicked.connect(passError.reject) layout.addWidget(okBtn) passError.exec_() return def cancelUpdates(self): #Needs way of closing subprocess during async run self.reject() return
class ObjListWindow(PBDialog): """Create a window managing a list (of bibtexs or of experiments)""" def __init__(self, parent=None, gridLayout=False): """Init using parent class and create common definitions Parameters: parent: the parent object gridLayout (boolean, default False): if True, use a QGridLayout, otherwise a QVBoxLayout """ super(ObjListWindow, self).__init__(parent) self.tableWidth = None self.proxyModel = None self.gridLayout = gridLayout self.filterInput = None self.proxyModel = None self.tableview = None if gridLayout: self.currLayout = QGridLayout() else: self.currLayout = QVBoxLayout() self.setLayout(self.currLayout) def triggeredContextMenuEvent(self, row, col, event): """Not implemented: requires a subclass""" raise NotImplementedError() def handleItemEntered(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def cellDoubleClick(self, index): """Not implemented: requires a subclass""" raise NotImplementedError() def createTable(self, *args, **kwargs): """Not implemented: requires a subclass""" raise NotImplementedError() def changeFilter(self, string): """Change the filter of the current view. Parameter: string: the filter string to be matched """ self.proxyModel.setFilterRegExp(str(string)) def addFilterInput(self, placeholderText, gridPos=(1, 0)): """Add a `QLineEdit` to change the filter of the list. Parameter: placeholderText: the text to be shown when no filter is present gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.filterInput = QLineEdit("", self) self.filterInput.setPlaceholderText(placeholderText) self.filterInput.textChanged.connect(self.changeFilter) if self.gridLayout: self.currLayout.addWidget(self.filterInput, *gridPos) else: self.currLayout.addWidget(self.filterInput) self.filterInput.setFocus() def setProxyStuff(self, sortColumn, sortOrder): """Prepare the proxy model to filter and sort the view. Parameter: sortColumn: the index of the column to use for sorting at the beginning sortOrder: the order for sorting (`Qt.AscendingOrder` or `Qt.DescendingOrder`) """ self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setSourceModel(self.tableModel) self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setFilterKeyColumn(-1) self.tableview = PBTableView(self) self.tableview.setModel(self.proxyModel) self.tableview.setSortingEnabled(True) self.tableview.setMouseTracking(True) self.tableview.setSelectionBehavior(QAbstractItemView.SelectRows) try: self.tableview.sortByColumn(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.tableview.sortByColumn(sortColumn, sortOrder) try: self.proxyModel.sort(self.tableModel.header.index("bibkey"), Qt.AscendingOrder) except (IndexError, ValueError): pass self.proxyModel.sort(sortColumn, sortOrder) self.currLayout.addWidget(self.tableview) def finalizeTable(self, gridPos=(1, 0)): """Resize the table to fit the contents, connect functions, add to layout Parameter: gridPos (tuple): if gridLayout is active, the position of the `QLineEdit` in the `QGridLayout` """ self.tableview.resizeColumnsToContents() maxh = QDesktopWidget().availableGeometry().height() maxw = QDesktopWidget().availableGeometry().width() self.setMaximumHeight(maxh) self.setMaximumWidth(maxw) hwidth = self.tableview.horizontalHeader().length() swidth = self.tableview.style().pixelMetric(QStyle.PM_ScrollBarExtent) fwidth = self.tableview.frameWidth() * 2 if self.tableWidth is None: if hwidth > maxw - (swidth + fwidth): self.tableWidth = maxw - (swidth + fwidth) else: self.tableWidth = hwidth + swidth + fwidth self.tableview.setFixedWidth(self.tableWidth) self.setMinimumHeight(600) self.tableview.resizeColumnsToContents() self.tableview.resizeRowsToContents() self.tableview.entered.connect(self.handleItemEntered) self.tableview.clicked.connect(self.cellClick) self.tableview.doubleClicked.connect(self.cellDoubleClick) if self.gridLayout: self.currLayout.addWidget(self.tableview, *gridPos) else: self.currLayout.addWidget(self.tableview) def recreateTable(self): """Delete the previous table widget and other layout items, then create new ones """ self.cleanLayout() self.createTable()
class ResultWidget(QWidget): def __init__(self, route=None): super().__init__() layout = QVBoxLayout() self.route = route self.thread_pool = QThreadPool() layout_send = QHBoxLayout() self.send_button = QPushButton('Send') self.send_button.clicked.connect(self.make_request) self.search_line = QLineEdit() self.search_line.setPlaceholderText('Search') self.search_line.textChanged.connect(self.search_result_reset) self.search_line.returnPressed.connect(self.search_result) self.response_status_label = QLabel() self.response_status_label.setFont(FONT_ROUTE) self.response_status_label.hide() self.elapsed_time_label = QLabel() self.elapsed_time_label.setFont(FONT_ROUTE) self.elapsed_time_label.hide() self.search_summary_label = QLabel() self.search_summary_label.setFont(FONT_ROUTE) self.search_summary_label.hide() if route is not None: layout_send.addWidget(self.send_button) layout_send.addWidget(self.response_status_label) layout_send.addWidget(self.elapsed_time_label) layout_send.addStretch(1) layout_send.addWidget(self.search_summary_label) layout_send.addWidget(self.search_line) layout.addLayout(layout_send) self.result_text_edit = ResultTextEdit() self.result_text_edit.setReadOnly(True) self.result_text_edit.setFont(TEXT_FONT) self.result_text_edit.setContextMenuPolicy(Qt.NoContextMenu) self.result_text_edit.search.connect(self.focus) self.shortcut = QShortcut(QKeySequence("Ctrl+Return"), self, self.make_request) self.result_text_edit.setUndoRedoEnabled(False) self.highlighter = TextHighlighter(self.result_text_edit.document()) layout.addWidget(self.result_text_edit) if route is not None: saved_result = load_request_result(route) self.result_text_edit.setPlainText(saved_result) self.setLayout(layout) def goto(self, to): c = self.result_text_edit.textCursor() c.movePosition(to, QTextCursor.MoveAnchor, 1) self.result_text_edit.setTextCursor(c) def search_result_reset(self): self.goto(QTextCursor.Start) string_format = QTextCharFormat() string_format.setBackground(QColor('#668B8B')) extras = [] self.search_positions = [] while True: extra = QTextEdit.ExtraSelection() found = self.result_text_edit.find(self.search_line.text()) if not found: break extra.cursor = self.result_text_edit.textCursor() extra.format = string_format self.search_positions.append(extra.cursor.position()) extras.append(extra) self.result_text_edit.setExtraSelections(extras) self.goto(QTextCursor.Start) self.search_result() def search_result(self): p = self.result_text_edit.palette() p.setColor(QPalette.Highlight, QColor("#ee799f")) self.result_text_edit.setPalette(p) search_settings = QTextDocument.FindFlags() mod = QApplication.keyboardModifiers() if (mod & Qt.ShiftModifier) != 0: search_settings |= QTextDocument.FindBackward r = self.result_text_edit.find(self.search_line.text(), search_settings) if not r: if (mod & Qt.ShiftModifier) != 0: self.goto(QTextCursor.End) else: self.goto(QTextCursor.Start) self.result_text_edit.find(self.search_line.text(), search_settings) if self.search_line.text() == '': self.search_summary_label.hide() return current_position = self.result_text_edit.textCursor().position() try: current_index = self.search_positions.index(current_position) except ValueError: current_index = -1 self.search_summary_label.show() self.search_summary_label.setText( '%s/%s' % (current_index + 1, len(self.search_positions))) def focus(self): self.search_line.setFocus() self.search_line.selectAll() def make_request(self): self.response_status_label.hide() self.elapsed_time_label.hide() self.result_text_edit.setPlainText('Loading..') try: group_values, route_values = get_parameter_values_for_route( self.route) request = self.route.get_request(group_values, route_values) worker = RequestWorker( request.method, request.url, params=request.params, headers=request.headers, json=request.json, ) worker.signals.result.connect(self.set_result) self.thread_pool.start(worker) except CaribouException as e: self.result_text_edit.setPlainText(str(e)) except Exception: self.result_text_edit.setPlainText(traceback.format_exc()) def set_result(self, text, status_code, elapsed_time): if status_code == 0: self.response_status_label.hide() self.elapsed_time_label.hide() else: p = self.response_status_label.palette() if status_code == 200: self.response_status_label.setText(str(status_code) + ' OK') p.setColor(QPalette.WindowText, QColor('#1FDA9A')) else: self.response_status_label.setText(str(status_code) + ' ERROR') p.setColor(QPalette.WindowText, QColor('#DB3340')) self.response_status_label.setPalette(p) self.response_status_label.show() self.elapsed_time_label.setText('%s ms' % int(elapsed_time * 1000)) self.elapsed_time_label.show() self.result_text_edit.setUpdatesEnabled(False) self.result_text_edit.setPlainText(text) self.result_text_edit.setUpdatesEnabled(True) save_request_result(self.route, text) persist_storage()