class AutomatonStateManager(QWidget): signalStateIdsRequest = Signal() signalSetStartingStateRequest = Signal(str) signalSetCurrentStateRequest = Signal(str) def __init__(self, parent): super(AutomatonStateManager, self).__init__(parent) self.startingStateButton = QPushButton('Set starting state: ', self) self.startingStateButton.clicked.connect(self.setStartingState) self.startingSelect = QComboBox(self) self.currentStateButton = QPushButton('Set current state: ', self) self.currentStateButton.clicked.connect(self.setCurrentState) self.currentSelect = QComboBox(self) self.signalStateIdsRequest.emit() layout = QHBoxLayout() layout.addWidget(self.startingStateButton) layout.addWidget(self.startingSelect) layout.addWidget(self.currentStateButton) layout.addWidget(self.currentSelect) layout.setSizeConstraint(QLayout.SetMaximumSize) self.setLayout(layout) @Slot(list) def populateStateSelect(self, stateIds): self.startingSelect.clear() self.currentSelect.clear() for stateId in stateIds: self.startingSelect.addItem('q{}'.format(stateIds.index(stateId)), stateId) self.currentSelect.addItem('q{}'.format(stateIds.index(stateId)), stateId) self.startingSelect.setCurrentIndex(0) self.currentSelect.setCurrentIndex(0) @Slot() def setStartingState(self): stateId = self.startingSelect.currentData() self.signalSetStartingStateRequest.emit(stateId) @Slot() def setCurrentState(self): stateId = self.currentSelect.currentData() self.signalSetCurrentStateRequest.emit(stateId) @Slot() def disableEdit(self): self.startingSelect.setDisabled(True) self.startingStateButton.setDisabled(True) self.currentSelect.setDisabled(True) self.currentStateButton.setDisabled(True) @Slot() def enableEdit(self): self.startingSelect.setDisabled(False) self.startingStateButton.setDisabled(False) self.currentSelect.setDisabled(False) self.currentStateButton.setDisabled(False)
class WdParameterValueEdit(WdParameterEditBase): def __init__(self, parent=None): super().__init__('val', parent) self.edit_widget = QLineEdit() self.combo_widget = QComboBox() self.add_subwidget(self.edit_widget) self.add_subwidget(self.combo_widget) self.combo_widget.setVisible(False) self.edit_widget.editingFinished.connect(self.on_text_edited) self.combo_widget.activated.connect(self.on_combo_selected) def set_parameter(self, parameter: Parameter): use_combo = parameter.help_val is not None self.combo_widget.setVisible(use_combo) self.edit_widget.setVisible(not use_combo) if use_combo: vals, labels = parameter.values_choice() self.combo_widget.clear() self.combo_widget.addItems(labels) else: self.combo_widget.clear() super().set_parameter(parameter) @Slot() def on_text_edited(self): if self.wdparameter is not None: try: val = self.wdparameter.scan_str(self.edit_widget.text()) except: self.update_from_model() return self.set_model_value(val) @Slot(int) def on_combo_selected(self, index: int): if self.wdparameter is not None: vals, labels = self.wdparameter.values_choice() val = list(vals)[index] self.set_model_value(val) def set_view_value(self, value): if value is None: value = '' if not isinstance(value, str): vals, labels = self.wdparameter.values_choice() if labels: try: index = vals.index(value) except ValueError: index = -1 self.combo_widget.setCurrentIndex(index) else: if isinstance(self.wdparameter, IntParameter): value = f'{value:.0f}' else: value = f'{value:g}' self.edit_widget.setText(value) else: self.edit_widget.setText(value) self.combo_widget.setEditText(value)
class IccTableEditorYearSpecificView(IccTableEditorView): """ Eine von IccTableEditorView abgeleitete Klasse, die in der Toolbar neben dem Speichern-Button eine Jahr-Combobox hat. Sie wird mit den Methoden addJahr, addJahre, setCurrentJahr und clearJahre bedient. Wird das Jahr geändert, wird ein yearChanged-Signal gesendet. """ yearChanged = Signal(int) def __init__(self, model: XBaseTableModel = None): IccTableEditorView.__init__(self, model) self._cboYear = QComboBox() self._cboYear.setFont(QFont("Arial", 14, weight=QFont.Bold)) self._cboYear.currentTextChanged.connect(self.onCurrentYearChanged) self.addTool(self._cboYear) def addJahr(self, jahr: int): self._cboYear.addItem(str(jahr)) def addJahre(self, jahre: List[int]): self._cboYear.addItems([str(j) for j in jahre]) def setCurrentJahr(self, jahr: int): self._cboYear.setCurrentText(str(jahr)) def clearJahre(self): self._cboYear.clear() def onCurrentYearChanged(self, sJahrNeu: str): self.yearChanged.emit(int(sJahrNeu))
def add_supplier_list_to_combo(self, combo: QComboBox): # clear QComboBox combo.clear() combo.clearEditText() if self.parent.sheets is None: combo.setEnabled(False) return if self.db is None: self.flag_db = False combo.setEnabled(False) return # DB Query and update QConboBox sql = "SELECT name_supplier_short FROM supplier;" out = self.db.get(sql) for supplier in out: combo.addItem(supplier[0]) name = self.get_supplier_name() index = combo.findText(name) if index >= 0: combo.setCurrentIndex(index) combo.setEnabled(False) else: combo.setEnabled(True)
class Voyage(QWidget): def __init__(self, parent=None): super(Voyage, self).__init__(parent) self.data = np.loadtxt(open("DS_P6_Voyage_Data.txt", "r"), delimiter=";", skiprows=1, dtype='str') self.cbCompagnie = QComboBox() self.cbCompagnie.currentIndexChanged.connect(self.updateDestinations) self.cbDestination = QComboBox() self.cbDestination.currentIndexChanged.connect(self.updateCourbe) self.imgCourbe = QLabel() self.imgCourbe.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) genLayout = QHBoxLayout() layoutCombo = QVBoxLayout() layoutCombo.addWidget(self.cbCompagnie) layoutCombo.addWidget(self.cbDestination) genLayout.addLayout(layoutCombo) genLayout.addWidget(self.imgCourbe) self.setLayout(genLayout) self.updateCompagnie() def updateCompagnie(self): companies = np.unique(self.data[:,0]) self.cbCompagnie.addItems(companies) def updateDestinations(self): print("updateDestinations") self.cbDestination.clear() # vide la comboBox pour y afficher du nouveau contenu après companie = self.cbCompagnie.currentText() filtre1 = self.data[self.data[:,0]==companie] # conserve tous les éléments sur lignes contenant la compagnie selectionnée destinations = filtre1[:, 4] self.cbDestination.addItems(np.unique(destinations)) self.updateCourbe() def updateCourbe(self): companie = self.cbCompagnie.currentText() filtre1 = self.data[self.data[:, 0] == companie] destination = self.cbDestination.currentText() filtre2 = filtre1[filtre1[:,4]==destination] tarifs = filtre2[:,1] plt.plot(tarifs) plt.savefig('tutu.png', format='png') # creation d'un fichier temporaire self.imgCourbe.setPixmap('tutu.png') plt.clf()
class Voyage(QWidget): def __init__(self, parent=None): super(Voyage, self).__init__(parent) self.data = np.loadtxt(open("voyage.csv", "r"), delimiter=";", skiprows=1, dtype='str') self.cbCompagnie = QComboBox() self.cbCompagnie.currentIndexChanged.connect(self.updateDestinations) self.cbDestination = QComboBox() self.cbDestination.currentIndexChanged.connect(self.updateCourbe) self.imgCourbe = QLabel() self.imgCourbe.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) genLayout = QHBoxLayout() layoutCombo = QVBoxLayout() layoutCombo.addWidget(self.cbCompagnie) layoutCombo.addWidget(self.cbDestination) genLayout.addLayout(layoutCombo) genLayout.addWidget(self.imgCourbe) self.setLayout(genLayout) self.updateCompagnie() def updateCompagnie(self): companies = np.unique(self.data[:,0]) self.cbCompagnie.addItems(companies) def updateDestinations(self): print("updateDestinations") self.cbDestination.clear() companie = self.cbCompagnie.currentText() filtre1 = self.data[self.data[:,0]==companie] destinations = filtre1[:, 4] self.cbDestination.addItems(np.unique(destinations)) self.updateCourbe() def updateCourbe(self): companie = self.cbCompagnie.currentText() filtre1 = self.data[self.data[:, 0] == companie] destination = self.cbDestination.currentText() filtre2 = filtre1[filtre1[:,4]==destination] tarifs = filtre2[:,1] plt.plot(tarifs) plt.savefig('tutu.png', format='png') self.imgCourbe.setPixmap('tutu.png') plt.clf()
class Code(QWidget): TRIAL_STATUS = ('on', 'off') def __init__(self, callback): super().__init__() self.callback = callback trial_label = QLabel('Trial:') self.trial_box = QSpinBox() self.trial_box.setFixedWidth(64) self.trial_box.setValue(1) #self.trial_box.setFocusPolicy(Qt.NoFocus) trial_status_label = QLabel('Trial Status:') self.trial_status = QComboBox() self.trial_status.addItems(self.TRIAL_STATUS) self.trial_status.setFocusPolicy(Qt.NoFocus) response_label = QLabel('Response:') self.response_box = QComboBox() self.response_box.setFocusPolicy(Qt.NoFocus) self.record_button = QPushButton('Record Event') self.record_button.clicked.connect(self.record_event) self.record_button.setEnabled(False) self.record_button.setFocusPolicy(Qt.NoFocus) layout = QHBoxLayout() layout.addWidget(trial_label) layout.addWidget(self.trial_box) layout.addWidget(trial_status_label) layout.addWidget(self.trial_status) layout.addWidget(response_label) layout.addWidget(self.response_box) layout.addStretch() layout.addWidget(self.record_button) self.setLayout(layout) def set_responses(self, responses): self.response_box.clear() self.response_box.addItems(responses) def record_event(self): event = Event(trial=self.trial_box.value(), status=self.trial_status.currentText() == 'on', response=self.response_box.currentText()) if self.trial_status.currentText() == 'off': self.trial_box.setValue(self.trial_box.value() + 1) self.trial_status.setCurrentText('on') self.callback(event)
def get_filelist(self, combo: QComboBox): combo.clear() combo.clearEditText() # SQLite con = sqlite3.connect(self.dbname) cur = con.cursor() cur.execute("SELECT name_file FROM file;") out = cur.fetchall() con.close() # add list of file to QComboBox for name_file in out: combo.addItem(name_file[0])
class StateManager(QWidget): signalStateIdsRequest = Signal() signalStateAdded = Signal() signalStateRemoveRequest = Signal(object) def __init__(self, parent): super(StateManager, self).__init__(parent) self.addButton = QPushButton('Add state...', self) self.addButton.clicked.connect(self.addState) self.removeButton = QPushButton('Remove state: ', self) self.removeButton.clicked.connect(self.removeState) self.stateSelect = QComboBox(self) layout = QHBoxLayout() layout.addWidget(self.addButton) layout.addWidget(self.removeButton) layout.addWidget(self.stateSelect) layout.setSizeConstraint(QLayout.SetMaximumSize) self.setLayout(layout) @Slot(list) def populateStateSelect(self, stateIds): self.stateSelect.clear() for stateId in stateIds: self.stateSelect.addItem('q{}'.format(stateIds.index(stateId)), stateId) self.stateSelect.setCurrentIndex(0) @Slot() def addState(self): self.signalStateAdded.emit() @Slot() def removeState(self): stateId = self.stateSelect.currentData() self.signalStateRemoveRequest.emit(stateId) @Slot() def disableEdit(self): self.stateSelect.setDisabled(True) self.addButton.setDisabled(True) self.removeButton.setDisabled(True) @Slot() def enableEdit(self): self.stateSelect.setDisabled(False) self.addButton.setDisabled(False) self.removeButton.setDisabled(False)
class ComboPlotWidget(PlotWidget): def __init__(self, parent=None): super().__init__(parent) self.combo = QComboBox() self.combo.setFixedWidth(150) self.lay.insertWidget(0, self.combo, alignment=QtCore.Qt.AlignCenter) self.lay.setMargin(0) self.lay.setSpacing(0) @Slot(list) def update_combo_box(self, data): self.combo.clear() for item in data: self.combo.addItem(item)
class ComboBox(QWidget): def __init__(self, parent=None, items=[]): super(ComboBox, self).__init__(parent) layout = QHBoxLayout() self.cb = QComboBox() self.items = items self.cb.addItems(self.items) self.cb.currentIndexChanged.connect(parent.comboSelectionChanged) layout.addWidget(self.cb) self.setLayout(layout) def update_items(self, items): self.items = items self.cb.clear() self.cb.addItems(self.items)
class DataTabel(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.combo_file = QComboBox() label1 = QLabel("Input:") self.data_models = {} self.table_view = QTableView() layout1 = QHBoxLayout() layout1.addWidget(label1) layout1.addWidget(self.combo_file) layout1.setStretch(1, 1) self.layout2 = QVBoxLayout() self.layout2.addLayout(layout1) self.layout2.addWidget(self.table_view) self.setLayout(self.layout2) self.combo_file.currentIndexChanged.connect(self.update_model) def initialize(self, data_sets): self.combo_file.clear() for (file_name, data_frame) in data_sets.items(): self.combo_file.addItem(file_name) model = DataModel(data_frame) self.data_models[file_name] = model if (self.combo_file.count() != 0): self.combo_file.setCurrentIndex(self.combo_file.count() - 1) self.update_model() def update_model(self): if (self.combo_file.currentText() in self.data_models): self.table_view.setModel( self.data_models[self.combo_file.currentText()]) else: self.table_view.setModel(DataModel()) def current_file(self): return self.combo_file.currentText()
class Widget(QWidget): """ 主窗口内的控件 """ def __init__(self, success_window): super().__init__() self.success_window = success_window self.sheetnames = "" # 左上的软件说明 self.description = QLabel('''软件说明: 处理Excel表格工具合集(校务数据中心自家用) 已实现功能: 1. 解除合并单元格并填充 2. 中式表头表格转换(转置) 3. 中式表头表格转换(只处理上表头) 4. 去除前后特定字符 5. 基于SHA256的文件加密 6. 表头转拼音首字母 7. 数据脱敏''') self.description.setGeometry(QRect(328, 240, 329, 27 * 4)) self.description.setWordWrap(True) self.description.setAlignment(Qt.AlignTop) # 右边的程序输出信息框 self.output_info = QTextEdit() self.output_info.setReadOnly(True) # 左下的文件读取路径 self.file_path_text = QLabel("表格所在位置:") self.file_path = QLineEdit() self.file_path.setReadOnly(True) self.file_path_button = QPushButton("打开") self.file_path_button.clicked.connect(self.open_file) # 左下的工作表名称 self.sheet_name_text = QLabel("工作表名称:") self.sheet_name_box = QComboBox() # 左下的工具按钮 self.unmerge_tool_button = QPushButton("解除合并单元格") self.unmerge_tool_button.clicked.connect(self.unmerge) self.transform_tool1_button = QPushButton("行列转置") self.transform_tool2_button = QPushButton("只处理上表头") self.strip_button = QPushButton("去除前后特定字符") self.encrypt_button = QPushButton("文件加密解密") self.pinyin_button = QPushButton("表头转拼音") self.pinyin_button.clicked.connect(self.pinyin) self.desensitize_button = QPushButton("数据脱敏") # 布局 self.layout = QHBoxLayout() self.file_path_layout = QHBoxLayout() self.button_layout1 = QHBoxLayout() self.button_layout2 = QHBoxLayout() self.left_layout = QVBoxLayout() self.sheet_name_layout = QHBoxLayout() # 将工具加入到布局 self.button_layout1.addWidget(self.unmerge_tool_button) self.button_layout1.addWidget(self.transform_tool1_button) self.button_layout1.addWidget(self.transform_tool2_button) self.button_layout2.addWidget(self.strip_button) self.button_layout2.addWidget(self.encrypt_button) self.button_layout2.addWidget(self.pinyin_button) self.button_layout2.addWidget(self.desensitize_button) self.file_path_layout.addWidget(self.file_path_text) self.file_path_layout.addWidget(self.file_path) self.file_path_layout.addWidget(self.file_path_button) self.sheet_name_layout.addWidget(self.sheet_name_text) self.sheet_name_layout.addWidget(self.sheet_name_box) self.left_layout.addWidget(self.description) self.left_layout.addLayout(self.file_path_layout) self.left_layout.addLayout(self.sheet_name_layout) self.left_layout.addLayout(self.button_layout1) self.left_layout.addLayout(self.button_layout2) self.layout.addLayout(self.left_layout) self.layout.addWidget(self.output_info) # 应用layout self.setLayout(self.layout) @Slot() def open_file(self): excel_file, _ = QFileDialog.getOpenFileName(self, 'Open file', '.', 'All Files (*)') if excel_file != "": logging.info("打开" + excel_file) self.file_path.setText(excel_file) file_type = excel_file.split('.')[-1] self.sheet_name_box.clear() if file_type == 'xlsx': self.sheetnames = show_sheetnames(excel_file) self.sheet_name_box.addItems(self.sheetnames) output = "打开{}\n工作表名称:\n".format(excel_file) for sheetname in self.sheetnames: output += sheetname + "\n" self.show_text(output) else: output = "打开" + excel_file + '\n' self.show_text(output) @Slot() def unmerge(self): filename = self.file_path.text() sheetname = self.sheet_name_box.currentText() if ExistUtil.check_exists(filename, sheetname): excel_loader = ExcelLoader(filename, sheetname) workbook, worksheet = excel_loader.load_excel() logging.info("读取{}成功!".format(filename)) self.show_text("读取{}成功!".format(filename)) unmerge_tool = UnmergeTool(workbook, worksheet) new_workbook, new_worksheet = unmerge_tool.excute() new_workbook.save( filename.split('/')[-1].replace( ".xlsx", "_" + sheetname + "_unmerged.xlsx")) logging.info("解除合并单元格成功!") self.show_text("解除合并单元格成功!") self.show_text("--------------------") self.success_window.show() @Slot() def pinyin(self): filename = self.file_path.text() sheetname = self.sheet_name_box.currentText() if ExistUtil.check_exists(filename, sheetname): excel_loader = ExcelLoader(filename, sheetname) workbook, worksheet = excel_loader.load_excel() logging.info("读取{}成功!".format(filename)) self.show_text("读取{}成功!".format(filename)) transformTool3 = TransformTool3(workbook, worksheet) new_workbook = transformTool3.excute() new_workbook.save( filename.split('/')[-1].replace( ".xlsx", "_" + sheetname + "(表头转拼音).xlsx")) logging.info("表头转拼音成功!") self.show_text("表头转拼音成功!") self.show_text("--------------------") self.success_window.show() def show_text(self, info: str): temp = self.output_info.toPlainText() + info + '\n' self.output_info.setPlainText(temp)
class QFileDescriptorViewer(QFrame): """ embeded in `StateInspector` Display content of a file descriptor ( include stdin/stdout/stderr ) for the selected state. """ STD = { 0: "stdin", 1: "stdout", 2: "stderr", } def __init__(self, state, parent, workspace): super().__init__(parent) self._state = state # type: SimState self.workspace = workspace self.select_fd = None self._current_fd = None self.textedit = None self._state.am_subscribe(self._watch_state) def dump_fd(self, fd): # Clean up when nothing is selected if fd == -1: self._current_fd = None self.textedit.setPlainText("") return if self._state.am_none: return self._current_fd = fd self.textedit.setPlainText( self._state.posix.dumps(fd).decode("ascii", "ignore").replace( "\x00", "\\x00")) def save_as(self): if self._state.am_none or self._current_fd is None: return filename, folder = QFileDialog.getSaveFileName(self, "Save content to ...", "", "Any file (*);") if filename and folder: save_to = os.path.join(folder, filename) open(save_to, "wb").write(self._state.posix.dumps(self._current_fd)) def _init_widgets(self): layout = QVBoxLayout() self.select_fd = QComboBox(self) self.select_fd.currentIndexChanged.connect(self.dump_fd) layout.addWidget(self.select_fd) self.textedit = QTextEdit(self) self.textedit.setAcceptRichText(False) self.textedit.setReadOnly(True) layout.addWidget(self.textedit) save_as = QPushButton("Save as...", self) save_as.clicked.connect(self.save_as) layout.addWidget(save_as) self.setLayout(layout) def _watch_state(self, **kwargs): # pylint: disable=unused-argument if self._state.am_none: return if self.select_fd is None: self._init_widgets() self.select_fd.clear() for fd, simfile in self._state.posix.fd.items(): if fd in self.STD: self.select_fd.addItem(self.STD[fd]) elif isinstance(simfile, SimFileDescriptor): self.select_fd.addItem(str(simfile.file.name)) else: self.select_fd.addItem(str(simfile))
class GraphFormWidget(QWidget): def __init__(self): QWidget.__init__(self) self.layout = self.CreateLayout() self.setLayout(self.layout) #Layout design def CreateLayout(self): globalLayout = QVBoxLayout() label_cat = QLabel("Category : ") self.cb_cat = QComboBox() self.cb_cat.addItems(["Active", "Control", "Death"]) self.cb_cat.currentIndexChanged.connect(self.cb_category_index_changed) label_patient = QLabel("Patient : ") self.cb_patient = QComboBox() self.cb_patient.addItems(GraphFormWidget.FindPatients(self.cb_cat.currentText())) label_electrode = QLabel("Electrode : ") self.cb_electrode = QComboBox() self.cb_electrode.addItems(getElectrodesList()) label_wave = QLabel("Wave type : ") self.cb_wave = QComboBox() self.cb_wave.addItems(["Alpha", "Beta", "Theta", "Delta"]) firstRowLayout = QHBoxLayout() firstRowLayout.setMargin(10) firstRowLayout.setSpacing(10) firstRowLayout.addWidget(label_cat) firstRowLayout.addWidget(self.cb_cat) firstRowLayout.addWidget(label_patient) firstRowLayout.addWidget(self.cb_patient) firstRowLayout.addWidget(label_electrode) firstRowLayout.addWidget(self.cb_electrode) firstRowLayout.addWidget(label_wave) firstRowLayout.addWidget(self.cb_wave) DefineLayoutChildAlignment(firstRowLayout, Qt.AlignHCenter) globalLayout.addItem(firstRowLayout) self.heatMapBtn = QPushButton("Show heatmap") self.heatMapBtn.clicked.connect(self.heatMapBtnClick) showBtn = QPushButton("Show graph") showBtn.clicked.connect(self.showBtnClick) secondRowLayout = QHBoxLayout() secondRowLayout.setMargin(10) secondRowLayout.setSpacing(10) secondRowLayout.addWidget(self.heatMapBtn) secondRowLayout.addWidget(showBtn) DefineLayoutChildAlignment(secondRowLayout, Qt.AlignHCenter) globalLayout.addItem(secondRowLayout) self.graphWidget = GraphWidget() globalLayout.addWidget(self.graphWidget) return globalLayout #Get list of patients def FindPatients(directory): return os.listdir('./Datas/' + directory) #Update list of patients when combobox changed def cb_category_index_changed(self, index): self.cb_patient.clear() self.cb_patient.addItems(GraphFormWidget.FindPatients(self.cb_cat.currentText())) #Load graph def showBtnClick(self): datas = getRawDatas(self.cb_patient.currentText(), self.cb_cat.currentText(), self.cb_wave.currentText()) datas = [datas['t'], datas[self.cb_electrode.currentText()]] self.graphWidget.Load(datas) #Load heatmap def heatMapBtnClick(self): self.htmapwidget = HeatMapWidget() self.htmapwidget.Load(self.cb_patient.currentText(), self.cb_cat.currentText(), self.cb_wave.currentText()) self.htmapwidget.show()
class CreationContainer(QWidget): """ Apparently just another level of parent class for social link display. Man I was stupid. Still am luigi2hands :param MainFrame mainframe: application mainframe :param QWidget op: parent widget :param int load: index to load maybe? """ def __init__(self, mainframe, op, load): QWidget.__init__(self) self.mainframe = mainframe self.op = op self.op.cc = self self.load = load # View initializers... self.actions = None self.window = None self.initUI() self.op.grid.addWidget(self, 0, 0, 2, 10) def initUI(self): """ Initialize the GUI. Does lots of stuff. """ self.grid = QGridLayout() self.setLayout(self.grid) self.actions = self.op.link.getIDs() self.actions.append("New element") types = ["Info", "Speak", "Camera Change", "Movement"] self.save = QPushButton(self, text="Save") self.grid.addWidget(self.save, 3, 0) self.existing_connections = QListWidget(self) self.populateExistingConnections() self.grid.addWidget(self.existing_connections, 1, 5, 2, 1) self.next = QComboBox(self) self.next.addItems(self.actions) self.next.setMaximumWidth(150) if self.load != 0: self.next.setCurrentIndex(self.op.i) self.grid.addWidget(self.next, 3, 2) self.window = None self.actOM = QComboBox(self) self.actOM.addItems(types) self.actOM.activated.connect(self.changeFrame) self.grid.addWidget(self.actOM, 0, 0, 1, 2) self.connect() self.next.setCurrentIndex(self.next.count() - 1) self.backB = QPushButton(self, text="Back to List Menu") self.backB.clicked.connect(self.back) self.grid.addWidget(self.backB, 3, 4) self.lead = QLabel(self, text="Leads to:") self.lead.setAlignment(Qt.AlignRight) self.grid.addWidget(self.lead, 3, 1) self.connectB = QPushButton(self, text="Connect") self.connectB.clicked.connect(self.lightConnect) self.grid.addWidget(self.connectB, 3, 3) self.follow_path = QPushButton(self, text="Enter linked element") self.follow_path.clicked.connect(self.follow) self.grid.addWidget(self.follow_path, 0, 6, 2, 1) self.rmvRel = QPushButton(self, text="Remove this connection") self.rmvRel.clicked.connect(self.removeRelation) self.grid.addWidget(self.rmvRel, 1, 6, 2, 1) self.conLab = QLabel(self, text="This action connects to:") self.grid.addWidget(self.conLab, 0, 5) def removeRelation(self): """ Remove a relation, which will also delete the uniquely dependant subtree. """ if not self.existing_connections.currentItem() or \ not popup("Are you sure you want to remove this relation? Any elements with a unique dependancy " "on this relation will also be deleted.\nIt is highly recommended you take a look at " "the graphical view of the tree in order to see the potential effects of the deletion.", "Warning"): return self.op.link.delRelation( self.op.i, self.actions.index(self.existing_connections.currentItem().text())) self.populateExistingConnections() self.updateElementList() self.op.linkstored.save() def populateExistingConnections(self): """ Display all the existing connections of the current node. """ self.existing_connections.clear() for relation in self.op.link.getRelations(self.op.i): self.existing_connections.addItem( self.op.link.getOneID(self.op.link.getItem(relation))) def back(self): """ Return to the higher-level cutscene container view... """ if not popup("Return to list main menu?\n(Lose any unsaved changes)", "Warning"): return self.close() self.op.cc = None self.op.viewF(False) def follow(self): """ Move on to the edit view of the selected relationship. """ if not self.existing_connections.currentItem() or \ self.existing_connections.currentItem().text() == "": return self.next.setCurrentIndex([ self.next.itemText(i) for i in range(self.next.count()) ].index(self.existing_connections.currentItem().text())) self.op.i = self.actions.index(self.next.currentText()) self.connect() self.next.setCurrentIndex(self.next.count() - 1) def lightConnect(self): """ Create a relationship between the current action and another. """ if not self.checkCached(): popup("Please save this action before linking it to a new one", "Information") return if self.next.currentText() == "New element": self.op.link.addRelation(self.op.i, self.op.link.size()) print("Linked to index " + str(self.op.link.size())) self.op.i = self.op.link.size() self.load = 0 self.changeFrame(0) self.updateElementList() else: self.op.link.addRelation( self.op.i, self.actions.index(self.next.currentText())) print("Linked to index " + str(self.actions.index(self.next.currentText()))) self.populateExistingConnections() def connect(self): """ Create a relationship between the current action and another, and enter the edit view of the relationship. :raises Exception: if the requested new action's type can't be processed (should never happen) """ print(self.next.currentText()) if self.next.currentText() == "New element": self.load = 0 self.changeFrame(0) else: if isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Info): self.actOM.setCurrentIndex(0) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Speak): self.actOM.setCurrentIndex(1) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Camera): self.actOM.setCurrentIndex(2) elif isinstance( self.op.link.getItem( self.actions.index(self.next.currentText())), Movement): self.actOM.setCurrentIndex(3) else: raise Exception("Not a type!") self.load = self.op.link.getItem( self.actions.index(self.next.currentText())) self.changeFrame(0) def checkCached(self): """ Check if the current element has been saved before. :returns: if the element has been saved :rtype: bool """ print(len(self.op.link.items) - 1) print(self.op.i) if self.op.link.getItem(self.op.i) == []: return False return True def updateElementList(self): """ Update the relationships list, I think. """ self.next.clear() self.actions = self.op.link.getIDs() self.actions.append("New element") self.next.addItems(self.actions) self.next.setCurrentIndex(len(self.actions) - 1) def changeFrame(self, _): """ Change view to edit a certain type of action. :param objct _: unused, but required by caller """ print("Changed to " + self.actOM.currentText()) try: self.window.close() except AttributeError: pass # No window open if self.actOM.currentText() == "Speak": self.window = SpeakFrame(self, self.load) elif self.actOM.currentText() == "Camera Change": self.window = CameraFrame(self, self.load) elif self.actOM.currentText() == "Movement": self.window = MoveFrame(self, self.load) else: # self.actOM.currentText() == "Info": self.window = InfoFrame(self, self.load) try: self.save.clicked.disconnect() except: #pylint: disable=bare-except pass self.save.clicked.connect(self.window.save) self.populateExistingConnections() self.updateElementList()
class NGL_HKLViewer(QWidget): def __init__(self, parent=None): super(NGL_HKLViewer, self).__init__(parent) self.verbose = 0 self.UseOSbrowser = False self.jscriptfname = "" self.devmode = False for e in sys.argv: if "verbose" in e: self.verbose = e.split("verbose=")[1] if "UseOSbrowser" in e: self.UseOSbrowser = e.split("UseOSbrowser=")[1] if "jscriptfname" in e: self.jscriptfname = e.split("jscriptfname=")[1] if "devmode" in e: self.devmode = True self.zmq_context = None self.bufsize = 20000 self.originalPalette = QApplication.palette() self.openFileNameButton = QPushButton("Load reflection file") self.openFileNameButton.setDefault(True) self.openFileNameButton.clicked.connect(self.OpenReflectionsFile) self.debugbutton = QPushButton("Debug") self.debugbutton.clicked.connect(self.DebugInteractively) self.settingsbtn = QPushButton("Settings") self.settingsbtn.clicked.connect(self.SettingsDialog) self.mousemoveslider = QSlider(Qt.Horizontal) self.mousemoveslider.setMinimum(0) self.mousemoveslider.setMaximum(300) self.mousemoveslider.setValue(0) self.mousemoveslider.sliderReleased.connect( self.onFinalMouseSensitivity) self.mousemoveslider.valueChanged.connect(self.onMouseSensitivity) self.mousesensitxtbox = QLineEdit('') self.mousesensitxtbox.setReadOnly(True) self.fontspinBox = QDoubleSpinBox() self.fontspinBox.setSingleStep(1) self.fontspinBox.setRange(4, 50) self.font = QFont() self.font.setFamily(self.font.defaultFamily()) self.fontspinBox.setValue(self.font.pointSize()) #self.fontspinBox.setValue(self.font.pixelSize()) self.fontspinBox.valueChanged.connect(self.onFontsizeChanged) self.Fontsize_labeltxt = QLabel() self.Fontsize_labeltxt.setText("Font size:") self.cameraPerspectCheckBox = QCheckBox() self.cameraPerspectCheckBox.setText("Perspective camera") self.cameraPerspectCheckBox.clicked.connect(self.onCameraPerspect) self.cameraPerspectCheckBox.setCheckState(Qt.Unchecked) self.settingsform = SettingsForm(self) self.MillerComboBox = QComboBox() self.MillerComboBox.activated.connect(self.onMillerComboSelchange) #self.MillerComboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.MillerLabel = QLabel() self.MillerLabel.setText("Selected HKL Scene") self.HKLnameedit = QLineEdit('') self.HKLnameedit.setReadOnly(True) self.textInfo = QTextEdit() self.textInfo.setLineWrapMode(QTextEdit.NoWrap) self.textInfo.setReadOnly(True) labels = [ "Label", "Type", "no. of HKLs", "Span of HKLs", "Min Max data", "Min Max sigmas", "d_min, d_max", "Symmetry unique", "Anomalous" ] self.millertable = QTableWidget(0, len(labels)) self.millertable.setHorizontalHeaderLabels(labels) self.millertable.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) # don't allow editing this table self.millertable.setEditTriggers(QTableWidget.NoEditTriggers) self.createExpansionBox() self.createFileInfoBox() self.CreateSliceTabs() self.createRadiiScaleGroupBox() self.createBinsBox() self.CreateFunctionTabs() mainLayout = QGridLayout() mainLayout.addWidget(self.FileInfoBox, 0, 0) mainLayout.addWidget(self.MillerLabel, 1, 0) mainLayout.addWidget(self.MillerComboBox, 2, 0) mainLayout.addWidget(self.functionTabWidget, 3, 0) mainLayout.addWidget(self.settingsbtn, 4, 0, 1, 1) #import code, traceback; code.interact(local=locals(), banner="".join( traceback.format_stack(limit=10) ) ) if self.UseOSbrowser == False: self.BrowserBox = QWebEngineView() mainLayout.addWidget(self.BrowserBox, 0, 1, 5, 3) self.BrowserBox.setUrl("https://cctbx.github.io/") #self.BrowserBox.setUrl("https://webglreport.com/") #self.BrowserBox.loadFinished.connect(self.onLoadFinished) mainLayout.setColumnStretch(2, 1) mainLayout.setRowStretch(0, 1) mainLayout.setRowStretch(1, 0) mainLayout.setRowStretch(2, 1) mainLayout.setRowStretch(3, 1) mainLayout.setColumnStretch(4, 0) self.setLayout(mainLayout) self.setWindowTitle("HKL-Viewer") self.cctbxproc = None self.LaunchCCTBXPython() self.out = None self.err = None self.comboviewwidth = 0 self.hklscenes_arrays = [] self.array_infotpls = [] self.matching_arrays = [] self.bin_infotpls = None self.bin_opacities = None self.html_url = "" self.spacegroups = [] self.info = [] self.infostr = "" self.fileisvalid = False self.NewFileLoaded = False self.NewHKLscenes = False self.updatingNbins = False self.binstableitemchanges = False self.show() def SettingsDialog(self): self.settingsform.show() def update(self): if self.cctbxproc: if self.cctbxproc.stdout: print(self.cctbxproc.stdout.read().decode("utf-8")) if self.cctbxproc.stderr: print(self.cctbxproc.stderr.read().decode("utf-8")) if self.out: print(self.out.decode("utf-8")) if self.err: print(self.err.decode("utf-8")) if self.zmq_context: try: msg = self.socket.recv( flags=zmq.NOBLOCK ) #To empty the socket from previous messages msgstr = msg.decode() self.infodict = eval(msgstr) #print("received from cctbx: " + str(self.infodict)) if self.infodict: if self.infodict.get("hklscenes_arrays"): self.hklscenes_arrays = self.infodict.get( "hklscenes_arrays", []) if self.infodict.get("array_infotpls"): self.array_infotpls = self.infodict.get( "array_infotpls", []) if self.infodict.get("bin_data_label"): self.BinDataComboBox.setCurrentText( self.infodict["bin_data_label"]) if self.infodict.get("bin_infotpls"): self.bin_infotpls = self.infodict["bin_infotpls"] self.nbins = len(self.bin_infotpls) self.updatingNbins = True self.Nbins_spinBox.setValue(self.nbins) self.updatingNbins = False self.binstable.clearContents() self.binstable.setRowCount(self.nbins) for row, bin_infotpl in enumerate(self.bin_infotpls): for col, elm in enumerate(bin_infotpl): # only allow changing the last column with opacity values if col != 3: item = QTableWidgetItem(str(elm)) else: item = QTableWidgetItem() item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setCheckState(Qt.Checked) item.setFlags(item.flags() ^ Qt.ItemIsEditable) self.binstable.setItem(row, col, item) if self.bin_opacities: self.update_table_opacities() if self.infodict.get("bin_opacities"): self.bin_opacities = self.infodict["bin_opacities"] if self.binstable.rowCount() > 0: self.update_table_opacities() if self.infodict.get("html_url"): self.html_url = self.infodict["html_url"] if self.UseOSbrowser == False: self.BrowserBox.setUrl(self.html_url) # workaround for background colour bug in chromium # https://bugreports.qt.io/browse/QTBUG-41960 self.BrowserBox.page().setBackgroundColor( QColor(100, 100, 100, 1.0)) if self.infodict.get("spacegroups"): self.spacegroups = self.infodict.get("spacegroups", []) self.SpaceGroupComboBox.clear() self.SpaceGroupComboBox.addItems(self.spacegroups) if self.infodict.get("merge_data"): self.mergedata = self.infodict["merge_data"] currentinfostr = "" if self.infodict.get("info"): currentinfostr = self.infodict.get("info", []) if self.infodict.get("NewFileLoaded"): self.NewFileLoaded = self.infodict.get( "NewFileLoaded", False) if self.infodict.get("NewHKLscenes"): self.NewHKLscenes = self.infodict.get( "NewHKLscenes", False) self.fileisvalid = True #print("ngl_hkl_infodict: " + str(ngl_hkl_infodict)) if currentinfostr: #print(currentinfostr) self.infostr += currentinfostr + "\n" # display no more than self.bufsize bytes of text self.infostr = self.infostr[-self.bufsize:] self.textInfo.setPlainText(self.infostr) self.textInfo.verticalScrollBar().setValue( self.textInfo.verticalScrollBar().maximum()) if self.NewFileLoaded and self.NewHKLscenes: #if self.mergedata == True : val = Qt.CheckState.Checked #if self.mergedata == None : val = Qt.CheckState.PartiallyChecked #if self.mergedata == False : val = Qt.CheckState.Unchecked #self.mergecheckbox.setCheckState(val ) #print("got hklscenes: " + str(self.hklscenes_arrays)) self.MillerComboBox.clear() self.MillerComboBox.addItems( [e[3] for e in self.hklscenes_arrays]) self.MillerComboBox.setCurrentIndex( -1) # unselect the first item in the list self.comboviewwidth = 0 for e in self.hklscenes_arrays: self.comboviewwidth = max( self.comboviewwidth, self.MillerComboBox.fontMetrics().width(e[3])) self.MillerComboBox.view().setMinimumWidth( self.comboviewwidth) self.millertable.clearContents() self.millertable.setRowCount(len( self.hklscenes_arrays)) for n, millarr in enumerate(self.array_infotpls): for m, elm in enumerate(millarr): self.millertable.setItem( n, m, QTableWidgetItem(str(elm))) self.functionTabWidget.setDisabled(True) self.NewFileLoaded = False if self.NewHKLscenes: self.BinDataComboBox.clear() self.BinDataComboBox.addItems( ["Resolution"] + [e[3] for e in self.hklscenes_arrays]) self.BinDataComboBox.view().setMinimumWidth( self.comboviewwidth) #self.BinDataComboBox.setCurrentIndex(-1) # unselect the first item in the list self.NewHKLscenes = False except Exception as e: errmsg = str(e) if "Resource temporarily unavailable" not in errmsg: print(errmsg + traceback.format_exc(limit=10)) pass def onFinalMouseSensitivity(self): val = self.mousemoveslider.value() / 100.0 self.NGL_HKL_command( 'NGL_HKLviewer.viewer.NGL.mouse_sensitivity = %f' % val) def onMouseSensitivity(self): val = self.mousemoveslider.value() / 100.0 self.mousesensitxtbox.setText("%2.2f" % val) def onFontsizeChanged(self, val): font = app.font() font.setPointSize(val) app.setFont(font) self.settingsform.setFixedSize(self.settingsform.sizeHint()) def onCameraPerspect(self, val): if self.cameraPerspectCheckBox.isChecked(): self.NGL_HKL_command("NGL_HKLviewer.camera_type = perspective") else: self.NGL_HKL_command("NGL_HKLviewer.camera_type = orthographic") def MergeData(self): if self.mergecheckbox.checkState() == Qt.CheckState.Checked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = True') if self.mergecheckbox.checkState() == Qt.CheckState.PartiallyChecked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = None') if self.mergecheckbox.checkState() == Qt.CheckState.Unchecked: self.NGL_HKL_command('NGL_HKLviewer.mergedata = False') def ExpandToP1(self): if self.expandP1checkbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.expand_to_p1 = True') else: self.NGL_HKL_command('NGL_HKLviewer.viewer.expand_to_p1 = False') def ExpandAnomalous(self): if self.expandAnomalouscheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.expand_anomalous = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.expand_anomalous = False') def showSysAbsent(self): if self.sysabsentcheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_systematic_absences = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_systematic_absences = False') def showMissing(self): if self.missingcheckbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.show_missing = True') else: self.NGL_HKL_command('NGL_HKLviewer.viewer.show_missing = False') def showOnlyMissing(self): if self.onlymissingcheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_only_missing = True') else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.show_only_missing = False') def showSlice(self): if self.showslicecheckbox.isChecked(): self.NGL_HKL_command('NGL_HKLviewer.viewer.slice_mode = True') if self.expandP1checkbox.isChecked(): self.NGL_HKL_command("""NGL_HKLviewer.viewer { expand_to_p1 = True inbrowser = False } """) if self.expandAnomalouscheckbox.isChecked(): self.NGL_HKL_command("""NGL_HKLviewer.viewer { expand_anomalous = True inbrowser = False } """) else: self.NGL_HKL_command("""NGL_HKLviewer.viewer { slice_mode = False inbrowser = True } """) def onSliceComboSelchange(self, i): rmin = self.array_infotpls[self.MillerComboBox.currentIndex()][3][0][i] rmax = self.array_infotpls[self.MillerComboBox.currentIndex()][3][1][i] self.sliceindexspinBox.setRange(rmin, rmax) self.NGL_HKL_command("NGL_HKLviewer.viewer.slice_axis = %s" % self.sliceaxis[i]) def onSliceIndexChanged(self, val): self.sliceindex = val self.NGL_HKL_command("NGL_HKLviewer.viewer.slice_index = %d" % self.sliceindex) def onBindataComboSelchange(self, i): if self.BinDataComboBox.currentText(): if self.BinDataComboBox.currentIndex() > 0: bin_scene_label = str(self.BinDataComboBox.currentIndex() - 1) else: bin_scene_label = "Resolution" self.NGL_HKL_command("NGL_HKLviewer.bin_scene_label = %s" % bin_scene_label) def update_table_opacities(self, allalpha=None): bin_opacitieslst = eval(self.bin_opacities) self.binstable_isready = False for binopacity in bin_opacitieslst: if not allalpha: alpha = float(binopacity.split(",")[0]) else: alpha = allalpha bin = int(binopacity.split(",")[1]) item = QTableWidgetItem() item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if alpha < 0.5: item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) item.setFlags(item.flags() ^ Qt.ItemIsEditable) self.binstable.setItem(bin, 3, item) self.binstable_isready = True def SetOpaqueAll(self): if self.binstableitemchanges: return bin_opacitieslst = eval(self.bin_opacities) nbins = len(bin_opacitieslst) sum = 0 for binopacity in bin_opacitieslst: sum += float(binopacity.split(",")[0]) if sum >= nbins: self.OpaqueAllCheckbox.setCheckState(Qt.Checked) if sum == 0: self.OpaqueAllCheckbox.setCheckState(Qt.Unchecked) if sum > 0.0 and sum < nbins: self.OpaqueAllCheckbox.setCheckState(Qt.PartiallyChecked) def onBinsTableItemChanged(self, item): row = item.row() column = item.column() try: if item.checkState() == Qt.Unchecked: newval = 0 else: newval = 1.0 if column == 3 and self.binstable_isready: # changing opacity assert (newval <= 1.0 and newval >= 0.0) bin_opacitieslst = eval(self.bin_opacities) bin_opacitieslst[row] = str(newval) + ', ' + str(row) self.bin_opacities = str(bin_opacitieslst) self.SetOpaqueAll() self.NGL_HKL_command( 'NGL_HKLviewer.viewer.NGL.bin_opacities = "%s"' % self.bin_opacities) except Exception as e: print(str(e)) #self.binstable.currentItem().setText( self.currentSelectedBinsTableVal) def onBinsTableItemSelectionChanged(self): row = self.binstable.currentItem().row() column = self.binstable.currentItem().column() self.currentSelectedBinsTableVal = self.binstable.currentItem().text() #print( "in itemSelectionChanged " + self.currentSelectedBinsTableVal) def onOpaqueAll(self): self.binstableitemchanges = True bin_opacitieslst = eval(self.bin_opacities) nbins = len(bin_opacitieslst) bin_opacitieslst = [] self.binstable_isready = False if self.OpaqueAllCheckbox.isChecked(): for i in range(nbins): bin_opacitieslst.append("1.0, %d" % i) else: for i in range(nbins): bin_opacitieslst.append("0.0, %d" % i) self.bin_opacities = str(bin_opacitieslst) self.NGL_HKL_command('NGL_HKLviewer.viewer.NGL.bin_opacities = "%s"' % self.bin_opacities) self.binstableitemchanges = False self.binstable_isready = True """ def onLoadFinished(self, val): pass #print("web page finished loading now") def onBinsTableitemActivated(self, item): row = item.row() column = item.column() currentval = item.text() #print( "in itemActivated " + currentval) def onBinsTableCellentered(self, row, col): pass #print( "in Cellentered " + self.binstable.currentItem().text() ) def onBinsTableCellPressed(self, row, col): pass #print( "in CellPressed " + self.binstable.currentItem().text() ) """ def onNbinsChanged(self, val): self.nbins = val if not self.updatingNbins: # avoid possible endless loop to cctbx self.NGL_HKL_command("NGL_HKLviewer.nbins = %d" % self.nbins) def onRadiiScaleChanged(self, val): self.radii_scale = val self.NGL_HKL_command(""" NGL_HKLviewer.viewer { nth_power_scale_radii = %f scale = %f } """ % (self.nth_power_scale, self.radii_scale)) def onPowerScaleChanged(self, val): self.nth_power_scale = val self.NGL_HKL_command(""" NGL_HKLviewer.viewer { nth_power_scale_radii = %f scale = %f } """ % (self.nth_power_scale, self.radii_scale)) def onManualPowerScale(self): if self.ManualPowerScalecheckbox.isChecked(): self.NGL_HKL_command( 'NGL_HKLviewer.viewer.nth_power_scale_radii = %f' % self.nth_power_scale) self.power_scale_spinBox.setEnabled(True) else: self.NGL_HKL_command( 'NGL_HKLviewer.viewer.nth_power_scale_radii = -1.0') self.power_scale_spinBox.setEnabled(False) self.nth_power_scale = -1.0 def OpenReflectionsFile(self): options = QFileDialog.Options() fileName, filtr = QFileDialog.getOpenFileName( self, "Load reflections file", "", "All Files (*);;MTZ Files (*.mtz);;CIF (*.cif)", "", options) if fileName: self.HKLnameedit.setText(fileName) #self.infostr = "" self.textInfo.setPlainText("") self.fileisvalid = False self.NGL_HKL_command('NGL_HKLviewer.filename = "%s"' % fileName) self.MillerComboBox.clear() self.BinDataComboBox.clear() def createExpansionBox(self): self.SpaceGroupComboBox = QComboBox() self.SpaceGroupComboBox.activated.connect(self.SpacegroupSelchange) self.SpacegroupLabel = QLabel() self.SpacegroupLabel.setText("Space Subgroups") self.mergecheckbox = QCheckBox() self.mergecheckbox.setText("Merge data") #self.mergecheckbox.setTristate (True) self.mergecheckbox.clicked.connect(self.MergeData) self.expandP1checkbox = QCheckBox() self.expandP1checkbox.setText("Expand to P1") self.expandP1checkbox.clicked.connect(self.ExpandToP1) self.expandAnomalouscheckbox = QCheckBox() self.expandAnomalouscheckbox.setText("Show Friedel pairs") self.expandAnomalouscheckbox.clicked.connect(self.ExpandAnomalous) self.sysabsentcheckbox = QCheckBox() self.sysabsentcheckbox.setText("Show Systematic Absences") self.sysabsentcheckbox.clicked.connect(self.showSysAbsent) self.missingcheckbox = QCheckBox() self.missingcheckbox.setText("Show Missing") self.missingcheckbox.clicked.connect(self.showMissing) self.onlymissingcheckbox = QCheckBox() self.onlymissingcheckbox.setText("Only Show Missing") self.onlymissingcheckbox.clicked.connect(self.showOnlyMissing) self.ExpansionBox = QGroupBox("Expansions") layout = QGridLayout() layout.addWidget(self.SpacegroupLabel, 0, 0) layout.addWidget(self.SpaceGroupComboBox, 0, 1) #layout.addWidget(self.mergecheckbox, 1, 0) layout.addWidget(self.expandP1checkbox, 1, 0) layout.addWidget(self.expandAnomalouscheckbox, 1, 1) layout.addWidget(self.sysabsentcheckbox, 2, 0) layout.addWidget(self.missingcheckbox, 3, 0) layout.addWidget(self.onlymissingcheckbox, 3, 1) layout.setRowStretch(0, 0) layout.setRowStretch(1, 0) layout.setRowStretch(2, 0) layout.setRowStretch(3, 1) self.ExpansionBox.setLayout(layout) def CreateSliceTabs(self): self.showslicecheckbox = QCheckBox() self.showslicecheckbox.setText("Show Slice") self.showslicecheckbox.clicked.connect(self.showSlice) self.sliceindexspinBox = QDoubleSpinBox() self.sliceindex = 0 self.sliceindexspinBox.setValue(self.sliceindex) self.sliceindexspinBox.setDecimals(0) self.sliceindexspinBox.setSingleStep(1) self.sliceindexspinBox.setRange(0, 20) self.sliceindexspinBox.valueChanged.connect(self.onSliceIndexChanged) self.SliceLabelComboBox = QComboBox() self.SliceLabelComboBox.activated.connect(self.onSliceComboSelchange) self.sliceaxis = ["h", "k", "l"] self.SliceLabelComboBox.addItems(self.sliceaxis) self.sliceTabWidget = QTabWidget() tab1 = QWidget() layout1 = QGridLayout() layout1.addWidget(self.showslicecheckbox, 0, 0, 1, 1) layout1.addWidget(self.SliceLabelComboBox, 0, 1, 1, 1) layout1.addWidget(self.sliceindexspinBox, 0, 2, 1, 1) tab1.setLayout(layout1) tab2 = QWidget() layout2 = QGridLayout() self.hvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.hvecval = 2.0 self.hvec_spinBox.setValue(self.hvecval) self.hvec_spinBox.setDecimals(2) self.hvec_spinBox.setSingleStep(0.5) self.hvec_spinBox.setRange(-100.0, 10.0) self.hvec_spinBox.valueChanged.connect(self.onHvecChanged) self.hvec_Label = QLabel() self.hvec_Label.setText("H") layout2.addWidget(self.hvec_Label, 0, 0, 1, 1) layout2.addWidget(self.hvec_spinBox, 0, 1, 1, 1) self.kvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.kvecval = 0.0 self.kvec_spinBox.setValue(self.kvecval) self.kvec_spinBox.setDecimals(2) self.kvec_spinBox.setSingleStep(0.5) self.kvec_spinBox.setRange(-100.0, 100.0) self.kvec_spinBox.valueChanged.connect(self.onKvecChanged) self.kvec_Label = QLabel() self.kvec_Label.setText("K") layout2.addWidget(self.kvec_Label, 1, 0, 1, 1) layout2.addWidget(self.kvec_spinBox, 1, 1, 1, 1) self.lvec_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.lvecval = 0.0 self.lvec_spinBox.setValue(self.lvecval) self.lvec_spinBox.setDecimals(2) self.lvec_spinBox.setSingleStep(0.5) self.lvec_spinBox.setRange(-100.0, 100.0) self.lvec_spinBox.valueChanged.connect(self.onLvecChanged) self.lvec_Label = QLabel() self.lvec_Label.setText("L") layout2.addWidget(self.lvec_Label, 2, 0, 1, 1) layout2.addWidget(self.lvec_spinBox, 2, 1, 1, 1) self.hkldist_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.hkldistval = 0.0 self.hkldist_spinBox.setValue(self.hkldistval) self.hkldist_spinBox.setDecimals(2) self.hkldist_spinBox.setSingleStep(0.5) self.hkldist_spinBox.setRange(-100.0, 100.0) self.hkldist_spinBox.valueChanged.connect(self.onHKLdistChanged) self.hkldist_Label = QLabel() self.hkldist_Label.setText("Distance from Origin") layout2.addWidget(self.hkldist_Label, 3, 0, 1, 1) layout2.addWidget(self.hkldist_spinBox, 3, 1, 1, 1) self.clipwidth_spinBox = QDoubleSpinBox(self.sliceTabWidget) self.clipwidthval = 0.5 self.clipwidth_spinBox.setValue(self.clipwidthval) self.clipwidth_spinBox.setDecimals(2) self.clipwidth_spinBox.setSingleStep(0.05) self.clipwidth_spinBox.setRange(0.0, 100.0) self.clipwidth_spinBox.valueChanged.connect(self.onClipwidthChanged) self.clipwidth_Label = QLabel() self.clipwidth_Label.setText("Clip Plane Width") layout2.addWidget(self.clipwidth_Label, 4, 0, 1, 1) layout2.addWidget(self.clipwidth_spinBox, 4, 1, 1, 1) self.ClipBox = QGroupBox("Normal Vector to Clip Plane") self.ClipBox.setLayout(layout2) layout3 = QGridLayout() self.ClipPlaneChkBox = QCheckBox(self.sliceTabWidget) self.ClipPlaneChkBox.setText( "Use clip plane normal to HKL vector pointing out") self.ClipPlaneChkBox.clicked.connect(self.onClipPlaneChkBox) layout3.addWidget(self.ClipPlaneChkBox, 0, 0) layout3.addWidget(self.ClipBox, 1, 0) tab2.setLayout(layout3) self.sliceTabWidget.addTab(tab1, "Explicit Slicing") self.sliceTabWidget.addTab(tab2, "Clip Plane Slicing") self.ClipBox.setDisabled(True) def onClipPlaneChkBox(self): if self.ClipPlaneChkBox.isChecked(): self.ClipBox.setDisabled(False) philstr = """NGL_HKLviewer.normal_clip_plane { h = %s k = %s l = %s hkldist = %s clipwidth = %s } NGL_HKLviewer.viewer.NGL.fixorientation = %s """ %(self.hvecval, self.kvecval, self.lvecval, self.hkldistval, self.clipwidthval, \ str(self.fixedorientcheckbox.isChecked()) ) self.NGL_HKL_command(philstr) else: self.ClipBox.setDisabled(True) self.NGL_HKL_command( "NGL_HKLviewer.normal_clip_plane.clipwidth = None") def onClipwidthChanged(self, val): self.clipwidthval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.clipwidth = %f" % self.clipwidthval) def onHKLdistChanged(self, val): self.hkldistval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.hkldist = %f" % self.hkldistval) def onHvecChanged(self, val): self.hvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.h = %f" % self.hvecval) def onKvecChanged(self, val): self.kvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.k = %f" % self.kvecval) def onLvecChanged(self, val): self.lvecval = val self.NGL_HKL_command("NGL_HKLviewer.normal_clip_plane.l = %f" % self.lvecval) def onFixedorient(self): self.NGL_HKL_command('NGL_HKLviewer.viewer.NGL.fixorientation = %s' \ %str(self.fixedorientcheckbox.isChecked())) def onMillerComboSelchange(self, i): self.NGL_HKL_command("NGL_HKLviewer.scene_id = %d" % i) #self.MillerComboBox.setCurrentIndex(i) if self.MillerComboBox.currentText(): self.functionTabWidget.setEnabled(True) self.expandAnomalouscheckbox.setEnabled(True) # don' allow anomalous expansion for data that's already anomalous for arrayinfo in self.array_infotpls: isanomalous = arrayinfo[-1] label = arrayinfo[0] if isanomalous and label == self.MillerComboBox.currentText( )[:len(label)]: self.expandAnomalouscheckbox.setDisabled(True) else: self.functionTabWidget.setDisabled(True) self.SpaceGroupComboBox.clear() self.SpaceGroupComboBox.addItems(self.spacegroups) # need to supply issymunique flag in infotuple #if self.hklscenes_arrays[ i ][6] == 0: # self.mergecheckbox.setEnabled(True) #else: # self.mergecheckbox.setEnabled(False) def createFileInfoBox(self): self.FileInfoBox = QGroupBox("Reflection File Information") layout = QGridLayout() layout.addWidget(self.openFileNameButton, 0, 0, 1, 2) if self.devmode: layout.addWidget(self.debugbutton, 0, 2, 1, 1) layout.addWidget(self.HKLnameedit, 1, 0, 1, 3) layout.addWidget(self.millertable, 2, 0, 1, 3) layout.addWidget(self.textInfo, 3, 0, 1, 3) #layout.setColumnStretch(1, 2) self.FileInfoBox.setLayout(layout) def createRadiiScaleGroupBox(self): self.RadiiScaleGroupBox = QGroupBox("Radii Size of HKL Spheres") self.ManualPowerScalecheckbox = QCheckBox() self.ManualPowerScalecheckbox.setText( "Manual Power Scaling of Sphere Radii") self.ManualPowerScalecheckbox.clicked.connect(self.onManualPowerScale) self.power_scale_spinBox = QDoubleSpinBox(self.RadiiScaleGroupBox) self.nth_power_scale = 0.5 self.power_scale_spinBox.setValue(self.nth_power_scale) self.power_scale_spinBox.setDecimals(2) self.power_scale_spinBox.setSingleStep(0.05) self.power_scale_spinBox.setRange(0.0, 1.0) self.power_scale_spinBox.valueChanged.connect(self.onPowerScaleChanged) self.power_scale_spinBox.setEnabled(False) self.powerscaleLabel = QLabel() self.powerscaleLabel.setText("Power scale Factor") self.radii_scale_spinBox = QDoubleSpinBox(self.RadiiScaleGroupBox) self.radii_scale = 1.0 self.radii_scale_spinBox.setValue(self.radii_scale) self.radii_scale_spinBox.setDecimals(1) self.radii_scale_spinBox.setSingleStep(0.1) self.radii_scale_spinBox.setRange(0.2, 2.0) self.radii_scale_spinBox.valueChanged.connect(self.onRadiiScaleChanged) self.radiiscaleLabel = QLabel() self.radiiscaleLabel.setText("Linear Scale Factor") layout = QGridLayout() layout.addWidget(self.ManualPowerScalecheckbox, 1, 0, 1, 2) layout.addWidget(self.powerscaleLabel, 2, 0, 1, 2) layout.addWidget(self.power_scale_spinBox, 2, 1, 1, 2) layout.addWidget(self.radiiscaleLabel, 3, 0, 1, 2) layout.addWidget(self.radii_scale_spinBox, 3, 1, 1, 2) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 0) self.RadiiScaleGroupBox.setLayout(layout) def createBinsBox(self): self.binstable = QTableWidget(0, 4) self.binstable_isready = False labels = [ "no. of HKLs", "lower bin value", "upper bin value", "opacity" ] self.binstable.setHorizontalHeaderLabels(labels) self.binstable.horizontalHeader().setDefaultAlignment(Qt.AlignLeft) self.bindata_labeltxt = QLabel() self.bindata_labeltxt.setText("Data binned:") self.Nbins_spinBox = QSpinBox() self.Nbins_spinBox.setSingleStep(1) self.Nbins_spinBox.setRange(1, 40) self.Nbins_spinBox.valueChanged.connect(self.onNbinsChanged) self.Nbins_labeltxt = QLabel() self.Nbins_labeltxt.setText("Number of bins:") self.OpaqueAllCheckbox = QCheckBox() #self.OpaqueAllCheckbox.setTristate() self.OpaqueAllCheckbox.setText("Show all data in bins") self.OpaqueAllCheckbox.clicked.connect(self.onOpaqueAll) self.binstable.itemChanged.connect(self.onBinsTableItemChanged) self.binstable.itemSelectionChanged.connect( self.onBinsTableItemSelectionChanged) self.BinDataComboBox = QComboBox() self.BinDataComboBox.activated.connect(self.onBindataComboSelchange) self.BinsGroupBox = QGroupBox("Bins") layout = QGridLayout() layout.addWidget(self.bindata_labeltxt, 0, 0) layout.addWidget(self.BinDataComboBox, 0, 1) layout.addWidget(self.Nbins_labeltxt, 0, 2) layout.addWidget(self.Nbins_spinBox, 0, 3) layout.addWidget(self.OpaqueAllCheckbox, 1, 2) layout.addWidget(self.binstable, 2, 0, 1, 4) layout.setColumnStretch(0, 0) layout.setColumnStretch(1, 2) layout.setColumnStretch(3, 1) self.BinsGroupBox.setLayout(layout) def DebugInteractively(self): import code, traceback code.interact(local=locals(), banner="".join(traceback.format_stack(limit=10))) def CreateFunctionTabs(self): self.functionTabWidget = QTabWidget() tab1 = QWidget() layout1 = QGridLayout() layout1.addWidget(self.ExpansionBox, 0, 0) layout1.setRowStretch(0, 0) tab1.setLayout(layout1) tab2 = QWidget() layout2 = QGridLayout() self.fixedorientcheckbox = QCheckBox(self.sliceTabWidget) self.fixedorientcheckbox.setText( "Fix orientation but allow zoom and translation") self.fixedorientcheckbox.clicked.connect(self.onFixedorient) layout2.addWidget(self.fixedorientcheckbox, 0, 0) layout2.addWidget(self.sliceTabWidget, 1, 0) tab2.setLayout(layout2) tab3 = QWidget() layout3 = QGridLayout() layout3.addWidget(self.RadiiScaleGroupBox, 0, 0) tab3.setLayout(layout3) tab4 = QWidget() layout4 = QGridLayout() layout4.addWidget(self.BinsGroupBox, 0, 0) tab4.setLayout(layout4) self.functionTabWidget.addTab(tab1, "Expand") self.functionTabWidget.addTab(tab2, "Slice") self.functionTabWidget.addTab(tab3, "Size") self.functionTabWidget.addTab(tab4, "Bins") self.functionTabWidget.setDisabled(True) def SpacegroupSelchange(self, i): self.NGL_HKL_command("NGL_HKLviewer.spacegroup_choice = %d" % i) def find_free_port(self): import socket s = socket.socket() s.bind(('', 0)) # Bind to a free port provided by the host. port = s.getsockname()[1] s.close() return port def LaunchCCTBXPython(self): self.sockport = self.find_free_port() self.zmq_context = zmq.Context() self.socket = self.zmq_context.socket(zmq.PAIR) self.socket.bind("tcp://127.0.0.1:%s" % self.sockport) try: msg = self.socket.recv( flags=zmq.NOBLOCK) #To empty the socket from previous messages except Exception as e: pass cmdargs = 'cctbx.python.bat -i -c "from crys3d.hklview import cmdlineframes;' \ + ' myHKLview = cmdlineframes.HKLViewFrame(useGuiSocket=%s, high_quality=True,' %self.sockport \ + ' jscriptfname = \'%s\', ' %self.jscriptfname \ + ' verbose=%s, UseOSBrowser= %s )"\n' %(self.verbose, str(self.UseOSbrowser)) self.cctbxproc = subprocess.Popen(cmdargs, shell=True, stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr) #time.sleep(1) def NGL_HKL_command(self, cmdstr): #print("sending:\n" + cmdstr) self.socket.send(bytes(cmdstr, "utf-8"))
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) # 设置时间 self.__time = QDateTime() # 创建图形界面 self.__SetupUI() self.__ConfigureFileToolBar() self.__ConfigureTranslateToolBar() self.__ConfigureMainLayout() # 设置ComboBox的显示内容 self.__ConfigureComboBox() # 设置保存文件的信息 self.__currentPath = QDir.currentPath() self.__ConfigureSysIniFile() self.__ConfigureHistoryFile() salt = random.randint(1466000000, 1467000000) self.__salt = str(salt) self.__httpClient = None self.__statusBar.showMessage( self.__GetCurrentTime() + " - Please choose a file or enter data!", 2000) self.show() def __del__(self): self.__historyFile.close() def __SetupUI(self): self.__mainWidget = QWidget() self.setCentralWidget(self.__mainWidget) self.__fileToolBar = QToolBar("File") self.addToolBar(self.__fileToolBar) self.__translateToolBar = QToolBar("Translate") self.addToolBar(self.__translateToolBar) self.__statusBar = QStatusBar() self.setStatusBar(self.__statusBar) self.setWindowIcon(QIcon("./image/translate.png")) def __ConfigureFileToolBar(self): self.__openFileAction = QAction(QIcon("./image/open.png"), "Open File") self.__fileToolBar.addAction(self.__openFileAction) self.__openFileAction.triggered.connect( self.__on_triggered_openFileAction) self.__saveFileAction = QAction(QIcon("./image/save.png"), "Save File") self.__fileToolBar.addAction(self.__saveFileAction) self.__saveFileAction.triggered.connect( self.__on_triggered_saveFileAction) def __ConfigureTranslateToolBar(self): self.__translateAction = QAction(QIcon("./image/translate.png"), "Translate") self.__translateToolBar.addAction(self.__translateAction) self.__translateAction.triggered.connect( self.__on_triggered_translateAction) self.__clearAction = QAction(QIcon("./image/clear.png"), "Clear") self.__translateToolBar.addAction(self.__clearAction) self.__clearAction.triggered.connect(self.__on_triggered_clearAction) def __ConfigureMainLayout(self): self.__appIDLabel = QLabel("AppID:") self.__appIDLineEdit = QLineEdit(self) self.__appIDLineEdit.returnPressed.connect( self.__on_returnPressed_appIDLineEdit) self.__keyLabel = QLabel("Key:") self.__keyLineEdit = QLineEdit(self) self.__keyLineEdit.returnPressed.connect( self.__on_returnPressed_keyLineEdit) self.__fromLabel = QLabel("From:") self.__fromComboBox = QComboBox(self) self.__toLabel = QLabel("To:") self.__toComboBox = QComboBox(self) self.__srcLabel = QLabel("Src Text:") self.__srcTextEdit = QTextEdit(self) self.__translateLabel = QLabel("Translate Text:") self.__translateTextEdit = QTextEdit(self) self.__mainLayout = QGridLayout() self.__mainLayout.addWidget(self.__appIDLabel, 0, 0) self.__mainLayout.addWidget(self.__appIDLineEdit, 0, 1, 1, 3) self.__mainLayout.addWidget(self.__keyLabel, 1, 0) self.__mainLayout.addWidget(self.__keyLineEdit, 1, 1, 1, 3) self.__mainLayout.addWidget(self.__fromLabel, 2, 0) self.__mainLayout.addWidget(self.__fromComboBox, 2, 1) self.__mainLayout.addWidget(self.__toLabel, 2, 2) self.__mainLayout.addWidget(self.__toComboBox, 2, 3) self.__mainLayout.addWidget(self.__srcLabel, 3, 0) self.__mainLayout.addWidget(self.__srcTextEdit, 3, 1, 1, 3) self.__mainLayout.addWidget(self.__translateLabel, 4, 0) self.__mainLayout.addWidget(self.__translateTextEdit, 4, 1, 1, 3) self.__mainWidget.setLayout(self.__mainLayout) def __ConfigureComboBox(self): self.__fromComboBox.clear() self.__fromComboBox.addItem("English", "en") self.__fromComboBox.addItem("Chinese", "zh") self.__fromComboBox.addItem("Auto", "auto") self.__fromComboBox.setCurrentIndex(2) self.__toComboBox.clear() self.__toComboBox.addItem("English", "en") self.__toComboBox.addItem("Chinese", "zh") self.__toComboBox.setCurrentIndex(1) def __ConfigureSysIniFile(self): iniFile = QFile("info.ini") if iniFile.exists(): self.__infoSettings = QSettings("info.ini", QSettings.IniFormat) self.__appIDLineEdit.setText( self.__infoSettings.value("info/appid")) self.__keyLineEdit.setText(self.__infoSettings.value("info/key")) else: if iniFile.open(QFile.ReadWrite): self.__infoSettings = QSettings("info.ini", QSettings.IniFormat) self.__infoSettings.beginGroup("info") self.__infoSettings.setValue("appid", "00000000000000000") self.__infoSettings.setValue("key", "00000000000000000") self.__infoSettings.endGroup() iniFile.close() self.__appIDLineEdit.setText("00000000000000000") self.__keyLineEdit.setText("00000000000000000") def __ConfigureHistoryFile(self): self.__historyFile = QFile("history.txt") if self.__historyFile.open(QFile.ReadWrite or QFile.Append): self.__historyFileStream = QTextStream(self.__historyFile) else: self.__statusBar.showMessage( self.__GetCurrentTime() + " - History fie create failed!", 2000) def __GetCurrentTime(self, format="hh:mm:ss"): return self.__time.currentDateTime().toString(format) def __GetSign(self, srcData, appid, key): sign = appid + srcData + self.__salt + key mymd5 = hashlib.md5(sign.encode()).hexdigest() return mymd5 def __on_triggered_openFileAction(self): filePath = QFileDialog.getOpenFileName(self, "open", self.__currentPath, "* txt") if filePath[0].strip(): file = QFile(filePath[0]) if file.open(QFile.ReadOnly): readData = str(file.readAll()) fileData = readData[2:readData.__len__() - 1].replace( r"\r\n", r" ") self.__srcTextEdit.insertPlainText(fileData) else: self.__statusBar.showMessage( self.__GetCurrentTime() + " - open file failed!", 2000) else: self.__statusBar.showMessage( self.__GetCurrentTime() + " - Choose file failed!", 2000) return def __on_triggered_saveFileAction(self): self.__historyFile.close() self.__historyFile.open(QFile.ReadWrite or QFile.Append) self.__statusBar.showMessage( self.__GetCurrentTime() + " - Save file successful!", 2000) def __on_triggered_translateAction(self): srcData = self.__srcTextEdit.toPlainText() if srcData.strip(): self.__translateTextEdit.clear() self.__translateTextEdit.document().clear() dstData = srcData.replace("\n", " ") else: self.__statusBar.showMessage( self.__GetCurrentTime() + " - There is no data!", 2000) return myurl = "/api/trans/vip/translate" appid = self.__appIDLineEdit.text() key = self.__keyLineEdit.text() strFrom = self.__fromComboBox.currentData() strTo = self.__toComboBox.currentData() mymd5 = self.__GetSign(dstData, appid, key) myurl = myurl + "?appid=" + appid + "&q=" + urllib.parse.quote( srcData ) + "&from=" + strFrom + "&to=" + strTo + "&salt=" + self.__salt + "&sign=" + mymd5 httpClient = http.client.HTTPConnection("api.fanyi.baidu.com") httpClient.request("GET", myurl) response = httpClient.getresponse() jsonResponse = response.read().decode("utf-8") js = json.loads(jsonResponse) translate = str(js["trans_result"][0]["dst"]) self.__translateTextEdit.insertPlainText(translate) self.__historyFileStream << translate + "\r\n" self.__statusBar.showMessage( self.__GetCurrentTime() + " - Translate successful!", 2000) def __on_triggered_clearAction(self): self.__srcTextEdit.clear() self.__translateTextEdit.clear() self.__statusBar.showMessage( self.__GetCurrentTime() + " - Clear successful!", 2000) def __on_returnPressed_appIDLineEdit(self): appid = self.__appIDLineEdit.text() if not appid.strip(): self.__statusBar.showMessage( self.__GetCurrentTime() + " - There is no appid!", 2000) return self.__infoSettings.beginGroup("info") self.__infoSettings.setValue("appid", appid) self.__infoSettings.endGroup() self.__statusBar.showMessage( self.__GetCurrentTime() + " - Enter appid successful!", 2000) def __on_returnPressed_keyLineEdit(self): key = self.__keyLineEdit.text() if not key.strip(): self.__statusBar.showMessage( self.__GetCurrentTime() + " - There is no key!", 2000) return self.__infoSettings.beginGroup("info") self.__infoSettings.setValue("key", key) self.__infoSettings.endGroup() self.__statusBar.showMessage( self.__GetCurrentTime() + " - Enter key successful!", 2000)
class LoadDatasetDialog(QDialog): dataset_loaded = Signal(GrainSizeDataset) def __init__(self, parent=None): super().__init__(parent=parent, f=Qt.Window) self.setWindowTitle(self.tr("Dataset Loader")) self.initialize_ui() self.file_dialog = QFileDialog(parent=self) self.filename = None # type: str self.workbook = None # type: typing.Union[openpyxl.Workbook, xlrd.Book] self.dataset = None # type: GrainSizeDataset def initialize_ui(self): self.setAttribute(Qt.WA_StyledBackground, True) self.main_layout = QGridLayout(self) self.filename_label = QLabel(self.tr("Filename:")) self.filename_display = QLabel(self.tr("Unknown")) self.main_layout.addWidget(self.filename_label, 0, 0) self.main_layout.addWidget(self.filename_display, 0, 1, 1, 2) self.select_button = QPushButton(qta.icon("mdi.file-table"), self.tr("Select")) self.select_button.clicked.connect(self.on_select_clicked) self.main_layout.addWidget(self.select_button, 0, 3) self.sheet_label = QLabel(self.tr("Sheet:")) self.sheet_combo_box = QComboBox() self.sheet_combo_box.addItem(self.tr("Empty")) self.main_layout.addWidget(self.sheet_label, 1, 0) self.main_layout.addWidget(self.sheet_combo_box, 1, 1, 1, 3) self.classes_row_label = QLabel( self.tr("Row With Grain-size Classes:")) self.classes_row_input = QSpinBox() self.classes_row_input.setRange(1, 999) self.main_layout.addWidget(self.classes_row_label, 2, 0, 1, 3) self.main_layout.addWidget(self.classes_row_input, 2, 3) self.sample_names_column_label = QLabel( self.tr("Column With Sample Names:")) self.sample_names_column_input = QSpinBox() self.sample_names_column_input.setRange(1, 999) self.main_layout.addWidget(self.sample_names_column_label, 3, 0, 1, 3) self.main_layout.addWidget(self.sample_names_column_input, 3, 3) self.distribution_start_row_label = QLabel( self.tr("Distribution Start Row:")) self.distribution_start_row_input = QSpinBox() self.distribution_start_row_input.setRange(2, 999999) self.main_layout.addWidget(self.distribution_start_row_label, 4, 0, 1, 3) self.main_layout.addWidget(self.distribution_start_row_input, 4, 3) self.distribution_start_column_label = QLabel( self.tr("Distribution Start Column:")) self.distribution_start_column_input = QSpinBox() self.distribution_start_column_input.setRange(2, 999999) self.main_layout.addWidget(self.distribution_start_column_label, 5, 0, 1, 3) self.main_layout.addWidget(self.distribution_start_column_input, 5, 3) self.try_load_button = QPushButton(qta.icon("fa5s.book-reader"), self.tr("Try Load")) self.try_load_button.clicked.connect(self.on_try_load_clicked) self.try_load_button.setEnabled(False) self.main_layout.addWidget(self.try_load_button, 6, 0, 1, 4) self.info_display = QTextEdit() self.info_display.setReadOnly(True) self.main_layout.addWidget(self.info_display, 7, 0, 1, 4) @property def sheet_index(self) -> int: sheet_index = self.sheet_combo_box.currentIndex() return sheet_index @property def sheet_name(self) -> str: sheet_name = self.sheet_combo_box.currentText() return sheet_name @property def data_layout(self): classes_row = self.classes_row_input.value() - 1 sample_names_column = self.sample_names_column_input.value() - 1 distribution_start_row = self.distribution_start_row_input.value() - 1 distribution_start_column = self.distribution_start_column_input.value( ) - 1 try: layout = DataLayoutSetting( classes_row=classes_row, sample_names_column=sample_names_column, distribution_start_row=distribution_start_row, distribution_start_column=distribution_start_column) return layout except DataLayoutError as e: self.show_error( f"The current setting is invalid.\n {e.__str__()}") return None def on_select_clicked(self): filename, _ = self.file_dialog.getOpenFileName(\ self, self.tr("Select a file"), None, self.tr("Excel (*.xlsx);;97-2003 Excel (*.xls);;CSV (*.csv)")) if filename is None or filename == "": self.show_warning(f"No file was selected.") return self.filename = filename file_type = get_type_by_name(filename) self.show_info(f"Data file [{file_type}] was selected: [{filename}].") if file_type == ReadFileType.CSV: sheet_names = [os.path.basename(filename)] elif file_type == ReadFileType.XLS: self.workbook = xlrd.open_workbook(filename) sheet_names = self.workbook.sheet_names() elif file_type == ReadFileType.XLSX: self.workbook = openpyxl.load_workbook(filename, read_only=True, data_only=True) sheet_names = self.workbook.sheetnames else: raise NotImplementedError(file_type) if file_type != ReadFileType.CSV: self.show_info( f"It has {len(sheet_names)} sheet(s), please select one.") self.filename_display.setText(os.path.basename(filename)) self.sheet_combo_box.clear() self.sheet_combo_box.addItems(sheet_names) self.try_load_button.setEnabled(True) def show_info(self, text: str): self.info_display.append( f'<font size="3" color="black">[{datetime.datetime.now()}] - {text}</font>\n' ) def show_warning(self, text: str): self.info_display.append( f'<font size="3" color="#fed71a">[{datetime.datetime.now()}] - {text}</font>\n' ) def show_error(self, text: str): self.info_display.append( f'<font size="3" color="#f03752">[{datetime.datetime.now()}] - {text}</font>\n' ) def show_success(self, text: str): self.info_display.append( f'<font size="3" color="#2c9678">[{datetime.datetime.now()}] - {text}</font>\n' ) def on_try_load_clicked(self): try: self.try_load() except Exception as e: self.show_error(f"Error raised while loading.\n {e.__str__()}") def try_load(self): layout = self.data_layout if layout is None: return assert self.filename is not None file_type = get_type_by_name(self.filename) self.show_info("Start to load raw data from the file.") QCoreApplication.processEvents() if file_type == ReadFileType.CSV: try: with open(self.filename, encoding="utf-8") as f: reader = csv.reader(f) raw_data = [row for row in reader] except Exception as e: self.show_error( f"Exception rasised when reading {file_type} file.\n {e.__str__()}" ) return elif file_type == ReadFileType.XLS: sheet = self.workbook.sheet_by_index(self.sheet_index) raw_data = [sheet.row_values(row) for row in range(sheet.nrows)] elif file_type == ReadFileType.XLSX: sheet = self.workbook[self.sheet_name] raw_data = [[value for value in row] for row in sheet.values] else: raise NotImplementedError(file_type) self.show_success(f"Raw data has been loaded from the file.") QCoreApplication.processEvents() try: classes_μm = np.array(raw_data[layout.classes_row] [layout.distribution_start_column:], dtype=np.float64) except Exception as e: self.show_error( f"Can not convert the row of classes to a numerical array, it may contains invalid values (e.g. text or empty cell).\n {e.__str__()}" ) return self.show_info( f"Grain-size classes in μm: [{','.join([f'{x: 0.4f}' for x in classes_μm[:3]])}, ...,{','.join([f'{x: 0.4f}' for x in classes_μm[-3:]])}]." ) GrainSizeDataset.validate_classes_μm(classes_μm) self.show_success("Validation of grain-size classes passed.") QCoreApplication.processEvents() names = [] distributions = [] i = layout.distribution_start_row + 1 for row_values in raw_data[layout.distribution_start_row:]: # check if it's a empty row, i.e. the values all are empty string is_empty_row = True for distribution_value in row_values[layout. distribution_start_column:]: if distribution_value != "" and distribution_value is not None: is_empty_row = False break # if it's a empty row, jump this row to process the next one if is_empty_row: self.show_warning(f"This row is empty, jump to next.") continue sample_name = row_values[layout.sample_name_column] self.show_info( f"Processing the {i} row, sample name is [{sample_name}].") if sample_name is None: sample_name = "NONE" self.show_warning( f"The sample name is invalid, use 'NONE' instead.") # users may use pure number as the sample name elif type(sample_name) != str: sample_name = str(sample_name) self.show_warning( f"The sample name is not text (may be a number), convert it to text." ) elif sample_name == "": sample_name = "EMPTY" self.show_warning( f"The sample name is a empty text, use 'EMPTY' instead.") try: distribution = np.array( row_values[layout.distribution_start_column:], dtype=np.float64) except Exception as e: self.show_error( f"Can not convert the distribution values at row [{i}] to a numerical array, it may contains invalid values (e.g. text or empty cell).\n {e.__str__()}" ) return try: GrainSizeDataset.validate_distribution(distribution) except Exception as e: self.show_error( f"Validation of the distribution array of sample [{sample_name}] did not pass.\n {e.__str__()}" ) return names.append(sample_name) distributions.append(distribution) i += 1 self.show_info(f"Validation of sample {sample_name} passed.") QCoreApplication.processEvents() self.show_success( "All data has been convert to array. Next to do the final validation." ) dataset = GrainSizeDataset() dataset.add_batch(classes_μm, names, distributions) self.dataset = dataset self.show_success( "Dataset has been loaded successfully, you can close this dialog now." ) self.dataset_loaded.emit(dataset)
class assSelect(QDialog): assSummary = Signal(list) def __init__(self): super().__init__() self.subDict = { '': { 'Fontname': '', 'Fontsize': '', 'PrimaryColour': '', 'SecondaryColour': '', 'OutlineColour': '', 'BackColour': '', 'Bold': '', 'Italic': '', 'Underline': '', 'StrikeOut': '', 'ScaleX': '', 'ScaleY': '', 'Spacing': '', 'Angle': '', 'BorderStyle': '', 'Outline': '', 'Shadow': '', 'Alignment': '', 'MarginL': '', 'MarginR': '', 'MarginV': '', 'Encoding': '', 'Tableview': [], 'Events': [] } } self.resize(950, 800) self.setWindowTitle('选择要导入的ass字幕轨道') layout = QGridLayout() self.setLayout(layout) layout.addWidget(QLabel('检测到字幕样式:'), 0, 0, 1, 1) layout.addWidget(QLabel(''), 0, 1, 1, 1) self.subCombox = QComboBox() self.subCombox.currentTextChanged.connect(self.selectChange) layout.addWidget(self.subCombox, 0, 2, 1, 1) self.subTable = QTableWidget() self.subTable.setEditTriggers(QAbstractItemView.NoEditTriggers) layout.addWidget(self.subTable, 1, 0, 6, 3) self.confirm = QPushButton('导入') self.confirm.clicked.connect(self.sendSub) layout.addWidget(self.confirm, 7, 0, 1, 1) self.confirmStyle = QPushButton('导入样式') self.confirmStyle.clicked.connect(self.sendSubStyle) layout.addWidget(self.confirmStyle, 7, 1, 1, 1) self.cancel = QPushButton('取消') self.cancel.clicked.connect(self.hide) layout.addWidget(self.cancel, 7, 2, 1, 1) def setDefault(self, subtitlePath='', index=0): if subtitlePath: self.assCheck(subtitlePath) self.index = index def selectChange(self, styleName): self.subTable.clear() self.subTable.setRowCount( len(self.subDict[styleName]) + len(self.subDict[styleName]['Tableview']) - 2) self.subTable.setColumnCount(4) for col in range(3): self.subTable.setColumnWidth(col, 160) self.subTable.setColumnWidth(3, 350) y = 0 for k, v in self.subDict[styleName].items(): if k not in ['Tableview', 'Events']: self.subTable.setItem(y, 0, QTableWidgetItem(k)) self.subTable.setItem(y, 1, QTableWidgetItem(v)) y += 1 elif k == 'Tableview': preConflict = False # 上一条字幕时轴有重叠 for cnt, line in enumerate(v): nextConflict = False start = calSubTime(line[0]) end = calSubTime(line[1]) if cnt < len(v) - 1: nextStart = calSubTime(v[cnt + 1][0]) if end > nextStart: nextConflict = True else: nextConflict = False delta = end - start if delta < 500 or delta > 8000: # 持续时间小于500ms或大于8s deltaError = 2 elif delta > 4500: # 持续时间大于4.5s且小于8s deltaError = 1 else: deltaError = 0 s, ms = divmod(delta, 1000) ms = ('%03d' % ms)[:2] delta = '持续 %s.%ss' % (s, ms) self.subTable.setItem(y, 0, QTableWidgetItem(line[0])) # 开始时间 if preConflict: self.subTable.item(y, 0).setBackground( QColor('#B22222')) # 红色警告 self.subTable.setItem(y, 1, QTableWidgetItem(line[1])) # 结束时间 if nextConflict: self.subTable.item(y, 1).setBackground( QColor('#B22222')) # 红色警告 self.subTable.setItem(y, 2, QTableWidgetItem(delta)) # 持续时间 if deltaError == 2: self.subTable.item(y, 2).setBackground( QColor('#B22222')) # 红色警告 elif deltaError == 1: self.subTable.item(y, 2).setBackground( QColor('#FA8072')) # 橙色警告 self.subTable.setItem(y, 3, QTableWidgetItem(line[2])) # 字幕文本 y += 1 preConflict = nextConflict # 将重叠信号传递给下一条轴 def sendSub(self): self.assSummary.emit([ self.index, self.subCombox.currentText(), self.subDict[self.subCombox.currentText()] ]) self.hide() def sendSubStyle(self): subData = self.subDict[self.subCombox.currentText()] subData['Events'] = {} self.assSummary.emit( [self.index, self.subCombox.currentText(), subData]) self.hide() def assCheck(self, subtitlePath): self.subDict = { '': { 'Fontname': '', 'Fontsize': '', 'PrimaryColour': '', 'SecondaryColour': '', 'OutlineColour': '', 'BackColour': '', 'Bold': '', 'Italic': '', 'Underline': '', 'StrikeOut': '', 'ScaleX': '', 'ScaleY': '', 'Spacing': '', 'Angle': '', 'BorderStyle': '', 'Outline': '', 'Shadow': '', 'Alignment': '', 'MarginL': '', 'MarginR': '', 'MarginV': '', 'Encoding': '', 'Tableview': [], 'Events': {} } } ass = codecs.open(subtitlePath, 'r', 'utf_8_sig') f = ass.readlines() ass.close() V4Token = False styleFormat = [] styles = [] eventToken = False eventFormat = [] events = [] for line in f: if '[V4+ Styles]' in line: V4Token = True elif V4Token and 'Format:' in line: styleFormat = line.replace(' ', '').strip().split(':')[1].split(',') elif V4Token and 'Style:' in line and styleFormat: styles.append(line.strip().split(':')[1].split(',')) elif '[Events]' in line: eventToken = True V4Token = False elif eventToken and 'Format:' in line: eventFormat = line.strip().split(':')[1].split(',') elif eventToken and 'Comment:' in line and eventFormat: events.append(line.strip().split('Comment:')[1].split( ',', len(eventFormat) - 1)) elif eventToken and 'Dialogue:' in line and eventFormat: events.append(line.strip().split('Dialogue:')[1].split( ',', len(eventFormat) - 1)) for cnt, _format in enumerate(eventFormat): _format = _format.replace(' ', '') if _format == 'Start': Start = cnt elif _format == 'End': End = cnt elif _format == 'Style': Style = cnt elif _format == 'Text': Text = cnt for style in styles: styleName = style[0] self.subDict[styleName] = { 'Fontname': '', 'Fontsize': '', 'PrimaryColour': '', 'SecondaryColour': '', 'OutlineColour': '', 'BackColour': '', 'Bold': '', 'Italic': '', 'Underline': '', 'StrikeOut': '', 'ScaleX': '', 'ScaleY': '', 'Spacing': '', 'Angle': '', 'BorderStyle': '', 'Outline': '', 'Shadow': '', 'Alignment': '', 'MarginL': '', 'MarginR': '', 'MarginV': '', 'Encoding': '', 'Tableview': [], 'Events': {} } for cnt, _format in enumerate(styleFormat): if _format in self.subDict[styleName]: self.subDict[styleName][_format] = style[cnt] for line in events: if styleName.replace(' ', '') == line[Style].replace(' ', ''): start = calSubTime(line[Start]) // 10 * 10 delta = calSubTime(line[End]) - start // 10 * 10 self.subDict[styleName]['Tableview'].append( [line[Start], line[End], line[Text]]) self.subDict[styleName]['Events'][start] = [ delta, line[Text] ] self.subCombox.clear() combox = [] for style in self.subDict.keys(): if style: combox.append(style) self.subCombox.addItems(combox)
class MainPage(qt.QWidget): def __init__(self, db_session, **kwargs): super(MainPage, self).__init__() self.db_session = db_session # Create central widget that will contain everything # (Bit odd design decision from QT, I would say, to separate widgets and # layouts. Now we need to have central _widget_ to contain layout to contain # widgets) central_widget = QWidget() central_widget.setStyleSheet("background: white;") # Add central widget to main window # Create main grid layout that will organize everything main_grid = qt.QGridLayout(central_widget) self.setLayout(main_grid) main_grid.setSpacing(0) main_grid.setMargin(0) # Yet again interesting design decision. On QT you cannot set style for layout. # Thus, we create widget that will contain layout and now we can set style for the widget. widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid = QWidget( ) widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid.setStyleSheet( ''' QObject { background: #FF005AA1; } QPushButton { background: #FF005AA1; color: white; text-align: center; border: none; font-weight: 500; font-size: 15px; height: 48px; width: 120px; } QPushButton:hover { background-color: #FF014a82; } QPushButton:checked { background: #FF01508c; } QPushButton:pressed { color: #FF005AA1; background: white; } QWidget{ background: #FF005AA1; } ''') # On left side we will have some (or at least one) button left_side_buttons = QVBoxLayout( widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid) left_side_buttons.setSpacing(0) left_side_buttons.setMargin(0) # And add it to main box the left most cell main_grid.addWidget( widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid, 0, 0) main_grid.setRowStretch(0, 1) # Column 0 must not stretch main_grid.setColumnStretch(0, 0) # Column 1 must stretch main_grid.setColumnStretch(1, 1) # Separator line line = qt.QFrame() line.setFrameShape(qt.QFrame.HLine) line.setFrameShadow(qt.QFrame.Sunken) # Add scan button self.scan_button = qt.QPushButton("Luo laskut") self.scan_button.clicked.connect(self.luo_lasku_pressed_handler) # Add widgets to container left_side_buttons.addWidget(self.scan_button) # Add separator line line = qt.QFrame() line.setFrameShape(qt.QFrame.HLine) line.setFrameShadow(qt.QFrame.Sunken) left_side_buttons.addWidget(line) # Add stretch that will stretch to fill rest of the space left_side_buttons.addStretch() self.list_of_visits = qt.QTreeWidget() self.list_of_visits.setColumnCount(3) self.list_of_visits.setHeaderLabels( ["Käyntipäivä", "Nimi", "Terapian laji", "Lisätiedot"]) self.list_of_visits.setSortingEnabled(True) # Allow multiselect self.list_of_visits.setSelectionMode( qt.QAbstractItemView.ExtendedSelection) third_stupid_widget = QWidget() right_side_layout = qt.QVBoxLayout(third_stupid_widget) main_grid.addWidget(third_stupid_widget, 0, 1) new_visit_date = QDateEdit(datetime.datetime.now()) new_visit_date.setCalendarPopup(True) new_visit_date.setDisplayFormat('dd.MM.yyyy') self.new_visit_customers_combobox = QComboBox() new_visit_type = QLineEdit() new_visit_type.setText("Terapia") self.update_page() self.new_visit_button = qt.QPushButton("Lisää käynti") second_stupid_widget = QWidget() new_visit_layout = QHBoxLayout(second_stupid_widget) right_side_layout.addWidget(second_stupid_widget) new_visit_layout.addWidget(new_visit_date) new_visit_layout.addWidget(self.new_visit_customers_combobox) new_visit_layout.addWidget(new_visit_type) new_visit_layout.addWidget(self.new_visit_button) right_side_layout.addWidget(self.list_of_visits) # Add properties view # main_grid.addWidget(qt.QPlainTextEdit(), 0, 2) def new_visit_handler(): for _customer in self.customers: if _customer.name == self.new_visit_customers_combobox.currentText( ): _customer.new_visit( cost=_customer.hour_price, visit_length_min=45, visit_date=new_visit_date.date().toPython(), visit_type=new_visit_type.text(), ) self.update_page() db_session.commit() self.new_visit_button.clicked.connect(new_visit_handler) # create context menu self.popMenu = qt.QMenu(self) self.popMenu.addAction( qt.QAction('Poista käynti', self.list_of_visits, triggered=self._delete_visit)) # set button context menu policy self.list_of_visits.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.list_of_visits.customContextMenuRequested.connect( self.on_context_menu) def on_context_menu(self, point): # show context menu self.popMenu.exec_(QtGui.QCursor.pos()) def luo_lasku_pressed_handler(self): import pdf_writer import therapist billed_customers = [] customers = self.db_session.query(customer.Customer).all() therapist = self.db_session.query(therapist.Therapist).first() for cust in customers: if cust.unbilled_visits(): billed_customers.append(cust) pdf_writer.write_invoice(therapist, cust) if billed_customers: pdf_writer.write_tilitys(therapist, billed_customers) for cust in customers: for _visit in cust.unbilled_visits(): _visit.billed = datetime.date.today() # Commit billed visits self.db_session.commit() self.update_page() def update_page(self): self.list_of_visits.clear() self.new_visit_customers_combobox.clear() self.customers = self.db_session.query(customer.Customer).group_by( customer.Customer.name) for _customer in self.customers: self.add_visits_for_customer(_customer) self.new_visit_customers_combobox.addItem(_customer.name) def add_visits_for_customer(self, _customer): for _visit in _customer.unbilled_visits(): cell_objects = { 0: 'visit_date', 1: 'NO_EDIT', 2: 'visit_type', 3: 'notes' } MyTreeWidget(self.list_of_visits, [ _visit.visit_date.strftime("%d.%m.%Y"), _customer.name, _visit.visit_type, _visit.notes, ], cell_objects=cell_objects, db_session=self.db_session, id=_visit.id, class_item=visit.Visit, class_instance=_visit) def _delete_visit(self): for _visit in self.list_of_visits.selectedItems(): _visit.delete() self.update_page()
class ViewStudentListToolbar(QToolBar): def __init__(self): """ Toolbar for the students list side panel tab """ QToolBar.__init__(self) self.current_group: str = None self.__config_mode = False # Widgets self.combo_groups = QComboBox() self.create_field = ViewAddLine() self.config_action_menu = ViewMenuButton( "Actions", self.create_field.show_field, [(tr("grp_action_import_csv"), "import_csv"), (tr("grp_action_create_group"), "create_group"), (tr("grp_action_del_group"), "delete_group"), 'sep', (tr("grp_action_create_student"), "create_student"), (tr("grp_action_del_student"), "killstudent"), 'sep', (tr("grp_action_auto_placement"), "auto_place")]) self.sort_actions_menu = ViewMenuButton( "Tri", self.create_field.show_field, [ (tr("grp_action_sort_asc"), "sort_asc"), (tr("grp_action_sort_desc"), "sort_desc"), (tr("grp_action_sort_by_place") + " Z", "sort_desks_Z"), (tr("grp_action_sort_by_place") + " 2", "sort_desks_2"), (tr("grp_action_sort_by_place") + " U", "sort_desks_U"), ]) # Signals self.sig_combo_changed: Signal = None self.combo_groups.activated.connect(self.on_group_changed) # Layout self.a_combo = self.addWidget(self.combo_groups) self.a_conf_menu = self.addWidget(self.config_action_menu) self.a_sort_menu = self.addWidget(self.sort_actions_menu) self.addWidget(self.create_field) self.__set_style() def __set_style(self) -> None: """ Inits the stylesheet of this widget """ # Toolbar self.setStyleSheet(get_stylesheet("toolbar")) def edit_student(self, student_id: int, student_data: str) -> None: """ Shows the creation field, with the student data (last name + first name) that can be edited. :param student_id: student id :param student_data: student last name + first name """ if self.__config_mode: self.create_field.show_field(str(student_id), student_data) def switch_config_mode(self, is_config_mode: bool) -> None: self.__config_mode = is_config_mode self.a_combo.setVisible(self.__config_mode) self.a_conf_menu.setVisible(self.__config_mode) self.a_sort_menu.setVisible(not self.__config_mode) def on_group_changed(self) -> None: """ Triggered when the combo selection changed, emits the signal if the selected group was updated. """ text = self.combo_groups.currentText() if text and text != self.current_group: self.current_group = text self.sig_combo_changed.emit(text) def init_groups(self, groups: list) -> None: """ Resets the combo box before adding all the groups to the combo. :param groups: groups names list :type groups: list """ self.reset_groups() self.__add_groups(groups) self.repaint() def __add_groups(self, list_groups: list) -> None: """ Adds the list of all specified groups inside the combo. :param list_groups: All the groups to add :type list_groups: list """ self.combo_groups.addItems(list_groups) def reset_groups(self) -> None: """ Resets the groups combo (clears it) """ self.combo_groups.clear()
class View(QMainWindow): current_mac = Signal(str) def __init__(self, model, pacer): super().__init__() self.setWindowTitle("OpenHRV") self.setWindowIcon(QIcon("./logo.png")) self.setGeometry(50, 50, 1750, 750) self.model = model self.pacer = pacer self.threadpool = QThreadPool() self.scanner = SensorScanner() self.scanner.mac_update.connect(self.model.set_mac_addresses) self.sensor = SensorClient() self.current_mac.connect(self.sensor.start) self.sensor.ibi_update.connect(self.model.set_ibis_buffer) self.ibis_plot = pg.PlotWidget() self.ibis_plot.setBackground("w") self.ibis_plot.setLabel("left", "Inter-Beat-Interval (msec)", **{"font-size": "25px"}) self.ibis_plot.setLabel("bottom", "Seconds", **{"font-size": "25px"}) self.ibis_plot.showGrid(y=True) self.ibis_plot.setYRange(300, 1500, padding=0) self.ibis_plot.setMouseEnabled(x=False, y=False) self.ibis_signal = pg.PlotCurveItem() pen = pg.mkPen(color=(0, 191, 255), width=7.5) self.ibis_signal.setPen(pen) self.ibis_signal.setData(self.model.seconds, self.model.ibis_buffer) self.ibis_plot.addItem(self.ibis_signal) self.pacer_plot = pg.PlotWidget() self.pacer_plot.setBackground("w") self.pacer_plot.setAspectLocked(lock=True, ratio=1) self.pacer_plot.setMouseEnabled(x=False, y=False) self.pacer_plot.disableAutoRange() self.pacer_plot.setXRange(-1, 1, padding=0) self.pacer_plot.setYRange(-1, 1, padding=0) self.pacer_plot.hideAxis("left") self.pacer_plot.hideAxis("bottom") self.pacer_disc = pg.PlotCurveItem() brush = pg.mkBrush(color=(135, 206, 250)) self.pacer_disc.setBrush(brush) self.pacer_disc.setFillLevel(1) self.pacer_plot.addItem(self.pacer_disc) self.pacer_rate = QSlider(Qt.Horizontal) self.pacer_rate.setRange(3, 10) self.pacer_rate.valueChanged.connect(self.model.set_breathing_rate) self.pacer_rate.setSliderPosition(self.model.breathing_rate) self.pacer_label = QLabel( f"Breathing Rate: {self.model.breathing_rate}") self.pacer_label.setFont(QFont("Arial", 25)) self.scan_button = QPushButton("Scan") self.scan_button.clicked.connect(self.scanner.scan) self.mac_menu = QComboBox() self.start_button = QPushButton("Start") self.start_button.clicked.connect(self.start_sensor) self.stop_button = QPushButton("Stop") self.stop_button.clicked.connect(self.stop_sensor) self.hrv_label = QLabel("Current HRV:") self.hrv_label.setFont(QFont("Arial", 25)) self.hrv_display = QLabel() self.hrv_display.setText("0") self.hrv_display.setFont(QFont("Arial", 50)) self.central_widget = QWidget() self.setCentralWidget(self.central_widget) self.hlayout0 = QHBoxLayout(self.central_widget) self.hlayout1 = QHBoxLayout() self.hlayout2 = QHBoxLayout() self.vlayout0 = QVBoxLayout() self.vlayout1 = QVBoxLayout() self.hlayout0.addLayout(self.vlayout0, stretch=75) self.hlayout0.addLayout(self.vlayout1, stretch=25) self.vlayout0.addWidget(self.ibis_plot) self.vlayout0.addLayout(self.hlayout1) self.vlayout0.addLayout(self.hlayout2) self.hlayout1.addWidget(self.scan_button) self.hlayout1.addWidget(self.mac_menu) self.hlayout2.addWidget(self.start_button) self.hlayout2.addWidget(self.stop_button) self.hlayout2.addWidget(self.hrv_label) self.hlayout2.addWidget(self.hrv_display) self.vlayout1.addWidget(self.pacer_plot, stretch=70) self.vlayout1.addWidget(self.pacer_rate, stretch=15) self.vlayout1.addWidget(self.pacer_label, stretch=15) self.model.ibis_buffer_update.connect(self.plot_ibis) self.model.ibis_buffer_update.connect(self.compute_local_hrv) self.model.hrv_buffer_update.connect(self.plot_local_hrv) self.model.mac_addresses_update.connect(self.list_macs) self.model.pacer_disk_update.connect(self.plot_pacer_disk) self.model.pacer_rate_update.connect(self.update_pacer_label) self.pacer.start() self.scanner_thread = QThread(self) self.scanner.moveToThread(self.scanner_thread) self.scanner_thread.start() self.sensor_thread = QThread(self) self.sensor.moveToThread(self.sensor_thread) self.sensor_thread.start() def start_sensor(self): if self.sensor.loop.is_running(): print("Client already running.") return mac = self.mac_menu.currentText() # TODO: return in case of invalid mac self.current_mac.emit(mac) # starts sensor def stop_sensor(self): if not self.sensor.loop.is_running(): print("No client running.") return self.sensor.stop() def compute_local_hrv(self, ibis): # TODO: move to model current_ibi_phase = np.sign( ibis[-1] - ibis[-2]) # 1: IBI rises, -1: IBI falls, 0: IBI constant if current_ibi_phase == 0: return if current_ibi_phase != self.model.last_ibi_phase: current_ibi_extreme = ibis[-2] local_hrv = abs(self.model.last_ibi_extreme - current_ibi_extreme) # potentially enforce constraints on local power here updated_hrv_buffer = self.model.hrv_buffer # copy avoids emission of model.hrv_buffer_update updated_hrv_buffer = np.roll(updated_hrv_buffer, -1) updated_hrv_buffer[-1] = local_hrv self.model.hrv_buffer = updated_hrv_buffer print(f"Local hrv: {local_hrv}!") self.model.last_ibi_extreme = current_ibi_extreme self.model.last_ibi_phase = current_ibi_phase def plot_ibis(self, ibis): self.ibis_signal.setData(self.model.seconds, ibis) def plot_local_hrv(self, hrv): self.hrv_display.setText(str(hrv[-1])) def list_macs(self, macs): self.mac_menu.clear() self.mac_menu.addItems(macs) def plot_pacer_disk(self, coordinates): self.pacer_disc.setData(*coordinates) def update_pacer_label(self, rate): self.pacer_label.setText(f"Breathing Rate: {rate}")
class Main(QMainWindow): send = Signal() play = Signal(str, int) stop = Signal() get = Signal() channelIdx = Signal(int) def __init__(self): super().__init__() self.setWindowTitle('Test Window') self.setGeometry(200, 300, 400, 200) # self.TcpClient = TcpClient(('127.0.0.1', 10000)) # self.TcpClient.start() self.qb = QComboBox(self) self.qb.resize(250, 28) self.qb.move(10, 11) self.btnGet = QPushButton('Get', self) self.btnGet.move(260, 10) self.qb1 = QComboBox(self) self.qb1.resize(100, 28) self.qb1.move(10, 50) self.channel = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13], [14, 15]] self.qb1.addItems( ['1,2', '3,4', '5,6', '7,8', '9,10', '11,12', '13,14', '15,16']) self.btnOpen = QPushButton('Open', self) self.btnOpen.move(10, 90) self.btnPlay = QPushButton('Play', self) self.btnPlay.move(110, 90) self.btnStop = QPushButton('Stop', self) self.btnStop.move(210, 90) self.Player = Player() self.play.connect(self.Player.play) self.stop.connect(self.Player.stop) self.btnOpen.clicked.connect(self.showDialog) self.btnPlay.clicked.connect(self.playFile) self.btnStop.clicked.connect(self.Player.stop) self.btnGet.clicked.connect(self.Player.get_devices) self.Player.audio_devices.connect(self.updateDevices) self.qb.currentIndexChanged.connect(self.changeDevice) self.qb1.currentIndexChanged.connect(self.changeChannel) self.channelIdx.connect(self.Player.changeChannel) self.Player.start() self.deviceNum = 0 self.asioChannel = [0, 1] self.show() def showDialog(self): self.file = QFileDialog.getOpenFileName(self, 'Open file', './') print(self.file[0]) def changeChannel(self): idx = self.qb1.currentIndex() self.asioChannel = self.channel[idx] self.channelIdx.emit(idx) def changeDevice(self): self.deviceNum = self.qb.currentIndex() @Slot(list) def updateDevices(self, devices): print(devices) self.qb.clear() self.qb.addItems(devices) def click(self): self.send.emit() def playFile(self): print('play') if self.file: self.play.emit(self.file[0], self.deviceNum)
class MainWindow(QMainWindow): # Main window def __init__(self): super().__init__() self.setWindowTitle = 'DD烤肉机' self.resize(1870, 820) self.mainWidget = QWidget() self.mainLayout = QGridLayout() # Grid layout self.mainLayout.setSpacing(10) self.mainWidget.setLayout(self.mainLayout) self.duration = 60000 self.bitrate = 2000 self.fps = 60 self.initProcess = InitProcess() self.previewSubtitle = PreviewSubtitle() self.dnldWindow = YoutubeDnld() self.exportWindow = exportSubtitle() self.videoDecoder = VideoDecoder() self.exportWindow.exportArgs.connect(self.exportSubtitle) self.stack = QStackedWidget() self.stack.setFixedWidth(1300) self.mainLayout.addWidget(self.stack, 0, 0, 10, 8) buttonWidget = QWidget() buttonLayout = QHBoxLayout() buttonWidget.setLayout(buttonLayout) self.playButton = QPushButton('从本地打开') self.playButton.clicked.connect(self.open) self.playButton.setFixedWidth(400) self.playButton.setFixedHeight(75) self.dnldButton = QPushButton('Youtube下载器') self.dnldButton.clicked.connect(self.popDnld) self.dnldButton.setFixedWidth(400) self.dnldButton.setFixedHeight(75) buttonLayout.addWidget(self.playButton) buttonLayout.addWidget(self.dnldButton) self.stack.addWidget(buttonWidget) self.videoPath = '' self.videoWidth = 1920 self.videoHeight = 1080 self.globalInterval = 200 self.setPlayer() self.setSubtitle() self.setToolBar() self.setCentralWidget(self.mainWidget) self.playStatus = False self.volumeStatus = True self.volumeValue = 100 self.subSelectedTxt = '' self.subReplayTime = 1 self.clipBoard = [] self.grabKeyboard() self.show() def setPlayer(self): self.playerWidget = QGraphicsVideoItem() self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.resize(1280, 730) self.scene.addItem(self.playerWidget) self.stack.addWidget(self.view) self.player = QMediaPlayer(self, QMediaPlayer.VideoSurface) self.player.setVideoOutput(self.playerWidget) self.view.installEventFilter(self) self.view.show() self.srtTextItemDict = {0: QGraphicsTextItem(), 1: QGraphicsTextItem(), 2: QGraphicsTextItem(), 3: QGraphicsTextItem(), 4: QGraphicsTextItem()} for _, srtTextItem in self.srtTextItemDict.items(): self.scene.addItem(srtTextItem) def setSubtitle(self): self.subtitleDict = {x: {-1: [100, '']} for x in range(5)} self.subTimer = QTimer() self.subTimer.setInterval(100) self.subtitle = QTableWidget() self.subtitle.setAutoScroll(False) self.subtitle.setEditTriggers(QAbstractItemView.NoEditTriggers) self.mainLayout.addWidget(self.subtitle, 0, 8, 10, 12) self.subtitle.setColumnCount(5) self.subtitle.selectRow(0) self.subtitle.setHorizontalHeaderLabels(['%s' % (i + 1) for i in range(5)]) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) for index in range(5): self.subtitle.setColumnWidth(index, 130) self.subtitle.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.subtitle.setEditTriggers(QAbstractItemView.DoubleClicked) self.subtitle.horizontalHeader().sectionClicked.connect(self.addSubtitle) self.subtitle.doubleClicked.connect(self.releaseKeyboard) self.subtitle.cellChanged.connect(self.subEdit) self.subtitle.verticalHeader().sectionClicked.connect(self.subHeaderClick) self.subtitle.setContextMenuPolicy(Qt.CustomContextMenu) self.subtitle.customContextMenuRequested.connect(self.popTableMenu) self.initSubtitle() def initSubtitle(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) for x in range(self.subtitle.columnCount()): for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, x, 1, 1) self.subtitle.setRowCount(self.duration // self.globalInterval + 1) for x in range(self.subtitle.columnCount()): for y in range(self.subtitle.rowCount()): self.subtitle.setItem(y, x, QTableWidgetItem('')) self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def addSubtitle(self, index): subtitlePath = QFileDialog.getOpenFileName(self, "请选择字幕", None, "字幕文件 (*.srt *.vtt *.ass *.ssa)")[0] if subtitlePath: self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) if subtitlePath.endswith('.ass') or subtitlePath.endswith('.ssa'): p = subprocess.Popen(['utils/ffmpeg.exe', '-y', '-i', subtitlePath, 'temp_sub.srt']) p.wait() subtitlePath = 'temp_sub.srt' subData = {} with open(subtitlePath, 'r', encoding='utf-8') as f: f = f.readlines() subText = '' YoutubeAutoSub = False for l in f: if '<c>' in l: YoutubeAutoSub = True break for cnt, l in enumerate(f): if '<c>' in l: lineData = l.split('c>') if len(lineData) > 3: subText, start, _ = lineData[0].split('<') start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(lineData[-3][1:-2]) // self.globalInterval * self.globalInterval for i in range(len(lineData) // 2): subText += lineData[i * 2 + 1][:-2] subData[start] = [end - start, subText] else: subText, start, _ = lineData[0].split('<') start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: subText += lineData[1][:-2] subData[start] = [self.globalInterval, subText] elif '-->' in l and f[cnt + 2].strip() and '<c>' not in f[cnt + 2]: subText = f[cnt + 2][:-1] start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval subData[start] = [end - start, subText] if '-->' in l and f[cnt + 1].strip() and not YoutubeAutoSub: start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval delta = end - start if delta > 10: if '<b>' in f[cnt + 1]: subData[start] = [delta, f[cnt + 1].split('<b>')[1].split('<')[0]] else: subData[start] = [delta, f[cnt + 1][:-1]] self.subtitleDict[index].update(subData) maxRow = 0 for _, v in self.subtitleDict.items(): startMax = max(v.keys()) rowCount = (startMax + v[startMax][0]) // self.globalInterval if rowCount > maxRow: maxRow = rowCount if maxRow < self.duration // self.globalInterval + 1: maxRow = self.duration // self.globalInterval else: self.duration = maxRow * self.globalInterval self.subtitle.setRowCount(maxRow) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) for start, rowData in subData.items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.refreshComboBox() self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def subTimeOut(self): fontColor = self.previewSubtitle.fontColor fontSize = (self.previewSubtitle.fontSize + 5) / 2.5 fontBold = self.previewSubtitle.bold fontItalic = self.previewSubtitle.italic fontShadowOffset = self.previewSubtitle.shadowOffset for _, srtTextItem in self.srtTextItemDict.items(): srtTextItem.setDefaultTextColor(fontColor) font = QFont() font.setFamily("微软雅黑") font.setPointSize(fontSize) font.setBold(fontBold) font.setItalic(fontItalic) srtTextItem.setFont(font) srtTextShadow = QGraphicsDropShadowEffect() srtTextShadow.setOffset(fontShadowOffset) srtTextItem.setGraphicsEffect(srtTextShadow) try: selected = self.subtitle.selectionModel().selection().indexes() for x, i in enumerate(selected): if self.subtitle.item(i.row(), x): txt = self.subtitle.item(i.row(), x).text() if txt: self.srtTextItemDict[x].setPlainText('#%s:' % (x + 1) + txt) txtSize = self.srtTextItemDict[x].boundingRect().size() posY = self.playerWidget.size().height() - txtSize.height() * (x + 1) posX = (self.playerWidget.size().width() - txtSize.width()) / 2 self.srtTextItemDict[x].setPos(posX, posY) else: self.srtTextItemDict[x].setPlainText('') else: self.srtTextItemDict[x].setPlainText('') except: pass def subHeaderClick(self, index): if self.player.duration(): position = index * self.globalInterval self.player.setPosition(position) self.videoSlider.setValue(position * 1000 // self.player.duration()) self.setTimeLabel() def subEdit(self, row, index): repeat = self.subtitle.rowSpan(row, index) self.setSubtitleDict(row, index, repeat, self.subtitle.item(row, index).text()) self.subtitle.cellChanged.disconnect(self.subEdit) for cnt in range(repeat): if self.subtitle.item(row + cnt, index).text(): self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) else: self.subtitle.item(row, index).setBackground(QBrush(QColor('#232629'))) self.subtitle.cellChanged.connect(self.subEdit) def setSubtitleDict(self, row, index, num, text): self.subtitleDict[index][row * self.globalInterval] = [num * self.globalInterval, text] def popTableMenu(self, pos): self.subtitle.cellChanged.disconnect(self.subEdit) pos = QPoint(pos.x() + 55, pos.y() + 30) menu = QMenu() copy = menu.addAction('复制') paste = menu.addAction('粘贴') setSpan = menu.addAction('合并') clrSpan = menu.addAction('拆分') addSub = menu.addAction('导入字幕') cutSub = menu.addAction('裁剪字幕') action = menu.exec_(self.subtitle.mapToGlobal(pos)) selected = self.subtitle.selectionModel().selection().indexes() yList = [selected[0].row(), selected[-1].row()] xSet = set() for i in range(len(selected)): xSet.add(selected[i].column()) if action == copy: for x in xSet: self.clipBoard = [] for y in range(yList[0], yList[1] + 1): if self.subtitle.item(y, x): self.clipBoard.append(self.subtitle.item(y, x).text()) else: self.clipBoard.append('') break elif action == paste: self.subtitle.cellChanged.connect(self.subEdit) for x in xSet: for cnt, text in enumerate(self.clipBoard): self.subtitle.setItem(yList[0] + cnt, x, QTableWidgetItem(text)) self.subtitleDict[x][(yList[0] + cnt) * self.globalInterval] = [self.globalInterval, text] self.subtitle.cellChanged.disconnect(self.subEdit) elif action == setSpan: for x in xSet: if not self.subtitle.item(yList[0], x): firstItem = '' else: firstItem = self.subtitle.item(yList[0], x).text() for y in range(yList[0], yList[1] + 1): self.subtitle.setSpan(y, x, 1, 1) self.subtitle.setItem(y, x, QTableWidgetItem(firstItem)) self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d'))) if y * self.globalInterval in self.subtitleDict[x]: del self.subtitleDict[x][y * self.globalInterval] for x in xSet: self.subtitle.setSpan(yList[0], x, yList[1] - yList[0] + 1, 1) self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem) elif action == clrSpan: for x in xSet: if not self.subtitle.item(yList[0], x): firstItem = '' else: firstItem = self.subtitle.item(yList[0], x).text() for cnt, y in enumerate(range(yList[0], yList[1] + 1)): self.subtitle.setSpan(y, x, 1, 1) if not cnt: self.subtitle.setItem(yList[0], x, QTableWidgetItem(firstItem)) if firstItem: self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d'))) else: self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) else: self.subtitle.setItem(y, x, QTableWidgetItem('')) self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem) break elif action == addSub: self.subtitle.cellChanged.connect(self.subEdit) for x in xSet: self.addSubtitle(x) self.subtitle.cellChanged.disconnect(self.subEdit) elif action == cutSub: for x in xSet: start = yList[0] * self.globalInterval end = yList[1] * self.globalInterval self.exportSubWindow(start, end, x + 1) self.subtitle.cellChanged.connect(self.subEdit) def setToolBar(self): ''' menu bar, file menu, play menu, tool bar. ''' toolBar = QToolBar() self.setContextMenuPolicy(Qt.NoContextMenu) self.addToolBar(toolBar) fileMenu = self.menuBar().addMenu('&文件') openAction = QAction(QIcon.fromTheme('document-open'), '&打开...', self, shortcut=QKeySequence.Open, triggered=self.open) fileMenu.addAction(openAction) downloadAction = QAction(QIcon.fromTheme('document-open'), '&Youtube下载器', self, triggered=self.popDnld) fileMenu.addAction(downloadAction) exitAction = QAction(QIcon.fromTheme('application-exit'), '&退出', self, shortcut='Ctrl+Q', triggered=self.close) fileMenu.addAction(exitAction) playMenu = self.menuBar().addMenu('&功能') self.playIcon = self.style().standardIcon(QStyle.SP_MediaPlay) self.pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause) self.playAction = toolBar.addAction(self.playIcon, '播放') self.playAction.triggered.connect(self.mediaPlay) self.volumeIcon = self.style().standardIcon(QStyle.SP_MediaVolume) self.volumeMuteIcon = self.style().standardIcon(QStyle.SP_MediaVolumeMuted) self.volumeAction = toolBar.addAction(self.volumeIcon, '静音') self.volumeAction.triggered.connect(self.volumeMute) previewAction = QAction(QIcon.fromTheme('document-open'), '&设置预览字幕', self, triggered=self.popPreview) playMenu.addAction(previewAction) decodeMenu = self.menuBar().addMenu('&输出') decodeAction = QAction(QIcon.fromTheme('document-open'), '&输出字幕及视频', self, triggered=self.decode) decodeMenu.addAction(decodeAction) self.volSlider = Slider() self.volSlider.setOrientation(Qt.Horizontal) self.volSlider.setMinimum(0) self.volSlider.setMaximum(100) self.volSlider.setFixedWidth(120) self.volSlider.setValue(self.player.volume()) self.volSlider.setToolTip(str(self.volSlider.value())) self.volSlider.pointClicked.connect(self.setVolume) toolBar.addWidget(self.volSlider) self.videoPositionEdit = LineEdit('00:00') self.videoPositionEdit.setAlignment(Qt.AlignRight) self.videoPositionEdit.setFixedWidth(75) self.videoPositionEdit.setFont(QFont('Timers', 14)) self.videoPositionEdit.clicked.connect(self.mediaPauseOnly) self.videoPositionEdit.editingFinished.connect(self.mediaPlayOnly) self.videoPositionLabel = QLabel(' / 00:00 ') self.videoPositionLabel.setFont(QFont('Timers', 14)) toolBar.addWidget(QLabel(' ')) toolBar.addWidget(self.videoPositionEdit) toolBar.addWidget(self.videoPositionLabel) self.timer = QTimer() self.timer.setInterval(100) self.videoSlider = Slider() self.videoSlider.setEnabled(False) self.videoSlider.setOrientation(Qt.Horizontal) self.videoSlider.setMinimum(0) self.videoSlider.setMaximum(1000) self.videoSlider.setFixedWidth(1000) self.videoSlider.sliderMoved.connect(self.timeStop) self.videoSlider.sliderReleased.connect(self.timeStart) self.videoSlider.pointClicked.connect(self.videoSliderClick) toolBar.addWidget(self.videoSlider) toolBar.addWidget(QLabel(' ')) self.globalIntervalComBox = QComboBox() self.globalIntervalComBox.addItems(['间隔 100ms', '间隔 200ms', '间隔 500ms', '间隔 1s']) self.globalIntervalComBox.setCurrentIndex(1) self.globalIntervalComBox.currentIndexChanged.connect(self.setGlobalInterval) toolBar.addWidget(self.globalIntervalComBox) toolBar.addWidget(QLabel(' ')) self.subEditComBox = QComboBox() self.refreshComboBox() toolBar.addWidget(self.subEditComBox) toolBar.addWidget(QLabel(' ')) moveForward = QPushButton('- 1') moveForward.setFixedWidth(50) toolBar.addWidget(moveForward) toolBar.addWidget(QLabel(' ')) moveAfterward = QPushButton('+ 1') moveAfterward.setFixedWidth(50) toolBar.addWidget(moveAfterward) toolBar.addWidget(QLabel(' ')) clearSub = QPushButton('清空') clearSub.setFixedWidth(50) toolBar.addWidget(clearSub) toolBar.addWidget(QLabel(' ')) outputSub = QPushButton('裁剪') outputSub.setFixedWidth(50) toolBar.addWidget(outputSub) moveForward.clicked.connect(self.moveForward) moveAfterward.clicked.connect(self.moveAfterward) clearSub.clicked.connect(self.clearSub) outputSub.clicked.connect(self.exportSubWindow) def setGlobalInterval(self, index): if not self.playStatus: self.mediaPlay() self.globalInterval = {0: 100, 1: 200, 2: 500, 3: 1000}[index] self.initSubtitle() self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) for index, subData in self.subtitleDict.items(): for start, rowData in subData.items(): startRow = start // self.globalInterval deltaRow = rowData[0] // self.globalInterval if deltaRow: endRow = startRow + deltaRow for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) if row >= 0: self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def moveForward(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) index = self.subEditComBox.currentIndex() for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, index, 1, 1) self.subtitle.setItem(y, index, QTableWidgetItem('')) self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629'))) tmpDict = self.subtitleDict[index] self.subtitleDict[index] = {} for start, rowData in tmpDict.items(): self.subtitleDict[index][start - self.globalInterval] = rowData for start, rowData in self.subtitleDict[index].items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def moveAfterward(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) index = self.subEditComBox.currentIndex() for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, index, 1, 1) self.subtitle.setItem(y, index, QTableWidgetItem('')) self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629'))) tmpDict = self.subtitleDict[index] self.subtitleDict[index] = {} for start, rowData in tmpDict.items(): self.subtitleDict[index][start + self.globalInterval] = rowData for start, rowData in self.subtitleDict[index].items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def clearSub(self): index = self.subEditComBox.currentIndex() reply = QMessageBox.information(self, '清空字幕', '清空第 %s 列字幕条?' % (index + 1), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) self.subtitleDict[index] = {0: [self.globalInterval, '']} for i in range(self.subtitle.rowCount()): self.subtitle.setSpan(i, index, 1, 1) self.subtitle.setItem(i, index, QTableWidgetItem('')) self.subtitle.item(i, index).setBackground(QBrush(QColor('#232629'))) self.subtitle.setHorizontalHeaderItem(index, QTableWidgetItem('%s' % (index + 1))) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def exportSubWindow(self, start=0, end=0, index=None): self.releaseKeyboard() self.exportWindow.hide() self.exportWindow.show() start = '00:00.0' if not start else self.splitTime(start) end = self.splitTime(self.duration) if not end else self.splitTime(end) if not index: index = self.subEditComBox.currentIndex() + 1 self.exportWindow.setDefault(start, end, index) def exportSubtitle(self, exportArgs): start = calSubTime2(exportArgs[0]) end = calSubTime2(exportArgs[1]) subStart = calSubTime2(exportArgs[2]) index = exportArgs[3] - 1 subData = self.subtitleDict[index] rowList = sorted(subData.keys()) exportRange = [] for t in rowList: if t >= start and t <= end: exportRange.append(t) subNumber = 1 with open(exportArgs[-1], 'w', encoding='utf-8') as exportFile: for t in exportRange: text = subData[t][1] if text: start = ms2Time(t + subStart) end = ms2Time(t + subStart + subData[t][0]) exportFile.write('%s\n%s --> %s\n%s\n\n' % (subNumber, start, end, text)) subNumber += 1 QMessageBox.information(self, '导出字幕', '导出完成', QMessageBox.Yes) self.exportWindow.hide() def refreshComboBox(self): self.subEditComBox.clear() for i in range(self.subtitle.columnCount()): self.subEditComBox.addItem('字幕 ' + str(i + 1)) def open(self): self.videoPath = QFileDialog.getOpenFileName(self, "请选择视频文件", None, "MP4格式 (*.mp4);;所有文件(*.*)")[0] if self.videoPath: cmd = ['utils/ffmpeg.exe', '-i', self.videoPath] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.wait() for l in p.stdout.readlines(): l = l.decode('utf8') if 'Duration' in l: self.duration = calSubTime(l.split(' ')[3][:-1]) if 'Stream' in l and 'DAR' in l: self.videoWidth, self.videoHeight = map(int, l.split(' [')[0].split(' ')[-1].split('x')) args = l.split(',') for cnt, arg in enumerate(args): if 'kb' in arg: self.bitrate = int(arg.split('kb')[0]) self.fps = int(args[cnt + 1].split('fps')[0]) break break self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) self.subtitle.setRowCount(self.duration // self.globalInterval + 1) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() url = QUrl.fromLocalFile(self.videoPath) self.stack.setCurrentIndex(1) self.playerWidget.setSize(QSizeF(1280, 720)) self.player.setMedia(url) self.playStatus = True self.videoSlider.setEnabled(True) self.mediaPlay() self.timer.start() self.timer.timeout.connect(self.timeOut) self.subTimer.start() self.subTimer.timeout.connect(self.subTimeOut) def popDnld(self): self.releaseKeyboard() self.dnldWindow.hide() self.dnldWindow.show() def popPreview(self): self.releaseKeyboard() self.previewSubtitle.hide() self.previewSubtitle.show() def decode(self): self.releaseKeyboard() self.videoDecoder.setDefault(self.videoPath, self.videoWidth, self.videoHeight, self.duration, self.bitrate, self.fps, self.subtitleDict) self.videoDecoder.hide() self.videoDecoder.show() def mediaPlay(self): if self.playStatus: self.player.play() self.grabKeyboard() self.timeStart() self.playStatus = False self.playAction.setIcon(self.pauseIcon) self.playAction.setText('暂停') else: self.player.pause() self.timeStop() self.playStatus = True self.playAction.setIcon(self.playIcon) self.playAction.setText('播放') def mediaPlayOnly(self): self.grabKeyboard() try: timeText = self.videoPositionEdit.text().split(':') m, s = timeText[:2] if not m: m = '00' if not s: s = '00' if len(m) > 3: m = m[:3] if len(s) > 2: s = s[:2] if m.isdigit(): m = int(m) if s.isdigit(): s = int(s) if s > 60: s = 60 total_m = self.player.duration() // 60000 if m > total_m: m = total_m self.player.setPosition(m * 60000 + s * 1000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) except: pass self.videoPositionEdit.setReadOnly(True) self.timeStart() def mediaPauseOnly(self): self.releaseKeyboard() self.videoPositionEdit.setReadOnly(False) self.player.pause() self.timeStop() self.playStatus = True self.playAction.setIcon(self.playIcon) self.playAction.setText('播放') def splitTime(self, playTime): playTime = playTime // 1000 m = str(playTime // 60) s = playTime % 60 s = ('0%s' % s)[-2:] if len(m) > 2: t = '%3s:%2s' % (m, s) else: t = '%2s:%2s' % (m, s) return t def timeOut(self): row = self.player.position() // self.globalInterval self.subtitle.selectRow(row) self.subtitle.verticalScrollBar().setValue(row - 10) if self.dnldWindow.isHidden() or self.exportWindow.isHidden() or self.videoDecoder.isHidden(): self.grabKeyboard() try: self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() except: pass def timeStop(self): self.timer.stop() def timeStart(self): self.timer.start() def videoSliderClick(self, p): self.videoSlider.setValue(p.x()) self.player.setPosition(p.x() * self.player.duration() // 1000) self.setTimeLabel() def setVolume(self, p): self.volumeValue = p.x() if self.volumeValue > 100: self.volumeValue = 100 if self.volumeValue < 0: self.volumeValue = 0 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) self.volSlider.setToolTip(str(self.volSlider.value())) if self.volumeValue: self.volumeStatus = True self.volumeAction.setIcon(self.volumeIcon) else: self.volumeStatus = False self.volumeAction.setIcon(self.volumeMuteIcon) def volumeMute(self): if self.volumeStatus: self.volumeStatus = False self.old_volumeValue = self.player.volume() self.player.setVolume(0) self.volSlider.setValue(0) self.volumeAction.setIcon(self.volumeMuteIcon) else: self.volumeStatus = True self.player.setVolume(self.old_volumeValue) self.volSlider.setValue(self.old_volumeValue) self.volumeAction.setIcon(self.volumeIcon) def setTimeLabel(self): now = self.player.position() total = self.player.duration() now = self.splitTime(now) total = self.splitTime(total) self.videoPositionEdit.setText(now) self.videoPositionLabel.setText(' / %s ' % total) def eventFilter(self, obj, event): if obj == self.view: if event.type() == QEvent.MouseButtonPress: self.mediaPlay() return QMainWindow.eventFilter(self, obj, event) def keyPressEvent(self, QKeyEvent): key = QKeyEvent.key() if key == Qt.Key_Left: if self.videoSlider.isEnabled(): self.player.setPosition(self.player.position() - 5000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() elif key == Qt.Key_Right: if self.videoSlider.isEnabled(): self.player.setPosition(self.player.position() + 5000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() elif key == Qt.Key_Up: self.volumeValue += 10 if self.volumeValue > 100: self.volumeValue = 100 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) elif key == Qt.Key_Down: self.volumeValue -= 10 if self.volumeValue < 0: self.volumeValue = 0 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) elif key == Qt.Key_Space: self.mediaPlay()
class MyGui(QWidget, GitCmd): def __init__(self, title="Create By ZZZ", path=DEFAULT_GIT_REPO): super(MyGui, self).__init__() GitCmd.__init__(self, path) # 初始化命令 self.show_info = None self.cmd_history = None self.cmd_history_cmd_list = list() # 复选框 self.check_box_select_all = None self.check_box = list() self.check_box_button = None # 默认值 self.show_log_num = DEFAULT_GIT_LOG_NUM self.file_list = DEFAULT_GIT_ADD_LIST self.gridLayout = QGridLayout(self) self.setGeometry(100, 100, 800, 700) self.setWindowTitle(title) # 记录当前widget最大行号 self.max_line_no = 0 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 显示信息相关 def add_info_text(self): # 添加消息显示框,我们使用列表方式显示 self.show_info = QListWidget() self.show_info.setFixedSize(800, 600) self.gridLayout.addWidget(self.show_info, 0, 0, 1, 4) # 单击触发绑定的槽函数 self.show_info.itemClicked.connect(self.text_block_clicked) # 命令行显示,我们使用下拉框 self.cmd_history = QComboBox() self.gridLayout.addWidget(self.cmd_history, 1, 0, 1, 4) # 设置行号 self.max_line_no = 2 def add_cmd(self, cmd): if len(self.cmd_history_cmd_list) < 10: self.cmd_history_cmd_list.append(cmd) else: self.cmd_history_cmd_list = self.cmd_history_cmd_list[1:].append(cmd) self.cmd_history.clear() self.cmd_history.addItems(reversed(self.cmd_history_cmd_list)) def update_cmd(self, extra: str): cur_cmd = self.cmd_history.currentText().split(" ") new_cmd = cur_cmd[:2] + [extra] # 拆分出来git和后面的命令,拼接参数 if cur_cmd: self.cmd_history.setItemText(0, " ".join(new_cmd)) # 对每一行都进行上色 def my_print(self, text_list: list, background: list): # self.show_info.clear() 这个可以清空显示 self.show_info.addItems([". . . . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . . . "]) for ind in range(len(text_list)): item = QListWidgetItem('%s' % text_list[ind]) item.setBackground(QColor(background[ind])) # 上色 self.show_info.addItem(item) self.show_info.scrollToBottom() # 自动到最后行 @staticmethod def text_block_clicked(item): # 这里没有什么要做的 # QMessageBox.information(self, "命令历史", "你选择了: " + item.text()) pass # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 添加按钮 def add_git_button(self): cmd_add = QPushButton('Git Add') cmd_reset = QPushButton('Git Reset') cmd_status = QPushButton('Git Status') cmd_log = QPushButton('Git Log') cmd_run = QPushButton('Run Cmd') line_no = self.max_line_no self.gridLayout.addWidget(cmd_add, line_no, 0) self.gridLayout.addWidget(cmd_reset, line_no, 1) self.gridLayout.addWidget(cmd_status, line_no, 2) self.gridLayout.addWidget(cmd_log, line_no, 3) self.gridLayout.addWidget(cmd_run, line_no + 1, 0) self.max_line_no = self.max_line_no + 2 cmd_log.clicked.connect(self.git_log) cmd_add.clicked.connect(self.git_add) cmd_reset.clicked.connect(self.git_reset) cmd_status.clicked.connect(self.git_status) cmd_run.clicked.connect(self.run_git) def run_git(self): cur_cmd = self.cmd_history.currentText() # 执行代码 if cur_cmd.startswith("git add"): result, background = self.cmd_git_add(self.file_list) self.my_print(result, background) elif cur_cmd.startswith("git status"): result, background = self.cmd_git_status() self.my_print(result, background) elif cur_cmd.startswith("git log"): result, background = self.cmd_git_log(self.show_log_num) self.my_print(result, background) elif cur_cmd.startswith("git reset"): result, background = self.cmd_git_reset(self.file_list) self.my_print(result, background) def git_log(self): # 日常清理 self.cleanup() # 记录命令 self.add_cmd("git log -" + self.show_log_num) # 可以直接运行 self.run_git() def git_add(self): # 日常清理 self.cleanup() # 文件选择 files = self.get_file_list_by_status() self.create_check_box(files) # 记录命令 self.add_cmd("git add .") def git_status(self): # 日常清理 self.cleanup() # 记录命令 self.add_cmd("git status") # 可以直接运行 self.run_git() def git_reset(self): # 日常清理 self.cleanup() # 文件选择 files = self.get_file_list_by_status() self.create_check_box(files) # 记录命令 self.add_cmd("git reset .") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 创建复选框 def create_check_box(self, opt_list: list): # 创建 self.check_box_select_all = QCheckBox('全选') # lambda可以传参:lambda: self.check_box_changes_all(<参数>) self.check_box_select_all.stateChanged.connect(lambda: self.check_box_changes_all()) for ind in range(len(opt_list)): self.check_box.append(QCheckBox(opt_list[ind])) self.check_box[ind].stateChanged.connect(lambda: self.check_box_changes()) # self.check_box_button = QPushButton('提交') # 布局 ind = self.max_line_no self.gridLayout.addWidget(self.check_box_select_all, ind, 0) ind = ind + 1 for check_box in self.check_box: self.gridLayout.addWidget(check_box, ind, 0) ind = ind + 1 # self.gridLayout.addWidget(self.check_box_button, ind, 0) # 添加按钮回调 # self.check_box_button.clicked.connect(self.check_box_ok) # 更新行号 # self.max_line_no = ind + 1 self.max_line_no = ind def check_box_ok(self): # 清除小部件 if self.check_box: self.file_list.clear() for check_box in self.check_box: # 更新列表 # if check_box.checkState() == Qt.Checked: # self.file_list.append(check_box.text()) # 清除 check_box.deleteLater() self.check_box.clear() if self.check_box_select_all: self.check_box_select_all.deleteLater() self.check_box_select_all = None if self.check_box_button: self.check_box_button.deleteLater() self.check_box_button = None def check_box_changes_all(self): if self.check_box_select_all.checkState() == Qt.Checked: for check_box in self.check_box: check_box.setChecked(True) elif self.check_box_select_all.checkState() == Qt.Unchecked: for check_box in self.check_box: check_box.setChecked(False) def check_box_changes(self): all_checked = True # one_checked = False self.file_list.clear() for check_box in self.check_box: if not check_box.isChecked(): all_checked = False # 只要有一个没勾选 else: self.file_list.append(check_box.text()) # 更新列表 # else: # one_checked = True # 只要有一个勾选 if all_checked: self.check_box_select_all.setCheckState(Qt.Checked) # elif one_checked: # self.check_box_select_all.setTristate() # 设置为3态选择框 # self.check_box_select_all.setCheckState(Qt.PartiallyChecked) # else: # self.check_box_select_all.setTristate() # 设置为3态选择框 # self.check_box_select_all.setCheckState(Qt.Unchecked) # 更新命令 files = " ".join(self.file_list) self.update_cmd(files) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 清理临时的小部件 def cleanup(self): self.check_box_ok() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 例子 def addButtonExample(self): # 创建一些小部件放在顶级窗口中 btn = QPushButton('press me') text = QLineEdit('enter text') listw = QListWidget() listw.addItems(["aa", "bb", "cc"]) # self.gridLayout = QGridLayout(self) # 将部件添加到布局中的适当位置, # addWidget参数:Widget实例, 起始row, 起始column, 占多少行(高度),占多少列(宽度) self.gridLayout.addWidget(btn, 0, 0) self.gridLayout.addWidget(text, 1, 0) self.gridLayout.addWidget(listw, 2, 0) # self.setLayout(self.gridLayout) # 画图1 def linePlot(self): plt1 = pg.PlotWidget() plt1.plot([i for i in range(10)], [i * i for i in range(10)]) self.gridLayout.addWidget(plt1, 0, 1, 1, 1) # 画图2 def scatterPlot(self): plt2 = pg.PlotWidget() x = np.random.normal(size=1000) y = np.random.normal(size=1000) plt2.plot(x, y, pen=None, symbol="o") self.gridLayout.addWidget(plt2, 1, 1, 1, 1) # 画图3 def three_curves(self): plt3 = pg.PlotWidget(title="Three plot curves") x = np.arange(1000) y = np.random.normal(size=(3, 1000)) for i in range(3): plt3.plot(x, y[i], pen=(i, 3)) # setting pen=(i,3) 自动创建3个不同颜色的笔 self.gridLayout.addWidget(plt3, 2, 1, 1, 1)
class SonstigeAusgabenView(IccView): def __init__(self, parent=None): IccView.__init__(self) #self.setWindowTitle( "Sonstige Ausgaben: Rechnungen, Abgaben, Gebühren etc." ) self._mainLayout = QtWidgets.QGridLayout(self) self._toolbarLayout = QHBoxLayout() self._summenLayout = QHBoxLayout() self._btnSave = QPushButton(self) self._btnComplexSort = QPushButton() self._editSearch = QLineEdit(self) self._btnSearchFwd = QPushButton(self) self._btnDbSearch = QPushButton(self) self._cboBuchungsjahr = QtWidgets.QComboBox(self) self._tvAuszahlungen = TableViewExt(self) self._buchungsdatumLayout = QHBoxLayout() self._sdBuchungsdatum = SmartDateEdit(self) self._btnAddDay = QPushButton(self) self._btnClearBuchungsdatum = QPushButton(self) self._objektRefLayout = QHBoxLayout() self._cboMasterobjekt = QComboBox(self) self._cboMietobjekt = QComboBox(self) self._editRechnungLineLayout = QHBoxLayout() self._cboKreditor = EditableCombo(self) self._cboBuchungstext = EditableCombo(self) self._sdRechnungsdatum = SmartDateEdit(self) self._feBetrag = FloatEdit(self) self._cboKostenart = QComboBox(self) self._cbUmlegbar = QCheckBox(self) self._cbWerterhaltend = QCheckBox(self) self._teBemerkung = QTextEdit(self) self._btnOk = QPushButton(self) self._btnClear = QPushButton(self) # Callbacks self._buchungsjahrChangedCallback = None self._saveActionCallback = None self._searchActionCallback = None self._dbSearchActionCallback = None self._masterobjektChangedCallback = None self._mietobjektChangedCallback = None self._kreditorChangedCallback = None self._submitChangesCallback = None self._justEditing: XSonstAus = None self._suspendCallbacks = False self._createGui() def _createGui(self): self._assembleToolbar() self._mainLayout.addLayout(self._toolbarLayout, 0, 0, alignment=Qt.AlignLeft) #self._assembleSummen() # self._toolbarLayout.addStretch( 50 ) # self._toolbarLayout.addLayout( self._summenLayout ) ### tableView tv = self._tvAuszahlungen tv.setSelectionBehavior(QAbstractItemView.SelectRows) tv.setAlternatingRowColors(True) tv.verticalHeader().setVisible(False) tv.horizontalHeader().setMinimumSectionSize(0) self._mainLayout.addWidget(tv, 1, 0, 1, 1) self._assembleBuchungsUndRechnungsdatum() self._mainLayout.addLayout(self._buchungsdatumLayout, 2, 0, alignment=Qt.AlignLeft) self._assembleObjektReference() self._mainLayout.addLayout(self._objektRefLayout, 3, 0, alignment=Qt.AlignLeft) self._assembleRechnungsdaten() self._mainLayout.addLayout(self._editRechnungLineLayout, 4, 0, alignment=Qt.AlignLeft) def _assembleToolbar(self): #### Combobox Buchungsjahr font = QFont("Arial", 14, weight=QFont.Bold) self._cboBuchungsjahr.setFont(font) self._cboBuchungsjahr.setToolTip( "Das hier eingestellte Jahr bestimmt die Rechnungen, die in der Tabelle angezeigt werden." ) self._cboBuchungsjahr.currentIndexChanged.connect( self.onBuchungsjahrChanged) self._toolbarLayout.addWidget(self._cboBuchungsjahr, stretch=0, alignment=Qt.AlignLeft) #### save button btn = self._btnSave btn.clicked.connect(self.onSave) btn.setFlat(True) btn.setEnabled(False) btn.setToolTip("Änderungen dieser View speichern") icon = QIcon(ICON_DIR + "save_30.png") btn.setIcon(icon) size = QSize(30, 30) btn.setFixedSize(size) iconsize = QSize(30, 30) btn.setIconSize(iconsize) self._toolbarLayout.addWidget(btn, stretch=0) ### complex sort button btn = self._btnComplexSort btn.clicked.connect(self.onSortComplex) btn.setFlat(True) btn.setEnabled(True) btn.setToolTip( "Nach Master, Kostenart, Kreditor, Mietobjekt, Buchungsdatum sortieren" ) icon = QIcon(ICON_DIR + "sort.png") btn.setIcon(icon) size = QSize(30, 30) btn.setFixedSize(size) iconsize = QSize(30, 30) btn.setIconSize(iconsize) self._toolbarLayout.addWidget(btn, stretch=0) ### search field for tableview search edi = self._editSearch edi.setPlaceholderText("Suche in Tabelle") edi.returnPressed.connect(self._onSearch) edi.setToolTip("Suchbegriff eingeben") self._toolbarLayout.addWidget(edi, stretch=0) btn = self._btnSearchFwd btn.clicked.connect(self._onSearch) size = QSize(30, 30) btn.setFixedSize(size) btn.setToolTip("Suche nach eingegebenem Begriff") icon = QIcon(ICON_DIR + "arrow_dn_30.png") btn.setIcon(icon) btn.setEnabled(True) self._toolbarLayout.addWidget(btn, stretch=0) def _assembleBuchungsUndRechnungsdatum(self): lbl = QLabel(self, text="Buchungsdatum: ") lbl.setFixedWidth(150) self._buchungsdatumLayout.addWidget(lbl) self._sdBuchungsdatum.setFixedWidth(85) self._sdBuchungsdatum.setToolTip( "Buchungsdatum. Kann leer bleiben, wenn Buchung noch nicht erfolgt ist" ) self._buchungsdatumLayout.addWidget(self._sdBuchungsdatum) size = QSize(25, 25) self._btnAddDay.setIcon(QIcon(ICON_DIR + "plus.png")) self._btnAddDay.setFixedSize(size) self._btnAddDay.setToolTip("Buchungsdatum um 1 Tag erhöhen") self._btnAddDay.clicked.connect(self.onAddDayToBuchungsdatum) self._buchungsdatumLayout.addWidget(self._btnAddDay) self._btnClearBuchungsdatum.setIcon(QIcon(ICON_DIR + "cancel.png")) self._btnClearBuchungsdatum.setFixedSize(size) self._btnClearBuchungsdatum.setToolTip("Buchungsdatum löschen") self._btnClearBuchungsdatum.clicked.connect(self.onClearBuchungsdatum) self._buchungsdatumLayout.addWidget(self._btnClearBuchungsdatum) self._sdRechnungsdatum.setPlaceholderText("Datum Rg.") self._sdRechnungsdatum.setMaximumWidth(85) self._sdRechnungsdatum.setToolTip("optional: Datum der Rechnung") self._buchungsdatumLayout.addSpacing(10) lbl = QLabel(text="Rechnungsdatum (optional): ") lbl.setFixedWidth(200) self._buchungsdatumLayout.addWidget(lbl) self._buchungsdatumLayout.addWidget(self._sdRechnungsdatum) def _assembleObjektReference(self): lbl = QLabel(self, text="Betroffenes Objekt: ") lbl.setFixedWidth(150) self._objektRefLayout.addWidget(lbl) self._cboMasterobjekt.setFixedWidth(155) self._cboMasterobjekt.setPlaceholderText("Haus") self._cboMasterobjekt.setToolTip( "Haus, auf das sich die Zahlung bezieht") self._cboMasterobjekt.currentIndexChanged.connect( self.onMasterobjektChanged) self._objektRefLayout.addWidget(self._cboMasterobjekt) self._cboMietobjekt.setPlaceholderText("Wohnung") self._cboMietobjekt.setToolTip( "optional: Wohnung, auf die sich die Zahlung bezieht") self._cboMietobjekt.currentIndexChanged.connect( self.onMietobjektChanged) self._objektRefLayout.addWidget(self._cboMietobjekt) def _assembleRechnungsdaten(self): self._cboKreditor.setToolTip("Kreditor") self._cboKreditor.setFixedWidth(200) self._cboKreditor.currentIndexChanged.connect(self.onKreditorChanged) self._editRechnungLineLayout.addWidget(self._cboKreditor) self._cboBuchungstext.setToolTip( "Identifikation der Zahlung durch Rechnungsnummer oder Buchungstext" ) self._cboBuchungstext.setMinimumWidth(100) self._editRechnungLineLayout.addWidget(self._cboBuchungstext, stretch=2) #Button for DB-Search btn = self._btnDbSearch btn.clicked.connect(self._onDbSearch) size = QSize(30, 30) btn.setFixedSize(size) btn.setToolTip("Suche Buchungstext in der DB") icon = QIcon(ICON_DIR + "search_30.png") btn.setIcon(icon) btn.setEnabled(True) self._editRechnungLineLayout.addWidget(btn) # Betragsfeld self._feBetrag.setPlaceholderText("Betrag") self._feBetrag.setMaximumWidth(70) self._feBetrag.setToolTip( "Positive Beträge sind Aus-, negative Einzahlungen (Gutschriften)") self._editRechnungLineLayout.addWidget(self._feBetrag, stretch=0, alignment=Qt.AlignLeft) # Combobox Kostenart self._cboKostenart.setPlaceholderText("Kostenart") self._cboKostenart.setFixedWidth(120) self._cboKostenart.setToolTip("Kostenart einstellen") self._editRechnungLineLayout.addWidget(self._cboKostenart, stretch=0, alignment=Qt.AlignLeft) vbox = QVBoxLayout() vbox.setSpacing(0) self._cbUmlegbar.setText("uml") self._cbUmlegbar.setToolTip( "Ob die Auszahlung auf den/die Mieter umlegbar sind") vbox.addWidget(self._cbUmlegbar) self._cbWerterhaltend.setText("wert") self._cbWerterhaltend.setToolTip( "Ob die Auszahlung der Werterhaltung der Wohnung dient") vbox.addWidget(self._cbWerterhaltend) self._editRechnungLineLayout.addLayout(vbox) self._teBemerkung.setPlaceholderText("Bemerkung zur Auszahlung") self._teBemerkung.setMaximumSize(QtCore.QSize(16777215, 50)) self._editRechnungLineLayout.addWidget(self._teBemerkung, stretch=1) vbox = QVBoxLayout() self._btnOk.setIcon(QIcon(ICON_DIR + "checked.png")) self._btnOk.setDefault(True) self._btnOk.setToolTip( "Neue oder geänderte Daten in Tabelle übernehmen (kein Speichern)") self._btnOk.clicked.connect(self.onOkEditFields) vbox.addWidget(self._btnOk) self._btnClear.setIcon(QIcon(ICON_DIR + "cancel.png")) self._btnClear.setToolTip("Änderungen verwerfen und Felder leeren") self._btnClear.clicked.connect(self.onClearEditFields) vbox.addWidget(self._btnClear) self._editRechnungLineLayout.addLayout(vbox) # def setContextMenuActions( self, actions:List[QAction] ) -> None: # self._contextMenuActions = actions def getSummen(self) -> XSonstAusSummen: summen = XSonstAusSummen() summen.summe_aus = self._idSummeAus.getIntValue() summen.summe_werterhaltend = self._idSummeW.getIntValue() summen.summe_umlegbar = self._idSummeU.getIntValue() return summen def onAddDayToBuchungsdatum(self): val = self._sdBuchungsdatum.getDate() if val: dt = getQDateFromIsoString(val) dt = dt.addDays(1) self._sdBuchungsdatum.setDate(dt.year(), dt.month(), dt.day()) def onClearBuchungsdatum(self): self._sdBuchungsdatum.clear() def setSaveButtonEnabled(self, enable: bool = True): self._btnSave.setEnabled(enable) def onSave(self): if self._saveActionCallback: self._saveActionCallback() def onSortComplex(self): sortoption1 = ("master_name", "kostenart", "kreditor", "mobj_id", "buchungsdatum") tm: SonstAusTableModel = self.getModel() tm.sortComplex(sortoption1) def _onSearch(self): if self._searchActionCallback: self._searchActionCallback(self._editSearch.text()) def _onDbSearch(self): if self._dbSearchActionCallback: #self._dbSearchActionCallback( self._editDbSearch.text() ) searchstring = self._cboBuchungstext.currentText() if searchstring: self._dbSearchActionCallback(searchstring) def onBuchungsjahrChanged(self, newindex): """ Slot für die Änderung des Buchungsjahrs. :param newindex: :return: """ if self._buchungsjahrChangedCallback: jahr = int(self._cboBuchungsjahr.currentText()) self._buchungsjahrChangedCallback(jahr) def onMasterobjektChanged(self, newindex: int): if self._masterobjektChangedCallback and not self._suspendCallbacks: self._masterobjektChangedCallback( self._cboMasterobjekt.currentText()) def onMietobjektChanged(self, newindex: int): pass def onKreditorChanged(self, newindex: int): if self._kreditorChangedCallback and not self._suspendCallbacks: self._kreditorChangedCallback(self._cboMasterobjekt.currentText(), self._cboMietobjekt.currentText(), self._cboKreditor.currentText()) def onOkEditFields(self, arg): """ OK gedrückt. Änderungen an Callback-Funktion melden. :param arg: :return: """ if self._submitChangesCallback: x: XSonstAus = self._getEditedXSonstAus() ok: bool = self._submitChangesCallback(x) if ok: self._tvAuszahlungen.clearSelection() if x.saus_id <= 0: # neuer Eintrag in Tabelle, nach unten scrollen self._tvAuszahlungen.scrollToBottom() def _getEditedXSonstAus(self) -> XSonstAus: x: XSonstAus = self._justEditing if self._justEditing else XSonstAus() x.buchungsjahr = int(self._cboBuchungsjahr.currentText()) x.buchungsdatum = self._sdBuchungsdatum.getDate() idx = self._cboMasterobjekt.currentIndex() x.master_name = "" if idx < 0 else self._cboMasterobjekt.currentText() idx = self._cboMietobjekt.currentIndex() x.mobj_id = "" if idx < 0 else self._cboMietobjekt.currentText() x.kreditor = self._cboKreditor.currentText() x.buchungstext = self._cboBuchungstext.currentText() x.rgdatum = self._sdRechnungsdatum.getDate() x.betrag = self._feBetrag.getFloatValue() * (-1) x.kostenart_lang = self._cboKostenart.currentText() x.umlegbar = self._cbUmlegbar.isChecked() x.werterhaltend = self._cbWerterhaltend.isChecked() x.rgtext = self._teBemerkung.toPlainText() return x def onClearEditFields(self, arg): self.clearEditFields() self._tvAuszahlungen.clearSelection() def getAuszahlungenTableView(self) -> QTableView: return self._tvAuszahlungen def setAuszahlungenTableModel(self, tm: SonstAusTableModel): self._tvAuszahlungen.setModel(tm) self._tvAuszahlungen.resizeColumnsToContents() #self._tvAuszahlungen.setColumnWidth( 0, 10 ) #self._tvAuszahlungen.setColumnWidth( 1, 10 ) def setBuchungsjahre(self, jahre: List[int]): """ setzt die Liste der auswählbaren Jahre für die Buchungsjahr-Combobox :param jahre: :return: """ for jahr in jahre: self._cboBuchungsjahr.addItem(str(jahr)) def setBuchungsjahr(self, jahr: int) -> None: """ setzt das Jahr, das in der Buchungsjahr-Combobox anzuzeigen ist :param jahr: :return: """ self._cboBuchungsjahr.setCurrentText(str(jahr)) def setBuchungsdatum(self, tag: int, monat: str): """ setzt Buchungstag und -monat. Das Jahr ergibt sich aus dem eingestellten Buchungsjahr :param tag: :param monat: :return: """ # self._sbTag.setValue( tag ) # self._cboMonat.setCurrentText( monat ) self._sdBuchungsdatum.\ setDate( int(self._cboBuchungsjahr.currentText()), getMonthIndex( monat ), tag ) def setMasterobjekte(self, masterobjekte: List[str]): for obj in masterobjekte: self._cboMasterobjekt.addItem(obj) def setMietobjekte(self, mietobjekte: List[str]): self._cboMietobjekt.clear() for obj in mietobjekte: self._cboMietobjekt.addItem(obj) self._cboMietobjekt.setCurrentIndex(0) def selectMietobjekt(self, mobj_id: str): self._cboMietobjekt.setCurrentText(mobj_id) def clearMietobjekte(self): self._cboMietobjekt.clear() def setKreditoren(self, kreditoren: List[str]): self._cboKreditor.clear() for k in kreditoren: self._cboKreditor.addItem(k) self._cboKreditor.setCurrentIndex(-1) def selectKreditor(self, kreditor: str): self._cboKreditor.setCurrentText(kreditor) def setLeistungsidentifikationen(self, idents: List[str]): self._cboBuchungstext.clear() for i in idents: self._cboBuchungstext.addItem(i) #self._cboRechnungsIdent.showPopup() def setCurrentLeistungsidentifikation(self, leistident: str) -> None: self._cboBuchungstext.setCurrentText(leistident) def getCurrentMasterobjekt(self) -> str: return self._cboMasterobjekt.currentText() def getCurrentMietobjekt(self) -> str: return self._cboMietobjekt.currentText() def getCurrentKreditor(self) -> str: return self._cboKreditor.currentText() def setCurrentKreditor(self, kreditor: str) -> None: self._cboKreditor.setCurrentText(kreditor) def getCurrentLeistungsidentifikation(self) -> str: return self._cboBuchungstext.currentText() def resetKreditoren(self): self._cboKreditor.setCurrentIndex(-1) def clearKreditoren(self): self._cboKreditor.clear() def setKostenarten(self, kostenarten: List[str]): self._cboKostenart.clear() for k in kostenarten: self._cboKostenart.addItem(k) self._cboKostenart.setCurrentIndex(-1) def getCurrentKostenart(self) -> str: return self._cboKostenart.currentText() def selectKostenart(self, kostenart: str): self._cboKostenart.setCurrentText(kostenart) def resetKostenart(self): self._cboKostenart.setCurrentIndex(-1) def clearEditFields(self): self._suspendCallbacks = True self._sdBuchungsdatum.clear() self._cboMasterobjekt.setCurrentIndex(-1) self._cboMietobjekt.setCurrentIndex(-1) self._cboKreditor.setCurrentIndex(-1) self._cboBuchungstext.setCurrentIndex(-1) self._sdRechnungsdatum.clear() self._feBetrag.clear() self._cboKostenart.setCurrentIndex(-1) self._cbUmlegbar.setChecked(False) self._cbWerterhaltend.setChecked(False) self._teBemerkung.clear() self._justEditing = None self._suspendCallbacks = False def provideEditFieldsPartly(self, umlegbar: bool, master_id: int, master_name: str, mobj_id: str, kreditor: str, kostenart_lang: str, buchungstext: str): self._cbUmlegbar.setChecked(umlegbar) self._cboMasterobjekt.setCurrentText(master_name) self._cboMietobjekt.setCurrentText(mobj_id) self._cboKreditor.setCurrentText(kreditor) self._cboBuchungstext.setCurrentText(buchungstext) self._cboKostenart.setCurrentText(kostenart_lang) #todo: weitermachen def provideEditFields(self, x: XSonstAus): self.clearEditFields() #self._suspendCallbacks = True self._justEditing = x if x.buchungsdatum: y, m, d = getDateParts(x.buchungsdatum) self._sdBuchungsdatum.setDate(y, m, d) else: self._sdBuchungsdatum.clear() if x.master_id is not None and x.master_id >= 0: #master_id kann auch 0 sein! (**alle**) self._cboMasterobjekt.setCurrentText(x.master_name) if x.mobj_id: self._cboMietobjekt.setCurrentText(x.mobj_id) if x.kreditor: self._cboKreditor.setCurrentText(x.kreditor) if x.kostenart: self._cboKostenart.setCurrentText(x.kostenart_lang) if x.buchungstext: self._cboBuchungstext.setCurrentText(x.buchungstext) if x.rgdatum: y, m, d = getDateParts(x.rgdatum) self._sdRechnungsdatum.setDate(y, m, d) self._feBetrag.setText(str(x.betrag * (-1))) self._cbUmlegbar.setChecked(x.umlegbar) self._cbWerterhaltend.setChecked(x.werterhaltend) self._teBemerkung.setText(x.rgtext) self._suspendCallbacks = False def getModel(self) -> IccTableModel: return self._tvAuszahlungen.model() def showException(self, title: str, exception: str, moretext: str = None): # todo: show Qt-Errordialog msgbox = QtWidgets.QMessageBox() msgbox.setWindowTitle(title) msgbox.setIcon(QMessageBox.Critical) msgbox.setText(exception) if moretext: msgbox.setInformativeText(moretext) msgbox.exec_() ################# SET CALLBACKS ############################ def setBuchungsjahrChangedCallback(self, cbfnc) -> None: """ Die callback-Funktion muss als Argument das neu eingestellte Jahr als integer akzeptieren :param cbfnc: :return: """ self._buchungsjahrChangedCallback = cbfnc def setSaveActionCallback(self, cbfnc) -> None: """ Die callback-FUnktion braucht keine Parameter empfangen. :param cbfnc: :return: """ self._saveActionCallback = cbfnc def setSearchActionCallback(self, cbfnc) -> None: """ Die callback-Funktion muss den Searchstring als Parameter empfangen. :param cbfnc: :return: """ self._searchActionCallback = cbfnc def setDbSearchActionCallback(self, cbfnc) -> None: """ Die callback-Funktion muss den Searchstring als Parameter empfangen. :param cbfnc: :return: """ self._dbSearchActionCallback = cbfnc def setMasterobjektChangedCallback(self, cbfnc): """ Die callback-Funktion muss einen String als Argument akzeptieren (Name des MAsterobjekts) :param cbfnc: :return: """ self._masterobjektChangedCallback = cbfnc def setMietobjektChangedCallback(self, cbfnc): """ Die callback-Funktion muss einen String als Argument akzeptieren (mobj_id) :param cbfnc: :return: """ self._mietobjektChangedCallback = cbfnc def setKreditorChangedCallback(self, cbfnc): """ Die callback Funktion muss 3 Argumente entgegennehmen können: master_name, mobj_id, neuer kreditor :param cbfnc: :return: """ self._kreditorChangedCallback = cbfnc def setSubmitChangesCallback(self, cbfnc): """ sets the one and only callback when the user hits the OK button in the edit fields area. The given callback function has to accept the edited XSonstAus object, :param cbfnc: :return: """ self._submitChangesCallback = cbfnc
class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.setWindowTitle("Chat Smasher") # Create Widgets self.edit = QLineEdit("Welcome") self.button = QPushButton("Load Files") self.stopButton = QPushButton("Stop") self.box1 = QComboBox() # Holds name of files self.filePreview = QTextBrowser() # Preview Files self.loadingBar = QProgressBar(self) self.preview = QTextBrowser() self.champBox = QComboBox() self.ConfirmButton = QPushButton("Start") # Create layout and add widgets layout = QVBoxLayout() self.label2 = QLabel() self.label2.setText("Caleb's Chat Smasher") self.label2.setStyleSheet( "QLabel { background-color : green; color : white; font-size: 20px; text-align : " "center; }") self.label = QLabel() pixmap = QPixmap('lek.png') self.timer = QBasicTimer() self.step = 0 self.label.setPixmap(pixmap) layout.addWidget(self.label2) layout.addWidget(self.label) #layout.addWidget(self.edit) self.champBox = QComboBox() # layout.addWidget(self.champBox) layout.addWidget(self.button) layout.addWidget(self.box1) layout.addWidget(self.filePreview) layout.addWidget(self.ConfirmButton) layout.addWidget(self.stopButton) self.loadingBar.setStyleSheet( "QProgressBar::chunk {background-color: red}") layout.addWidget(self.loadingBar) #self.file # Set layout self.setLayout(layout) p = self.palette() p.setColor(self.foregroundRole(), QColor(10, 10, 10, 127)) p.setColor(self.backgroundRole(), QColor(0, 0, 0, 127)) self.setPalette(p) self.setFixedWidth(450) self.setFixedHeight(700) #make connections self.button.clicked.connect(self.imclicked) self.ConfirmButton.clicked.connect(self.newStart) self.stopButton.clicked.connect(self.stop) self.box1.activated.connect(self.updatePreview) def start(self): print("Ready to Go") myFile = pathlib.Path.cwd() / 'copypastas' / self.box1.currentText() clicking.type_page(myFile) self.loadingBar.setStyleSheet( "QProgressBar::chunk {background-color: green } QProgressBar {text-align: center}" ) def stop(self): self.timer.stop() #self.loadingBar.setValue(0) def imclicked(self): self.updatelist() def newStart(self): global stepper stepper = 0 self.loadingBar.setValue(0) self.loadingBar.setStyleSheet( "QProgressBar::chunk {background-color: red;} QProgressBar {text-align: center}" ) self.startTracking() def updatelist(self): self.box1.clear() fileNames = fileHandling.getFileNames() for names in fileNames: self.box1.addItem(names) self.updatePreview() def updatePreview(self): self.filePreview.clear() myFile = pathlib.Path.cwd() / 'copypastas' / self.box1.currentText() with open(myFile, 'r') as pageRead: for line in pageRead: self.filePreview.append(line) def startTracking(self): self.timer.start(80, self) def timerEvent(self, event): global stepper stepper += 1 self.loadingBar.setValue(stepper) if self.loadingBar.value() == 100: self.start() self.timer.stop()
def update_combobox(box: QComboBox, labels: List[str]) -> None: """Update the combobox menu.""" box.blockSignals(True) box.clear() box.insertItems(0, labels) box.blockSignals(False)
class CamView(AbstractView): def __init__(self, name: str = "CAM_NONE", log_handlers: [StreamHandler] = None): self._logger = getLogger(__name__) if log_handlers: for h in log_handlers: self._logger.addHandler(h) self._logger.debug("Initializing") super().__init__(name) """ Min size for cam window """ self._subwindow_height = 222 self._subwindow_width = 518 self._initialization_bar_frame = EasyFrame() self._initialization_bar_frame.setMouseTracking(True) self._initialization_bar_frame.setMaximumHeight(70) self._initialization_bar_layout = QVBoxLayout( self._initialization_bar_frame) self._initialization_bar_label = QLabel(self._initialization_bar_frame) self._initialization_bar_label.setMouseTracking(True) self._initialization_bar = QProgressBar(self._initialization_bar_frame) self._initialization_bar.setMouseTracking(True) self._initialization_bar.setMaximumHeight(15) self._initialization_bar.setTextVisible(True) self._initialization_bar.setAlignment(Qt.AlignHCenter) self._initialization_bar_layout.addWidget( self._initialization_bar_label) self._initialization_bar_layout.addWidget(self._initialization_bar) self._cam_settings_frame = EasyFrame() self._cam_settings_layout = QGridLayout(self._cam_settings_frame) self._resolution_selector_label = QLabel(self._cam_settings_frame) self._resolution_selector_label.setAlignment(Qt.AlignLeft) self._resolution_selector = QComboBox(self._cam_settings_frame) self._resolution_selector.setMaximumHeight(22) self._cam_settings_layout.addWidget(self._resolution_selector_label, 0, 0) self._cam_settings_layout.addWidget(self._resolution_selector, 0, 1) self._fps_selector_label = QLabel(self._cam_settings_frame) self._fps_selector_label.setAlignment(Qt.AlignLeft) self._fps_selector = QComboBox(self._cam_settings_frame) self._fps_selector.setMaximumHeight(22) self._cam_settings_layout.addWidget(self._fps_selector_label, 1, 0) self._cam_settings_layout.addWidget(self._fps_selector, 1, 1) self._show_feed_checkbox_label = QLabel(self._cam_settings_frame) self._show_feed_checkbox_label.setAlignment(Qt.AlignLeft) self._show_feed_checkbox = QCheckBox() self._show_feed_checkbox.setChecked(True) self._show_feed_checkbox.setLayoutDirection(Qt.RightToLeft) self._cam_settings_layout.addWidget(self._show_feed_checkbox_label, 2, 0) self._cam_settings_layout.addWidget(self._show_feed_checkbox, 2, 1) self._use_cam_checkbox_label = QLabel(self._cam_settings_frame) self._use_cam_checkbox_label.setAlignment(Qt.AlignLeft) self._use_cam_checkbox = QCheckBox() self._use_cam_checkbox.setChecked(True) self._use_cam_checkbox.setLayoutDirection(Qt.RightToLeft) self._cam_settings_layout.addWidget(self._use_cam_checkbox_label, 3, 0) self._cam_settings_layout.addWidget(self._use_cam_checkbox, 3, 1) self._use_overlay_checkbox_label = QLabel(self._cam_settings_frame) self._use_overlay_checkbox_label.setAlignment(Qt.AlignLeft) self._use_overlay_checkbox = QCheckBox() self._use_overlay_checkbox.setChecked(True) self._use_overlay_checkbox.setLayoutDirection(Qt.RightToLeft) self._cam_settings_layout.addWidget(self._use_overlay_checkbox_label, 4, 0) self._cam_settings_layout.addWidget(self._use_overlay_checkbox, 4, 1) self._image_display_frame = EasyFrame() self._image_display_layout = QVBoxLayout(self._image_display_frame) self._image_display_label = QLabel(self._image_display_frame) self._image_display_label.setAlignment(Qt.AlignHCenter) self._image_display = QLabel(self._image_display_frame) self._image_display.setAlignment(Qt.AlignCenter) self._image_display.setMouseTracking(True) self._image_display_layout.addWidget(self._image_display_label) self._image_display_layout.addWidget(self._image_display) spacer = QSpacerItem(1, 1, vData=QSizePolicy.Expanding) self._dev_sets_frame = EasyFrame() self._dev_sets_layout = QVBoxLayout(self._dev_sets_frame) self.config_button = ClickAnimationButton() self.config_button.clicked.connect(self._config_button_handler) self.layout().addWidget(self.config_button, 0, 0, Qt.AlignTop | Qt.AlignRight) self.config_button.setFixedSize(30, 25) self.config_button.setStyleSheet( "background-color: rgba(200, 200, 200, 50%)") self._dev_sets_layout.addWidget(self._cam_settings_frame) self._dev_sets_layout.addItem(spacer) self.layout().addWidget(self._image_display, 0, 0) self.layout().addWidget(self._initialization_bar_frame, 0, 0) self._config_items = [ self._resolution_selector, self._fps_selector, self._use_cam_checkbox, self._show_feed_checkbox, self._use_overlay_checkbox, ] config_win_w = 350 config_win_h = len(self._config_items) * 30 self.config_button.raise_() self._config_win = ConfigPopUp() self._config_win.setLayout(self._dev_sets_layout) self._config_win.setFixedSize(config_win_w, config_win_h) self._rec_label = QLabel() self._rec_label.setStyleSheet( "background-color: rgba(0, 0, 0, 0%); color: red; font: 20px") self._rec_label.hide() self.layout().addWidget(self._rec_label, 0, 0, Qt.AlignBottom | Qt.AlignRight) self.layout().setMargin(0) self._window_changing = False self._showing_images = False self._hidden = False w = 320 self._aspect_ratio = 9 / 16 self.resize(w, self.heightForWidth(w)) self._strings = dict() self._lang_enum = LangEnum.ENG self.setMinimumSize(self._subwindow_width, self._subwindow_height) self.old_size = QSize(self.width(), self.height()) self._logger.debug("Initialized") def set_show_feed_button_handler(self, func) -> None: """ Add handler for show camera selector. :param func: The handler. :return None: """ self._logger.debug("running") self._show_feed_checkbox.toggled.connect(func) self._logger.debug("done") def set_resolution_selector_handler(self, func) -> None: """ Add handler for resolution selector. :param func: The handler. :return None: """ self._logger.debug("running") self._resolution_selector.activated.connect(func) self._logger.debug("done") def set_fps_selector_handler(self, func) -> None: """ Add handler for resolution selector. :param func: The handler. :return None: """ self._logger.debug("running") self._fps_selector.activated.connect(func) self._logger.debug("done") def set_use_cam_button_handler(self, func) -> None: """ Add handler for use camera selector. :param func: The handler. :return None: """ self._logger.debug("running") self._use_cam_checkbox.toggled.connect(func) self._logger.debug("done") def set_use_overlay_button_handler(self, func) -> None: """ Add handler for use camera selector. :param func: The handler. :return None: """ self._logger.debug("running") self._use_overlay_checkbox.toggled.connect(func) self._logger.debug("done") def _config_button_handler(self) -> None: """ Show config pop up. :return None: """ self._logger.debug("running") self.config_button.setStyleSheet( "background-color: rgba(200, 200, 200, 50%)") self._config_win.exec_() self._logger.debug("done") @property def language(self) -> LangEnum: """ :return: The current lang enum being used. """ return self._lang_enum @language.setter def language(self, lang: LangEnum) -> None: """ Set the language for this view object. :param lang: The language to use. :return None: """ self._logger.debug("running") self._lang_enum = lang self._strings = strings[lang] self._set_texts() self._set_tooltips() self._logger.debug("done") @property def resolution_list(self) -> list: """ Get list of resolutions. :return list: The list of resolutions. """ ret = list() return ret @resolution_list.setter def resolution_list(self, res_list: list) -> None: """ Set list of resolutions available to res_list. :param res_list: The list of available resolutions. :return None: """ self._logger.debug("running") self._resolution_selector.clear() for item in res_list: self._resolution_selector.addItem(str(item)) self._logger.debug("done") @property def resolution(self) -> str: """ Get the current resolution selection. :return str: The current resolution. """ return self._resolution_selector.currentText() @resolution.setter def resolution(self, res: str) -> None: """ Set the current resolution selection. :param res: The resolution to set to. :return None: """ self._resolution_selector.setCurrentIndex( self._resolution_selector.findText(res)) @property def fps_list(self) -> list: """ Get list of fps options. :return list: The list of fps options. """ ret = list() return ret @fps_list.setter def fps_list(self, fps_list: list) -> None: """ Set list of available fps to fps_list. :param fps_list: :return None: """ self._logger.debug("running") self._fps_selector.clear() for item in fps_list: self._fps_selector.addItem(str(item)) self._logger.debug("done") @property def fps(self) -> str: """ Get the current fps selection. :return str: The current fps selection. """ return self._fps_selector.currentText() @fps.setter def fps(self, fps: str) -> None: """ Set the current fps selection. :param fps: The fps to set to. :return None: """ self._logger.debug("running") self._fps_selector.setCurrentIndex(self._fps_selector.findText(fps)) self._logger.debug("done") @property def use_feed(self) -> bool: """ Get the current use_cam setting. :return bool: User selection for using cam. """ return self._show_feed_checkbox.isChecked() @use_feed.setter def use_feed(self, useable: bool) -> None: """ Set use_cam setting. :param useable: The setting to set to. :return None: """ self._logger.debug("running") self._show_feed_checkbox.setChecked(useable) self._logger.debug("Done") @property def use_cam(self) -> bool: """ Get the current use_cam setting. :return bool: User selection for using cam. """ return self._use_cam_checkbox.isChecked() @use_cam.setter def use_cam(self, useable: bool) -> None: """ Set use_cam setting. :param useable: The setting to set to. :return None: """ self._logger.debug("running") self._use_cam_checkbox.setChecked(useable) self._logger.debug("Done") @property def use_overlay(self) -> bool: """ Get the current use_overlay setting. :return bool: User selection for using overlay. """ return self._use_overlay_checkbox.isChecked() @use_overlay.setter def use_overlay(self, useable: bool) -> None: """ Set use_overlay setting. :param useable: The setting to set to. :return None: """ self._logger.debug("running") self._use_overlay_checkbox.setChecked(useable) self._logger.debug("Done") def heightForWidth(self, w: int) -> int: return int(w * self._aspect_ratio) def widthForHeight(self, h: int) -> int: return int(h / self._aspect_ratio) def hideEvent(self, hideEvent: QHideEvent): """ Track minimize event. :param hideEvent: :return None: """ self._hidden = True def showEvent(self, showEvent: QShowEvent): """ Track restore event. :param showEvent: :return None: """ self._hidden = False def update_image(self, image: QPixmap = None, msg: str = None) -> None: """ Update image viewer with new image. :param image: The new image to show. :param msg: The text to show if no image. :return None: """ self._logger.debug("running") if not self._window_changing: if image is not None: temp_image_w = image.scaledToWidth(self.width() - 15) temp_image_h = image.scaledToHeight(self.height() - 35) if temp_image_w.height() > self.height() - 35: self._image_display.setPixmap(temp_image_h) else: self._image_display.setPixmap(temp_image_w) elif msg is not None: self._image_display.setText(msg) self._logger.debug("done") def show_images(self) -> None: """ Show image display and hide initialization bar. :return None: """ self._logger.debug("running") geo = self.geometry() self._showing_images = True self._initialization_bar_frame.hide() self._image_display.show() self.config_button.show() self.setStyleSheet("background-color: black") self.setGeometry(geo) self._logger.debug("done") def show_initialization(self) -> None: """ Show initialization bar and hide image display. :return None: """ self._logger.debug("running") self._showing_images = False self._image_display.hide() self.config_button.hide() self._initialization_bar_frame.show() self._logger.debug("done") def update_init_bar(self, progress: int) -> None: """ set progress bar value to progress. :param progress: The value to set progress bar to. :return None: """ self._logger.debug("running") if progress > 100: progress = 100 elif progress < 0: progress = 0 self._initialization_bar.setValue(progress) self._logger.debug("done") def set_config_active(self, is_active: bool) -> None: """ Set whether this camera config options are usable. :param is_active: Usable. :return None: """ self._logger.debug("running") if self._showing_images: if is_active: self._rec_label.hide() elif self.use_cam: self._rec_label.show() for item in self._config_items: item.setEnabled(is_active) self._logger.debug("done") def _set_texts(self) -> None: """ Set the texts in this view object. :return None: """ self._logger.debug("running") self._initialization_bar_label.setText( self._strings[StringsEnum.INITIALIZATION_BAR_LABEL]) self._initialization_bar.setValue(0) self._image_display_label.setText( self._strings[StringsEnum.IMAGE_DISPLAY_LABEL]) self._image_display.setText(self._strings[StringsEnum.IMAGE_DISPLAY]) self._show_feed_checkbox_label.setText( self._strings[StringsEnum.SHOW_FEED_CHECKBOX_LABEL]) self._use_cam_checkbox_label.setText( self._strings[StringsEnum.USE_CAM_CHECKBOX_LABEL]) self._use_overlay_checkbox_label.setText( self._strings[StringsEnum.USE_OVERLAY_CHECKBOX_LABEL]) self._resolution_selector_label.setText( self._strings[StringsEnum.RESOLUTION_SELECTOR_LABEL]) self._fps_selector_label.setText( self._strings[StringsEnum.FPS_SELECTOR_LABEL]) self._config_win.setWindowTitle( self.get_name() + " " + self._strings[StringsEnum.CONFIG_TAB_LABEL]) self.config_button.setText("...") self._rec_label.setText("rec ●") self._logger.debug("done") def _set_tooltips(self) -> None: """ Set the tooltips in this view object. :return None: """ self._logger.debug("running") self._resolution_selector_label.setToolTip( self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP]) self._resolution_selector.setToolTip( self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP]) self._fps_selector_label.setToolTip( self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP]) self._fps_selector.setToolTip( self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP]) self._show_feed_checkbox_label.setToolTip( self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP]) self._show_feed_checkbox.setToolTip( self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP]) self._use_cam_checkbox_label.setToolTip( self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP]) self._use_cam_checkbox.setToolTip( self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP]) self._use_overlay_checkbox_label.setToolTip( self._strings[StringsEnum.USE_OVERLAY_TOOLTIP]) self._use_overlay_checkbox.setToolTip( self._strings[StringsEnum.USE_OVERLAY_TOOLTIP]) self._image_display.setToolTip( self._strings[StringsEnum.IMAGE_DISPLAY_TOOLTIP]) self._logger.debug("done")