class DynamicVariableEditor(DynVarForm, DynVarBase): def __init__(self, parent=None): super(DynamicVariableEditor, self).__init__() self.setupUi(self) self._model = None self._data_mapper = QDataWidgetMapper(self) @property def model(self): return self._model @model.setter def model(self, model): self._model = model self._data_mapper.setModel(model) self._data_mapper.addMapping(self.dyn_var_name, 0) self._data_mapper.addMapping(self.dyn_var_default, 1) self._data_mapper.addMapping(self.dyn_var_start, 2) self._data_mapper.addMapping(self.dyn_var_end, 3) self._data_mapper.addMapping(self.dyn_var_log, 4) self._data_mapper.addMapping(self.dyn_var_send, 5) self._data_mapper.addMapping(self.dyn_var_stepsize, 6, 'text') self.dyn_var_log.clicked.connect(self.dyn_var_log.clearFocus) self.dyn_var_send.clicked.connect(self.dyn_var_send.clearFocus) def selectionChanged(self, current_index, old_index): self._data_mapper.setCurrentIndex(current_index.row())
def __init__(self, contact_list_model, contact_index): super().__init__() ui_file = BASE_UI_PATH / "edit_contact_window.ui" uic.loadUi(ui_file, self) self.gender_editbox.addItems(GENDER_LIST) contact = contact_list_model.contact_by_index(contact_index) mapper = QDataWidgetMapper(self) mapper.setModel(contact_list_model) for section, name in enumerate(contact.field_names()): mapper.addMapping(getattr(self, f"{name}_editbox"), section) mapper.setCurrentIndex(contact_index)
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.splitter) self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems) self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.verticalHeader().setDefaultSectionSize(22) self.ui.tableView.horizontalHeader().setDefaultSectionSize(60) def __openTable(self): self.tabModel = QSqlTableModel(self, self.DB) self.tabModel.setTable("employee") self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.tabModel.setSort(self.tabModel.fieldIndex("empNo"), Qt.AscendingOrder) if(self.tabModel.select()==False): QMessageBox.critical(self, "错误信息", "打开数据表错误,错误信息\n"+self.tabModel.lastError().text()) return self.__getFieldNames() self.tabModel.setHeaderData(self.fldNum["empNo"], Qt.Horizontal, "工号") self.tabModel.setHeaderData(self.fldNum["Name"], Qt.Horizontal, "姓名") self.tabModel.setHeaderData(self.fldNum["Gender"], Qt.Horizontal, "性别") self.tabModel.setHeaderData(self.fldNum["Birthday"], Qt.Horizontal, "出生日期") self.tabModel.setHeaderData(self.fldNum["Province"], Qt.Horizontal, "省份") self.tabModel.setHeaderData(self.fldNum["Department"], Qt.Horizontal, "部门") self.tabModel.setHeaderData(self.fldNum["Salary"], Qt.Horizontal, "工资") self.tabModel.setHeaderData(self.fldNum["Memo"], Qt.Horizontal, "备注") self.tabModel.setHeaderData(self.fldNum["Photo"], Qt.Horizontal, "照片") self.mapper = QDataWidgetMapper() self.mapper.setModel(self.tabModel) self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) self.mapper.addMapping(self.ui.dbSpinEmpNo, self.fldNum["empNo"]) self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"]) self.mapper.addMapping(self.ui.dbComboSex, self.fldNum["Gender"]) self.mapper.addMapping(self.ui.dbEditBirth, self.fldNum["Birthday"]) self.mapper.addMapping(self.ui.dbComboProvince, self.fldNum["Province"]) self.mapper.addMapping(self.ui.dbComboDep, self.fldNum["Department"]) self.mapper.addMapping(self.ui.dbSpinSalary, self.fldNum["Salary"]) self.mapper.addMapping(self.ui.dbEditMemo, self.fldNum["Memo"]) self.mapper.toFirst() self.selModel = QItemSelectionModel(self.tabModel) self.selModel.currentChanged.connect(self.do_currentChanged) self.selModel.currentRowChanged.connect(self.do_currentRowChanged) self.ui.tableView.setModel(self.tabModel) self.ui.tableView.setSelectionModel(self.selModel) self.ui.tableView.setColumnHidden(self.fldNum["Memo"], True) self.ui.tableView.setColumnHidden(self.fldNum["Photo"], True) strList = ("男", "女") self.__delegatesex = QmyComboBoxDelegate() self.__delegatesex.setItems(strList, False) self.ui.tableView.setItemDelegateForColumn(self.fldNum["Gender"], self.__delegatesex) strList = ("销售部", "技术部", "生产部", "行政部") self.__delegateDepart = QmyComboBoxDelegate() self.__delegateDepart.setItems(strList, True) self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"], self.__delegateDepart) self.ui.actOpenDB.setEnabled(False) self.ui.actOpenDB.setEnabled(False) self.ui.actRecAppend.setEnabled(True) self.ui.actRecInsert.setEnabled(True) self.ui.actRecDelete.setEnabled(True) self.ui.actScan.setEnabled(True) self.ui.groupBoxSort.setEnabled(True) self.ui.groupBoxFilter.setEnabled(True) def __getFieldNames(self): emptyRec = self.tabModel.record() self.fldNum = {} for i in range(emptyRec.count()): fieldName = emptyRec.fieldName(i) self.ui.comboFields.addItem(fieldName) self.fldNum.setdefault(fieldName) self.fldNum[fieldName]=i print(self.fldNum) def do_currentChanged(self, current, previous): self.ui.actSubmit.setEnabled(self.tabModel.isDirty()) self.ui.actRevert.setEnabled(self.tabModel.isDirty()) def do_currentRowChanged(self, current, previous): self.ui.actRecDelete.setEnabled(current.isValid()) self.ui.actPhoto.setEnabled(current.isValid()) self.ui.actPhotoClear.setEnabled(current.isValid()) if(current.isValid() == False): self.ui.dbLabPhoto.clear() return self.mapper.setCurrentIndex(current.row()) curRec = self.tabModel.record(current.row()) if(curRec.isNull("Photo")): self.ui.dbLabPhoto.clear() else: data = curRec.value("Photo") pic = QPixmap() pic.loadFromData(data) w = self.ui.dbLabPhoto.size().width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(w)) @pyqtSlot() def on_actOpenDB_triggered(self): dbFilename ,flt = QFileDialog.getOpenFileName(self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)") if (dbFilename == ''): return self.DB = QSqlDatabase.addDatabase("QSQLITE") self.DB.setDatabaseName(dbFilename) if self.DB.open(): self.__openTable() else: QMessageBox.warning(self, "错误", "打开数据库失败") @pyqtSlot() def on_actSubmit_triggered(self): res = self.tabModel.submitAll() if(res == False): QMessageBox.information(self, "消息", "数据保存错误,错误信息\n" + self.tabModel.lastError().text()) else: self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() def on_actRevert_triggered(self): self.tabModel.revertAll() self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() def on_actRecAppend_triggered(self): self.tabModel.insertRow(self.tabModel.rowCount(), QModelIndex()) curIndex = self.tabModel.index(self.tabModel.rowCount()-1, 1) self.selModel.clearSelection() self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) currow = curIndex.row() self.tabModel.setData(self.tabModel.index(currow, self.fldNum["empNo"]), 2000+self.tabModel.rowCount()) self.tabModel.setData(self.tabModel.index(currow, self.fldNum["Gender"]), "男") @pyqtSlot() def on_actRecInsert_triggered(self): curIndex = self.ui.tableView.currentIndex() self.tabModel.insertRow(curIndex.row(), QModelIndex()) self.selModel.clearSelection() self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_actRecDelete_triggered(self): curIndex = self.selModel.currentIndex() self.tabModel.removeRow(curIndex.row()) @pyqtSlot() def on_actPhotoClear_triggered(self): curRecNo = self.selModel.currentIndex().row() curRec = self.tabModel.record(curRecNo) curRec.setNull("Photo") self.tabModel.setRecord(curRecNo, curRec) self.ui.dbLabPhoto.clear() @pyqtSlot() def on_actPhoto_triggered(self): fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "", "照片(*.jpg") if(fileName==''): return file=QFile(fileName) file.open(QIODevice.ReadOnly) try: data = file.readAll() finally: file.close() curRecNo = self.selModel.currentIndex().row() curRec = self.tabModel.record(curRecNo) curRec.setValue("Photo", data) self.tabModel.setRecord(curRecNo, curRec) pic = QPixmap() pic.loadFromData(data) w = self.ui.dbLabPhoto.width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(w)) @pyqtSlot() def on_actScan_triggered(self): if(self.tabModel.rowCount()==0): return for i in range(self.tabModel.rowCount()): aRec = self.tabModel.record(i) salary = aRec.value("Salary") salary = salary*1.1 aRec.setValue("Salary", salary) self.tabModel.setRecord(i, aRec) if(self.tabModel.submitAll()): QMessageBox.information(self, "消息", "涨工资计算完毕了") @pyqtSlot() def on_comboFields_currentIndexChanged(self, index): if self.ui.radioBtnAscend.isChecked(): self.tabModel.setSort(index, Qt.AscendingOrder) else: self.tabModel.setSort(index, Qt.DescendingOrder) self.tabModel.select() @pyqtSlot() def on_radioBtnAscend_clicked(self): self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.AscendingOrder) self.tabModel.select() @pyqtSlot() def on_radioBtnDescend_clicked(self): self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.DescendingOrder) self.tabModel.select() @pyqtSlot() def on_radioBtnMan_clicked(self): self.tabModel.setFilter("Gender='男'") @pyqtSlot() def on_radioBtnWoman_clicked(self): self.tabModel.setFilter("Gender='女'") @pyqtSlot() def on_radioBtnBoth_clicked(self): self.tabModel.setFilter("")
class MyMainWindow(VCPMainWindow): """Main window class for the VCP.""" def __init__(self, *args, **kwargs): super(MyMainWindow, self).__init__(*args, **kwargs) self.formNextBtn.clicked.connect(self.formNext) self.formPreviousBtn.clicked.connect(self.formPrevious) self.classNextBtn.clicked.connect(self.classNext) self.classPreviousBtn.clicked.connect(self.classPrevious) self.sizeNextBtn.clicked.connect(self.sizeNext) self.sizePreviousBtn.clicked.connect(self.sizePrevious) if not self.open_db(): print('Failed to Open Database') self.formModelInit() #self.sizeModelInit() def open_db(self): db = QSqlDatabase.addDatabase('QSQLITE') db.setDatabaseName(current_path + 'sfc.db') db.open() return db def formModelInit(self): self.formMapper = QDataWidgetMapper(self) self.formModel = QSqlQueryModel(self) self.formModel.setQuery('SELECT DISTINCT form FROM threads') self.formMapper.setModel(self.formModel) self.formMapper.addMapping(self.formLbl, 0, b'text') self.formMapper.currentIndexChanged.connect(self.formChanged) self.formMapper.toLast() self.formsLast = self.formMapper.currentIndex() self.formMapper.toFirst() self.formIndexLbl.setText('{}'.format(self.formMapper.currentIndex())) self.classModelInit() def formNext(self): #print('before {}'.format(self.mapper.currentIndex())) if self.formMapper.currentIndex() != self.formsLast: self.formMapper.toNext() else: self.formMapper.toFirst() self.formIndexLbl.setText('{}'.format(self.formMapper.currentIndex())) #print('after {}'.format(self.mapper.currentIndex())) self.classModelInit() def formPrevious(self): if self.formMapper.currentIndex() != 0: self.formMapper.toPrevious() else: self.formMapper.toLast() self.formIndexLbl.setText('{}'.format(self.formMapper.currentIndex())) self.classModelInit() def formChanged(self): # is fired before the change is complete pass def classModelInit(self): print('class update') self.classMapper = QDataWidgetMapper(self) self.classModel = QSqlQueryModel(self) form = self.formLbl.text() print(form) classSelect = "SELECT DISTINCT class FROM threads WHERE form = '{}'".format( form) self.classModel.setQuery(classSelect) self.classMapper.setModel(self.classModel) self.classMapper.addMapping(self.classLbl, 0, b'text') #self.classMapper.currentIndexChanged.connect(self.formChanged) self.classMapper.toLast() self.classLast = self.classMapper.currentIndex() self.classMapper.toFirst() self.classIndexLbl.setText('{}'.format( self.classMapper.currentIndex())) self.sizeModelInit() def classNext(self): #print('before {}'.format(self.mapper.currentIndex())) if self.classMapper.currentIndex() != self.classLast: self.classMapper.toNext() else: self.classMapper.toFirst() self.classIndexLbl.setText('{}'.format( self.classMapper.currentIndex())) #print('after {}'.format(self.mapper.currentIndex())) self.sizeModelInit(self.sizeMapper.currentIndex()) def classPrevious(self): if self.classMapper.currentIndex() != 0: self.classMapper.toPrevious() else: self.classMapper.toLast() self.classIndexLbl.setText('{}'.format( self.classMapper.currentIndex())) self.sizeModelInit(self.sizeMapper.currentIndex()) def sizeModelInit(self, index=0): self.sizeMapper = QDataWidgetMapper(self) self.sizeModel = QSqlQueryModel(self) form = str(self.formLbl.text()) fit = self.classLbl.text() sizeSelect = "SELECT * FROM threads WHERE form = '{}' AND class = '{}'".format( form, fit) self.sizeModel.setQuery(sizeSelect) self.sizeMapper.setModel(self.sizeModel) self.sizeMapper.addMapping(self.threadLbl, 0, b'text') self.sizeMapper.addMapping(self.pitchLbl, 3, b'text') self.sizeMapper.addMapping(self.majorDiameterLbl, 4, b'text') self.sizeMapper.addMapping(self.maxMajorDiameterLbl, 5, b'text') self.sizeMapper.addMapping(self.minMajorDiameterLbl, 6, b'text') self.sizeMapper.addMapping(self.pitchDiameterLbl, 7, b'text') self.sizeMapper.addMapping(self.maxPitchDiameterLbl, 8, b'text') self.sizeMapper.addMapping(self.minPitchDiameterLbl, 9, b'text') self.sizeMapper.addMapping(self.minMinorDiameterLbl, 10, b'text') self.sizeMapper.currentIndexChanged.connect(self.formChanged) self.sizeMapper.toLast() self.sizeLast = self.sizeMapper.currentIndex() self.sizeMapper.setCurrentIndex(index) #self.sizeMapper.toFirst() self.sizeIndexLbl.setText('{}'.format(self.sizeMapper.currentIndex())) def sizeNext(self): #print('before {}'.format(self.mapper.currentIndex())) if self.sizeMapper.currentIndex() != self.sizeLast: self.sizeMapper.toNext() else: self.sizeMapper.toFirst() self.sizeIndexLbl.setText('{}'.format(self.sizeMapper.currentIndex())) #print('after {}'.format(self.mapper.currentIndex())) def sizePrevious(self): if self.sizeMapper.currentIndex() != 0: self.sizeMapper.toPrevious() else: self.sizeMapper.toLast() self.sizeIndexLbl.setText('{}'.format(self.sizeMapper.currentIndex()))
class MasternodeOutputsTab(QWidget): """Widget that is used to select a masternode output.""" def __init__(self, parent): super(MasternodeOutputsTab, self).__init__(parent) self.dialog = parent self.manager = parent.manager include_frozen_checkbox = QCheckBox(_('Include frozen addresses')) include_frozen_checkbox.setChecked(False) self.scan_outputs_button = QPushButton( _('Scan For Masternode Outputs')) def on_scan_outputs(): """Call scan_for_outputs() with whether to include frozen addresses.""" self.scan_for_outputs(include_frozen_checkbox.isChecked()) self.scan_outputs_button.clicked.connect(on_scan_outputs) self.status_edit = QLineEdit() self.status_edit.setReadOnly(True) self.valid_outputs_list = MasternodeOutputsWidget() self.valid_outputs_list.outputSelected.connect(self.set_output) self.collateral_edit = PrevOutWidget() self.collateral_edit.setReadOnly(True) self.mapper = QDataWidgetMapper() self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.dialog.masternodes_widget.proxy_model) model = self.dialog.masternodes_widget.model self.mapper.addMapping(self.collateral_edit, model.VIN, b'string') self.save_output_button = QPushButton(_('Save')) self.save_output_button.setEnabled(False) self.save_output_button.clicked.connect(self.save_output) vbox = QVBoxLayout() desc = ' '.join([ 'Use this tab to scan for and choose a collateral payment for your masternode.', 'A valid collateral payment is exactly 15000000 VESTX.' ]) desc = QLabel(_(desc)) desc.setWordWrap(True) vbox.addWidget(desc) status_box = QHBoxLayout() status_box.setContentsMargins(0, 0, 0, 0) status_box.addWidget(QLabel(_('Status:'))) status_box.addWidget(self.status_edit, stretch=1) vbox.addLayout(status_box) valid_outputs_box = QVBoxLayout() valid_outputs_box.setContentsMargins(0, 0, 0, 0) valid_outputs_box.addWidget(QLabel(_('Masternode Outputs:'))) valid_outputs_box.addWidget(self.valid_outputs_list) vbox.addLayout( util.Buttons(include_frozen_checkbox, self.scan_outputs_button)) vbox.addLayout(valid_outputs_box) vbox.addWidget(self.collateral_edit) vbox.addLayout(util.Buttons(self.save_output_button)) self.setLayout(vbox) def scan_for_outputs(self, include_frozen): """Scan for 15000000 VESTX outputs. If one or more is found, populate the list and enable the sign button. """ self.valid_outputs_list.clear() exclude_frozen = not include_frozen coins = list( self.manager.get_masternode_outputs(exclude_frozen=exclude_frozen)) if len(coins) > 0: self.valid_outputs_list.add_outputs(coins) else: self.status_edit.setText( _('No 15000000 VESTX outputs were found.')) self.status_edit.setStyleSheet( util.ColorScheme.RED.as_stylesheet()) def set_output(self, vin): """Set the selected output.""" self.collateral_edit.set_dict(vin) self.save_output_button.setEnabled(True) def save_output(self): """Save the selected output as the current masternode's collateral.""" self.mapper.submit() # Determine the masternode's collateral key using this output. self.dialog.populate_collateral_key() def set_mapper_index(self, row): """Set the row that the data widget mapper should use.""" self.valid_outputs_list.clear() self.status_edit.clear() self.status_edit.setStyleSheet( util.ColorScheme.DEFAULT.as_stylesheet()) self.mapper.setCurrentIndex(row) mn = self.dialog.masternodes_widget.masternode_for_row(row) status_text = _('Masternode has no collateral payment assigned.') can_scan = not mn.announced # Disable the scan_outputs button if the masternode already has an assigned output. if mn.vin.get('value', 0) == COIN * 15000000: can_scan = False self.valid_outputs_list.add_output(mn.vin) status_text = _('Masternode already has a collateral payment.') self.status_edit.setText(_(status_text)) self.scan_outputs_button.setEnabled(can_scan)
class MainWindow(QMainWindow): # 继承主窗口函数的类, 继承编写的主函数 def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) # 初始化运行A窗口类下的 setupUi 函数 self.open_alltable() self.enterList = {} self.outList = {} self.name_RFID = { '直齿轮': '01B0E00000020010B1', '斜齿轮': '01B0E00000030010B2', '齿轮轴': '01A0E00000010010A1', '光轴': '01A0E00000010010A2', '曲柄': '01C0E00000020010C1', '摇杆': '01C0E00000010010C2' } self.RFID_kind = dict([(value, key) for (key, value) in self.name_RFID.items()]) self.capacity = { '直齿轮': 18, '斜齿轮': 18, '齿轮轴': 24, '光轴': 24, '曲柄': 36, '摇杆': 36 } self.nameNum = { '直齿轮': 3, '斜齿轮': 3, '齿轮轴': 4, '光轴': 4, '曲柄': 6, '摇杆': 6 } self.locateName = { '直齿轮': ['A', 'B', 1], '斜齿轮': ['C', 'D', 1], '齿轮轴': ['A', 'B', 2], '光轴': ['C', 'D', 2], '曲柄': ['A', 'B', 3], '摇杆': ['C', 'D', 3] } self.get_locState() # 获取所有货位的空闲状态 # 初始化出入库按钮使能状态 self.ui.outScan_pushButton.setEnabled(False) self.ui.enterScan_pushButton.setEnabled(False) self.currentList = self.Absolute_statis('current') # 获取入库记录里各种工件的数量 print(self.currentList) def open_alltable(self): ## tableView显示属性设置 self.ui.current_tableView.setSelectionBehavior( QAbstractItemView.SelectItems) self.ui.current_tableView.setSelectionMode( QAbstractItemView.SingleSelection) self.ui.current_tableView.setAlternatingRowColors(True) # 设置相邻记录的不同颜色 self.ui.current_tableView.verticalHeader().setDefaultSectionSize( 22) # 单元格高度 self.ui.current_tableView.horizontalHeader().setDefaultSectionSize( 160) # 单元格宽度 self.ui.enter_tableView.setSelectionBehavior( QAbstractItemView.SelectItems) self.ui.enter_tableView.setSelectionMode( QAbstractItemView.SingleSelection) self.ui.enter_tableView.setAlternatingRowColors(True) # 设置相邻记录的不同颜色 self.ui.enter_tableView.verticalHeader().setDefaultSectionSize( 22) # 单元格高度 self.ui.enter_tableView.horizontalHeader().setDefaultSectionSize( 160) # 单元格宽度 self.ui.out_tableView.setSelectionBehavior( QAbstractItemView.SelectItems) self.ui.out_tableView.setSelectionMode( QAbstractItemView.SingleSelection) self.ui.out_tableView.setAlternatingRowColors(True) # 设置相邻记录的不同颜色 self.ui.out_tableView.verticalHeader().setDefaultSectionSize( 22) # 单元格高度 self.ui.out_tableView.horizontalHeader().setDefaultSectionSize( 160) # 单元格宽度 self.ui.VICEtableView.setSelectionBehavior( QAbstractItemView.SelectItems) self.ui.VICEtableView.setSelectionMode( QAbstractItemView.SingleSelection) self.ui.VICEtableView.setAlternatingRowColors(True) # 设置相邻记录的不同颜色 self.ui.VICEtableView.verticalHeader().setDefaultSectionSize( 22) # 单元格高度 self.ui.VICEtableView.horizontalHeader().setDefaultSectionSize( 240) # 单元格宽度 # 连接到数据库并打开 self.DB = QSqlDatabase.addDatabase( 'QSQLITE') # 建立与数据库的连接,即QSqlDatabase对象 self.DB.setDatabaseName('MES5.db') # 设置数据库名称 self.DB.open() # 打开数据库 print('数据库打开成功') ## 打开现有库存数据表 self.current_tabModel = QSqlTableModel(self, self.DB) # 创建数据表的模型 self.current_tabModel.setTable('工件信息表') # 设置需要连接的数据表 self.current_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) ## 打开入库记录表 self.enter_tabModel = QSqlTableModel(self, self.DB) # 创建数据表的模型 self.enter_tabModel.setTable('入库记录表') # 设置需要连接的数据表 self.enter_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) ## 打开出库记录表 self.out_tabModel = QSqlTableModel(self, self.DB) # 创建数据表的模型 self.out_tabModel.setTable('出库记录表') # 设置需要连接的数据表 self.out_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) ## 打开固定批RFID表======================================================== self.vice_tabModel = QSqlTableModel(self, self.DB) # 创建数据表的模型 self.vice_tabModel.setTable('新建表') # 设置需要连接的数据表 self.vice_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.ui.VICEtableView.setModel( self.vice_tabModel) # 为一个QTableView组件设置一个QSqlTabelModel模型 self.vice_tabModel.select() # 建立RFID与组件的映射关系 self.mapper = QDataWidgetMapper() self.mapper.setModel(self.vice_tabModel) self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) ##界面组件与tabelmodel的具体字段之间的联系 self.mapper.addMapping(self.ui.RFIDlineEdit, 0) self.mapper.toFirst() # 移动到首记录 # 选中数据时信号的发射 self.selModel = QItemSelectionModel(self.vice_tabModel) self.selModel.currentRowChanged.connect(self.do_currentRowChanged) self.ui.VICEtableView.setSelectionModel(self.selModel) # 设置选择模型 # =============================================================================== self.refresh() print('数据表打开成功') ##获取字段名和序号的字典数据 empty = self.current_tabModel.record() # 得到的是一个空的记录,获取表的字段定义 self.fldNum = {} for i in range(empty.count()): filedname = empty.fieldName(i) empty.field(filedname).setReadOnly(True) # 每个字段设置为只读 self.fldNum.setdefault( filedname, i) # 如果字典中包含有给定键,则返回该键对应的值,否则将键添加到字典中,默认值为None print(self.fldNum) print(self.current_tabModel.record().count()) def do_currentRowChanged(self, current): self.mapper.setCurrentIndex(current.row()) def refresh(self): self.ui.current_tableView.setModel(self.current_tabModel) self.current_tabModel.select() self.ui.enter_tableView.setModel( self.enter_tabModel) # 为一个QTableView组件设置一个QSqlTabelModel模型 self.enter_tabModel.select() self.ui.out_tableView.setModel( self.out_tabModel) # 为一个QTableView组件设置一个QSqlTabelModel模型 self.out_tabModel.select() self.inventory_used() #################################路径规划与货位分配########################################### def get_locState(self): # 获取所有货位的状态 self.locationState = {} DecodeLoc = {'A': 0, 'B': 1, 'C': 0, 'D': 1} # 解码字典 for key, value in self.nameNum.items(): self.locationState[key] = np.zeros((2, 3, value), dtype=int) if self.current_tabModel.record(0).isNull('货位') == True: pass else: currentRow = self.current_tabModel.rowCount() # 库存的已记录数 # 根据现有库存更新货位的状态 for i in range(currentRow): curRec = self.current_tabModel.record(i) location = curRec.value('货位') kindname = curRec.value('种类') x = DecodeLoc[location[0]] # 对已有的工件的货位编码进行解码 y = int(location[1]) - 1 z = int(location[5]) - 1 self.locationState[kindname][x][y][z] = 1 #货位分配函数 def allocation(self, name, num, label): # 输入工件名称和对应的数量 if label == 'i': sign = 0 else: sign = 1 itsloc = self.locationState[name] for i in range(3): data = itsloc[:, 0:i + 1] data = data.reshape(1, -1)[0] itsum = sum(data == sign) if itsum >= num: forward_double = i + 1 break idle_loc = np.where( itsloc[:, 0:forward_double] == sign) # 寻找前forward_double对货架的空闲货位 locating = [] # 存放接收工件的货位 for i in range(num): x = idle_loc[0][i] y = idle_loc[1][i] z = idle_loc[2][i] self.locationState[name][x][y][z] = 1 - sign # 分配好后即更新货位状态 locating.append([x, y, z]) EncodeLoc = [] for i in locating: s = self.locateName[name][i[0]] + str(i[1] + 1) + '-' + \ str(self.locateName[name][2]) + '-' + str(i[2] + 1) EncodeLoc.append(s) return EncodeLoc, forward_double def getLocation(self, outList, direct): ALLlocation = [] forwardLocation = {} for key, value in outList.items(): location, position = self.allocation(key, value, direct) ALLlocation = ALLlocation + location forwardLocation[key] = position - 1 return ALLlocation, forwardLocation # 表里的工件统计 def statistics(self, model): n = model.rowCount() # 总行数 all_list = {} for i in range(n): # 统计入库记录里各种工件的数量 rec = model.record(i) if rec.value('种类') in all_list: all_list[rec.value('种类')] += 1 else: all_list[rec.value('种类')] = 1 return all_list def Absolute_statis(self, label): myModel = QSqlQueryModel(self) if label == 'current': myModel.setQuery("select 种类 from 工件信息表") elif label == 'enter': myModel.setQuery("select 种类 from 入库记录表") elif label == 'out': myModel.setQuery("select 种类 from 出库记录表") allnum = myModel.rowCount() all_dict = {} for i in range(allnum): rec = myModel.record(i) if rec.value('种类') in all_dict: all_dict[rec.value('种类')] += 1 else: all_dict[rec.value('种类')] = 1 return all_dict #寻找出入库记录的最大批次 def getMaxbatch(self, label): myModel = QSqlQueryModel(self) if label == 'enter': myModel.setQuery("select 批次 from 入库记录表") elif label == 'out': myModel.setQuery("select 批次 from 出库记录表") n = myModel.rowCount() if myModel.record(0).isNull('批次') == True: # 检测入库记录里的最大批次 max_batch = 0 else: max_batch = myModel.record(n - 1).value('批次') # 批次按顺序排列,查找最大批次 print('共有%d条记录,最大批次为%d' % (n, max_batch)) return max_batch #################################主操作界面#################################################### # 容量不足信息打印 def on_enterNum_spinBox_valueChanged(self): self.enter_Warning() def on_enterKind_comboBox_currentIndexChanged(self): self.enter_Warning() def enter_Warning(self): num = self.ui.enterNum_spinBox.value() enterKind = self.ui.enterKind_comboBox.currentText() if enterKind not in self.currentList: currentNum = 0 else: currentNum = self.currentList[enterKind] if num + currentNum > self.capacity[enterKind]: self.ui.enterList_pushButton.setEnabled(False) # self.ui.enterScan_pushButton.setEnabled(False) warningText = '⚠警告!' + enterKind + '已经超出库容上限!' else: self.ui.enterList_pushButton.setEnabled(True) # self.ui.enterScan_pushButton.setEnabled(True) warningText = '' self.ui.textEdit.setPlainText(warningText) #############入库函数 ##入库添加工件及对应数量 @pyqtSlot() def on_enterList_pushButton_clicked(self): enterKind = self.ui.enterKind_comboBox.currentText() enterNum = self.ui.enterNum_spinBox.value() if enterKind in self.enterList: self.enterList[enterKind] += enterNum else: self.enterList[enterKind] = enterNum # 激活出库按钮使能状态 self.ui.enterScan_pushButton.setEnabled(True) print(self.enterList) ##扫描入库 @pyqtSlot() def on_enterScan_pushButton_clicked(self): # 根据入库记录里的RFID生成新的RFID enteredList = self.statistics(self.enter_tabModel) # 获取入库记录里各种工件的数量 RFID_list = [] for key in self.enterList.keys(): # 对要入库的工件种类进行迭代 for i in range(self.enterList[key]): if key not in enteredList: no = i + 6 else: no = enteredList[key] + i + 6 RFID = self.name_RFID[key] + str(no).zfill(6) RFID_list.append(RFID) # 将RFID写入txt文件来模拟货物 filename = '卸货区' if not os.path.isdir(filename): os.makedirs(filename) with open('卸货区\待入库货工件.txt', 'w', encoding='utf8') as f: for s in RFID_list: f.write(s + '\n') # 从卸货区寻找模拟货物 dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找入库货物", "", "模拟货物(*.txt)") if (dbFilename == ''): return with open(dbFilename, 'r', encoding='utf8') as f: enterRFID = f.readlines() all_location, forwardLocation = self.getLocation(self.enterList, 'i') self.ui.widget.get_path(forwardLocation, 'i') # 绘制路径 self.enter(enterRFID, all_location) # 入库操作 def enter(self, enterRFID, all_location): #print('入库函数,enterRFID=',enterRFID,'all_location=',all_location) # 准备写入工件信息表和入库记录表 currentQuery = QSqlQuery(self.DB) enterQuery = QSqlQuery(self.DB) currentQuery.prepare('''INSERT INTO 工件信息表 (RFID,种类,货位,生产商, 批次,入库日期,入库时间,重量) VALUES(:RFID,:kind,:location,:manufacture,:batch, :enterDate,:enterTime,:weight)''') enterQuery.prepare('''INSERT INTO 入库记录表 (RFID,种类,生产商, 批次,入库日期,入库时间) VALUES(:RFID,:kind, :manufacture,:batch, :enterDate,:enterTime)''') # 准备数据(都是恒量) RFID_manufacture = { 'E0000001': '西安交大一厂', 'E0000002': '西安交大二厂', 'E0000003': '西安交大三厂' } max_batch = self.getMaxbatch('enter') enterDate = self.ui.dealdate.date().toString(Qt.ISODate) # 获取日期 enterTime = time.strftime('%H:%M:%S', time.localtime(time.time())) # 获取时分秒 weightList = { '直齿轮': 15, '斜齿轮': 20, '齿轮轴': 7, '光轴': 5, '曲柄': 2, '摇杆': 1 } check = True # 扫码并写入记录表 for i in range(len(enterRFID)): # 解码 s = enterRFID[i].rstrip('\n') kind = self.RFID_kind[s[0:18]] manufacture = RFID_manufacture[s[4:12]] weight = weightList[kind] # 加入现有库存 currentQuery.bindValue(":RFID", s) currentQuery.bindValue(":kind", kind) currentQuery.bindValue(":location", all_location[i]) currentQuery.bindValue(":manufacture", manufacture) currentQuery.bindValue(":batch", max_batch + 1) currentQuery.bindValue(":enterDate", enterDate) currentQuery.bindValue(":enterTime", enterTime) currentQuery.bindValue(":weight", weight) res = currentQuery.exec() # 执行SQL语句 check = check & res # 加入入库记录表 enterQuery.bindValue(":RFID", s) enterQuery.bindValue(":kind", kind) enterQuery.bindValue(":manufacture", manufacture) enterQuery.bindValue(":batch", max_batch + 1) enterQuery.bindValue(":enterDate", enterDate) enterQuery.bindValue(":enterTime", enterTime) enterQuery.exec() # 执行SQL语句 if check == False: QMessageBox.critical( self, "错误", "添加记录出现错误\n" + currentQuery.lastError().text()) print('入库异常') else: self.enterList = {} self.refresh() self.ui.enterScan_pushButton.setEnabled(False) self.ui.textEdit.setPlainText('入库操作成功') #############出库函数 # 库存不足信息打印 def on_outNum_spinBox_valueChanged(self): self.out_Warning() def on_outKind_comboBox_currentIndexChanged(self): self.out_Warning() def out_Warning(self): num = self.ui.outNum_spinBox.value() outKind = self.ui.outKind_comboBox.currentText() self.currentList = self.Absolute_statis('current') if outKind not in self.currentList: # 防止有些工件没有时作为字典的键出错 currentNum = 0 else: currentNum = self.currentList[outKind] if num > currentNum: self.ui.outList_pushButton.setEnabled(False) # self.ui.outScan_pushButton.setEnabled(False) warningText = '⚠警告!' + outKind + '已经超出库存上限!' else: self.ui.outList_pushButton.setEnabled(True) # self.ui.outScan_pushButton.setEnabled(True) warningText = '' self.ui.textEdit.setPlainText(warningText) # 添加出库工件 @pyqtSlot() def on_outList_pushButton_clicked(self): outKind = self.ui.outKind_comboBox.currentText() outNum = self.ui.outNum_spinBox.value() if outKind in self.outList: self.outList[outKind] += outNum else: self.outList[outKind] = outNum self.ui.outScan_pushButton.setEnabled(True) print("要出库的货物:", self.outList) @pyqtSlot() def on_outScan_pushButton_clicked(self): currentRow = self.current_tabModel.rowCount() # 库存的已记录数 RFID_list = [] outLocation, forwardLocation = self.getLocation(self.outList, 'o') # 从现有库存里取符合条件的RFID for i in range(currentRow): curRec = self.current_tabModel.record(i) location = curRec.value('货位') if location in outLocation: RFID_list.append(curRec.value('RFID')) # 将RFID写入模拟货物 filename = '发货区' if not os.path.isdir(filename): os.makedirs(filename) with open('发货区\待出库货工件.txt', 'w', encoding='utf8') as f: for s in RFID_list: f.write(s + '\n') # 从卸货区寻找模拟货物 dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找出库货物", "", "模拟货物(*.txt)") if (dbFilename == ''): return with open(dbFilename, 'r', encoding='utf8') as f: outRFID = f.readlines() for i in range(len(outRFID)): # 去除所有的换行符 outRFID[i] = outRFID[i].rstrip('\n') self.ui.widget.get_path(forwardLocation, 'o') #出库路径绘制 self.out(outRFID) def out(self, outRFID): # 出库函数,参数只有RFID列表 currentRow = self.current_tabModel.rowCount() # 库存的已记录数 currentQuery = QSqlQuery(self.DB) # 准备删除 outQuery = QSqlQuery(self.DB) # 准备插入 outQuery.prepare('''INSERT INTO 出库记录表 (RFID,种类,生产商, 批次,出库日期,出库时间) VALUES(:RFID,:kind, :manufacture,:batch, :outDate,:outTime)''') currentQuery.prepare('''DELETE FROM 工件信息表 WHERE RFID=:ID''') # 获取出库记录表里的最大批次 batch = self.getMaxbatch('out') outDate = self.ui.dealdate.date().toString(Qt.ISODate) outTime = time.strftime('%H:%M:%S', time.localtime(time.time())) check = True # 读取要出库的工件的RFID for i in range(currentRow): # 遍历现有库存找到要出库的RFID curRec = self.current_tabModel.record(i) if curRec.value('RFID') in outRFID: outQuery.bindValue(":RFID", curRec.value('RFID')) outQuery.bindValue(":kind", curRec.value('种类')) outQuery.bindValue(":manufacture", curRec.value('生产商')) outQuery.bindValue(":batch", batch + 1) outQuery.bindValue(":outDate", outDate) outQuery.bindValue(":outTime", outTime) outQuery.exec() # 执行SQL语句 currentQuery.bindValue(":ID", curRec.value('RFID')) res = currentQuery.exec() check = check & res if check == False: QMessageBox.critical( self, "错误", "出库记录出现错误\n" + currentQuery.lastError().text()) else: self.refresh() self.outList = {} self.ui.outScan_pushButton.setEnabled(False) self.ui.textEdit.setPlainText('出库操作成功') self.out_Warning() # 库存不足则打印信息,改变按键使能状态 # =================================副操作界面================================================== def getCurrentNum(self): currentQryModel = QSqlQueryModel(self) currentQryModel.setQuery("select RFID from 工件信息表") allnum = currentQryModel.rowCount() return allnum, currentQryModel ##单件扫描 @pyqtSlot() def on_emitPushButton_pressed(self): RFID = self.ui.RFIDlineEdit.text() forwardLocation = {} kind = self.RFID_kind[RFID[0:18]] kindlist = [] kindlist.append(RFID) allnum, currentQryModel = self.getCurrentNum() for i in range(allnum): cur = currentQryModel.record(i) if RFID == cur.value('RFID'): self.out(kindlist) self.get_locState() return # 因为已经指定了RFID,所以出库没有路径规划 location, position = self.allocation(kind, 1, 'i') self.enter(kindlist, location) forwardLocation[kind] = position - 1 self.ui.widget.get_path(forwardLocation, 'i') ##多件扫描 @pyqtSlot() def on_ScanPushButton_pressed(self): outRFID = [] inkindNum = {} dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找入库货物", "", "模拟货物(*.txt)") if (dbFilename == ''): return with open(dbFilename, 'r', encoding='utf8') as f: RFID = f.readlines() for i in range(len(RFID)): # 去除所有的换行符 RFID[i] = RFID[i].rstrip('\n') allnum, currentQryModel = self.getCurrentNum() for i in range(allnum): cur = currentQryModel.record(i) if cur.value('RFID') in RFID: outRFID.append(cur.value('RFID')) # 如果现有库存里存在,则添加到出库RFID列表中 RFID.remove(cur.value('RFID')) # 移除 if outRFID != []: self.out(outRFID) self.get_locState() if RFID != []: for i in RFID: kind = self.RFID_kind[i[0:18]] if kind in inkindNum: inkindNum[kind] += 1 else: inkindNum[kind] = 1 inLocation, forwardLocation = self.getLocation(inkindNum, 'i') self.ui.widget.get_path(forwardLocation, 'i') #绘制路径 self.enter(RFID, inLocation) #入库操作 #################################现有库存界面#################################################### ##种类过滤 def on_currentComboBox_currentIndexChanged(self, curText): self.current_filter() ##批次过滤 def on_batchSpinBox_valueChanged(self, num): self.current_filter() ##是否选择批次 def on_batchCheckBox_stateChanged(self): self.current_filter() def current_filter(self): kind = self.ui.currentComboBox.currentText() batch = self.ui.batchSpinBox.value() if kind == '全选': if self.ui.batchCheckBox.isChecked() == True: self.current_tabModel.setFilter("批次='%d'" % (batch)) else: self.current_tabModel.setFilter("") else: if self.ui.batchCheckBox.isChecked() == True: self.current_tabModel.setFilter("批次='%d' and 种类='%s'" % (batch, kind)) else: self.current_tabModel.setFilter("种类='%s'" % (kind)) # 已用库存百分比显示 def inventory_used(self): # 通过进度条表示库存余量 currentQryModel = QSqlQueryModel(self) currentQryModel.setQuery("select RFID from 工件信息表") allnum = currentQryModel.rowCount() progress = int((100 * allnum / 156) + 0.5) self.ui.progressBar.setValue(progress) @pyqtSlot() def on_delete_pushButton_pressed(self): query = QSqlQuery(self.DB) print('开始删除') query.exec("DELETE FROM 工件信息表 WHERE 批次>=0") query.exec("DELETE FROM 出库记录表 WHERE 批次>=0") check = query.exec("DELETE FROM 入库记录表 WHERE 批次>=0") if check == False: QMessageBox.critical(self, "错误", "删除记录出现错误\n" + query.lastError().text()) else: self.refresh() #################################入库记录界面#################################################### ##种类过滤 def on_enterComboBox_currentIndexChanged(self): self.enter_filter() ##日期过滤 def on_enterDate_dateChanged(self): self.enter_filter() ##是否选择批次 def on_enterCheckBox_stateChanged(self): self.enter_filter() def enter_filter(self): kind = self.ui.enterComboBox.currentText() date = self.ui.enterDate.date().toString(Qt.ISODate) if self.ui.enterCheckBox.isChecked() == True: if kind == '全选': self.enter_tabModel.setFilter("入库日期='%s'" % (date)) else: self.enter_tabModel.setFilter("入库日期='%s' and 种类='%s'" % (date, kind)) else: if kind == '全选': self.enter_tabModel.setFilter("") else: self.enter_tabModel.setFilter("种类='%s'" % (kind)) # 入库记录可视化 @pyqtSlot() def on_drawEnter_pushButton_pressed(self): self.recordDemo(self.enter_tabModel) #################################出库记录界面#################################################### ##种类过滤 def on_outComboBox_currentIndexChanged(self): self.out_filter() ##日期过滤 def on_outDate_dateChanged(self): self.out_filter() ##是否选择批次 def on_outCheckBox_stateChanged(self): self.out_filter() def out_filter(self): kind = self.ui.outComboBox.currentText() date = self.ui.outDate.date().toString(Qt.ISODate) if self.ui.outCheckBox.isChecked() == True: if kind == '全选': self.out_tabModel.setFilter("出库日期='%s'" % (date)) else: self.out_tabModel.setFilter("出库日期='%s' and 种类='%s'" % (date, kind)) else: if kind == '全选': self.out_tabModel.setFilter("") else: self.out_tabModel.setFilter("种类='%s'" % (kind)) # 出库记录可视化 @pyqtSlot() def on_drawOut_pushButton_pressed(self): self.recordDemo(self.out_tabModel) #################################数据可视化################################################ # 现有库存可视化 @pyqtSlot() def on_drawCurrent_pushButton_pressed(self): # def demo(self): #self.currentList = self.statistics(self.current_tabModel) self.currentList = self.Absolute_statis('current') labels = [] values = [] for key, value in self.currentList.items(): labels.append(key) values.append(value) if self.ui.pie_radioButton.isChecked() == True: trace = [go.Pie(labels=labels, values=values)] layout = go.Layout(title='工件库存比例配比图', ) elif self.ui.bar_radioButton.isChecked() == True: trace = [go.Bar(x=labels, y=values)] layout = go.Layout(title='工件库存直方图', ) print(labels) print(values) fig = go.Figure(data=trace, layout=layout) file = 'F:\source\python代码\MES库存管理\VisualData' if not os.path.isdir(file): os.makedirs(file) filename = 'F:\source\python代码\MES库存管理\VisualData\\currentDemo.html' pyof.plot(fig, filename=filename, auto_open=False) win = DemoWindow(filename) win.exec() def recordDemo(self, model): record = {} enterRow = model.rowCount() # 库存的已记录数 dateName = model.record().fieldName(4) # 入库日期&出库日期 TimeName = model.record().fieldName(5) for i in range(enterRow): curRec = model.record(i) kind = curRec.value('种类') date = curRec.value(dateName) Time = curRec.value(TimeName) dateTime = date + ' ' + Time dateRecord = {} if kind not in record: # 工件种类第一次检索到,将其添加到reord中 dateRecord[dateTime] = 1 # 同时将对应的日期添加到record中 record[kind] = dateRecord else: if dateTime not in record[kind]: # 种类存在,但是第一次检索到某个日期时 record[kind][dateTime] = 1 else: record[kind][dateTime] += 1 traces = [] for key1 in record.keys(): x = [] y = [] for key2 in record[key1].keys(): x.append(key2) y.append(record[key1][key2]) trace = go.Scatter( x=x, y=y, # mode = 'markers', name=key1) traces.append(trace) layout = go.Layout(title=dateName[0:2] + '记录', ) fig = go.Figure(data=traces, layout=layout) file = 'F:\source\python代码\MES库存管理\VisualData' if not os.path.isdir(file): os.makedirs(file) filename = 'F:\source\python代码\MES库存管理\VisualData\\recordDemo.html' pyof.plot(fig, filename=filename, auto_open=False) win = DemoWindow(filename) win.exec()
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setCentralWidget(self.ui.splitter) # tableView显示属性设置 self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.verticalHeader().setDefaultSectionSize(22) self.ui.tableView.horizontalHeader().setDefaultSectionSize(60) ## self.ui.tableView.resizeColumnsToContents() ## ==============自定义功能函数============ def __getFieldNames(self): ##获取所有字段名称 emptyRec = self.qryModel.record() #获取空记录,只有字段名 self.fldNum = {} #字段名与序号的字典 for i in range(emptyRec.count()): fieldName = emptyRec.fieldName(i) self.fldNum.setdefault(fieldName) self.fldNum[fieldName] = i print(self.fldNum) def __openTable(self): ##查询数据 self.qryModel = QSqlQueryModel(self) self.qryModel.setQuery( '''SELECT empNo, Name, Gender, Birthday, Province, Department, Salary FROM employee ORDER BY empNo''' ) if self.qryModel.lastError().isValid(): QMessageBox.critical( self, "错误", "数据表查询错误,错误信息\n" + self.qryModel.lastError().text()) return self.ui.statusBar.showMessage("记录条数:%d" % self.qryModel.rowCount()) self.__getFieldNames() #获取字段名和序号 ##设置字段显示名,直接使用序号 self.qryModel.setHeaderData(0, Qt.Horizontal, "工号") self.qryModel.setHeaderData(1, Qt.Horizontal, "姓名") self.qryModel.setHeaderData(2, Qt.Horizontal, "性别") self.qryModel.setHeaderData(3, Qt.Horizontal, "出生日期") self.qryModel.setHeaderData(4, Qt.Horizontal, "省份") self.qryModel.setHeaderData(5, Qt.Horizontal, "部门") self.qryModel.setHeaderData(6, Qt.Horizontal, "工资") ## self.qryModel.setHeaderData(self.fldNum["empNo"], Qt.Horizontal, "工号") ## self.qryModel.setHeaderData(self.fldNum["Name"], Qt.Horizontal, "姓名") ## self.qryModel.setHeaderData(self.fldNum["Gender"], Qt.Horizontal, "性别") ## self.qryModel.setHeaderData(self.fldNum["Birthday"], Qt.Horizontal, "出生日期") ## self.qryModel.setHeaderData(self.fldNum["Province"], Qt.Horizontal, "省份") ## self.qryModel.setHeaderData(self.fldNum["Department"], Qt.Horizontal, "部门") ## self.qryModel.setHeaderData(self.fldNum["Salary"], Qt.Horizontal, "工资") ##创建界面组件与数据模型的字段之间的数据映射 self.mapper = QDataWidgetMapper() self.mapper.setModel(self.qryModel) #设置数据模型 ## self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) ##界面组件与qryModel的具体字段之间的联系 ## self.mapper.addMapping(self.ui.dbSpinEmpNo, self.fldNum["empNo"]) ## self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"]) ## self.mapper.addMapping(self.ui.dbComboSex, self.fldNum["Gender"]) ## self.mapper.addMapping(self.ui.dbEditBirth, self.fldNum["Birthday"]) ## self.mapper.addMapping(self.ui.dbComboProvince, self.fldNum["Province"] ) ## self.mapper.addMapping(self.ui.dbComboDep, self.fldNum["Department"] ) ## self.mapper.addMapping(self.ui.dbSpinSalary,self.fldNum["Salary"] ) self.mapper.addMapping(self.ui.dbSpinEmpNo, 0) self.mapper.addMapping(self.ui.dbEditName, 1) self.mapper.addMapping(self.ui.dbComboSex, 2) self.mapper.addMapping(self.ui.dbEditBirth, 3) self.mapper.addMapping(self.ui.dbComboProvince, 4) self.mapper.addMapping(self.ui.dbComboDep, 5) self.mapper.addMapping(self.ui.dbSpinSalary, 6) self.mapper.toFirst() #移动到首记录 self.selModel = QItemSelectionModel(self.qryModel) #关联选择模型 self.selModel.currentRowChanged.connect( self.do_currentRowChanged) #选择行变化时 self.ui.tableView.setModel(self.qryModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selModel) #设置选择模型 self.ui.actOpenDB.setEnabled(False) def __refreshTableView(self): ##刷新tableView显示 index = self.mapper.currentIndex() curIndex = self.qryModel.index(index, 1) #QModelIndex self.selModel.clearSelection() #清空选择项 self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##“打开数据库”按钮 def on_actOpenDB_triggered(self): dbFilename, flt = QFileDialog.getOpenFileName( self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)") if (dbFilename == ''): return #打开数据库 self.DB = QSqlDatabase.addDatabase("QSQLITE") #添加 SQL LITE数据库驱动 self.DB.setDatabaseName(dbFilename) #设置数据库名称 ## DB.setHostName() ## DB.setUserName() ## DB.setPassword() if self.DB.open(): #打开数据库 self.__openTable() #打开数据表 else: QMessageBox.warning(self, "错误", "打开数据库失败") @pyqtSlot() ##首记录 def on_actRecFirst_triggered(self): self.mapper.toFirst() self.__refreshTableView() @pyqtSlot() ##前一记录 def on_actRecPrevious_triggered(self): self.mapper.toPrevious() self.__refreshTableView() @pyqtSlot() ##后一条记录 def on_actRecNext_triggered(self): self.mapper.toNext() self.__refreshTableView() @pyqtSlot() ##最后一条记录 def on_actRecLast_triggered(self): self.mapper.toLast() self.__refreshTableView() ## =============自定义槽函数=============================== def do_currentRowChanged(self, current, previous): ##记录移动时触发 if (current.isValid() == False): self.ui.dbLabPhoto.clear() #清除图片显示 return self.mapper.setCurrentIndex(current.row()) #更新数据映射的行号 first = (current.row() == 0) #是否首记录 last = (current.row() == self.qryModel.rowCount() - 1) #是否尾记录 self.ui.actRecFirst.setEnabled(not first) #更新使能状态 self.ui.actRecPrevious.setEnabled(not first) self.ui.actRecNext.setEnabled(not last) self.ui.actRecLast.setEnabled(not last) curRec = self.qryModel.record(current.row()) #获取当前记录,QSqlRecord类型 empNo = curRec.value("EmpNo") #不需要加 toInt()函数 query = QSqlQuery(self.DB) query.prepare( '''SELECT EmpNo, Memo, Photo FROM employee WHERE EmpNo = :ID''') query.bindValue(":ID", empNo) ## if not query.exec_(): #注意,在PyQt5.11.2之前的版本里只能使用exec_()函数 if not query.exec( ): #注意,在PyQt5.11.2添加了遗漏的overload型exec()函数,在PyQt5.11.2里没问题了 QMessageBox.critical(self, "错误", "执行SQL语句错误\n" + query.lastError().text()) return else: query.first() picData = query.value("Photo") if (picData == None): #图片字段内容为空 self.ui.dbLabPhoto.clear() else: #显示照片 pic = QPixmap() pic.loadFromData(picData) W = self.ui.dbLabPhoto.size().width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W)) memoData = query.value("Memo") #显示备注 self.ui.dbEditMemo.setPlainText(memoData)
class ImageDetailWindow(QDialog): logger = logging.getLogger(__name__) def __init__(self, app, imageListModel): super().__init__() self.ui = Ui_Dialog() self.ui.setupUi(self) self.app = app self.setWindowTitle("Image Detail") self.imageListModel = imageListModel def plot(self, modelIndex): self.mapper = QDataWidgetMapper(self) self.mapper.setModel(self.imageListModel) self.mapper.addMapping(self.ui.lineEditFile, 1) self.mapper.addMapping(self.ui.lineEditHash, 2) self.mapper.addMapping(self.ui.lineEditTarget, 3) self.mapper.addMapping(self.ui.lineEditFrame, 4) self.mapper.addMapping(self.ui.lineEditFilter, 5) self.mapper.addMapping(self.ui.lineEditExposure, 6) self.mapper.addMapping(self.ui.lineEditTemp, 7) self.mapper.addMapping(self.ui.lineEditXbinning, 8) self.mapper.addMapping(self.ui.lineEditYbinning, 9) self.mapper.addMapping(self.ui.lineEditSiteLat, 10) self.mapper.addMapping(self.ui.lineEditSiteLong, 11) self.mapper.addMapping(self.ui.lineEditRa, 12) self.mapper.addMapping(self.ui.lineEditDec, 13) self.mapper.addMapping(self.ui.lineEditAlt, 14) self.mapper.addMapping(self.ui.lineEditAz, 15) self.mapper.addMapping(self.ui.lineEditDate, 16) self.mapper.addMapping(self.ui.lineEditGain, 17) self.mapper.addMapping(self.ui.lineEditOffset, 18) self.mapper.addMapping(self.ui.lineEditSubframeScale, 19) self.mapper.addMapping(self.ui.lineEditCameraGain, 20) self.mapper.addMapping(self.ui.lineEditCameraResolution, 21) self.mapper.addMapping(self.ui.lineEditScaleUnit, 22) self.mapper.addMapping(self.ui.lineEditDataUnit, 23) self.mapper.addMapping(self.ui.lineEditCsvFile, 24) self.mapper.addMapping(self.ui.lineEditFwhm, 25) self.mapper.addMapping(self.ui.lineEditEccentricity, 26) self.mapper.addMapping(self.ui.lineEditSnrWeight, 27) self.mapper.addMapping(self.ui.lineEditNoise, 28) self.mapper.setCurrentIndex(modelIndex.row()) self.ui.lineEditRaF.setText( self.convertCoord(self.ui.lineEditRa.text(), "hms")) self.ui.lineEditDecF.setText( self.convertCoord(self.ui.lineEditDec.text(), "dms")) self.ui.lineEditSiteLatF.setText( self.convertCoord(self.ui.lineEditSiteLat.text(), "lat")) self.ui.lineEditSiteLongF.setText( self.convertCoord(self.ui.lineEditSiteLong.text(), "long")) self.ui.lineEditAltF.setText( self.convertCoord(self.ui.lineEditAlt.text(), "dms")) self.ui.lineEditAzF.setText( self.convertCoord(self.ui.lineEditAz.text(), "dms")) cr = self.imageListModel.index(modelIndex.row(), 1) t = self.imageListModel.data(cr, QtCore.Qt.DisplayRole) self.mplwidget = MatplotlibWidget(self.ui.MplWidget) self.mplwidget.setFileName(t) self.mplwidget.plot() try: self.resize(self.app.settings.value("sizeDetailW")) self.move(self.app.settings.value("posDetailW")) except Exception as e: self.logger.error(f"{e}") self.show() def closeEvent(self, event): self.app.settings.setValue("sizeDetailW", self.size()) self.app.settings.setValue("posDetailW", self.pos()) try: self.close() except Exception as e: self.logger.debug(f"Closing not existing window {e}") event.accept() def convertCoord(self, coord, type="dms"): if type == "dms": a = Angle(coord, u.deg) value = str( a.to_string(unit=u.degree, precision=0, sep=("°", "'", "''"))) elif type == "hms": a = Angle(coord, u.deg) value = str( a.to_string(unit=u.hour, precision=0, sep=("h", "m", "s"))) elif type == "lat": a = Latitude(coord, u.deg) a.wrap_angle = 90 * u.deg value = str( a.to_string(unit=u.degree, precision=0, sep=("°", "'", "''"))) elif type == "long": a = Longitude(coord, u.deg) a.wrap_angle = 180 * u.deg value = str( a.to_string(unit=u.degree, precision=0, sep=("°", "'", "''"))) return str(value)
class MainWindow(QMainWindow): def __init__(self, data): super().__init__() self.resize(400, 600) self.setWindowTitle('Logger Skeleton') self.statusBar().showMessage("Ready", 2000) # Make widgets #################################### self.tabs = QTabWidget(self) self.setCentralWidget(self.tabs) # Add tabs self.table_tab = QWidget(self) self.stats_tab = QWidget(self) self.tabs.addTab(self.table_tab, "Table") self.tabs.addTab(self.stats_tab, "Stats") # Table tab ########################################################### self.table_view = QTableView(self.table_tab) self.text_edit = QPlainTextEdit() self.btn_add_row = QPushButton("Add a row") #self.btn_remove_row = QPushButton("Remove selected rows") table_tab_vbox = QVBoxLayout() table_tab_vbox.addWidget(self.table_view) table_tab_vbox.addWidget(self.text_edit) table_tab_vbox.addWidget(self.btn_add_row) #table_tab_vbox.addWidget(self.btn_remove_row) self.table_tab.setLayout(table_tab_vbox) # Set model ####################################### my_model = DataQtModel(data, parent=self) # TODO: right use of "parent" ? # Proxy model ##################################### proxy_model = QSortFilterProxyModel( parent=self) # TODO: right use of "parent" ? proxy_model.setSourceModel(my_model) self.table_view.setModel(proxy_model) #self.table_view.setModel(my_model) # Set the view #################################### self.table_view.setSelectionBehavior( QAbstractItemView.SelectRows ) # Select the full row when a cell is selected (See http://doc.qt.io/qt-5/qabstractitemview.html#selectionBehavior-prop ) #self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) # Set selection mode. See http://doc.qt.io/qt-5/qabstractitemview.html#selectionMode-prop self.table_view.setAlternatingRowColors(True) self.table_view.setSortingEnabled(True) self.table_view.setColumnWidth( 0, 200) # TODO: automatically get the best width self.table_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # https://stackoverflow.com/q/17535563 self.table_view.setColumnHidden(COMMENT_COLUMN_INDEX, True) delegate = Delegate() self.table_view.setItemDelegate(delegate) # Set key shortcut ################################ # see https://stackoverflow.com/a/17631703 and http://doc.qt.io/qt-5/qaction.html#details # Add row action add_action = QAction(self.table_view) add_action.setShortcut(Qt.CTRL | Qt.Key_N) add_action.triggered.connect(self.add_row_btn_callback) self.table_view.addAction(add_action) # Delete action del_action = QAction(self.table_view) del_action.setShortcut(Qt.Key_Delete) del_action.triggered.connect(self.remove_row_callback) self.table_view.addAction(del_action) # Set QDataWidgetMapper ########################### self.mapper = QDataWidgetMapper() self.mapper.setModel( proxy_model ) # WARNING: do not use `my_model` here otherwise the index mapping will be wrong! self.mapper.addMapping(self.text_edit, COMMENT_COLUMN_INDEX) self.mapper.toFirst() # TODO: is it a good idea ? self.table_view.selectionModel().selectionChanged.connect( self.update_selection) # Set slots ####################################### self.btn_add_row.clicked.connect(self.add_row_btn_callback) #self.btn_remove_row.clicked.connect(self.remove_row_callback) #self.table_view.setColumnHidden(1, True) # Stats tab ########################################################### # See https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html stats_tab_layout = QVBoxLayout(self.stats_tab) self.plot_canvas = PlotCanvas(data, self.stats_tab, width=5, height=4, dpi=100) stats_tab_layout.addWidget(self.plot_canvas) ################################################### #proxy_model.dataChanged.connect(plot_canvas.update_figure) #proxy_model.rowsInserted.connect(plot_canvas.update_figure) # TODO #proxy_model.rowsRemoved.connect(plot_canvas.update_figure) # TODO self.tabs.currentChanged.connect( self.updatePlot ) # Update the stats plot when the tabs switch to the stats tab # Show ############################################ self.show() def update_selection(self, selected, deselected): index = self.table_view.selectionModel().currentIndex() self.mapper.setCurrentIndex(index.row()) print("Index: ", index.row()) def updatePlot(self, index): """ Parameters ---------- index Returns ------- """ if index == self.tabs.indexOf(self.stats_tab): self.plot_canvas.update_figure() def add_row_btn_callback(self): parent = QModelIndex() # More useful with e.g. tree structures #row_index = 0 # Insert new rows to the begining row_index = self.table_view.model().rowCount( parent) # Insert new rows to the end self.table_view.model().insertRows(row_index, 1, parent) def remove_row_callback(self): parent = QModelIndex() # More useful with e.g. tree structures # See http://doc.qt.io/qt-5/model-view-programming.html#handling-selections-in-item-views #current_index = self.table_view.selectionModel().currentIndex() #print("Current index:", current_index.row(), current_index.column()) selection_index_list = self.table_view.selectionModel().selectedRows() selected_row_list = [ selection_index.row() for selection_index in selection_index_list ] print("Current selection:", selected_row_list) #row_index = 0 # Remove the first row #row_index = self.table_view.model().rowCount(parent) - 1 # Remove the last row # WARNING: the list of rows to remove MUST be sorted in reverse order # otherwise the index of rows to remove may change at each iteration of the for loop! # TODO: there should be a lock mechanism to avoid model modifications from external sources while iterating this loop... # Or as a much simpler alternative, modify the ItemSelectionMode to forbid the non contiguous selection of rows and remove the following for loop for row_index in sorted(selected_row_list, reverse=True): # Remove rows one by one to allow the removql of non-contiguously selected rows (e.g. "rows 0, 2 and 3") success = self.table_view.model().removeRows(row_index, 1, parent) if not success: raise Exception("Unknown error...") # TODO
class APISSharding(QDialog, FORM_CLASS): shardingEditsSaved = pyqtSignal(bool) def __init__(self, iface, dbm, parent=None): """Constructor.""" super(APISSharding, self).__init__(parent) self.iface = iface self.dbm = dbm self.setupUi(self) # Initial window size/pos last saved. Use default values for first time if GetWindowSize("sharding"): self.resize(GetWindowSize("sharding")) self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat) self.editMode = False self.addMode = False self.initalLoad = True # Signals/Slot Connections self.rejected.connect(self.onReject) #self.uiButtonBox.rejected.connect(self.onReject) self.uiOkBtn.clicked.connect(self.onAccept) self.uiCancelBtn.clicked.connect(self.cancelEdit) self.uiSaveBtn.clicked.connect(self.saveEdits) mViewPictures = QMenu() aViewPicturesPreview = mViewPictures.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'image.png')), "in Vorschau") aViewPicturesPreview.triggered.connect(self.viewPictures) aViewPicturesFolder = mViewPictures.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'image.png')), "in Ordner") aViewPicturesFolder.triggered.connect(self.openPictures) self.uiViewPicturesTBtn.setMenu(mViewPictures) self.uiViewPicturesTBtn.clicked.connect( self.uiViewPicturesTBtn.showMenu) mViewSketches = QMenu() aViewSketchesPreview = mViewSketches.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'sketch.png')), "in Vorschau") aViewSketchesPreview.triggered.connect(self.viewSketches) aViewSketchesFolder = mViewSketches.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'sketch.png')), "in Ordner") aViewSketchesFolder.triggered.connect(self.openSketches) self.uiViewSketchesTBtn.setMenu(mViewSketches) self.uiViewSketchesTBtn.clicked.connect( self.uiViewSketchesTBtn.showMenu) self.initalLoad = False def openSharding(self, siteNumber, shardingNumber): self.initalLoad = True self.siteNumber = siteNumber self.shardingNumber = shardingNumber #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber, shardingNumber))) # Setup sharding model self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("begehung") self.model.setFilter("fundortnummer='{0}' AND begehung='{1}'".format( self.siteNumber, self.shardingNumber)) res = self.model.select() self.setupMapper() self.mapper.toFirst() self.setKgNameAndCode() self.initalLoad = False def setKgNameAndCode(self): query = QSqlQuery(self.dbm.db) qryStr = u"select CASE WHEN katastralgemeinde IS NULL AND katastralgemeindenummer IS NULL THEN '--' ELSE katastralgemeindenummer || ' - ' || katastralgemeinde END AS kg FROM fundort WHERE fundortnummer = '{0}'".format( self.siteNumber) query.exec_(qryStr) query.first() self.uiCadastralCommunityEdit.setText(query.value(0)) def setupMapper(self): self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setItemDelegate(ShardingDelegate()) self.mapper.setModel(self.model) self.mandatoryEditors = [self.uiShardingDate] # LineEdits & PlainTextEdits self.intValidator = QIntValidator() self.doubleValidator = QDoubleValidator() self.lineEditMaps = { "fundortnummer": { "editor": self.uiSiteNumberEdit }, "begehung": { "editor": self.uiShardingNumberEdit }, "name": { "editor": self.uiNameEdit }, "parzelle": { "editor": self.uiPlotPTxt }, "sichtbarkeit": { "editor": self.uiVisibilityEdit }, "verbleib": { "editor": self.uiWhereaboutsEdit }, "funde": { "editor": self.uiFindsPTxt }, "morphologie": { "editor": self.uiMorphologyPTxt }, "sonstiges": { "editor": self.uiMiscellaneousPTxt } } for key, item in self.lineEditMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) if "validator" in item: item["editor"].setValidator(item["validator"]) #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"])) item["editor"].textChanged.connect(self.onLineEditChanged) # Date and Times self.mapper.addMapping(self.uiShardingDate, self.model.fieldIndex("datum")) # ComboBox without Model self.mapper.addMapping(self.uiShardingTypeCombo, self.model.fieldIndex("begehtyp")) self.uiShardingTypeCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiShardingTypeCombo.setAutoCompletion(True) self.uiShardingTypeCombo.lineEdit().setValidator( InListValidator([ self.uiShardingTypeCombo.itemText(i) for i in range(self.uiShardingTypeCombo.count()) ], self.uiShardingTypeCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionPlantCoverCombo, self.model.fieldIndex("zustand_bewuchs")) self.uiConditionPlantCoverCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionPlantCoverCombo.setAutoCompletion(True) self.uiConditionPlantCoverCombo.lineEdit().setValidator( InListValidator([ self.uiConditionPlantCoverCombo.itemText(i) for i in range(self.uiConditionPlantCoverCombo.count()) ], self.uiConditionPlantCoverCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionLightCombo, self.model.fieldIndex("zustand_licht")) self.uiConditionLightCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionLightCombo.setAutoCompletion(True) self.uiConditionLightCombo.lineEdit().setValidator( InListValidator([ self.uiConditionLightCombo.itemText(i) for i in range(self.uiConditionLightCombo.count()) ], self.uiConditionLightCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionSoilCombo, self.model.fieldIndex("zustand_boden")) self.uiConditionSoilCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionSoilCombo.setAutoCompletion(True) self.uiConditionSoilCombo.lineEdit().setValidator( InListValidator([ self.uiConditionSoilCombo.itemText(i) for i in range(self.uiConditionSoilCombo.count()) ], self.uiConditionSoilCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionMoistureCombo, self.model.fieldIndex("zustand_feuchtigkeit")) self.uiConditionMoistureCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionMoistureCombo.setAutoCompletion(True) self.uiConditionMoistureCombo.lineEdit().setValidator( InListValidator([ self.uiConditionMoistureCombo.itemText(i) for i in range(self.uiConditionMoistureCombo.count()) ], self.uiConditionMoistureCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionRainCombo, self.model.fieldIndex("zustand_abgeregnet")) self.uiConditionRainCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionRainCombo.setAutoCompletion(True) self.uiConditionRainCombo.lineEdit().setValidator( InListValidator([ self.uiConditionRainCombo.itemText(i) for i in range(self.uiConditionRainCombo.count()) ], self.uiConditionRainCombo.lineEdit(), None, self)) def onLineEditChanged(self): sender = self.sender() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: sender.setStyleSheet( "{0} {{background-color: rgb(153, 204, 255);}}".format( sender.metaObject().className())) self.editorsEdited.append(sender) def onAccept(self): ''' Check DB Save options when pressing OK button Update Plugin Status ''' # Save Settings SetWindowSize("sharding", self.size()) self.accept() def onReject(self): ''' Run some actions when the user closes the dialog ''' if self.editMode: res = self.cancelEdit() if res: SetWindowSize("sharding", self.size()) self.close() else: self.show() else: SetWindowSize("sharding", self.size()) self.close() def addNewSharding(self, siteNumber): self.initalLoad = True self.siteNumber = siteNumber # get new sharding number query = QSqlQuery(self.dbm.db) qryStr = "SELECT CASE WHEN max(begehung) IS NULL THEN 1 ELSE max(begehung)+1 END begehungNeu FROM begehung WHERE fundortnummer='{0}'".format( self.siteNumber) query.exec_(qryStr) query.first() self.shardingNumber = query.value(0) self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("begehung") self.model.setFilter("fundortnummer='{0}'".format(self.siteNumber)) res = self.model.select() #self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() row = self.model.rowCount() #QMessageBox.information(None, "begehung", "{0}".format(row)) self.model.insertRow(row) #QMessageBox.information(None, "begehung", "{0}".format(self.model.rowCount())) self.setupMapper() self.mapper.toLast() self.addMode = True self.startEditMode() # self.mapper.submit() # self.model.insertRow(row) # self.mapper.setCurrentIndex(row) self.uiSiteNumberEdit.setText(self.siteNumber) self.uiShardingNumberEdit.setText(str(self.shardingNumber)) now = QDate.currentDate() self.uiShardingDate.setDate(now) self.setKgNameAndCode() #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber,nn))) self.initalLoad = False def removeNewSharding(self): self.initalLoad = True row = self.mapper.currentIndex() self.model.removeRow(row + 1) self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.toLast() self.initalLoad = False def saveEdits(self): #Check Mandatory fields flag = False for mEditor in self.mandatoryEditors: cName = mEditor.metaObject().className() if cName == 'QDateEdit': value = mEditor.date().toString("yyyy-MM-dd") elif cName == 'QLineEdit': value = mEditor.text() elif cName == 'QComboBox': if mEditor.isEditable(): value = mEditor.lineEdit().text() else: if mEditor.currentIndex == -1: value = '' else: value = '1' if value.strip() == "": flag = True mEditor.setStyleSheet( "{0} {{background-color: rgb(240, 160, 160);}}".format( cName)) if mEditor not in self.editorsEdited: self.editorsEdited.append(mEditor) else: if mEditor in self.editorsEdited: mEditor.setStyleSheet( "{0} {{background-color: rgb(153, 204, 255);}}".format( cName)) #else: #mEditor.setStyleSheet("") if flag: QMessageBox.warning( self, self.tr(u"Benötigte Felder Ausfüllen"), self. tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind." )) return False #saveToModel currIdx = self.mapper.currentIndex() #QMessageBox.information(None, "begehung", "{0}".format(currIdx)) #now = QDate.currentDate() #self.uiLastChangesDate.setDate(now) self.mapper.submit() self.mapper.setCurrentIndex(currIdx) # emit signal self.shardingEditsSaved.emit(True) self.endEditMode() return True def cancelEdit(self): currIdx = self.mapper.currentIndex() if self.editMode: result = QMessageBox.question( self, self.tr(u"Änderungen wurden vorgenommen!"), self.tr(u"Möchten Sie die Änerungen speichern?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) #save or not save if result == QMessageBox.Yes: res = self.saveEdits() if res: return True else: return False elif result == QMessageBox.No: if self.addMode: #self.close() self.done(1) self.removeNewSharding() self.endEditMode() return True else: self.mapper.setCurrentIndex(currIdx) self.endEditMode() return True def startEditMode(self): self.editMode = True self.uiOkBtn.setEnabled(False) self.uiSaveBtn.setEnabled(True) self.uiCancelBtn.setEnabled(True) self.editorsEdited = [] self.uiShardingDate.setReadOnly(not self.addMode) if self.uiShardingDate.isReadOnly(): self.uiShardingDate.setStyleSheet( "background-color: rgb(218, 218, 218);") else: self.uiShardingDate.setStyleSheet("") def endEditMode(self): self.editMode = False self.addMode = False self.uiOkBtn.setEnabled(True) self.uiSaveBtn.setEnabled(False) self.uiCancelBtn.setEnabled(False) self.uiShardingDate.setReadOnly(not self.addMode) self.uiShardingDate.setStyleSheet( "background-color: rgb(218, 218, 218);") for editor in self.editorsEdited: cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): editor.setStyleSheet( "{0} {{background-color: rgb(218, 218, 218);}}".format( cName)) else: editor.setStyleSheet("") self.editorsEdited = [] def viewPictures(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_foto_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType self.loadInImageViewer(path) def openPictures(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_foto_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType if not OpenFileOrFolder(path): QMessageBox.information( self, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path)) def viewSketches(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_sketch_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType self.loadInImageViewer(path) def openSketches(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_sketch_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType if not OpenFileOrFolder(path): QMessageBox.information( None, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path)) def getFolderNameSite(self, siteNumber): query = QSqlQuery(self.dbm.db) #qryStr = u"SELECT trim(katastralgemeinde) || ' ' || trim(katastralgemeindenummer) || '.' || substr('000' || fundortnummer_nn_legacy, -3, 3) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'".format(siteNumber) query.prepare( u"SELECT land || '\\' || CASE WHEN land = 'AUT' THEN replace(replace(replace(replace(lower(trim(katastralgemeinde)), '.',''), '-', ' '), '(', ''), ')', '') || ' ' ELSE '' END || substr('000000' || fundortnummer_nn, -6, 6) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'" .format(siteNumber)) query.exec_() query.first() return query.value(0) def loadInImageViewer(self, path): dir = QDir(path) if dir.exists(): entryList = dir.entryList(['*.jpg'], QDir.Files) if len(entryList) > 0: # load in thumb viewer # QMessageBox.information(None, u"Begehung", u",".join(entryList)) imagePathList = [] for image in entryList: imagePathList.append(path + u'\\' + image) widget = APISThumbViewer() widget.load(imagePathList) widget.show() if widget.exec_(): pass # app.exec_() else: QMessageBox.information( self, u"Begehung", u"Es wurden keine Dateien [*.jpg] für diesen Fundort gefunden." ) else: QMessageBox.information( self, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path))
class DeviceEditDialog(QDialog): def __init__(self, model, row, *args, **kwargs): super(DeviceEditDialog, self).__init__(*args, **kwargs) self.setMinimumWidth(400) self.setWindowTitle("Edit device") self.settings = QSettings() self.settings.beginGroup("Devices") self.mapper = QDataWidgetMapper() self.mapper.setModel(model) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) vl = VLayout() gbTopic = QGroupBox("MQTT Topic") self.topic = QLineEdit() self.topic.setPlaceholderText("unique name of your device") self.mapper.addMapping(self.topic, DevMdl.TOPIC) self.full_topic = QLineEdit() self.full_topic.setPlaceholderText("must contain %prefix% and %topic%") self.mapper.addMapping(self.full_topic, DevMdl.FULL_TOPIC) tfl = QFormLayout() tfl.addRow("Topic", self.topic) tfl.addRow("Full topic", self.full_topic) gbTopic.setLayout(tfl) btnSave = QPushButton("Save") btnCancel = QPushButton("Cancel") hl_btns = HLayout() hl_btns.addStretch(1) hl_btns.addWidgets([btnSave, btnCancel]) vl.addWidgets([gbTopic]) vl.addLayout(hl_btns) self.setLayout(vl) self.mapper.setCurrentIndex(row) btnSave.clicked.connect(self.accept) btnCancel.clicked.connect(self.reject) def accept(self): full_topic = self.full_topic.text() if not full_topic.endswith('/'): self.full_topic.setText(full_topic + "/") if not len(self.topic.text()) > 0: QMessageBox.critical(self, "Error", "Topic is required.") elif not "%topic%" in full_topic: QMessageBox.critical(self, "Error", "%topic% is required in FullTopic.") elif not "%prefix%" in full_topic: QMessageBox.critical(self, "Error", "%prefix% is required in FullTopic.") elif self.topic.text() not in self.settings.childGroups(): self.mapper.submit() self.done(QDialog.Accepted) else: QMessageBox.critical(self, "Error", "Device '{}' already on the device list.".format(self.topic.text())) def reject(self): self.mapper.revert() self.done(QDialog.Rejected)
class EmployeeEditView(QWidget, Ui_FormEditDeleteEmployee): def __init__(self, employee_model, employee_controller, main_window): super().__init__() self.setupUi(self) self.employee_model: EmployeeModel = employee_model self.employee_controller: EmployeeController = employee_controller self.main_window: MainWindowView = main_window self.mapper = QDataWidgetMapper() self.set_employee_editor() def show_editor(self, s=None): # load role combobox self.load_employee_positions_combobox() # Set the selected employee to the editor i = self.is_selected() if i & i >= 0: self.mapper.setCurrentIndex(i) self.show() def clear_fields(self): self.lineEditEmployeeID.clear() self.dteEditEmployeeDate.clear() self.spinEditEmployeeSalary.clear() self.cmbEditEmployeeRole.clear() self.load_employee_positions_combobox() def load_employee_positions_combobox(self): positions = self.employee_model.get_employee_positions() self.cmbEditEmployeePosition.addItem("") self.cmbEditEmployeePosition.addItems(positions) def is_selected(self, s=None) -> int: # print(self.selection_model.hasSelection()) # print(self.selection_model.isRowSelected(0)) index = self.main_window.tblEmployees.selectionModel().currentIndex().row() return index def set_employee_editor(self, index=0): self.btnEditEmployeePrevious.clicked.connect(self.mapper.toPrevious) self.btnEditEmployeeNext.clicked.connect(self.mapper.toNext) self.btnEditEmployeeSave.clicked.connect(self.update_button_action) self.btnEditEmployeeDelete.clicked.connect(self.delete_button_action) self.mapper.setModel(self.main_window.employee_sql_query_model) self.mapper.addMapping(self.lineEditEmployeeID, 0) self.mapper.addMapping(self.lineEditEmployeeName, 1) self.mapper.addMapping(self.cmbEditEmployeePosition, 2) self.mapper.addMapping(self.spinEditEmployeeSalary, 3) self.mapper.addMapping(self.dteEditEmployeeDate, 4) # self.set_student_table(self.model) # if index > 0: # self.mapper.setCurrentIndex(index) self.mapper.toFirst() def update_button_action(self, saved): employee_id: int = int(self.lineEditEmployeeID.text()) employee_name: str = self.lineEditEmployeeName.text() employee_role: str = self.cmbEditEmployeePosition.currentText() employee_salary: float = float(self.spinEditEmployeeSalary.cleanText()) employee_date: str = self.dteEditEmployeeDate.text() employee: Employee = Employee(employee_name, employee_role, employee_salary, employee_date) self.employee_controller.update_employee(employee, employee_id) def delete_button_action(self): dialog_alert_view: DialogAlertView = DialogAlertView() employee_id = int(self.lineEditEmployeeID.text()) dialog_alert_view.show_dialog(True, 4) self.employee_controller.delete_employee(employee_id)
class CraftingRequirementsEditor(QWidget): def __init__(self, parent=None): super().__init__(parent=parent) layout = QGridLayout(self) self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) self.model = None self.equip_type = None self._map_equip_id_to_index = {} self.item_model = StructTableModel(EqCrtEntry.fields(), self) self.item_mapper = QDataWidgetMapper(self) self.item_mapper.setItemDelegate(ItemDelegate()) self.item_mapper.setModel(self.item_model) self.t9n_item_model = ItmTranslationModel(self) self.add_row(0, "Item", "Quantity") self.add_row_edit(1, EqCrtEntry.item1_id.index, EqCrtEntry.item1_qty.index) self.add_row_edit(2, EqCrtEntry.item2_id.index, EqCrtEntry.item2_qty.index) self.add_row_edit(3, EqCrtEntry.item3_id.index, EqCrtEntry.item3_qty.index) self.add_row_edit(4, EqCrtEntry.item4_id.index, EqCrtEntry.item4_qty.index) self.layout().setRowStretch(4, 1) def set_current(self, equip_id): if equip_id in self._map_equip_id_to_index: self.setDisabled(False) index = self._map_equip_id_to_index[equip_id] self.item_mapper.setCurrentIndex(index) else: self.setDisabled(True) def add_row(self, row, value1, value2): self.layout().addWidget(QLabel(value1), row, 0, Qt.AlignTop) self.layout().addWidget(QLabel(value2), row, 1, Qt.AlignTop) def add_row_edit(self, row, mapping1, mapping2): id_editor = QComboBox(self) id_editor.setModel(self.t9n_item_model) id_editor.setEditable(True) qty_editor = QSpinBox(self) qty_editor.setMinimum(0) qty_editor.setMaximum(0xff) self.item_mapper.addMapping(id_editor, mapping1) self.item_mapper.addMapping(qty_editor, mapping2) self.layout().addWidget(id_editor, row, 0, Qt.AlignTop) self.layout().addWidget(qty_editor, row, 1, Qt.AlignTop) def set_model(self, model, equip_type): self.model = model self.equip_type = equip_type if model is None: return crafting_model = model.get_relation_data("crafting") t9n_item_model = model.get_relation_data("t9n_item") if crafting_model: self.item_model.update(crafting_model.entries) self._map_equip_id_to_index = { entry.equip_id: index for index, entry in enumerate(crafting_model.entries) if not equip_type or equip_type == entry.equip_type } if t9n_item_model: self.t9n_item_model.update(t9n_item_model)
class TaskView(QWidget): close = pyqtSignal() def __init__(self, model): super().__init__() self.header = QLabel('') self.desc = QLineEdit() self.date = QDateEdit() self.time = QTimeEdit() self.init_ui() self.mapper = QDataWidgetMapper() self.mapper.setModel(model) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.addMapping(self.desc, TaskModel.col_desc) self.mapper.addMapping(self.date, TaskModel.col_date) self.mapper.addMapping(self.time, TaskModel.col_time) def set_task(self, index): self.mapper.setCurrentIndex(index) self.header.setText('РЕДАКТИРОВАНИЕ ЗАДАЧИ') # text = 'НОВАЯ ЗАДАЧА' # self.date.setDate(QDate().currentDate()) def create_date(self): self.date.setDisplayFormat('dd.MM.yyyy') self.date.setCalendarPopup(True) self.date.setFixedWidth(120) return self.date def create_time(self): self.time.setDisplayFormat('hh.mm') self.time.setFixedWidth(120) return self.time def create_date_buttons(self): date_lt = QHBoxLayout() btn_now = QPushButton('сегодня') btn_now.clicked.connect(lambda: self.date.setDate(QDate().currentDate())) date_lt.addWidget(btn_now, 0, Qt.AlignCenter) btn_tomorrow = QPushButton('завтра') btn_tomorrow.clicked.connect(lambda: self.date.setDate(QDate().currentDate().addDays(1))) date_lt.addWidget(btn_tomorrow, 0, Qt.AlignCenter) btn_week_later = QPushButton('через неделю') btn_week_later.clicked.connect(lambda: self.date.setDate(QDate().currentDate().addDays(7))) date_lt.addWidget(btn_week_later, 0, Qt.AlignCenter) return date_lt # def create_time_choice(self): # self.time.setMaxVisibleItems(15) # self.time.setStyleSheet('QComboBox { combobox-popup: 0; }') # for it in range(24): # self.time.insertItem(it * 2 + 0, '%.2d:00' % it) # self.time.insertItem(it * 2 + 1, '%.2d:30' % it) # # return self.time def save(self): print('save', self.mapper.submit()) self.close.emit() def cancel(self): self.close.emit() def remove(self): self.mapper.model().removeRow(self.mapper.currentIndex()) self.close.emit() def create_control_buttons(self): control_lt = QHBoxLayout() btn_save = QPushButton('Сохранить') btn_save.clicked.connect(self.save) control_lt.addWidget(btn_save, 0, Qt.AlignCenter) btn_cancel = QPushButton('Отменить') btn_cancel.clicked.connect(self.cancel) control_lt.addWidget(btn_cancel, 0, Qt.AlignCenter) btn_remove = QPushButton('Удалить') btn_remove.clicked.connect(self.remove) control_lt.addWidget(btn_remove, 1, Qt.AlignRight) return control_lt def create_main_form(self): fm = QFormLayout() fm.addRow(self.header) fm.addRow(QLabel('')) fm.addRow(self.desc) fm.addRow(QLabel('')) fm.addRow(QLabel('Когда это нужно сделать?')) fm.addRow(self.create_date()) fm.addRow(self.create_date_buttons()) fm.addRow(QLabel('')) fm.addRow(QLabel('Во сколько?')) fm.addRow(self.create_time()) return fm def init_ui(self): layout = QVBoxLayout() layout.addLayout(self.create_main_form()) layout.addStretch() layout.addLayout(self.create_control_buttons()) self.setLayout(layout)
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setCentralWidget(self.ui.splitter) ## tableView显示属性设置 self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems) self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.verticalHeader().setDefaultSectionSize(22) self.ui.tableView.horizontalHeader().setDefaultSectionSize(60) ## ==============自定义功能函数============ def __getFieldNames(self): ##获取所有字段名称 emptyRec = self.tabModel.record() #获取空记录,只有字段名 self.fldNum = {} #字段名与序号的字典 for i in range(emptyRec.count()): fieldName = emptyRec.fieldName(i) self.ui.comboFields.addItem(fieldName) self.fldNum.setdefault(fieldName) self.fldNum[fieldName] = i print(self.fldNum) def __openTable(self): ##打开数据表 self.tabModel = QSqlTableModel(self, self.DB) #数据模型 self.tabModel.setTable("employee") #设置数据表 self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit ) #数据保存方式,OnManualSubmit , OnRowChange self.tabModel.setSort(self.tabModel.fieldIndex("empNo"), Qt.AscendingOrder) #排序 if (self.tabModel.select() == False): #查询数据失败 QMessageBox.critical( self, "错误信息", "打开数据表错误,错误信息\n" + self.tabModel.lastError().text()) return self.__getFieldNames() #获取字段名和序号 ##字段显示名 self.tabModel.setHeaderData(self.fldNum["empNo"], Qt.Horizontal, "工号") self.tabModel.setHeaderData(self.fldNum["Name"], Qt.Horizontal, "姓名") self.tabModel.setHeaderData(self.fldNum["Gender"], Qt.Horizontal, "性别") self.tabModel.setHeaderData(self.fldNum["Birthday"], Qt.Horizontal, "出生日期") self.tabModel.setHeaderData(self.fldNum["Province"], Qt.Horizontal, "省份") self.tabModel.setHeaderData(self.fldNum["Department"], Qt.Horizontal, "部门") self.tabModel.setHeaderData(self.fldNum["Salary"], Qt.Horizontal, "工资") self.tabModel.setHeaderData(self.fldNum["Memo"], Qt.Horizontal, "备注") #这两个字段不在tableView中显示 self.tabModel.setHeaderData(self.fldNum["Photo"], Qt.Horizontal, "照片") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("empNo"), Qt.Horizontal, "工号") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Name"), Qt.Horizontal, "姓名") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Gender"), Qt.Horizontal, "性别") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Birthday"), Qt.Horizontal, "出生日期") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Province"), Qt.Horizontal, "省份") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Department"),Qt.Horizontal, "部门") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Salary"), Qt.Horizontal, "工资") ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Memo"), Qt.Horizontal, "备注") #这两个字段不在tableView中显示 ## self.tabModel.setHeaderData(self.tabModel.fieldIndex("Photo"), Qt.Horizontal, "照片") ##创建界面组件与数据模型的字段之间的数据映射 self.mapper = QDataWidgetMapper() self.mapper.setModel(self.tabModel) #设置数据模型 self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) ##界面组件与tabModel的具体字段之间的联系 self.mapper.addMapping(self.ui.dbSpinEmpNo, self.fldNum["empNo"]) self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"]) self.mapper.addMapping(self.ui.dbComboSex, self.fldNum["Gender"]) self.mapper.addMapping(self.ui.dbEditBirth, self.fldNum["Birthday"]) self.mapper.addMapping(self.ui.dbComboProvince, self.fldNum["Province"]) self.mapper.addMapping(self.ui.dbComboDep, self.fldNum["Department"]) self.mapper.addMapping(self.ui.dbSpinSalary, self.fldNum["Salary"]) self.mapper.addMapping(self.ui.dbEditMemo, self.fldNum["Memo"]) self.mapper.toFirst() #移动到首记录 self.selModel = QItemSelectionModel(self.tabModel) #选择模型 self.selModel.currentChanged.connect(self.do_currentChanged) #当前项变化时触发 self.selModel.currentRowChanged.connect( self.do_currentRowChanged) #选择行变化时 self.ui.tableView.setModel(self.tabModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selModel) #设置选择模型 self.ui.tableView.setColumnHidden(self.fldNum["Memo"], True) #隐藏列 self.ui.tableView.setColumnHidden(self.fldNum["Photo"], True) #隐藏列 ##tableView上为“性别”和“部门”两个字段设置自定义代理组件 strList = ("男", "女") self.__delegateSex = QmyComboBoxDelegate() self.__delegateSex.setItems(strList, False) self.ui.tableView.setItemDelegateForColumn( self.fldNum["Gender"], self.__delegateSex) #Combbox选择型 strList = ("销售部", "技术部", "生产部", "行政部") self.__delegateDepart = QmyComboBoxDelegate() self.__delegateDepart.setItems(strList, True) self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"], self.__delegateDepart) ##更新actions和界面组件的使能状态 self.ui.actOpenDB.setEnabled(False) self.ui.actRecAppend.setEnabled(True) self.ui.actRecInsert.setEnabled(True) self.ui.actRecDelete.setEnabled(True) self.ui.actScan.setEnabled(True) self.ui.groupBoxSort.setEnabled(True) self.ui.groupBoxFilter.setEnabled(True) ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##选择数据库,打开数据表 def on_actOpenDB_triggered(self): dbFilename, flt = QFileDialog.getOpenFileName( self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)") if (dbFilename == ''): return #打开数据库 self.DB = QSqlDatabase.addDatabase("QSQLITE") #添加 SQLITE数据库驱动 self.DB.setDatabaseName(dbFilename) #设置数据库名称 ## DB.setHostName() ## DB.setUserName() ## DB.setPassword() if self.DB.open(): #打开数据库 self.__openTable() #打开数据表 else: QMessageBox.warning(self, "错误", "打开数据库失败") @pyqtSlot() ##保存修改 def on_actSubmit_triggered(self): res = self.tabModel.submitAll() if (res == False): QMessageBox.information( self, "消息", "数据保存错误,错误信息\n" + self.tabModel.lastError().text()) else: self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() ##取消修改 def on_actRevert_triggered(self): self.tabModel.revertAll() self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() ##添加记录 def on_actRecAppend_triggered(self): self.tabModel.insertRow(self.tabModel.rowCount(), QModelIndex()) #在末尾添加一个记录 curIndex = self.tabModel.index(self.tabModel.rowCount() - 1, 1) #创建最后一行的ModelIndex self.selModel.clearSelection() #清空选择项 self.selModel.setCurrentIndex( curIndex, QItemSelectionModel.Select) #设置刚插入的行为当前选择行 currow = curIndex.row() #获得当前行 self.tabModel.setData(self.tabModel.index(currow, self.fldNum["empNo"]), 2000 + self.tabModel.rowCount()) #自动生成编号 self.tabModel.setData( self.tabModel.index(currow, self.fldNum["Gender"]), "男") @pyqtSlot() ##插入记录 def on_actRecInsert_triggered(self): curIndex = self.ui.tableView.currentIndex() #QModelIndex self.tabModel.insertRow(curIndex.row(), QModelIndex()) self.selModel.clearSelection() #清除已有选择 self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() ##删除记录 def on_actRecDelete_triggered(self): curIndex = self.selModel.currentIndex() #获取当前选择单元格的模型索引 self.tabModel.removeRow(curIndex.row()) #删除当前行 @pyqtSlot() ##清除照片 def on_actPhotoClear_triggered(self): curRecNo = self.selModel.currentIndex().row() curRec = self.tabModel.record(curRecNo) #获取当前记录,QSqlRecord curRec.setNull("Photo") #设置为空值 self.tabModel.setRecord(curRecNo, curRec) self.ui.dbLabPhoto.clear() #清除界面上的图片显示 @pyqtSlot() ##设置照片 def on_actPhoto_triggered(self): fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "", "照片(*.jpg)") if (fileName == ''): return file = QFile(fileName) #fileName为图片文件名 file.open(QIODevice.ReadOnly) try: data = file.readAll() #QByteArray finally: file.close() curRecNo = self.selModel.currentIndex().row() curRec = self.tabModel.record(curRecNo) #获取当前记录QSqlRecord curRec.setValue("Photo", data) #设置字段数据 self.tabModel.setRecord(curRecNo, curRec) pic = QPixmap() pic.loadFromData(data) W = self.ui.dbLabPhoto.width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W)) #在界面上显示 @pyqtSlot() ##涨工资,遍历数据表所有记录 def on_actScan_triggered(self): if (self.tabModel.rowCount() == 0): return for i in range(self.tabModel.rowCount()): aRec = self.tabModel.record(i) #获取当前记录 ## salary=aRec.value("Salary").toFloat() #错误,无需再使用toFloat()函数 salary = aRec.value("Salary") salary = salary * 1.1 aRec.setValue("Salary", salary) self.tabModel.setRecord(i, aRec) if (self.tabModel.submitAll()): QMessageBox.information(self, "消息", "涨工资计算完毕") @pyqtSlot(int) ##排序字段变化 def on_comboFields_currentIndexChanged(self, index): if self.ui.radioBtnAscend.isChecked(): self.tabModel.setSort(index, Qt.AscendingOrder) else: self.tabModel.setSort(index, Qt.DescendingOrder) self.tabModel.select() @pyqtSlot() ##升序 def on_radioBtnAscend_clicked(self): self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.AscendingOrder) self.tabModel.select() @pyqtSlot() ##降序 def on_radioBtnDescend_clicked(self): self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.DescendingOrder) self.tabModel.select() @pyqtSlot() ##过滤,男 def on_radioBtnMan_clicked(self): self.tabModel.setFilter("Gender='男'") ## print(self.tabModel.filter()) ## self.tabModel.select() @pyqtSlot() ##数据过滤,女 def on_radioBtnWoman_clicked(self): self.tabModel.setFilter("Gender='女' ") ## print(self.tabModel.filter()) ## self.tabModel.select() @pyqtSlot() ##取消数据过滤 def on_radioBtnBoth_clicked(self): self.tabModel.setFilter("") ## print(self.tabModel.filter()) ## self.tabModel.select() ## =============自定义槽函数=============================== def do_currentChanged(self, current, previous): ##更新actPost和actCancel 的状态 self.ui.actSubmit.setEnabled(self.tabModel.isDirty()) #有未保存修改时可用 self.ui.actRevert.setEnabled(self.tabModel.isDirty()) def do_currentRowChanged(self, current, previous): #行切换时的状态控制 self.ui.actRecDelete.setEnabled(current.isValid()) self.ui.actPhoto.setEnabled(current.isValid()) self.ui.actPhotoClear.setEnabled(current.isValid()) if (current.isValid() == False): self.ui.dbLabPhoto.clear() #清除图片显示 return self.mapper.setCurrentIndex(current.row()) #更新数据映射的行号 curRec = self.tabModel.record(current.row()) #获取当前记录,QSqlRecord类型 if (curRec.isNull("Photo")): #图片字段内容为空 self.ui.dbLabPhoto.clear() else: ## data=bytearray(curRec.value("Photo")) #可以工作 data = curRec.value("Photo") # 也可以工作 pic = QPixmap() pic.loadFromData(data) W = self.ui.dbLabPhoto.size().width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W))
class APISFilm(QDialog, FORM_CLASS): FIRST, PREV, NEXT, LAST = range(4) OBLIQUE, VERTICAL = range(2) def __init__(self, iface, dbm, imageRegistry, apisLayer, parent=None): """Constructor.""" super(APISFilm, self).__init__(parent) self.iface = iface self.dbm = dbm self.imageRegistry = imageRegistry self.apisLayer = apisLayer self.parent = parent self.setupUi(self) # Initial window size/pos last saved. Use default values for first time if GetWindowSize("film"): self.resize(GetWindowSize("film")) if GetWindowPos("film"): self.move(GetWindowPos("film")) self.printingOptionsDlg = None self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat) self.editMode = False self.addMode = False self.initalLoad = True #self.uiInitalEntryQgsDate.setCalendarPopup(False) #self.uiLastChangesQgsDate.setCalendarPopup(False) # Signals/Slot Connections self.rejected.connect(self.onReject) self.uiOkBtn.clicked.connect(self.onAccept) self.uiCancelBtn.clicked.connect(self.cancelEdit) self.uiSaveBtn.clicked.connect(self.saveEdits) self.uiFilmSelectionBtn.clicked.connect(self.openFilmSelectionDialog) self.uiNewFilmBtn.clicked.connect(self.openNewFilmDialog) self.uiSearchFilmBtn.clicked.connect(self.openSearchFilmDialog) self.uiEditWeatherBtn.clicked.connect(self.openEditWeatherDialog) self.uiExportPdfBtn.clicked.connect(self.exportDetailsPdf) self.uiShowFlightPathBtn.clicked.connect(lambda: self.openFlightPathDialog([self.uiCurrentFilmNumberEdit.text()])) # For LaLe Mode if self.settings.value("APIS/disable_site_and_findspot", "0") != "1": self.uiListSitesOfFilmBtn.setEnabled(True) self.uiListSitesOfFilmBtn.clicked.connect(self.openSiteSelectionListDialog) else: self.uiListSitesOfFilmBtn.setEnabled(False) self.uiListImagesOfFilmBtn.clicked.connect(self.openImageSelectionListDialog) self.uiExtractGpsFromImagesBtn.clicked.connect(self.extractGpsFromImages) self.uiWeatherCodeEdit.textChanged.connect(self.generateWeatherCode) self.uiFilmModeCombo.currentIndexChanged.connect(self.onFilmModeChanged) self.uiEditProjectTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("projekt", self.uiProjectSelectionCombo)) self.uiEditCopyrightTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("copyright", self.uiCopyrightCombo)) # self.uiEditProjectTableBtn.clicked.connect(lambda: VersionToCome()) # self.uiEditCopyrightTableBtn.clicked.connect(lambda: VersionToCome()) # init Project Btn self.uiAddProjectBtn.clicked.connect(self.addProject) self.uiRemoveProjectBtn.clicked.connect(self.removeProject) # Setup Sub-Dialogs self.filmSelectionDlg = APISFilmNumberSelection(self) self.newFilmDlg = APISFilmNew(parent=self) self.searchFilmDlg = APISFilmSearch(self.dbm, self) # (self.iface, self.dbm) self.editWeatherDlg = APISWeather(self.iface, self.dbm, self) self.flightPathDlg = APISFlightPath(self.iface, self.dbm, self.apisLayer, self) self.siteSelectionListDlg = APISSiteSelectionList(self.iface, self.dbm, self.imageRegistry, self.apisLayer, self) self.imageSelectionListDlg = APISImageSelectionList(self.iface, self.dbm, self.imageRegistry, self.apisLayer, parent=self) self.systemTableEditorDlg = None # Setup film model self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("film") self.model.select() while (self.model.canFetchMore()): self.model.fetchMore() self.setupMapper() self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None) self.setupComboBox(self.newFilmDlg.uiProducerCombo, "hersteller", 2, None) self.setupNavigation() self.mapper.toFirst() self.initalLoad = False def setupMapper(self): self.mapper = QDataWidgetMapper(self) self.mapper.currentIndexChanged.connect(self.onCurrentIndexChanged) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setItemDelegate(FilmDelegate()) self.mapper.setModel(self.model) self.mandatoryEditors = [self.uiImageCountEdit, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiFilmModeCombo] self.disableEditorsIfOblique = [self.uiCameraNumberEdit, self.uiCalibratedFocalLengthEdit] # LineEdits & PlainTextEdits self.intValidator = QIntValidator() self.doubleValidator = QDoubleValidator() self.lineEditMaps = { "filmnummer": { "editor": self.uiCurrentFilmNumberEdit }, "hersteller": { "editor": self.uiProducerEdit }, "anzahl_bilder": { "editor": self.uiImageCountEdit, "validator": self.intValidator }, "militaernummer": { "editor": self.uiMilitaryNumberEdit }, "militaernummer_alt": { "editor": self.uiOldMilitaryNumberEdit }, "form1": { "editor": self.uiFormat1Edit }, "form2": { "editor": self.uiFormat2Edit }, "kalibrierungsnummer": { "editor": self.uiCameraNumberEdit }, "kammerkonstante": { "editor": self.uiCalibratedFocalLengthEdit, "validator": self.doubleValidator }, "kassettennummer": { "editor": self.uiCassetteEdit }, "art_ausarbeitung": { "editor": self.uiFilmMakeEdit }, "fotograf": { "editor": self.uiPhotographerEdit }, "pilot": { "editor": self.uiPilotEdit }, "flugzeug": { "editor": self.uiAirplaneEdit }, "abflug_flughafen": { "editor": self.uiDepartureAirportEdit }, "ankunft_flughafen": { "editor": self.uiArrivalAirportEdit }, "flugzeit": { "editor": self.uiFlightDurationEdit }, "wetter": { "editor": self.uiWeatherCodeEdit }, "kommentar": { "editor": self.uiCommentsPTxt } } for key, item in self.lineEditMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) if "validator" in item: item["editor"].setValidator(item["validator"]) #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"])) item["editor"].textChanged.connect(self.onLineEditChanged) #Text #self.mapper.addMapping(self.uiCommentsPTxt, self.model.fieldIndex("kommentar")) # Date and Times self.mapper.addMapping(self.uiFlightDate, self.model.fieldIndex("flugdatum")) #self.mapper.addMapping(self.uiFlightQgsDate, self.model.fieldIndex("flugdatum")) self.mapper.addMapping(self.uiInitalEntryDate, self.model.fieldIndex("datum_ersteintrag")) #self.mapper.addMapping(self.uiInitalEntryQgsDate, self.model.fieldIndex("datum_ersteintrag")) self.mapper.addMapping(self.uiLastChangesDate, self.model.fieldIndex("datum_aenderung")) #self.mapper.addMapping(self.uiLastChangesQgsDate, self.model.fieldIndex("datum_aenderung")) self.mapper.addMapping(self.uiDepartureTime, self.model.fieldIndex("abflug_zeit")) self.mapper.addMapping(self.uiArrivalTime, self.model.fieldIndex("ankunft_zeit")) self.uiDepartureTime.timeChanged.connect(self.onFlightTimeChanged) self.uiArrivalTime.timeChanged.connect(self.onFlightTimeChanged) # ComboBox without Model self.mapper.addMapping(self.uiFilmModeCombo, self.model.fieldIndex("weise")) self.uiFilmModeCombo.editTextChanged.connect(self.onLineEditChanged) completer = QCompleter(self.uiFilmModeCombo.model()) self.uiFilmModeCombo.setCompleter(completer) self.uiFilmModeCombo.lineEdit().setValidator(InListValidator([self.uiFilmModeCombo.itemText(i) for i in range(self.uiFilmModeCombo.count())], self.uiFilmModeCombo.lineEdit(), None, self)) # ComboBox with Model self.comboBoxMaps = { "archiv": { "editor": self.uiArchiveCombo, "table": "hersteller", "modelcolumn": 2, "depend": None }, "kamera": { "editor": self.uiCameraCombo, "table": "kamera", "modelcolumn": 0, "depend": [{"form1": self.uiFormat1Edit}, {"form2": self.uiFormat2Edit}] }, "filmfabrikat": { "editor": self.uiFilmMakeCombo, "table": "film_fabrikat", "modelcolumn": 0, "depend": [{"art": self.uiFilmMakeEdit}] }, "target": { "editor": self.uiTargetCombo, "table": "target", "modelcolumn": 0, "depend": None }, "copyright": { "editor": self.uiCopyrightCombo, "table": "copyright", "modelcolumn": 0, "depend": None } } for key, item in self.comboBoxMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) self.setupComboBox(item["editor"], item["table"], item["modelcolumn"], item["depend"]) item["editor"].editTextChanged.connect(self.onLineEditChanged) self.mapper.addMapping(self.uiProjectList, self.model.fieldIndex("projekt")) def fixComboBoxDropDownListSizeAdjustemnt(self, cb): scroll = 0 if cb.count() <= cb.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent) iconWidth = cb.iconSize().width() max = 0 for i in range(cb.count()): width = cb.view().fontMetrics().width(cb.itemText(i)) if max < width: max = width QMessageBox.information(self, "info", "scroll: {0}, max: {1}, icon: {2}".format(scroll, max, iconWidth)) #cb.view().setMinimumWidth(scroll + max) def setupComboBox(self, editor, table, modelColumn, depend): model = QSqlRelationalTableModel(self, self.dbm.db) model.setTable(table) model.removeColumn(0) model.select() tv = QTableView() editor.setView(tv) tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) tv.setSelectionMode(QAbstractItemView.SingleSelection) tv.setSelectionBehavior(QAbstractItemView.SelectRows) tv.setAutoScroll(False) editor.setModel(model) editor.setModelColumn(modelColumn) editor.setInsertPolicy(QComboBox.NoInsert) tv.resizeColumnsToContents() tv.resizeRowsToContents() tv.verticalHeader().setVisible(False) tv.horizontalHeader().setVisible(True) #tv.setMinimumWidth(tv.horizontalHeader().length()) tv.horizontalHeader().setStretchLastSection(True) #tv.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) tv.resizeColumnsToContents() scroll = 0 if editor.count() <= editor.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent) tv.setMinimumWidth(tv.horizontalHeader().length() + scroll) #self.fixComboBoxDropDownListSizeAdjustemnt(editor) #editor.resize(tv.horizontalHeader().sizeHint()) completer = QCompleter(editor.model()) editor.setCompleter(completer) #editor.setAutoCompletion(True) editor.lineEdit().setValidator(InListValidator([editor.itemText(i) for i in range(editor.count())], editor.lineEdit(), depend, self)) if depend: editor.currentIndexChanged.connect(partial(self.updateDepends, editor, depend)) def updateDepends(self, editor, depend): for dep in depend: for key, value in dep.items(): idx = editor.model().createIndex(editor.currentIndex(), editor.model().fieldIndex(key)) value.setText(str(editor.model().data(idx))) #QMessageBox.warning(None, "Test", str(idx)) def setupNavigation(self): self.uiFirstFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.FIRST)) self.uiPreviousFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.PREV)) self.uiNextFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.NEXT)) self.uiLastFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.LAST)) self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.intRecordValidator = QIntValidator(1, self.model.rowCount()) self.uiCurrentFilmCountEdit.setValidator(self.intRecordValidator) self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1)) self.uiCurrentFilmCountEdit.editingFinished.connect(lambda: self.loadRecordById(int(self.uiCurrentFilmCountEdit.text()) - 1)) # QMessageBox.warning(None, "Test", str(self.mapper.itemDelegate())) def enableItemsInLayout(self, layout, enable): for i in range(layout.count()): if layout.itemAt(i).widget(): layout.itemAt(i).widget().setEnabled(enable) def loadRecordByNavigation(self, mode): #self.mapper.submit() #self.submitChanges() self.initalLoad = True if mode == APISFilm.FIRST: self.mapper.toFirst() elif mode == APISFilm.PREV: self.mapper.toPrevious() elif mode == APISFilm.NEXT: self.mapper.toNext() elif mode == APISFilm.LAST: self.mapper.toLast() self.initalLoad = False def loadRecordById(self, id): #self.submitChanges self.initalLoad = True self.mapper.setCurrentIndex(id) self.initalLoad = False def loadRecordByKeyAttribute(self, attribute, value): #self.model.setFilter(attribute + " = '" + value + "'") #self.model.select() # self.mapper.toFirst() query = QSqlQuery(self.dbm.db) #qryStr = "select {0} from film where {0} = '{1}' limit 1".format(attribute, value) #qryStr = "SELECT rowid FROM film WHERE {0} = '{1}' limit 1".format(attribute, value) qryStr = "SELECT" \ " (SELECT COUNT(*)" \ " FROM film AS t2" \ " WHERE t2.rowid < t1.rowid" \ " ) + (" \ " SELECT COUNT(*)" \ " FROM film AS t3" \ " WHERE t3.rowid = t1.rowid AND t3.rowid < t1.rowid" \ " ) AS rowNum" \ " FROM film AS t1" \ " WHERE {0} = '{1}'" \ " ORDER BY t1.rowid ASC".format(attribute, value) query.exec_(qryStr) #QMessageBox.warning(None, "Test", str(query.size()) + ',' + str(query.numRowsAffected())) query.first() fn = query.value(0) if fn is not None: self.loadRecordById(fn) return True else: # Film does not exist QMessageBox.warning(None, "Film Nummer", str("Der Film mit der Nummer {0} existiert nicht!".format(value))) return False #self.model.setFilter('') #self.model.select() #while (self.model.canFetchMore()): #self.model.fetchMore() def submitChanges(self): self.mapper.submit() def onCurrentIndexChanged(self): self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1)) self.onFilmModeChanged() def onFlightTimeChanged(self): dTime = self.uiDepartureTime.time() aTime = self.uiArrivalTime.time() flightDuration = dTime.secsTo(aTime) self.uiFlightDurationEdit.setText(str(flightDuration / 60)) def disableIfOblique(self, isOblique): for editor in self.disableEditorsIfOblique: editor.setDisabled(isOblique) def onFilmModeChanged(self): if self.uiFilmModeCombo.currentText() == u'schräg': self.disableIfOblique(True) else: self.disableIfOblique(False) def onLineEditChanged(self): sender = self.sender() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: sender.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(sender.metaObject().className())) self.editorsEdited.append(sender) def onComboBoxChanged(self, editor): pass def addProject(self): editor = self.uiProjectList value = self.uiProjectSelectionCombo.currentText() notInList = True for row in range(editor.count()): if value == editor.item(row).data(0): notInList = False break if notInList: editor.addItem(value) editor.sortItems() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) def removeProject(self): editor = self.uiProjectList editor.takeItem(self.uiProjectList.currentRow()) if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) def onAccept(self): ''' Check DB Save options when pressing OK button Update Plugin Status ''' self.accept() def onReject(self): ''' Run some actions when the user closes the dialog ''' if self.editMode: res = self.cancelEdit() if res: self.close() else: self.show() else: self.close() def closeEvent(self, e): # Write window size and position to QSettings if self.editMode: self.onReject() else: SetWindowSizeAndPos("film", self.size(), self.pos()) e.accept() def extractGpsFromImages(self): key = self.uiCurrentFilmNumberEdit.text() e2p = Exif2Points(self.iface, key) layer = e2p.run() if layer: self.apisLayer.requestShapeFile(layer, groupName="Flugwege", addToCanvas=True) def exportDetailsPdf(self): if self.printingOptionsDlg is None: self.printingOptionsDlg = APISPrintingOptions(self) self.printingOptionsDlg.setWindowTitle("Druck Optionen: Film") self.printingOptionsDlg.configure(False, False, visPersonalDataChk=True) self.printingOptionsDlg.show() if self.printingOptionsDlg.exec_(): printPersonalData = self.printingOptionsDlg.printPersonalData() APISPrinterQueue([{'type': APISTemplatePrinter.FILM, 'idList': [self.uiCurrentFilmNumberEdit.text()], 'options': {'personalData': printPersonalData}}], OutputMode.MergeNone, openFile=self.printingOptionsDlg.uiOpenFilesChk.isChecked(), openFolder=self.printingOptionsDlg.uiOpenFolderChk.isChecked(), dbm=self.dbm, parent=self) def openSearchFilmDialog(self): """Run method that performs all the real work""" # show the dialog self.searchFilmDlg.show() #self.filmSelectionDlg.uiFilmNumberEdit.setFocus() # Run the dialog event loop and See if OK was pressed if self.searchFilmDlg.exec_(): # QMessageBox.warning(None, "FilmNumber", self.searchFilmDlg.generateSearchQuery()) model = QSqlRelationalTableModel(self, self.dbm.db) model.setTable("film") searchMode, searchFilter = self.searchFilmDlg.generateSearchFilter() # QMessageBox.information(self, "info", searchFilter) model.setFilter(searchFilter) model.select() rc = model.rowCount() while (model.canFetchMore()): model.fetchMore() rc = model.rowCount() query = QSqlQuery(self.dbm.db) searchQuery = "select filmnummer, substr(filmnummer, 3, 8) as 'ohne_hersteller', flugdatum, anzahl_bilder, weise, art_ausarbeitung, militaernummer, militaernummer_alt from film where {0}".format(searchFilter) query.exec_(searchQuery) querySize = 0 while(query.next()): querySize += 1 query.seek(-1) # if model.rowCount(): if querySize > 0: # open film selection list dialog searchListDlg = APISFilmSelectionList(self.iface, model, self.dbm, self.imageRegistry, parent=self) searchListDlg.uiFilmCountLbl.setText(str(rc)) searchListDlg.uiFilmCountDescriptionLbl.setText(u"Film gefunden" if model.rowCount() == 1 else u"Filme gefunden") searchListDlg.uiFilmSearchModeLbl.setText(searchMode) res = searchListDlg.loadFilmListBySqlQuery(query) if res and searchListDlg.exec_(): #QMessageBox.warning(None, "FilmNumber", unicode(searchListDlg.filmNumberToLoad)) self.loadRecordByKeyAttribute("filmnummer", searchListDlg.filmNumberToLoad) else: QMessageBox.warning(self, u"Film Suche", u"Keine Ergebnisse mit den angegebenen Suchkriterien.") self.openSearchFilmDialog() #QMessageBox.warning(None, "FilmNumber", u"{0}, rows: {1}".format(self.searchFilmDlg.generateSearchQuery(), model.rowCount())) # Get Search String/Query #if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()): #self.openFilmSelectionDialog() def openFilmSelectionDialog(self): """Run method that performs all the real work""" self.filmSelectionDlg.show() self.filmSelectionDlg.uiFilmNumberEdit.setFocus() if self.filmSelectionDlg.exec_(): if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()): self.openFilmSelectionDialog() def openNewFilmDialog(self): """Run method that performs all the real work""" self.newFilmDlg.show() if self.newFilmDlg.exec_(): self.addNewFilm(self.newFilmDlg.flightDate(), self.newFilmDlg.useLastEntry(), self.newFilmDlg.producer(), self.newFilmDlg.producerCode()) def openEditWeatherDialog(self): self.editWeatherDlg.setWeatherCode(self.uiWeatherCodeEdit.text()) self.editWeatherDlg.show() if self.editWeatherDlg.exec_(): self.uiWeatherCodeEdit.setText(self.editWeatherDlg.weatherCode()) #self.uiWeatherPTxt.setPlainText(self.editWeatherDlg.weatherDescription()) def generateWeatherCode(self): weatherDescription = self._generateWeatherCode(self.uiWeatherCodeEdit.text()) self.uiWeatherPTxt.setPlainText(weatherDescription) def _generateWeatherCode(self, weatherCode): categories = ["Low Cloud Amount", "Visibility Kilometres", "Low Cloud Height", "Weather", "Remarks Mission", "Remarks Weather"] query = QSqlQuery(self.dbm.db) pos = 0 help = 0 weatherDescription = "" for c in weatherCode: qryStr = "select description from wetter where category = '{0}' and code = '{1}' limit 1".format(categories[pos - help], c) query.exec_(qryStr) query.first() fn = query.value(0) if pos <= 5: weatherDescription += categories[pos] + ': ' + fn if pos < 5: weatherDescription += '\n' else: weatherDescription += '; ' + fn if pos >= 5: help += 1 pos += 1 return weatherDescription def openSystemTableEditorDialog(self, table, updateEditor): if self.dbm: self.systemTableEditorDlg = APISAdvancedInputDialog(self.dbm, table, False, parent=self) if self.systemTableEditorDlg.tableExists: if self.systemTableEditorDlg.exec_(): # See if OK was pressed # rec = self.systemTableEditorDlg.getRecord() # Update updateEditor # self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None) self.updateComboBox(updateEditor) else: QMessageBox.warning(self, "Tabelle nicht vorhanden", "Die Tabelle {0} ist in der APIS Datenbank nicht vorhanden".format(table)) else: QMessageBox.warning(self, "Warning Database", "Die APIS Datenbank konnte nicht gefunden werden.") def updateComboBox(self, updateEditor): updateEditor.model().select() tv = updateEditor.view() tv.resizeRowsToContents() tv.resizeColumnsToContents() scroll = 0 if updateEditor.count() <= updateEditor.maxVisibleItems() else QApplication.style().pixelMetric( QStyle.PM_ScrollBarExtent) tv.setMinimumWidth(tv.horizontalHeader().length() + scroll) updateEditor.setCurrentIndex(updateEditor.count() - 1) if updateEditor.validator(): updateEditor.lineEdit().setValidator( InListValidator([updateEditor.itemText(i) for i in range(updateEditor.count())], updateEditor.lineEdit(), None, self)) def openFlightPathDialog(self, filmList, toClose=None): self.flightPathDlg.viewFilms(filmList) # DEBUG self.flightPathDlg.show() if self.flightPathDlg.exec_(): #TODO load Data in TOC, Close Windows if toClose: toClose.close() self.close() def openSiteSelectionListDialog(self): if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL: fromTable = "luftbild_senk_fp" elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE: fromTable = "luftbild_schraeg_fp" query = QSqlQuery(self.dbm.db) query.prepare("SELECT fundortnummer, flurname, katastralgemeinde, fundgewinnung, sicherheit FROM fundort WHERE fundortnummer IN (SELECT DISTINCT fo.fundortnummer FROM fundort fo, {0} WHERE fo.geometry IS NOT NULL AND {0}.geometry IS NOT NULL AND {0}.filmnummer = '{1}' AND Intersects({0}.geometry, fo.geometry) AND fo.ROWID IN (SELECT ROWID FROM SpatialIndex WHERE f_table_name = 'fundort' AND search_frame = {0}.geometry)) ORDER BY katastralgemeindenummer, land, fundortnummer_nn".format(fromTable, self.uiCurrentFilmNumberEdit.text())) query.exec_() info = u"gefunden, die vom Film {0} abgedeckt/geschnitten werden.".format(self.uiCurrentFilmNumberEdit.text()) res = self.siteSelectionListDlg.loadSiteListBySpatialQuery(query, info) if res: self.siteSelectionListDlg.show() if self.siteSelectionListDlg.exec_(): pass def openImageSelectionListDialog(self): if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL: fromTable = 'luftbild_senk_cp' spatialIndicator = 'massstab' elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE: fromTable = 'luftbild_schraeg_cp' spatialIndicator = 'radius' query = QSqlQuery(self.dbm.db) query.prepare("SELECT cp.bildnummer AS bildnummer, cp.filmnummer AS filmnummer, cp.{2} AS mst_radius, f.weise AS weise, f.art_ausarbeitung AS art FROM {0} AS cp, film AS f WHERE cp.filmnummer = '{1}' AND f.filmnummer = '{1}'".format(fromTable, self.uiCurrentFilmNumberEdit.text(), spatialIndicator)) query.exec_() res = self.imageSelectionListDlg.loadImageListBySqlQuery(query) if res: self.imageSelectionListDlg.show() if self.imageSelectionListDlg.exec_(): pass def addNewFilm(self, flightDate, useLastEntry, producer, producerCode): self.initalLoad = True self.addMode = True self.startEditMode() row = self.model.rowCount() self.mapper.submit() while (self.model.canFetchMore()): self.model.fetchMore() self.model.insertRow(row) if useLastEntry: #copy last row for c in range(1, self.model.columnCount()): value = self.model.data(self.model.createIndex(row - 1, c)) self.model.setData(self.model.createIndex(row, c), value) editor = self.mapper.mappedWidgetAt(c) if editor and not (value == 'NULL' or value == ''): cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): pass else: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) self.mapper.setCurrentIndex(row) self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.uiFlightDate.setDate(flightDate) #self.uiFlightQgsDate.setDate(flightDate) self.uiProducerEdit.setText(producer) self.uiArchiveCombo.lineEdit().setText(producer) if not useLastEntry: self.uiWeatherCodeEdit.setText("9990X") #now = QDateTime.currentDateTime() now = QDate.currentDate() self.uiInitalEntryDate.setDate(now) #self.uiInitalEntryQgsDate.setDateTime(now) self.uiLastChangesDate.setDate(now) #self.uiLastChangesQgsDate.setDateTime(now) self.uiFilmModeCombo.setEnabled(True) #Filmnummer hh = producerCode yyyy = flightDate.toString("yyyy") mm = flightDate.toString("MM") query = QSqlQuery(self.dbm.db) qryStr = "select max(filmnummer_nn) from film where filmnummer_hh_jjjj_mm = '{0}{1}{2}' limit 1".format(hh, yyyy, mm) query.exec_(qryStr) query.first() fn = query.value(0) if isinstance(fn, int): nn = str(fn + 1).zfill(2) else: nn = "01" self.uiCurrentFilmNumberEdit.setText("{0}{1}{2}{3}".format(hh, yyyy, mm, nn)) self.initalLoad = False def removeNewFilm(self): self.initalLoad = True row = self.mapper.currentIndex() self.model.removeRow(row) self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.mapper.toLast() self.initalLoad = False def saveEdits(self): # Check Mandatory fields flag = False for mEditor in self.mandatoryEditors: cName = mEditor.metaObject().className() if cName == 'QLineEdit': value = mEditor.text() elif cName == 'QComboBox': value = mEditor.lineEdit().text() if value.strip() == "": flag = True mEditor.setStyleSheet("{0} {{background-color: rgb(240, 160, 160);}}".format(cName)) if mEditor not in self.editorsEdited: self.editorsEdited.append(mEditor) else: if mEditor in self.editorsEdited: mEditor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(cName)) #else: #mEditor.setStyleSheet("") if flag: QMessageBox.warning(self, self.tr(u"Benötigte Felder Ausfüllen"), self.tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind.")) return False #saveToModel currIdx = self.mapper.currentIndex() #now = QDateTime.currentDateTime() now = QDate.currentDate() self.uiLastChangesDate.setDate(now) #self.uiLastChangesQgsDate.setDateTime(now) res = self.mapper.submit() if not res: sqlError = self.mapper.model().lastError() QMessageBox.information(self, "Submit", u"Error: {0}, {1}".format(res, sqlError.text())) while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.setCurrentIndex(currIdx) self.endEditMode() return True def cancelEdit(self): if self.editMode: result = QMessageBox.question(self, self.tr(u"Änderungen wurden vorgenommen!"), self.tr(u"Möchten Sie die Änerungen speichern?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) #save or not save if result == QMessageBox.Yes: res = self.saveEdits() if res: return True else: return False elif result == QMessageBox.No: if self.addMode: self.removeNewFilm() self.mapper.setCurrentIndex(self.mapper.currentIndex()) self.endEditMode() return True def startEditMode(self): self.editMode = True self.enableItemsInLayout(self.uiTopHorizontalLayout, False) self.enableItemsInLayout(self.uiBottomHorizontalLayout, False) self.uiOkBtn.setEnabled(False) self.uiSaveBtn.setEnabled(True) self.uiCancelBtn.setEnabled(True) self.editorsEdited = [] def endEditMode(self): self.editMode = False self.addMode = False self.enableItemsInLayout(self.uiTopHorizontalLayout, True) self.enableItemsInLayout(self.uiBottomHorizontalLayout, True) self.uiOkBtn.setEnabled(True) self.uiSaveBtn.setEnabled(False) self.uiCancelBtn.setEnabled(False) for editor in self.editorsEdited: cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): editor.setStyleSheet("{0} {{background-color: rgb(218, 218, 218);}}".format(cName)) else: editor.setStyleSheet("") self.editorsEdited = [] self.uiFilmModeCombo.setEnabled(False) def showEvent(self, evnt): # QMessageBox.information(self, "info", "db requires update: {0}".format(self.dbm.dbRequiresUpdate)) if self.dbm.dbRequiresUpdate: self.initalLoad = True for editor in [self.uiArchiveCombo, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiCopyrightCombo, self.uiProjectSelectionCombo, self.newFilmDlg.uiProducerCombo]: self.updateComboBox(editor) currIdx = self.mapper.currentIndex() self.model.select() while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.setCurrentIndex(currIdx) self.dbm.dbRequiresUpdate = False self.initalLoad = False
class MainWindow(QMainWindow): def __init__(self, data): super().__init__() self.resize(400, 600) self.setWindowTitle('Logger Skeleton') self.statusBar().showMessage("Ready", 2000) # Make widgets #################################### self.tabs = QTabWidget(self) self.setCentralWidget(self.tabs) # Add tabs self.table_tab = QWidget(self) self.stats_tab = QWidget(self) self.tabs.addTab(self.table_tab, "Table") self.tabs.addTab(self.stats_tab, "Stats") # Table tab ########################################################### self.table_view = QTableView(self.table_tab) self.text_edit = QPlainTextEdit() self.btn_add_row = QPushButton("Add a row") #self.btn_remove_row = QPushButton("Remove selected rows") table_tab_vbox = QVBoxLayout() table_tab_vbox.addWidget(self.table_view) table_tab_vbox.addWidget(self.text_edit) table_tab_vbox.addWidget(self.btn_add_row) #table_tab_vbox.addWidget(self.btn_remove_row) self.table_tab.setLayout(table_tab_vbox) # Set model ####################################### my_model = DataQtModel(data, parent=self) # TODO: right use of "parent" ? # Proxy model ##################################### proxy_model = QSortFilterProxyModel(parent=self) # TODO: right use of "parent" ? proxy_model.setSourceModel(my_model) self.table_view.setModel(proxy_model) #self.table_view.setModel(my_model) # Set the view #################################### self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) # Select the full row when a cell is selected (See http://doc.qt.io/qt-5/qabstractitemview.html#selectionBehavior-prop ) #self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) # Set selection mode. See http://doc.qt.io/qt-5/qabstractitemview.html#selectionMode-prop self.table_view.setAlternatingRowColors(True) self.table_view.setSortingEnabled(True) self.table_view.setColumnWidth(0, 200) # TODO: automatically get the best width self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # https://stackoverflow.com/q/17535563 self.table_view.setColumnHidden(COMMENT_COLUMN_INDEX, True) delegate = Delegate() self.table_view.setItemDelegate(delegate) # Set key shortcut ################################ # see https://stackoverflow.com/a/17631703 and http://doc.qt.io/qt-5/qaction.html#details # Add row action add_action = QAction(self.table_view) add_action.setShortcut(Qt.CTRL | Qt.Key_N) add_action.triggered.connect(self.add_row_btn_callback) self.table_view.addAction(add_action) # Delete action del_action = QAction(self.table_view) del_action.setShortcut(Qt.Key_Delete) del_action.triggered.connect(self.remove_row_callback) self.table_view.addAction(del_action) # Set QDataWidgetMapper ########################### self.mapper = QDataWidgetMapper() self.mapper.setModel(proxy_model) # WARNING: do not use `my_model` here otherwise the index mapping will be wrong! self.mapper.addMapping(self.text_edit, COMMENT_COLUMN_INDEX) self.mapper.toFirst() # TODO: is it a good idea ? self.table_view.selectionModel().selectionChanged.connect(self.update_selection) # Set slots ####################################### self.btn_add_row.clicked.connect(self.add_row_btn_callback) #self.btn_remove_row.clicked.connect(self.remove_row_callback) #self.table_view.setColumnHidden(1, True) # Stats tab ########################################################### # See https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html stats_tab_layout = QVBoxLayout(self.stats_tab) self.plot_canvas = PlotCanvas(data, self.stats_tab, width=5, height=4, dpi=100) stats_tab_layout.addWidget(self.plot_canvas) ################################################### #proxy_model.dataChanged.connect(plot_canvas.update_figure) #proxy_model.rowsInserted.connect(plot_canvas.update_figure) # TODO #proxy_model.rowsRemoved.connect(plot_canvas.update_figure) # TODO self.tabs.currentChanged.connect(self.updatePlot) # Update the stats plot when the tabs switch to the stats tab # Show ############################################ self.show() def update_selection(self, selected, deselected): index = self.table_view.selectionModel().currentIndex() self.mapper.setCurrentIndex(index.row()) print("Index: ", index.row()) def updatePlot(self, index): """ Parameters ---------- index Returns ------- """ if index == self.tabs.indexOf(self.stats_tab): self.plot_canvas.update_figure() def add_row_btn_callback(self): parent = QModelIndex() # More useful with e.g. tree structures #row_index = 0 # Insert new rows to the begining row_index = self.table_view.model().rowCount(parent) # Insert new rows to the end self.table_view.model().insertRows(row_index, 1, parent) def remove_row_callback(self): parent = QModelIndex() # More useful with e.g. tree structures # See http://doc.qt.io/qt-5/model-view-programming.html#handling-selections-in-item-views #current_index = self.table_view.selectionModel().currentIndex() #print("Current index:", current_index.row(), current_index.column()) selection_index_list = self.table_view.selectionModel().selectedRows() selected_row_list = [selection_index.row() for selection_index in selection_index_list] print("Current selection:", selected_row_list) #row_index = 0 # Remove the first row #row_index = self.table_view.model().rowCount(parent) - 1 # Remove the last row # WARNING: the list of rows to remove MUST be sorted in reverse order # otherwise the index of rows to remove may change at each iteration of the for loop! # TODO: there should be a lock mechanism to avoid model modifications from external sources while iterating this loop... # Or as a much simpler alternative, modify the ItemSelectionMode to forbid the non contiguous selection of rows and remove the following for loop for row_index in sorted(selected_row_list, reverse=True): # Remove rows one by one to allow the removql of non-contiguously selected rows (e.g. "rows 0, 2 and 3") success = self.table_view.model().removeRows(row_index, 1, parent) if not success: raise Exception("Unknown error...") # TODO
class PhoneLogDlg(QDialog): FIRST, PREV, NEXT, LAST = range(4) def __init__(self, parent=None): super(PhoneLogDlg, self).__init__(parent) callerLabel = QLabel("&Caller:") self.callerEdit = QLineEdit() callerLabel.setBuddy(self.callerEdit) today = QDate.currentDate() startLabel = QLabel("&Start:") self.startDateTime = QDateTimeEdit() startLabel.setBuddy(self.startDateTime) self.startDateTime.setDateRange(today, today) self.startDateTime.setDisplayFormat(DATETIME_FORMAT) endLabel = QLabel("&End:") self.endDateTime = QDateTimeEdit() endLabel.setBuddy(self.endDateTime) self.endDateTime.setDateRange(today, today) self.endDateTime.setDisplayFormat(DATETIME_FORMAT) topicLabel = QLabel("&Topic:") topicEdit = QLineEdit() topicLabel.setBuddy(topicEdit) outcomeLabel = QLabel("&Outcome:") self.outcomeComboBox = QComboBox() outcomeLabel.setBuddy(self.outcomeComboBox) firstButton = QPushButton() firstButton.setIcon(QIcon(":/first.png")) prevButton = QPushButton() prevButton.setIcon(QIcon(":/prev.png")) nextButton = QPushButton() nextButton.setIcon(QIcon(":/next.png")) lastButton = QPushButton() lastButton.setIcon(QIcon(":/last.png")) addButton = QPushButton("&Add") addButton.setIcon(QIcon(":/add.png")) deleteButton = QPushButton("&Delete") deleteButton.setIcon(QIcon(":/delete.png")) quitButton = QPushButton("&Quit") quitButton.setIcon(QIcon(":/quit.png")) if not MAC: addButton.setFocusPolicy(Qt.NoFocus) deleteButton.setFocusPolicy(Qt.NoFocus) fieldLayout = QGridLayout() fieldLayout.addWidget(callerLabel, 0, 0) fieldLayout.addWidget(self.callerEdit, 0, 1, 1, 3) fieldLayout.addWidget(startLabel, 1, 0) fieldLayout.addWidget(self.startDateTime, 1, 1) fieldLayout.addWidget(endLabel, 1, 2) fieldLayout.addWidget(self.endDateTime, 1, 3) fieldLayout.addWidget(topicLabel, 2, 0) fieldLayout.addWidget(topicEdit, 2, 1, 1, 3) fieldLayout.addWidget(outcomeLabel, 3, 0) fieldLayout.addWidget(self.outcomeComboBox, 3, 1, 1, 3) navigationLayout = QHBoxLayout() navigationLayout.addWidget(firstButton) navigationLayout.addWidget(prevButton) navigationLayout.addWidget(nextButton) navigationLayout.addWidget(lastButton) fieldLayout.addLayout(navigationLayout, 4, 0, 1, 2) buttonLayout = QVBoxLayout() buttonLayout.addWidget(addButton) buttonLayout.addWidget(deleteButton) buttonLayout.addStretch() buttonLayout.addWidget(quitButton) layout = QHBoxLayout() layout.addLayout(fieldLayout) layout.addLayout(buttonLayout) self.setLayout(layout) self.model = QSqlRelationalTableModel(self) self.model.setTable("calls") self.model.setRelation(OUTCOMEID, QSqlRelation("outcomes", "id", "name")) self.model.setSort(STARTTIME, Qt.AscendingOrder) self.model.select() self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.model) self.mapper.setItemDelegate(QSqlRelationalDelegate(self)) self.mapper.addMapping(self.callerEdit, CALLER) self.mapper.addMapping(self.startDateTime, STARTTIME) self.mapper.addMapping(self.endDateTime, ENDTIME) self.mapper.addMapping(topicEdit, TOPIC) relationModel = self.model.relationModel(OUTCOMEID) self.outcomeComboBox.setModel(relationModel) self.outcomeComboBox.setModelColumn(relationModel.fieldIndex("name")) self.mapper.addMapping(self.outcomeComboBox, OUTCOMEID) self.mapper.toFirst() firstButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.FIRST)) prevButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.PREV)) nextButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.NEXT)) lastButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.LAST)) addButton.clicked.connect(self.addRecord) deleteButton.clicked.connect(self.deleteRecord) quitButton.clicked.connect(self.done) self.setWindowTitle("Phone Log") def done(self, result=None): self.mapper.submit() QDialog.done(self, True) def addRecord(self): row = self.model.rowCount() self.mapper.submit() self.model.insertRow(row) self.mapper.setCurrentIndex(row) now = QDateTime.currentDateTime() self.startDateTime.setDateTime(now) self.endDateTime.setDateTime(now) self.outcomeComboBox.setCurrentIndex( self.outcomeComboBox.findText("Unresolved")) self.callerEdit.setFocus() def deleteRecord(self): caller = self.callerEdit.text() starttime = self.startDateTime.dateTime().toString(DATETIME_FORMAT) if (QMessageBox.question( self, "Delete", "Delete call made by<br>{0} on {1}?".format(caller, starttime), QMessageBox.Yes | QMessageBox.No) == QMessageBox.No): return row = self.mapper.currentIndex() self.model.removeRow(row) self.model.submitAll() self.model.select() if row + 1 >= self.model.rowCount(): row = self.model.rowCount() - 1 self.mapper.setCurrentIndex(row) def saveRecord(self, where): row = self.mapper.currentIndex() self.mapper.submit() if where == PhoneLogDlg.FIRST: row = 0 elif where == PhoneLogDlg.PREV: row = 0 if row <= 1 else row - 1 elif where == PhoneLogDlg.NEXT: row += 1 if row >= self.model.rowCount(): row = self.model.rowCount() - 1 elif where == PhoneLogDlg.LAST: row = self.model.rowCount() - 1 self.mapper.setCurrentIndex(row)
class MyDialog(QDialog): def __init__(self, parent=None): super(MyDialog, self).__init__(parent) self.datas() self.selfSetUp() self.setUpWidgets() self.setUpLayouts() self.setUpModels() self.setUpMapper() self.setUpConnections() def datas(self): self.kinds = ['vegetale', 'animale'] def selfSetUp(self): self.setWindowTitle('TableView v 0.2') self.setMinimumSize(QSize(int(680 * 1.5), int(600 * 1.5))) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) sizePolicy.setWidthForHeight(self.sizePolicy().hasWidthForHeight()) self.setSizePolicy(sizePolicy) def setUpWidgets(self): # self.table = Mytable(self) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) sizePolicy.setWidthForHeight(self.sizePolicy().hasWidthForHeight()) self.table = QLineEdit() self.table.setStyleSheet("background-color: rgb(255, 255, 127)") labSize = QSize(100, 30) self.table.setFixedSize(labSize) self.table.setSizePolicy(sizePolicy) self.combo = ComboSenzaFreccia(self) botSize = QSize(30, 30) self.bot_next = QPushButton(text='Next', parent=self) self.bot_prev = QPushButton(text='Prev', parent=self) self.bot_prev.setSizePolicy(sizePolicy) self.bot_next.setSizePolicy(sizePolicy) self.bot_prev.setFixedSize(botSize) self.bot_next.setFixedSize(botSize) def setUpLayouts(self): self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.finalLay = QHBoxLayout() self.finalLay.setObjectName("finalLay") self.prevLay = QVBoxLayout() self.prevLay.setObjectName("prevLay") self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem) self.bot_prev.setObjectName("bot_prev") self.horizontalLayout_3.addWidget(self.bot_prev) self.prevLay.addLayout(self.horizontalLayout_3) spacerItem1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.prevLay.addItem(spacerItem1) self.finalLay.addLayout(self.prevLay) self.centLay = QVBoxLayout() self.centLay.setObjectName("centLay") self.verticalLayout_2 = QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") self.combo.setMaxVisibleItems(12) self.combo.setMaxCount(12) self.combo.setObjectName("ComboSenzaFreccia") self.verticalLayout_2.addWidget(self.combo) # self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setObjectName("table") # self.table.horizontalHeader().setStretchLastSection(True) self.verticalLayout_2.addWidget(self.table) self.centLay.addLayout(self.verticalLayout_2) self.finalLay.addLayout(self.centLay) self.nextLay = QVBoxLayout() self.nextLay.setObjectName("nextLay") self.horizontalLayout_4 = QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.bot_next.setObjectName("bot_next") self.horizontalLayout_4.addWidget(self.bot_next) spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem2) self.nextLay.addLayout(self.horizontalLayout_4) spacerItem3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.nextLay.addItem(spacerItem3) self.finalLay.addLayout(self.nextLay) self.horizontalLayout.addLayout(self.finalLay) self.setLayout(self.horizontalLayout) def setUpLayouts_old(self): vboxPrev = QVBoxLayout() self.prevLay = QHBoxLayout() sp = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) vboxPrev.addItem(sp) vboxPrev.addWidget(self.bot_prev) sp = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.prevLay.addLayout(vboxPrev) self.prevLay.addItem(sp) vboxPrev = QVBoxLayout() self.nextLay = QHBoxLayout() sp = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) vboxPrev.addWidget(self.bot_next) vboxPrev.addItem(sp) sp = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.nextLay.addLayout(vboxPrev) self.nextLay.addItem(sp) self.centLay = QVBoxLayout() self.centLay.addWidget(self.combo) self.centLay.addWidget(self.table) self.finalLay = QHBoxLayout() self.finalLay.addLayout(self.prevLay) self.finalLay.addLayout(self.centLay) self.finalLay.addLayout(self.nextLay) self.setLayout(self.finalLay) def setUpModels(self): ## sono gli items che devo essere nella combo (es: i mesi) items = ['cane', 'gatto', 'melo', 'pero'] #i numeri 4 e 2 passati come argomenti per il modello base indicano le righe e le colonne del modello # basate sulla len di items e di self.kinds self.model = QStandardItemModel(4, 2, self) # questo è il modello passato alla combo, che ha come elementi gli items self.typeModel = QStringListModel(items, self) self.combo.setModel(self.typeModel) # a ogni elemento di items deve corrispondere un valore, self.kinds, ricavato dall'indice types = ("1", "1", "0", "0") # per ogni item viene assegnato il valore nel modello matrice # la mappatura ha nella colonna 0 la combobox e gli viene assegnato un item # alla colonna 1 del modello viene assegnato il riferimento a self.kinds passato attraverso types for row, item in enumerate(items): self.model.setItem(row, 0, QStandardItem(item)) self.model.setItem(row, 1, QStandardItem(self.kinds[int(types[row])])) # self.model.setItem(row, 1, QStandardItem(types[row])) # for row, col in enumerate() def setUpMapper(self): self.mapper = QDataWidgetMapper(self) self.mapper.setModel(self.model) # self.mapper.addMapping(self.table,1,b'currentIndex') self.mapper.addMapping(self.table, 1) # self.mapper.addMapping(self.combo,0,b'currentIndex') self.mapper.addMapping(self.combo, 0) self.mapper.currentIndexChanged.connect(self.updateButtons) self.mapper.toFirst() def setUpConnections(self): self.bot_next.clicked.connect(self.mapper.toNext) self.bot_prev.clicked.connect(self.mapper.toPrevious) try: self.combo.currentIndexChanged.connect( lambda x: self.mapper.setCurrentIndex(x)) pass except: print(fex()) # self.combo.currentIndexChanged.connect(lambda x: self.mapper.model().c) def updateButtons(self, row): self.bot_prev.setEnabled(row > 0) self.bot_next.setEnabled(row < self.model.rowCount() - 1) print('mapper current index', self.mapper.currentIndex()) print('combo current index', self.combo.currentIndex()) # print('mapper model rows count', self.mapper.model().rowCount()) print('-' * 20)
class ManagerMainui(QMainWindow, Ui_MainWindow): def __init__(self): super(ManagerMainui, self).__init__() self.setupUi(self) self.opendb() self.show() self.lianjie() self.setCentralWidget(self.splitter) self.table_view.setSelectionBehavior(QAbstractItemView.SelectItems) self.table_view.setSelectionMode( QAbstractItemView.SingleSelection) # 一次选择单行还是多行 self.table_view.setAlternatingRowColors(True) # 隔行自动改变颜色 self.table_view.verticalHeader().setDefaultSectionSize(22) self.table_view.horizontalHeader().setDefaultSectionSize(60) # 为菜单添加动作 self.filemenu.addAction(self.exit_Act) self.Updata_Menu.addAction(self.Updata_Act) # 当前页 self.currentPage = 0 # 总页数 self.totalPage = 0 # 总记录数 self.totalRecord = 0 # 每页数据数 self.pageRecord = 10 def opendb(self): db = QSqlDatabase.addDatabase('QSQLITE') db.setDatabaseName('F:/pycharm项目/图书管理系统NEW/AllDataBase/book.db') if db.open(): self._biaocaozuo() else: QMessageBox.information(self, 'warning', '无法建立与数据库的连接') return False def _biaocaozuo(self): self.model = QtSql.QSqlTableModel() self.model.setTable('BookData') self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) # 设置保存策略 self.table_view.setModel(self.model) self.model.select() self.model.setHeaderData(0, Qt.Horizontal, 'ISBN') self.model.setHeaderData(1, Qt.Horizontal, '书名') self.model.setHeaderData(2, Qt.Horizontal, '作者') self.model.setHeaderData(3, Qt.Horizontal, '出版社') self.model.setHeaderData(4, Qt.Horizontal, '出版日期') self.model.setHeaderData(5, Qt.Horizontal, '评分') self.model.setHeaderData(6, Qt.Horizontal, '照片') self.table_view.setColumnHidden(6, True) self.mapper = QDataWidgetMapper() self.mapper.setModel(self.model) self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) self.mapper.addMapping(self.lineEdit_ISBN, 0) self.mapper.addMapping(self.lineEdit_shuming, 1) self.mapper.addMapping(self.lineEdit_zuozhe, 2) self.mapper.addMapping(self.lineEdit_chubanshe, 3) self.mapper.addMapping(self.lineEdit_chubanriqi, 4) self.mapper.addMapping(self.lineEdit_pingfen, 5) self.mapper.toFirst() self.selModel = QItemSelectionModel(self.model) # 选择模型 self.table_view.setSelectionModel(self.selModel) self.selModel.currentChanged.connect( self.do_currentChanged) # 当前项变化时触发 self.selModel.currentRowChanged.connect( self.do_currentRowChanged) # 选择行变化时 # @pyqtSlot() ##保存修改 def on_p_baocun_triggered(self): result = QMessageBox.question(self, 'warning', '你要保存你的修改吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if result == QMessageBox.Yes: res = self.model.submitAll() if (res == False): QMessageBox.information( self, "消息", "数据保存错误,错误信息\n" + self.model.lastError().text()) else: QMessageBox.information(self, "message", "保存成功\n") self.p_baocun.setEnabled(False) self.p_quxiao.setEnabled(False) else: QMessageBox.information(self, 'message', 'Thanks') # @pyqtSlot() ##取消修改 def on_p_quxiao_triggered(self): # self.model.revertAll() result = QMessageBox.question(self, 'warning', '确认取消之前所有的的操作吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if result == QMessageBox.Yes: self.model.revertAll() self.p_baocun.setEnabled(False) self.p_quxiao.setEnabled(False) else: self.p_baocun.setEnabled(True) self.p_quxiao.setEnabled(True) # @pyqtSlot() ##添加记录 def on_p_zengjia_triggered(self): #self.model.insertRows(self.model.rowCount(), 1) self.model.insertRow(self.model.rowCount(), QModelIndex()) # 在末尾添加一个记录 curIndex = self.model.index(self.model.rowCount() - 1, 1) # 创建最后一行的ModelIndex self.selModel.clearSelection() # 清空选择项 self.selModel.setCurrentIndex( curIndex, QItemSelectionModel.Select) # 设置刚插入的行为当前选择行 # 删除记录 def on_p_sanchu_triggered(self): # if self.p_baocun.isEnabled(): result = QMessageBox.question(self, 'warning', '确认删除该记录吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if result == QMessageBox.Yes: self.model.removeRow(self.table_view.currentIndex().row()) self.p_baocun.setEnabled(True) self.p_quxiao.setEnabled(True) else: self.p_baocun.setEnabled(False) self.p_quxiao.setEnabled(False) # 插入记录 def on_p_charu_triggered(self): curIndex = self.table_view.currentIndex() # QModelIndex self.model.insertRow(curIndex.row(), QModelIndex()) self.selModel.clearSelection() # 清除已有选择 self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) # 对当前行设置图片 def on_p_photo_triggered(self): fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "", "照片(*.jpg)") if (fileName == ''): return file = QFile(fileName) # fileName为图片文件名 file.open(QIODevice.ReadOnly) try: data = file.readAll() # QByteArray finally: file.close() curRecNo = self.selModel.currentIndex().row() curRec = self.model.record(curRecNo) # 获取当前记录QSqlRecord curRec.setValue("Photo", data) # 设置字段数据 self.model.setRecord(curRecNo, curRec) pic = QPixmap() pic.loadFromData(data) W = self.dbLabPhoto.width() self.dbLabPhoto.setPixmap(pic.scaledToWidth(W)) # 在界面上显示 def closeEvent(self, event): """ 提示保存 """ if self.p_baocun.isEnabled(): r = QMessageBox.warning(self, "注意", "你还没有保存,现在保存下?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if r == QMessageBox.No: event.accept() else: event.ignore() def chaxun_ISBN(self): text1 = self.lineEdit_chaxun.text() self.model.setFilter(("ISBN='%s'" % (text1))) def chaxun_zuozhe(self): text2 = self.lineEdit_chaxun.text() self.model.setFilter(("author='%s'" % (text2))) def chaxun_shumin(self): text3 = self.lineEdit_chaxun.text() self.model.setFilter(("title='%s'" % (text3))) def chaxun_(self): """ 查找图书 """ searchtext = self.lineEdit_chaxun.text() if searchtext: if self.comboBox_chaxun.currentText() == "ISBN": self.chaxun_ISBN() elif self.comboBox_chaxun.currentText() == "书名": self.chaxun_shumin() elif self.comboBox_chaxun.currentText() == "作者": self.chaxun_zuozhe() else: QMessageBox.information(self, "提示", "请输入搜索关键词!") def on_p_quxiaoCX_triggered(self): self.lineEdit_chaxun.clear() self.model.setFilter("") def do_currentChanged(self, current, previous): # 更新actPost和actCancel 的状态 self.p_baocun.setEnabled(self.model.isDirty()) # 有未保存修改时可用 self.p_quxiao.setEnabled(self.model.isDirty()) def do_currentRowChanged(self, current, previous): # 行切换时的状态控制 self.mapper.setCurrentIndex(current.row()) if (current.isValid() == False): self.dbLabPhoto.clear() # 清除图片显示 return self.mapper.setCurrentIndex(current.row()) # 更新数据映射的行号 curRec = self.model.record(current.row()) # 获取当前记录,QSqlRecord类型 if (curRec.isNull("Photo")): # 图片字段内容为空 self.dbLabPhoto.clear() else: # data=bytearray(curRec.value("Photo")) #可以工作 data = curRec.value("Photo") # 也可以工作 pic = QPixmap() pic.loadFromData(data) W = self.dbLabPhoto.size().width() self.dbLabPhoto.setPixmap(pic.scaledToWidth(W)) def scrapy(self): """启动爬虫,在线更新功能""" # cmdline.execute(" scrapy ".split()) self.hide() try: run = ScrapyRun() finally: pass def lianjie(self): self.p_zengjia.clicked.connect(self.on_p_zengjia_triggered) self.p_baocun.clicked.connect(self.on_p_baocun_triggered) self.p_quxiao.clicked.connect(self.on_p_quxiao_triggered) self.p_sanchu.clicked.connect(self.on_p_sanchu_triggered) self.p_charu.clicked.connect(self.on_p_charu_triggered) self.p_photo.clicked.connect(self.on_p_photo_triggered) self.p_chaxun.clicked.connect(self.chaxun_) self.p_quxiaoCX.clicked.connect(self.on_p_quxiaoCX_triggered) self.p_tuichu.clicked.connect(self.close) self.exit_Act.triggered.connect(self.close) self.Updata_Act.triggered.connect(self.scrapy)
class QmyMainWindow(QMainWindow): def __init__(self, parent=None, dbFilename='None'): super().__init__(parent) # Call the parent class. Create window. self.ui = Ui_MainWindow() # Create UI object self.ui.setupUi(self) # Create UI interface self.ui.tabWidget.setVisible(True) self.setCentralWidget(self.ui.tabWidget) # tableView setting self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems) self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.verticalHeader().setDefaultSectionSize(44) self.ui.tableView.horizontalHeader().setDefaultSectionSize(70) self.ui.tableView.setSortingEnabled(True) # Initialize chart self.__iniPieChart() # Initialize pie chart self.__iniStackedBar() # Stacked bar mpl.rcParams['font.sans-serif'] = ['Calibri'] mpl.rcParams['font.size'] = 8 # Choose the SQLITE database drive self.DB = QSqlDatabase.addDatabase("QSQLITE") self.DB.setDatabaseName(dbFilename) # Set the name of database if self.DB.open(): # Open database self.__openTable() # Open tables else: QMessageBox.warning(self, "Warning", "Failed to open the database.") # ==============Self-defined Fuctions============ def __getFieldNames(self): # Get names of all fields. # Get empty records, only field name. emptyRec = self.tabModel.record() self.fldNum = {} # Dictionary of field name and index. for i in range(emptyRec.count()): fieldName = emptyRec.fieldName(i) self.fldNum.setdefault(fieldName) self.fldNum[fieldName] = i def __openTable(self): # Open the table of database self.tabModel = QSqlTableModel(self, self.DB) # Data model # Set the table of database TODO: Can user insert their own tables from # the database? self.tabModel.setTable("battery") # Data storage,OnManualSubmit , OnRowChange self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) # self.tabModel.setSort( # self.tabModel.fieldIndex("RANDOM"), # Qt.DescendingOrder) # Sorting if (self.tabModel.select() == False): # Failed to query the data QMessageBox.critical( self, "Wrong", "Something wrong. Failed to open the database\n" + self.tabModel.lastError().text()) return # self.tabModel.setFilter("NUM_RECORDS LIKE 'NONE'") self.__getFieldNames() # Get the field name and index # Field name shown for i in self.fldNum: self.tabModel.setHeaderData(self.fldNum[i], Qt.Horizontal, i.capitalize()) # Create mappings between interface widget and the field name of data model self.mapper = QDataWidgetMapper() self.mapper.setModel(self.tabModel) # Setting data model self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) # The relations between interface widget and field name of tabModel self.mapper.addMapping(self.ui.dbEditValue, self.fldNum["Value"]) self.mapper.addMapping(self.ui.dbEditRunit, self.fldNum["Raw_unit"]) self.mapper.addMapping(self.ui.dbComboProperty, self.fldNum["Property"]) self.mapper.addMapping(self.ui.dbEditUnit, self.fldNum["Unit"]) self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"]) self.mapper.addMapping(self.ui.dbEditEname, self.fldNum["Extracted_name"]) self.mapper.addMapping(self.ui.dbEditRvalue, self.fldNum["Raw_value"]) self.mapper.addMapping(self.ui.dbEditDOI_2, self.fldNum["DOI"]) self.mapper.addMapping(self.ui.dbEditDOI_4, self.fldNum["Date"]) self.mapper.addMapping(self.ui.dbEditDOI_3, self.fldNum["Title"]) self.mapper.addMapping(self.ui.dbEditDOI, self.fldNum["Journal"]) self.mapper.addMapping(self.ui.dbEditTag, self.fldNum["Tag"]) self.mapper.addMapping(self.ui.dbEditInfo, self.fldNum["Info"]) self.mapper.addMapping(self.ui.dbEditType, self.fldNum["Type"]) self.mapper.addMapping(self.ui.dbEditWarning, self.fldNum["Warning"]) self.mapper.addMapping(self.ui.dbEditSpecifier, self.fldNum["Specifier"]) self.mapper.toFirst() # Move to the first record self.selModel = QItemSelectionModel(self.tabModel) # Select model self.selModel.currentChanged.connect( self.do_currentChanged) # Trigger when the current changed self.selModel.currentRowChanged.connect( self.do_currentRowChanged) # Trigger when the current row changed self.ui.tableView.setModel(self.tabModel) # Setting the data model self.ui.tableView.setSelectionModel( self.selModel) # Setting the selection model # self.ui.tableView.setColumnHidden(self.fldNum["TAG"], True) #Hide columns # self.ui.tableView.setColumnHidden(self.fldNum["INFO"], True) #Hide # columns self.ui.tableView.setColumnHidden(self.fldNum["Extracted_name"], True) # Hide columns self.ui.tableView.setColumnHidden(self.fldNum["Unit"], True) # Hide columns self.ui.tableView.setColumnHidden(self.fldNum["Num_records"], True) # Hide columns # self.ui.tableView.setColumnHidden( # self.fldNum["RAW_VALUE"], True) # Hide columns # Update the conditions of actions of interface widget self.ui.actRecAppend.setEnabled(True) self.ui.actRecInsert.setEnabled(True) self.ui.actRecDelete.setEnabled(True) self.ui.btnDrawPieChart.setEnabled(True) # Pie Chart self.ui.spinPieSize.setEnabled(True) self.ui.spinHoleSize.setEnabled(True) self.ui.chkBox_PieLegend.setEnabled(True) self.ui.generateButton_3.setEnabled(True) self.ui.searchButton_3.setEnabled(True) self.ui.clearButton_3.setEnabled(True) self.ui.frame_4.setEnabled(True) self.ui.frame_3.setEnabled(True) self.ui.searchInput.returnPressed.connect(self.ui.searchButton.click) self.ui.searchInput_3.returnPressed.connect( self.ui.searchButton_3.click) def __iniPieChart(self): # Initialize pie chart chart = QChart() # chart.setTitle("Piechart") chart.setAnimationOptions(QChart.SeriesAnimations) chart.setTheme(QChart.ChartTheme(0)) self.ui.chartViewPie.setChart(chart) # Setting chart for chart view self.ui.chartViewPie.setRenderHint(QPainter.Antialiasing) self.ui.chartViewPie.setCursor(Qt.CrossCursor) # Setting cross cursor def __iniStackedBar(self): # Initialize stacked bar chart chart = QChart() # chart.setTitle("Number of property records for each chemical") chart.setAnimationOptions(QChart.SeriesAnimations) chart.setTheme(QChart.ChartTheme(0)) self.ui.chartViewStackedBar.setChart(chart) # Set chart self.ui.chartViewStackedBar.setRenderHint(QPainter.Antialiasing) self.ui.chartViewStackedBar.setCursor(Qt.CrossCursor) # Set mouse # ==========Table tab slot function================== @pyqtSlot() # Save changes def on_actSubmit_triggered(self): res = self.tabModel.submitAll() if (res == False): QMessageBox.information( self, "Information", "Failed to store the changes. Wrong information. \n" + self.tabModel.lastError().text()) else: self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() # Cancel changes def on_actRevert_triggered(self): self.tabModel.revertAll() self.ui.actSubmit.setEnabled(False) self.ui.actRevert.setEnabled(False) @pyqtSlot() # Add records def on_actRecAppend_triggered(self): self.tabModel.insertRow( self.tabModel.rowCount(), QModelIndex()) # Add one record in the last row curIndex = self.tabModel.index(self.tabModel.rowCount() - 1, 1) # Create ModelIndex of the last row self.selModel.clearSelection() # Clear selections # Choosing the current row when selection. self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) currow = curIndex.row() # Get current row @pyqtSlot() # Insert records def on_actRecInsert_triggered(self): curIndex = self.ui.tableView.currentIndex() # QModelIndex self.tabModel.insertRow(curIndex.row(), QModelIndex()) self.selModel.clearSelection() # Clear selections self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() # Delete records def on_actRecDelete_triggered(self): # Get the current index of current model curIndex = self.selModel.currentIndex() self.tabModel.removeRow(curIndex.row(), QModelIndex()) # Delete the current row self.tabModel.submit() @pyqtSlot() # Help message box def on_actHelp_triggered(self): msg = QMessageBox() msg.about( self, "Help", '<div>' '<h3>Table: Query the database according to data types and name or DOI.</h3>' '<ul>' '<li>Search the exact compound name in "<em>Exact Match</em>". Search the element or part of compound name in "<em>Generic Match</em>". </li>' '<li>Click the "<em>Home</em>" or "<em>All</em>" button to view the full database</li>' '<li>Refer to "<em>Correctness</em>" column for database evaluation details. </li>' '<li>You can add your own database entries using the "<em>Insert</em>" tab; click "<em>Save</em>" to save the changes.</li>' '</ul>' '<h3>Figure: Statistical analysis of the database.</h3>' '<ul>' '<li><em>Pie chart</em> shows the proportion of data records.</li>' '<li><em>Stacked bar chart</em> shows the data types for each compound. First input the compound name, click "<em>Add</em>" and then "<em>Generate</em>" data for overview. </li>' '<li><em>Histogram </em>shows the distribution of each data type.</li>' '<li><em>Venn diagram</em> shows the correlation of each data type.</li>' '</ul>' '</div>') @pyqtSlot() # Filtering def on_radioBtnVoltage_clicked(self): flag, sqlmerge = self.merged_or_not() print(sqlmerge) self.tabModel.setFilter("PROPERTY LIKE 'Voltage' AND %s" % sqlmerge) @pyqtSlot() # Filtering def on_radioBtnCoulombic_clicked(self): flag, sqlmerge = self.merged_or_not() self.tabModel.setFilter("PROPERTY LIKE 'Coulombic Efficiency' AND %s" % sqlmerge) @pyqtSlot() # Filtering def on_radioBtnConductivity_clicked(self): flag, sqlmerge = self.merged_or_not() self.tabModel.setFilter("PROPERTY LIKE 'Conductivity' AND %s" % sqlmerge) @pyqtSlot() # Filetering def on_radioBtnCapacity_clicked(self): flag, sqlmerge = self.merged_or_not() self.tabModel.setFilter("PROPERTY LIKE 'Capacity' AND %s" % sqlmerge) @pyqtSlot() # Filtering def on_radioBtnEnergy_clicked(self): flag, sqlmerge = self.merged_or_not() self.tabModel.setFilter("PROPERTY LIKE 'Energy' AND %s" % sqlmerge) @pyqtSlot() # Cancel Filetering def on_radioBtnAll_clicked(self): flag, sqlmerge = self.merged_or_not() self.tabModel.setFilter("%s" % sqlmerge) # print(self.tabModel.filter()) # self.tabModel.select() def get_elements(self): element_dic = { "Hydrogen": "H", "Helium": "He", "Lithium": "Li", "Beryllium": "Be", "Boron": "B", "Carbon": "C", "Nitrogen": "N", "Oxygen": "O", "Fluorine": "F", "Neon": "Ne", "Sodium": "Na", "Magnesium": "Mg", "Aluminum": "Al", "Silicon": "Si", "Phosphorus": "P", "Sulfur": "S", "Chlorine": "Cl", "Argon": "Ar", "Potassium": "K", "Calcium": "Ca", "Scandium": "Sc", "Titanium": "Ti", "Vanadium": "V", "Chromium": "Cr", "Manganese": "Mn", "Iron": "Fe", "Cobalt": "Co", "Nickel": "Ni", "Copper": "Cu", "Zinc": "Zn", "Gallium": "Ga", "Germanium": "Ge", "Arsenic": "As", "Selenium": "Se", "Bromine": "Br", "Krypton": "Kr", "Rubidium": "Rb", "Strontium": "Sr", "Yttrium": "Y", "Zirconium": "Zr", "Niobium": "Nb", "Molybdenum": "Mo", "Technetium": "Tc", "Ruthenium": "Ru", "Rhodium": "Rh", "Palladium": "Pd", "Silver": "Ag", "Cadmium": "Cd", "Indium": "In", "Tin": "Sn", "Antimony": "Sb", "Tellurium": "Te", "Iodine": "I", "Xenon": "Xe", "Cesium": "Cs", "Barium": "Ba", "Lanthanum": "La", "Cerium": "Ce", "Praseodymium": "Pr", "Neodymium": "Nd", "Promethium": "Pm", "Samarium": "Sm", "Europium": "Eu", "Gadolinium": "Gd", "Terbium": "Tb", "Dysprosium": "Dy", "Holmium": "Ho", "Erbium": "Er", "Thulium": "Tm", "Ytterbium": "Yb", "Lutetium": "Lu", "Hafnium": "Hf", "Tantalum": "Ta", "Tungsten": "W", "Rhenium": "Re", "Osmium": "Os", "Iridium": "Ir", "Platinum": "Pt", "Gold": "Au", "Mercury": "Hg", "Thallium": "Tl", "Lead": "Pb", "Bismuth": "Bi", "Polonium": "Po", "Astatine": "At", "Radon": "Rn", "Francium": "Fr", "Radium": "Ra", "Actinium": "Ac", "Thorium": "Th", "Protactinium": "Pa", "Uranium": "U", "Neptunium": "Np", "Plutonium": "Pu", "Americium": "Am", "Curium": "Cm", "Berkelium": "Bk", "Californium": "Cf", "Einsteinium": "Es", "Fermium": "Fm", "Mendelevium": "Md", "Nobelium": "No", "Lawrencium": "Lr", "Rutherfordium": "Rf", "Dubnium": "Db", "Seaborgium": "Sg", "Bohrium": "Bh", "Hassium": "Hs", "Meitnerium": "Mt", "Darmstadtium": "Ds", "Roentgenium": "Rg", "Copernicium": "Cn", "Nihonium": "Nh", "Flerovium": "Fl", "Moscovium": "Mc", "Livermorium": "Lv", "Tennessine": "Ts", "Oganesson": "Og" } return element_dic def merged_or_not(self): flag = self.ui.mergeBox.isChecked() if flag: sqlmerge = "NUM_RECORDS NOT LIKE 'NONE'" else: sqlmerge = "NUM_RECORDS LIKE 'NONE'" return flag, sqlmerge @pyqtSlot() def on_homeButton_clicked(self): self.tabModel.setFilter("NUM_RECORDS LIKE 'NONE'") self.ui.mergeBox.setChecked(False) @pyqtSlot() def on_mergeButton_clicked(self): self.tabModel.setFilter("NUM_RECORDS NOT LIKE 'NONE'") self.ui.mergeBox.setChecked(True) @pyqtSlot() def on_searchButton_clicked(self): searchtext = self.ui.searchInput.text() searchclass = self.ui.searchClass.currentText() matchtype = self.ui.matchType.currentText() flag, sqlmerge = self.merged_or_not() if searchclass == "DOI": if matchtype == "Exact Match": self.tabModel.setFilter("DOI LIKE '%s' AND %s" % (searchtext, sqlmerge)) elif matchtype == "Generic Match": self.tabModel.setFilter("DOI LIKE '%%%s%%' AND %s" % (searchtext, sqlmerge)) if self.tabModel.rowCount() == 0: self.tabModel.setFilter("") QMessageBox.warning( self, "Warning", "No such DOIs in the database. Please search new DOI.") elif searchclass == "Warning": if matchtype == "Exact Match": self.tabModel.setFilter("WARNING LIKE '%s' AND %s" % (searchtext, sqlmerge)) elif matchtype == "Generic Match": self.tabModel.setFilter("WARNING LIKE '%%%s%%' AND %s" % (searchtext, sqlmerge)) if self.tabModel.rowCount() == 0: self.tabModel.setFilter("") QMessageBox.warning( self, "Warning", "No such DOIs in the database. Please search new DOI.") elif searchclass == 'Name': try: searchtext = self.get_elements()[searchtext.capitalize()] except BaseException: pass if matchtype == "Exact Match": if self.ui.radioBtnAll.isChecked(): self.tabModel.setFilter("%s LIKE '%s' " % (searchclass, searchtext)) elif self.ui.radioBtnVoltage.isChecked(): self.tabModel.setFilter( "%s LIKE '%s' AND PROPERTY LIKE 'VOLTAGE' AND %s" % (searchclass, searchtext, sqlmerge)) elif self.ui.radioBtnCapacity.isChecked(): self.tabModel.setFilter( "%s LIKE '%s' AND PROPERTY LIKE 'CAPACITY' AND %s" % (searchclass, searchtext, sqlmerge)) elif self.ui.radioBtnConductivity.isChecked(): self.tabModel.setFilter( "%s LIKE '%s' AND PROPERTY LIKE 'CONDUCTIVITY' AND %s" % (searchclass, searchtext, sqlmerge)) elif self.ui.radioBtnCoulombic.isChecked(): self.tabModel.setFilter( "%s LIKE '%s' AND PROPERTY LIKE 'COULOMBIC EFFICIENCY' AND %s " % (searchclass, searchtext, sqlmerge)) elif self.ui.radioBtnEnergy.isChecked(): self.tabModel.setFilter( "%s LIKE '%s' AND PROPERTY LIKE 'ENERGY'AND %s " % (searchclass, searchtext, sqlmerge)) elif matchtype == "Generic Match": if self.ui.radioBtnAll.isChecked(): self.tabModel.setFilter( "(EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s') AND %s" % (searchtext, searchtext, sqlmerge)) elif self.ui.radioBtnVoltage.isChecked(): self.tabModel.setFilter( "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s" % (searchtext, searchtext, sqlmerge)) elif self.ui.radioBtnCapacity.isChecked(): self.tabModel.setFilter( "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s" % (searchtext, searchtext, sqlmerge)) elif self.ui.radioBtnConductivity.isChecked(): self.tabModel.setFilter( "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s" % (searchtext, searchtext, sqlmerge)) elif self.ui.radioBtnCoulombic.isChecked(): self.tabModel.setFilter( "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s" % (searchtext, searchtext, sqlmerge)) elif self.ui.radioBtnEnergy.isChecked(): self.tabModel.setFilter( "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s" % (searchtext, searchtext, sqlmerge)) if self.tabModel.rowCount() == 0: self.tabModel.setFilter("") QMessageBox.warning( self, "Warning", "No such compounds in the database. Please search new compounds." ) # ============Picture Tab 1, Pie Chart===================== @pyqtSlot() # Draw the pie chart def on_btnDrawPieChart_clicked(self): self.draw_pieChart() @pyqtSlot(float) # Set holeSize def on_spinHoleSize_valueChanged(self, arg1): seriesPie = self.ui.chartViewPie.chart().series()[0] seriesPie.setHoleSize(arg1) @pyqtSlot(float) # Set pieSize def on_spinPieSize_valueChanged(self, arg1): seriesPie = self.ui.chartViewPie.chart().series()[0] seriesPie.setPieSize(arg1) @pyqtSlot(bool) # Set legend checkbox def on_chkBox_PieLegend_clicked(self, checked): self.ui.chartViewPie.chart().legend().setVisible(checked) def pie_data( self): # Return a list of property name and the number of property num_list = [] pro_list = [ "CAPACITY", "CONDUCTIVITY", "COULOMBIC EFFICIENCY", "ENERGY", "VOLTAGE" ] for i in range(len(pro_list)): query = QSqlQuery( db=self.DB, query= "SELECT COUNT(NAME) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'" % pro_list[i]) # Query database while query.next(): num_value = query.value(0) # Returned value for each query item = self.ui.treeWidget_2.topLevelItem(i) # The ith row # The 2nd column item.setText(1, str(num_value)) item.setTextAlignment(1, Qt.AlignHCenter) num_list.append(num_value) return pro_list, num_list def draw_pieChart(self): # Draw the pie chart chart = self.ui.chartViewPie.chart() chart.legend().setAlignment(Qt.AlignRight) # AlignRight,AlignBottom chart.removeAllSeries() # Delete all series seriesPie = QPieSeries() # Pie chart series seriesPie.setHoleSize(self.ui.spinHoleSize.value()) # Hole size seriesPie.setPieSize(self.ui.spinPieSize.value()) # Pie size sec_count = 5 # Number of properties seriesPie.setLabelsVisible(True) # Label pro, num = self.pie_data() for i in range(sec_count): seriesPie.append(pro[i], num[i]) seriesPie.setLabelsVisible(True) # Label # Pie hoverd when mouse selected seriesPie.hovered.connect(self.do_pieHovered) chart.addSeries(seriesPie) chart.setTitle("Proportion of data records for each property") font = QFont() font.setPointSize(12) font.setWeight(75) chart.setTitleFont(font) font = QFont() font.setPointSize(12) font.setBold(False) font.setWeight(35) legend = chart.legend() legend.setFont(font) # =========Picture tab 2. StackedBar========= @pyqtSlot() # Draw StackedBar def on_btnStackedBar_clicked(self): self.draw_stackedBar() @pyqtSlot() # Draw horizontal StackedBar def on_btnStackedBarH_clicked(self): self.draw_stackedBar(False) # Search button in the Stacked bar chart tab. Add name to the first column # of the table. @pyqtSlot() def on_searchButton_3_clicked(self): searchtext = self.ui.searchInput_3.text() current_index = self.ui.stackedWidget.topLevelItemCount() item_0 = QtWidgets.QTreeWidgetItem(self.ui.stackedWidget) item_0.setText(0, searchtext) @pyqtSlot() # Generate data using the input chemical names def on_generateButton_3_clicked(self): self.ui.zoominButton.setEnabled(True) self.ui.zoomoutButton.setEnabled(True) self.ui.originalButton.setEnabled(True) self.ui.btnStackedBar.setEnabled(True) # Stacked bar chart self.ui.btnStackedBarH.setEnabled(True) current_index = self.ui.stackedWidget.topLevelItemCount() chemical_list = [ self.ui.stackedWidget.topLevelItem(index).text(0) for index in range(current_index) ] # Get a list of the inputed chemical name pro_list = [ "CAPACITY", "CONDUCTIVITY", "COULOMBIC EFFICIENCY", "ENERGY", "VOLTAGE" ] for row, chemical in enumerate(chemical_list): for index, pro in enumerate(pro_list): query = QSqlQuery( db=self.DB, query= "SELECT SUM(NUM_RECORDS) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NAME LIKE '%s' " % (pro, chemical)) while query.next(): num_value = query.value(0) print(num_value) if num_value == "": num_value = 0 item = self.ui.stackedWidget.topLevelItem( row) # The row'th row item.setText(index + 1, str(num_value)) item.setTextAlignment(index + 1, Qt.AlignHCenter) @pyqtSlot() # Clear button def on_clearButton_3_clicked(self): self.ui.stackedWidget.clear() @pyqtSlot() # Zoom in def on_zoominButton_clicked(self): self.ui.chartViewStackedBar.chart().zoom(1.2) @pyqtSlot() # Zoom out def on_zoomoutButton_clicked(self): self.ui.chartViewStackedBar.chart().zoom(0.8) @pyqtSlot() # Reset original size def on_originalButton_clicked(self): self.ui.chartViewStackedBar.chart().zoomReset() def draw_stackedBar(self, isVertical=True): # Stacked bar chart chart = self.ui.chartViewStackedBar.chart() chart.removeAllSeries() # Remove all series chart.removeAxis(chart.axisX()) # remove axis chart.removeAxis(chart.axisY()) if isVertical: # Vertical chart.setTitle("Number of property records for each chemical ") chart.legend().setAlignment(Qt.AlignBottom) else: # Horizontal chart.setTitle("Number of property records for each chemical") chart.legend().setAlignment(Qt.AlignRight) # Create data sets setCapacity = QBarSet("Capacity") setConductivity = QBarSet("Conductivity") setCoulombic = QBarSet("Coulombic") setEnergy = QBarSet("Energy") setVoltage = QBarSet("Voltage") chemical_Count = self.ui.stackedWidget.topLevelItemCount() nameList = [] # Chemical lists for i in range(chemical_Count): item = self.ui.stackedWidget.topLevelItem(i) # print(item.text(1)) nameList.append(item.text(0)) setCapacity.append(float(item.text(1))) setConductivity.append(float(item.text(2))) setCoulombic.append(float(item.text(3))) setEnergy.append(float(item.text(4))) setVoltage.append(float(item.text(5))) # Create series if isVertical: seriesBar = QStackedBarSeries() else: seriesBar = QHorizontalStackedBarSeries() seriesBar.append(setCapacity) seriesBar.append(setConductivity) seriesBar.append(setCoulombic) seriesBar.append(setEnergy) seriesBar.append(setVoltage) seriesBar.setLabelsVisible(True) # Show labels for each bar seriesBar.setLabelsFormat("@value") seriesBar.setLabelsPosition(QAbstractBarSeries.LabelsCenter) seriesBar.setBarWidth(0.3) chart.addSeries(seriesBar) axisStud = QBarCategoryAxis() # Category axis axisStud.append(nameList) axisStud.setRange(nameList[0], nameList[chemical_Count - 1]) axisValue = QValueAxis() # Value axis # axisValue.setRange(0, 300) axisValue.setTitleText("Number of records") # axisValue.setTickCount(6) axisValue.applyNiceNumbers() if isVertical: chart.setAxisX(axisStud, seriesBar) chart.setAxisY(axisValue, seriesBar) else: chart.setAxisY(axisStud, seriesBar) chart.setAxisX(axisValue, seriesBar) for marker in chart.legend().markers(): # QLegendMarker lists marker.clicked.connect(self.do_LegendMarkerClicked) # =========Picture tab 3. Histogram========= @pyqtSlot(bool) # Show toolbar def on_gBoxHist_toolbar_2_clicked(self, checked): self.ui.widgetHist_2.setToolbarVisible(checked) @pyqtSlot() # Draw def on_histButton_clicked(self): self.__drawHist() def hist_data(self, pro): query = QSqlQuery( db=self.DB, query= "SELECT VALUE FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'" % pro) data = [] while query.next(): num_value = query.value(0) data.append(num_value) return data def __drawHist(self): # Histogram pro = self.ui.propertycomboBox_2.currentText() data = self.hist_data(pro) self.ui.widgetHist_2.figure.clear() # Clear figure ax = self.ui.widgetHist_2.figure.add_subplot(1, 1, 1) if pro == 'Capacity': M, bins, patches = ax.hist( [5000 if float(i) > 4999 else float(i) for i in data], bins='auto', color='darkgreen', alpha=0.5, rwidth=1) ax.set_xlim(0, 5001) # ax.set_ylim(0,15000) ax.tick_params(labelsize=12) ax.set_xticklabels(['0', '1000', '2000', '3000', '4000', '5000+']) ax.set_xlabel('Capacity (mAh/g)', fontsize=14) ax.set_ylabel('Frequency', fontsize=14) ax.set_title('Battery Capacity Distrbution', fontsize=14) ax.figure.canvas.draw() elif pro == "Voltage": count1 = [] for i in data: count1.append(float(i)) n, bins, patches = ax.hist(x=count1, bins='auto', range=(0, 8), color='r', alpha=0.5, rwidth=1) ax.set_xticklabels(['0', '1', '2', '3', '4', '5', '6', '7', '8+']) ax.set_xlim(0, 8) ax.tick_params(labelsize=12) ax.set_xlabel('Voltage (V)', fontsize=14) ax.set_ylabel('Frequency', fontsize=14) ax.set_title('Battery Voltage Distrbution', fontsize=14) ax.figure.canvas.draw() elif pro == "Energy": n, bins, patches = ax.hist( [3000 if float(i) > 2999 else float(i) for i in data], bins='auto', color='y', alpha=0.5, rwidth=1) ax.set_xticklabels( ['0', '500', '1000', '1500', '2000', '2500', '3000+']) ax.set_xlim(0, 3001) ax.tick_params(labelsize=12) ax.set_xlabel('Energy (Wh/kg)', fontsize=14) ax.set_ylabel('Frequency', fontsize=14) ax.set_title('Battery Energy Distrbution', fontsize=14) ax.figure.canvas.draw() elif pro == "Coulombic Efficiency": dataplot = [float(i) for i in data] n, bins, patches = ax.hist(x=dataplot, bins='auto', color='c', alpha=0.5, rwidth=1) ax.set_xlim(0, 100) ax.tick_params(labelsize=12) ax.set_xlabel('Coulombic Effciency (%)', fontsize=14) ax.set_ylabel('Frequency', fontsize=14) ax.set_title('Battery Coulombic Effciency Distrbution', fontsize=14) ax.figure.canvas.draw() elif pro == "Conductivity": dataplot = [float(i) for i in data] n, bins, patches = ax.hist(x=dataplot, bins=np.logspace( np.log10(1e-15), np.log10(1)), color='k', alpha=0.5, rwidth=1) ax.set_xlim(1e-20, 10) ax.set_xscale('log') ax.tick_params(labelsize=12) ax.set_xlabel('log10 (Conductivity (S/cm))', fontsize=14) ax.set_ylabel('Frequency', fontsize=14) ax.set_title('Battery Conductivity Distrbution', fontsize=14) ax.figure.canvas.draw() # =========Picture tab 4. Venn diagram========= @pyqtSlot() # Draw def on_btnVenn_clicked(self): self.__drawVenn() @pyqtSlot(bool) # Show toolbar def on_gBoxHist_toolbar_3_clicked(self, checked): self.ui.widgetVenn.setToolbarVisible(checked) def __drawVenn(self): self.ui.widgetVenn.figure.clear() # Clear figure pro_list = [ "Capacity", "Conductivity", "Coulombic Efficiency", "Energy", "Voltage" ] data_dic = {} color_dic = dict(zip(pro_list, ['C0', 'C2', 'C6', 'C8', 'C9'])) for i in pro_list: query = QSqlQuery( db=self.DB, query= "SELECT COUNT(DISTINCT NAME) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'" % i) while query.next(): num_value = query.value(0) data_dic[i] = num_value for i, combo in enumerate(itertools.combinations(pro_list, 2)): query = QSqlQuery( db=self.DB, query= "SELECT COUNT() FROM (SELECT DISTINCT NAME AS PRO1 FROM BATTERY WHERE PROPERTY LIKE '%s'AND NUM_RECORDS LIKE 'NONE') INNER JOIN (SELECT DISTINCT NAME AS PRO2 FROM BATTERY WHERE PROPERTY LIKE '%s'AND NUM_RECORDS LIKE 'NONE') ON PRO1 = PRO2" % combo) while query.next(): num = query.value(0) x3 = num x1 = data_dic[combo[0]] - x3 x2 = data_dic[combo[1]] - x3 hf = self.ui.widgetVenn.figure # hf.set_figheight(30) # hf.set_figwidth(30) # print(dir(hf)) hf.set_size_inches((10, 10)) ax1 = hf.add_subplot(5, 2, i + 1) v = venn2(subsets=(x1, x2, x3), set_labels=(combo[0], combo[1]), ax=ax1) v.get_patch_by_id('A').set_alpha(1) v.get_patch_by_id('A').set_color(color_dic[combo[0]]) v.get_patch_by_id('B').set_color(color_dic[combo[1]]) ax1.figure.canvas.draw() # =============Self-defined slot function=============================== # Update the conditions of actPost and actCancel def do_currentChanged(self, current, previous): self.ui.actSubmit.setEnabled( self.tabModel.isDirty()) # Use when not saving changes self.ui.actRevert.setEnabled(self.tabModel.isDirty()) def do_currentRowChanged(self, current, previous): # Control during row changes self.ui.actRecDelete.setEnabled(current.isValid()) # Update current row index of mapping self.mapper.setCurrentIndex(current.row()) # Get current record,QSqlRecord curRec = self.tabModel.record(current.row()) def do_pieHovered(self, pieSlice, state): # Mouse move in and out in the pie chart pieSlice.setExploded(state) # Pop-up animation if state: # Show the tab of percentages self.__oldLabel = pieSlice.label() # Save original labels pieSlice.setLabel(self.__oldLabel + ": %.1f%%" % (pieSlice.percentage() * 100)) font = QFont() font.setPointSize(10) font.setBold(False) font.setWeight(25) pieSlice.setLabelFont(font) else: # show original labels pieSlice.setLabel(self.__oldLabel) font = QFont() font.setPointSize(10) font.setBold(False) font.setWeight(25) pieSlice.setLabelFont(font) def do_LegendMarkerClicked(self): # Click legend marker marker = self.sender() # QLegendMarker marker.series().setVisible(not marker.series().isVisible()) marker.setVisible(True) alpha = 1.0 if not marker.series().isVisible(): alpha = 0.5 brush = marker.labelBrush() # QBrush color = brush.color() # QColor color.setAlphaF(alpha) brush.setColor(color) marker.setLabelBrush(brush) brush = marker.brush() color = brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setBrush(brush) pen = marker.pen() # QPen color = pen.color() color.setAlphaF(alpha) pen.setColor(color) marker.setPen(pen)
class MyMainWindow(VCPMainWindow): """Main window class for the VCP.""" def __init__(self, *args, **kwargs): super(MyMainWindow, self).__init__(*args, **kwargs) self.threadFormFwdBtn.clicked.connect(self.threadFormFwd) self.threadFormBackBtn.clicked.connect(self.threadFormBack) self.threadClassFwdBtn.clicked.connect(self.threadClassFwd) self.threadClassBackBtn.clicked.connect(self.threadClassBack) self.threadSizeFwdBtn.clicked.connect(self.threadSizeFwd) self.threadSizeBackBtn.clicked.connect(self.threadSizeBack) self.sptmSizeFwdBtn.clicked.connect(self.sptmSizeFwd) self.sptmSizeBackBtn.clicked.connect(self.sptmSizeBack) self.drillSizeFwdBtn.clicked.connect(self.drillSizeFwd) self.drillSizeBackBtn.clicked.connect(self.drillSizeBack) self.numPassesSP.valueChanged.connect(self.numPassesCalc) self.holeDiaSb.valueChanged.connect(self.holeDiaCalc) self.linearFeedSb.valueChanged.connect(self.linearFeedCalc) self.genGcodeBtn.clicked.connect(self.genGcode) self.threadCountSb.valueChanged.connect(self.threadHeightCalc) self.testFwdBtn.clicked.connect(self.testFwd) self.testBackBtn.clicked.connect(self.testBack) self.saveFilePb.clicked.connect(self.saveFile) if not self.open_db(): print('Failed to Open Database') self.sptmSizeInit() self.threadFormInit() self.numPassesCalc() def open_db(self): db = QSqlDatabase.addDatabase('QSQLITE') db.setDatabaseName(current_path + 'threads.db') db.open() return db def threadFormInit(self): self.formMapper = QDataWidgetMapper(self) self.formModel = QSqlQueryModel(self) self.formModel.setQuery('SELECT DISTINCT form FROM internal_threads') self.formMapper.setModel(self.formModel) self.formMapper.addMapping(self.threadFormLbl, 0, b'text') self.formMapper.toLast() self.formsLast = self.formMapper.currentIndex() self.formMapper.toFirst() self.threadClassInit() def threadFormFwd(self): if self.formMapper.currentIndex() != self.formsLast: self.formMapper.toNext() else: self.formMapper.toFirst() self.threadClassInit() def threadFormBack(self): if self.formMapper.currentIndex() != 0: self.formMapper.toPrevious() else: self.formMapper.toLast() self.threadClassInit() def threadClassInit(self): self.classMapper = QDataWidgetMapper(self) self.classModel = QSqlQueryModel(self) form = self.threadFormLbl.text() classSelect = "SELECT DISTINCT class FROM internal_threads \ WHERE form = '{}'".format(form) self.classModel.setQuery(classSelect) self.classMapper.setModel(self.classModel) self.classMapper.addMapping(self.threadClassLbl, 0, b'text') self.classMapper.toLast() self.classLast = self.classMapper.currentIndex() self.classMapper.toFirst() self.threadSizeInit() def threadClassFwd(self): if self.classMapper.currentIndex() != self.classLast: self.classMapper.toNext() else: self.classMapper.toFirst() self.threadSizeInit(self.sizeMapper.currentIndex()) def threadClassBack(self): if self.classMapper.currentIndex() != 0: self.classMapper.toPrevious() else: self.classMapper.toLast() self.threadSizeInit(self.sizeMapper.currentIndex()) def threadSizeInit(self, index = 0): self.sizeMapper = QDataWidgetMapper(self) self.sizeModel = QSqlQueryModel(self) form = self.threadFormLbl.text() threadClass = self.threadClassLbl.text() sizeSelect = "SELECT size, pitch, major_dia, \ min_major_dia, max_minor_dia, min_minor_dia, \ max_pitch_dia, min_pitch_dia FROM internal_threads WHERE form \ = '{}' AND class = '{}'".format(form, threadClass) self.sizeModel.setQuery(sizeSelect) self.sizeMapper.setModel(self.sizeModel) self.sizeMapper.addMapping(self.threadSizeLbl, 0, b'text') self.sizeMapper.addMapping(self.threadTPILbl, 1, b'text') self.sizeMapper.addMapping(self.threadMajorDiaLbl, 2, b'text') self.sizeMapper.addMapping(self.minMajorDiaLbl, 3, b'text') self.sizeMapper.addMapping(self.maxMinorDiaLbl, 4, b'text') self.sizeMapper.addMapping(self.minMinorDiaLbl, 5, b'text') self.sizeMapper.addMapping(self.maxPitchDiaLbl, 6, b'text') self.sizeMapper.addMapping(self.minPitchDiaLbl, 7, b'text') self.sizeMapper.toLast() self.sizeLast = self.sizeMapper.currentIndex() self.sizeMapper.setCurrentIndex(index) self.drillSizeInit() self.threadSizeCalc() self.numPassesCalc() self.threadHeightCalc() def threadSizeFwd(self): if self.sizeMapper.currentIndex() != self.sizeLast: self.sizeMapper.toNext() else: self.sizeMapper.toFirst() self.drillSizeInit() self.threadSizeCalc() self.numPassesCalc() self.threadHeightCalc() def threadSizeBack(self): if self.sizeMapper.currentIndex() != 0: self.sizeMapper.toPrevious() else: self.sizeMapper.toLast() self.drillSizeInit() self.threadSizeCalc() self.numPassesCalc() self.threadHeightCalc() def threadSizeCalc(self): # PDO calculations threadMajorDia = float(self.threadMajorDiaLbl.text()) drillDia = float(self.holeDiaSb.value()) standardPDO = threadMajorDia - drillDia self.sptmThreadingPDOLbl.setText('{:.04f}'.format(standardPDO)) # Actual thread height = 1/2 PDO threadHeightStandard = standardPDO / 2 self.threadHeightStdLbl.setText('{:.04f}'.format(threadHeightStandard)) threadTrangleHeight = threadHeightStandard / 0.625 self.threadTriangleHeightLbl.setText('{:.04f}'.format(threadTrangleHeight)) threadPushOutAdj = threadTrangleHeight * 0.125 self.threadPushOutAdjLbl.setText('{:.04f}'.format(threadPushOutAdj)) threadPDOAdjustOut = threadPushOutAdj * 2 self.threadPDOAdjustOutLbl.setText('{:.04f}'.format(threadPDOAdjustOut)) # -2*(Crest*(SQRT(3)/2)) sptmCrest = float(self.sptmCrestLbl.text()) threadPDOCrestAdj = -2 * (sptmCrest * (sqrt(3)/2)) self.threadPDOCrestAdjLbl.setText('{:.04f}'.format(threadPDOCrestAdj)) finalPDO = standardPDO + threadPDOAdjustOut + threadPDOCrestAdj self.threadFinalPDOLbl.setText('{:.04f}'.format(finalPDO)) # if final PDO is greater than tip height check if self.sptmTipHeight > finalPDO: self.sptmTipOkLbl.setText('OK') else: self.sptmTipOkLbl.setText('Tip Too Small') # set maximum number of threads threadTPI = float(self.threadTPILbl.text()) threadPitch = 1.0 / threadTPI maxDepth = float(self.sptmMaxDepthLbl.text()) maxThreads = int(maxDepth / threadPitch) def sptmSizeInit(self): self.sptmMapper = QDataWidgetMapper(self) self.sptmModel = QSqlQueryModel(self) self.sptmModel.setQuery('SELECT * FROM sptm') self.sptmMapper.setModel(self.sptmModel) self.sptmMapper.addMapping(self.sptmSizeLbl, 0, b'text') self.sptmMapper.addMapping(self.sptmDiaLbl, 1, b'text') self.sptmMapper.addMapping(self.sptmCrestLbl, 2, b'text') self.sptmMapper.addMapping(self.sptmMaxDepthLbl, 3, b'text') self.sptmMapper.addMapping(self.sptmFlutesLbl, 4, b'text') self.sptmMapper.addMapping(self.sptmNeckDiaLbl, 5, b'text') self.sptmMapper.toLast() self.sptmLast = self.sptmMapper.currentIndex() self.sptmMapper.toFirst() def sptmSizeFwd(self): if self.sptmMapper.currentIndex() != self.sptmLast: self.sptmMapper.toNext() else: self.sptmMapper.toFirst() self.sptmCalc() def sptmSizeBack(self): if self.sptmMapper.currentIndex() != 0: self.sptmMapper.toPrevious() else: self.sptmMapper.toLast() self.sptmCalc() def sptmCalc(self): drillDiameter = float(self.holeDiaSb.value()) sptmCutterDia = float(self.sptmDiaLbl.text()) if sptmCutterDia < drillDiameter: self.sptmDiaOkLbl.setText('Ok') else: self.sptmDiaOkLbl.setText('TOO BIG!') sptmNeckDia = float(self.sptmNeckDiaLbl.text()) self.sptmTipHeight = sptmCutterDia - sptmNeckDia self.sptmTipHeightLbl.setText('{:.4f}'.format(self.sptmTipHeight)) def drillSizeInit(self): self.drillMapper = QDataWidgetMapper(self) self.drillQueryModel = QSqlQueryModel(self) minMinorDia = str(self.minMinorDiaLbl.text()) maxMinorDia = str(self.maxMinorDiaLbl.text()) drillSelect = "SELECT * FROM drills WHERE dia >= '{}' \ AND dia <= '{}'".format(minMinorDia, maxMinorDia) self.drillQueryModel.setQuery(drillSelect) self.drillMapper.setModel(self.drillQueryModel) self.drillMapper.addMapping(self.drillTypeLbl, 0, b'text') self.drillMapper.addMapping(self.drillSizeLbl, 1, b'text') self.drillMapper.addMapping(self.drillDiaLbl, 2, b'text') self.drillMapper.toLast() self.drillLast = self.drillMapper.currentIndex() self.drillMapper.toFirst() # setup hole dia spinbox self.holeDiaSb.setMinimum(float(self.minMinorDiaLbl.text())) self.holeDiaSb.setMaximum(float(self.maxMinorDiaLbl.text())) # setup pitch dia spinbox self.pitchDiaSb.setMinimum(float(self.minPitchDiaLbl.text())) self.pitchDiaSb.setMaximum(float(self.maxPitchDiaLbl.text())) self.sptmCalc() self.threadPercent() def drillSizeFwd(self): if self.drillMapper.currentIndex() != self.drillLast: self.drillMapper.toNext() else: self.drillMapper.toFirst() self.sptmCalc() self.threadPercent() self.threadSizeCalc() def drillSizeBack(self): if self.drillMapper.currentIndex() != 0: self.drillMapper.toPrevious() else: self.drillMapper.toLast() self.sptmCalc() self.threadPercent() self.threadSizeCalc() def threadPercent(self): majorDia = float(self.threadMajorDiaLbl.text()) minorDia = float(self.drillDiaLbl.text()) # note for metric convert to TPI threadPitch = float(self.threadTPILbl.text()) threadEngagement = ((majorDia - minorDia) * threadPitch) / 0.01299 self.threadPercentLbl.setText('{:.0f}%'.format(threadEngagement)) def threadHeightCalc(self): pitch = 1.0 / float(self.threadTPILbl.text()) height = self.threadCountSb.value() * pitch self.threadsHeight.setText('{:.4f}"'.format(height)) def numPassesCalc(self): majorDia = float(self.threadMajorDiaLbl.text()) minorDia = float(self.holeDiaSb.value()) threadDepth = (majorDia - minorDia) if self.numPassesSP.value() == 1: self.passDiaLbl_0.setText('{:.4f}'.format(majorDia)) self.passDiaLbl_1.setText('') self.passDiaLbl_2.setText('') self.passDiaLbl_3.setText('') self.passPercentLbl_1.setText('100%') self.passPercentLbl_2.setText('') self.passPercentLbl_3.setText('') self.passPercentLbl_4.setText('') if self.numPassesSP.value() == 2: self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.65))) self.passDiaLbl_1.setText('{:.4f}'.format(majorDia)) self.passDiaLbl_2.setText('') self.passDiaLbl_3.setText('') self.passPercentLbl_1.setText('65%') self.passPercentLbl_2.setText('35%') self.passPercentLbl_3.setText('') self.passPercentLbl_4.setText('') if self.numPassesSP.value() == 3: self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.50))) self.passDiaLbl_1.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.80))) self.passDiaLbl_2.setText('{:.4f}'.format(majorDia)) self.passDiaLbl_3.setText('') self.passPercentLbl_1.setText('50%') self.passPercentLbl_2.setText('30%') self.passPercentLbl_3.setText('20%') self.passPercentLbl_4.setText('') if self.numPassesSP.value() == 4: self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.40))) self.passDiaLbl_1.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.67))) self.passDiaLbl_2.setText('{:.4f}'.format(minorDia \ + (threadDepth * 0.87))) self.passDiaLbl_3.setText('{:.4f}'.format(majorDia)) self.passPercentLbl_1.setText('40%') self.passPercentLbl_2.setText('27%') self.passPercentLbl_3.setText('20%') self.passPercentLbl_4.setText('13%') def holeDiaCalc(self): majorDia = float(self.threadMajorDiaLbl.text()) minorDia = self.holeDiaSb.value() # note for metric convert to TPI threadPitch = float(self.threadTPILbl.text()) threadEngagement = ((majorDia - minorDia) * threadPitch) / 0.01299 self.threadPerLbl.setText('{:.1f}%'.format(threadEngagement)) def genGcode(self): # make sure your using the hole size as the starting point self.gcodeText.setPlainText("; JT's Thread Mill Wizard") self.gcodeText.append('; Thread {}'.format(self.threadSizeLbl.text())) self.gcodeText.append('F25') xCoord = self.xCoord.text() yCoord = self.yCoord.text() self.gcodeText.append('G0 X{} Y{} Z0.125'.format(xCoord, yCoord)) zStart = self.zStart.text() pitch = 1.0 / float(self.threadTPILbl.text()) threadsHeight = (self.threadCountSb.value() + 1) * pitch zEnd = float(zStart) + threadsHeight self.gcodeText.append('G1 Z{}'.format(zEnd)) self.gcodeText.append('G91') self.gcodeText.append('; Number of thread passes {}' \ .format(self.numPassesSP.value())) for i in range(self.numPassesSP.value()): passDiameter = float(getattr(self, 'passDiaLbl_' + str(i)).text()) # go to hole bottom threadTPI = float(self.threadTPILbl.text()) threadPitch = 1.0 / threadTPI self.gcodeText.append('G0 Z-{}'.format(threadsHeight)) # go to start of lead in arc cutterClearance = 0.020 minorDia = float(self.holeDiaSb.value()) toolDia = float(self.sptmDiaLbl.text()) yStartLeadIn = -((minorDia - (cutterClearance * 2)) - toolDia) / 2 self.gcodeText.append('G1 Y{:.4f}'.format(yStartLeadIn)) # lead in arc sptmCutterDia = float(self.sptmDiaLbl.text()) leadInYEnd = ((passDiameter - sptmCutterDia) / 2) + abs(yStartLeadIn) leadInZEnd = threadPitch / 2 leadInJOffset = leadInYEnd / 2 self.gcodeText.append('G3 X0.0 Y{:.4f} Z{:.4f} J{:.4f}' \ .format(leadInYEnd, leadInZEnd, leadInJOffset)) # spiral up threadCount = int(self.threadCountSb.text()) finalZ = threadPitch * threadCount jOffset = -(passDiameter - sptmCutterDia) / 2 self.gcodeText.append('G3 J{} Z{} P{}'. \ format(jOffset, finalZ, threadCount)) # lead out arc leadOutYEnd = -((passDiameter - sptmCutterDia) / 2) - abs(yStartLeadIn) leadOutZEnd = threadPitch / 2 leadOutJOffset = -(leadInYEnd / 2) self.gcodeText.append('G3 X0.0 Y{:.4f} Z{:.4f} J{:.4f}' \ .format(leadOutYEnd, leadOutZEnd, leadOutJOffset)) # go to center yCenter = ((minorDia - (cutterClearance * 2)) - toolDia) / 2 self.gcodeText.append('G1 Y{:.4f}'.format(yCenter)) self.gcodeText.append('G90') #self.gcodeText.append('G0 X2 Y2') self.gcodeText.append('M2') def linearFeedCalc(self): # Internal Threads # Linear feed * ((Major thread dia - Tool dia) / Major thread dia) minorDia = float(self.holeDiaSb.value()) majorDia = float(self.threadMajorDiaLbl.text()) cutterDia = float(self.sptmDiaLbl.text()) linearFeed = self.linearFeedSb.value() circularFeed = ((majorDia - cutterDia) / majorDia) * linearFeed self.circularFeedLbl.setText('{:.1f}'.format(circularFeed)) def testFwd(self): self.gcodeText.append('line du') def testBack(self): pass def saveFile(self): ngcFile = os.path.join(os.getenv("HOME"), 'linuxcnc/nc_files', 'jt.ngc') with open(ngcFile, 'w') as f: f.write(str(self.gcodeText.toPlainText())) """
class StudentEditView(QWidget, Ui_FormEditDeleteStudent): def __init__(self, student_model, student_controller, main_window): super().__init__() self.setupUi(self) self.student_model: StudentModel = student_model self.student_controller: StudentController = student_controller self.main_window: MainWindowView = main_window self.mapper = QDataWidgetMapper() self.set_student_editor() def show_editor(self, s=None): i = self.is_selected() if i & i >= 0: self.mapper.setCurrentIndex(i) self.show() def clear_fields(self): self.lineEditStudentID.clear() self.lineEditStudentAge.clear() self.lineEditStudentName.clear() self.lineEditStudentGrade.clear() def is_selected(self, s=None) -> int: # print(self.selection_model.hasSelection()) # print(self.selection_model.isRowSelected(0)) index = self.main_window.tblStudents.selectionModel().currentIndex( ).row() return index def set_student_editor(self, index=0): self.btnEditStudentPrevious.clicked.connect(self.mapper.toPrevious) self.btnEditStudentNext.clicked.connect(self.mapper.toNext) self.btnEditStudentSave.clicked.connect(self.update_button_action) self.btnEditStudentDelete.clicked.connect(self.delete_button_action) self.mapper.setModel(self.main_window.student_sql_query_model) self.mapper.addMapping(self.lineEditStudentID, 0) self.mapper.addMapping(self.lineEditStudentName, 1) self.mapper.addMapping(self.lineEditStudentGrade, 2) self.mapper.addMapping(self.lineEditStudentAge, 3) # self.set_student_table(self.model) # if index > 0: # self.mapper.setCurrentIndex(index) self.mapper.toFirst() def update_button_action(self, saved): student_id = int(self.lineEditStudentID.text()) student_name = self.lineEditStudentName.text() student_grade = self.lineEditStudentGrade.text() student_age = self.lineEditStudentAge.text() student: Student = Student(student_name, student_age, student_grade) self.student_controller.update_student(student, student_id) def delete_button_action(self): dialog_alert_view: DialogAlertView = DialogAlertView() student_id = int(self.lineEditStudentID.text()) dialog_alert_view.show_dialog(True, 4) self.student_controller.delete_student(student_id)
class Soduku(QtWidgets.QMainWindow, soduku_window.Ui_MainWindow): def __init__(self, parent=None): super(Soduku, self).__init__(parent) self.setupUi(self) self.pushButton_2.clicked.connect(self.solve) self.initLine() self.colums = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] self.progressBar.setMaximum(100) self.progressBar.setMinimum(0) self.progressBar.setValue(0) # self.progressBar.hide() self.pushButton.clicked.connect(self.clear) data = {} for column in self.colums: data[column] = [ v for k, v in sorted({ x.objectName(): x.text() for x in self.findChildren(QtWidgets.QLineEdit, QtCore.QRegExp(f"{column}")) }.items()) ] self.df = pd.DataFrame.from_dict(json.load(open("test.json"))) # self.df = pd.DataFrame.from_dict(data, dtype="int") self.model = manager(self.df) self.mapperA = QDataWidgetMapper() self.mapperA.setModel(self.model) self.mapperA.setCurrentIndex(0) self.mapperA.addMapping(self.A1, 0) self.mapperA.addMapping(self.B1, 1) self.mapperA.addMapping(self.C1, 2) self.mapperA.addMapping(self.D1, 3) self.mapperA.addMapping(self.E1, 4) self.mapperA.addMapping(self.F1, 5) self.mapperA.addMapping(self.G1, 6) self.mapperA.addMapping(self.H1, 7) self.mapperA.addMapping(self.I1, 8) self.mapperB = QDataWidgetMapper() self.mapperB.setModel(self.model) self.mapperB.setCurrentIndex(1) self.mapperB.addMapping(self.A2, 0) self.mapperB.addMapping(self.B2, 1) self.mapperB.addMapping(self.C2, 2) self.mapperB.addMapping(self.D2, 3) self.mapperB.addMapping(self.E2, 4) self.mapperB.addMapping(self.F2, 5) self.mapperB.addMapping(self.G2, 6) self.mapperB.addMapping(self.H2, 7) self.mapperB.addMapping(self.I2, 8) self.mapperC = QDataWidgetMapper() self.mapperC.setModel(self.model) self.mapperC.setCurrentIndex(2) self.mapperC.addMapping(self.A3, 0) self.mapperC.addMapping(self.B3, 1) self.mapperC.addMapping(self.C3, 2) self.mapperC.addMapping(self.D3, 3) self.mapperC.addMapping(self.E3, 4) self.mapperC.addMapping(self.F3, 5) self.mapperC.addMapping(self.G3, 6) self.mapperC.addMapping(self.H3, 7) self.mapperC.addMapping(self.I3, 8) self.mapperD = QDataWidgetMapper() self.mapperD.setModel(self.model) self.mapperD.setCurrentIndex(3) self.mapperD.addMapping(self.A4, 0) self.mapperD.addMapping(self.B4, 1) self.mapperD.addMapping(self.C4, 2) self.mapperD.addMapping(self.D4, 3) self.mapperD.addMapping(self.E4, 4) self.mapperD.addMapping(self.F4, 5) self.mapperD.addMapping(self.G4, 6) self.mapperD.addMapping(self.H4, 7) self.mapperD.addMapping(self.I4, 8) self.mapperE = QDataWidgetMapper() self.mapperE.setModel(self.model) self.mapperE.setCurrentIndex(4) self.mapperE.addMapping(self.A5, 0) self.mapperE.addMapping(self.B5, 1) self.mapperE.addMapping(self.C5, 2) self.mapperE.addMapping(self.D5, 3) self.mapperE.addMapping(self.E5, 4) self.mapperE.addMapping(self.F5, 5) self.mapperE.addMapping(self.G5, 6) self.mapperE.addMapping(self.H5, 7) self.mapperE.addMapping(self.I5, 8) self.mapperF = QDataWidgetMapper() self.mapperF.setModel(self.model) self.mapperF.setCurrentIndex(5) self.mapperF.addMapping(self.A6, 0) self.mapperF.addMapping(self.B6, 1) self.mapperF.addMapping(self.C6, 2) self.mapperF.addMapping(self.D6, 3) self.mapperF.addMapping(self.E6, 4) self.mapperF.addMapping(self.F6, 5) self.mapperF.addMapping(self.G6, 6) self.mapperF.addMapping(self.H6, 7) self.mapperF.addMapping(self.I6, 8) self.mapperG = QDataWidgetMapper() self.mapperG.setModel(self.model) self.mapperG.setCurrentIndex(6) self.mapperG.addMapping(self.A7, 0) self.mapperG.addMapping(self.B7, 1) self.mapperG.addMapping(self.C7, 2) self.mapperG.addMapping(self.D7, 3) self.mapperG.addMapping(self.E7, 4) self.mapperG.addMapping(self.F7, 5) self.mapperG.addMapping(self.G7, 6) self.mapperG.addMapping(self.H7, 7) self.mapperG.addMapping(self.I7, 8) self.mapperH = QDataWidgetMapper() self.mapperH.setModel(self.model) self.mapperH.setCurrentIndex(7) self.mapperH.addMapping(self.A8, 0) self.mapperH.addMapping(self.B8, 1) self.mapperH.addMapping(self.C8, 2) self.mapperH.addMapping(self.D8, 3) self.mapperH.addMapping(self.E8, 4) self.mapperH.addMapping(self.F8, 5) self.mapperH.addMapping(self.G8, 6) self.mapperH.addMapping(self.H8, 7) self.mapperH.addMapping(self.I8, 8) self.mapperI = QDataWidgetMapper() self.mapperI.setModel(self.model) self.mapperI.setCurrentIndex(8) self.mapperI.addMapping(self.A9, 0) self.mapperI.addMapping(self.B9, 1) self.mapperI.addMapping(self.C9, 2) self.mapperI.addMapping(self.D9, 3) self.mapperI.addMapping(self.E9, 4) self.mapperI.addMapping(self.F9, 5) self.mapperI.addMapping(self.G9, 6) self.mapperI.addMapping(self.H9, 7) self.mapperI.addMapping(self.I9, 8) self.threadpool = QThreadPool() index1 = self.model.createIndex(0, 0) index2 = self.model.createIndex(8, 8) self.model.dataChanged.emit(index1, index2) self.view = QtWidgets.QTableView() self.view.setModel(self.model) def clear(self): self.model.clearData() def initLine(self): for child in self.findChildren(QtWidgets.QLineEdit): validator = NotEmptyValidator(child) child.setValidator(validator) def solve(self): self.start = time.time() # Do a easy solve solve = Solve(self.model._data) solve.signals.result.connect(self.result) solve.signals.finished.connect(self.finished) self.threadpool.start(solve) # If easy solved gave no solution, try to to guess one number and solve! def solve_2(self, dataframe): self.progressBar.show() solve2 = Solve2(dataframe) solve2.signals.result.connect(self.result2) solve2.signals.finished.connect(self.finished) solve2.signals.progress.connect(self.progress) self.threadpool.start(solve2) def progress(self, progress): self.progressBar.setValue(progress) def result(self, dataframe): print(dataframe) self.model._data = dataframe index1 = self.model.createIndex(0, 0) index2 = self.model.createIndex(8, 8) self.model.dataChanged.emit(index1, index2) if "" in dataframe.values: pass # If easy solved gave no solution, try to to guess one number and solve! # self.solve_2(dataframe) def result2(self, dataframe): self.model._data = dataframe index1 = self.model.createIndex(0, 0) index2 = self.model.createIndex(8, 8) self.model.dataChanged.emit(index1, index2) if "" in dataframe.values: self.progressBar.setTextVisible(True) self.progressBar.setFormat("Failed to solve current soduku") self.progressBar.setAlignment(Qt.AlignCenter) def finished(self): self.progressBar.setValue(100) self.progressBar.setFormat( f"Solved in {(time.time() - self.start):.2f} s ") self.progressBar.setAlignment(Qt.AlignCenter) def thread_complete(self): print("Done") def product_dict(self, inp): return (dict(zip(inp.keys(), values)) for values in product(*inp.values()))
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.splitter) self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.verticalHeader().setDefaultSectionSize(22) self.ui.tableView.horizontalHeader().setDefaultSectionSize(60) @pyqtSlot() def on_actOpenDB_triggered(self): dbFilename, flt = QFileDialog.getOpenFileName( self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)") if (dbFilename == ''): return self.DB = QSqlDatabase.addDatabase("QSQLITE") self.DB.setDatabaseName(dbFilename) if self.DB.open(): self.__openTable() else: QMessageBox.warning(self, "错误", "打开数据库失败") def __openTable(self): self.qryModel = QSqlQueryModel(self) self.qryModel.setQuery( '''SELECT empNo, Name, Gender, Birthday, Province, Department, Salary FROM employee ORDER BY empNo''' ) if self.qryModel.lastError().isValid(): QMessageBox.critical( self, "错误", "数据表查询错误,错误信息\n" + self.qryModel.lastError().text()) return self.ui.statusBar.showMessage("记录条数:%d" % self.qryModel.rowCount()) self.__getFieldNames() self.qryModel.setHeaderData(0, Qt.Horizontal, "工号") self.qryModel.setHeaderData(1, Qt.Horizontal, "姓名") self.qryModel.setHeaderData(2, Qt.Horizontal, "性别") self.qryModel.setHeaderData(3, Qt.Horizontal, "出生日期") self.qryModel.setHeaderData(4, Qt.Horizontal, "省份") self.qryModel.setHeaderData(5, Qt.Horizontal, "部门") self.qryModel.setHeaderData(6, Qt.Horizontal, "工资") self.mapper = QDataWidgetMapper() self.mapper.setModel(self.qryModel) self.mapper.addMapping(self.ui.dbSpinEmpNo, 0) self.mapper.addMapping(self.ui.dbEditName, 1) self.mapper.addMapping(self.ui.dbComboSex, 2) self.mapper.addMapping(self.ui.dbEditBirth, 3) self.mapper.addMapping(self.ui.dbComboProvince, 4) self.mapper.addMapping(self.ui.dbComboDep, 5) self.mapper.addMapping(self.ui.dbSpinSalary, 6) self.mapper.toFirst() self.selModel = QItemSelectionModel(self.qryModel) self.selModel.currentRowChanged.connect(self.do_currentRowChanged) self.ui.tableView.setModel(self.qryModel) self.ui.tableView.setSelectionModel(self.selModel) self.ui.actOpenDB.setEnabled(False) def __refreshTableView(self): index = self.mapper.currentIndex() curIndex = self.qryModel.index(index, 1) self.selModel.clearSelection() self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) def __getFieldNames(self): emptyRec = self.qryModel.record() self.fldNum = {} for i in range(emptyRec.count()): fieldName = emptyRec.fieldName(i) self.fldNum.setdefault(fieldName) self.fldNum[fieldName] = i print(self.fldNum) @pyqtSlot() def on_actRecFirst_triggered(self): self.mapper.toFirst() self.__refreshTableView() @pyqtSlot() def on_actRecPrevious_triggered(self): self.mapper.toPrevious() self.__refreshTableView() @pyqtSlot() def on_actRecNext_triggered(self): self.mapper.toNext() self.__refreshTableView() @pyqtSlot() def on_actRecLast_triggered(self): self.mapper.toLast() self.__refreshTableView() def do_currentRowChanged(self, current, previous): if (current.isValid() == False): self.ui.dbLabPhoto.clear() return self.mapper.setCurrentIndex(current.row()) first = (current.row() == 0) last = (current.row() == self.qryModel.rowCount() - 1) self.ui.actRecFirst.setEnabled(not first) self.ui.actRecPrevious.setEnabled(not first) self.ui.actRecNext.setEnabled(not last) self.ui.actRecLast.setEnabled(not last) curRec = self.qryModel.record(current.row()) empNo = curRec.value("EmpNo") query = QSqlQuery(self.DB) query.prepare( '''SELECT EmpNo, Memo, Photo FROM employee WHERE EmpNo = :ID''') query.bindValue(":ID", empNo) if not query.exec(): QMessageBox.critical(self, "错误", "执行SQL语句错误\n" + query.lastError().text()) return else: query.first() picData = query.value("Photo") if (picData == None): self.ui.dbLabPhoto.clear() else: pic = QPixmap() pic.loadFromData(picData) W = self.ui.dbLabPhoto.size().width() self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W)) memoData = query.value("Memo") self.ui.dbEditMemo.setPlainText(memoData)
class SignAnnounceWidget(QWidget): """Widget that displays information about signing a Masternode Announce.""" def __init__(self, parent): super(SignAnnounceWidget, self).__init__(parent) self.dialog = parent self.manager = parent.manager # Displays the status of the masternode. self.status_edit = QLineEdit() self.status_edit.setReadOnly(True) self.alias_edit = QLineEdit() self.collateral_edit = PrevOutWidget() self.delegate_edit = QLineEdit() self.delegate_edit.setFont(QFont(util.MONOSPACE_FONT)) for i in [self.alias_edit, self.collateral_edit, self.delegate_edit]: i.setReadOnly(True) self.mapper = QDataWidgetMapper() self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.dialog.masternodes_widget.proxy_model) model = self.dialog.masternodes_widget.model self.mapper.addMapping(self.alias_edit, model.ALIAS) self.mapper.addMapping(self.collateral_edit, model.VIN, b'string') self.mapper.addMapping(self.delegate_edit, model.DELEGATE) self.sign_button = QPushButton(_('Activate Masternode')) self.sign_button.setEnabled(False) self.sign_button.clicked.connect(self.sign_announce) status_box = QHBoxLayout() status_box.setContentsMargins(0, 0, 0, 0) status_box.addWidget(QLabel(_('Status:'))) status_box.addWidget(self.status_edit, stretch=1) vbox = QVBoxLayout() vbox.addLayout(status_box) form = QFormLayout() form.addRow(_('Alias:'), self.alias_edit) form.addRow(_('Collateral vestx Output:'), self.collateral_edit) form.addRow(_('Masternode Private Key:'), self.delegate_edit) vbox.addLayout(form) vbox.addLayout(util.Buttons(self.sign_button)) self.setLayout(vbox) def set_mapper_index(self, row): """Set the row that the data widget mapper should use.""" self.status_edit.clear() self.status_edit.setStyleSheet( util.ColorScheme.DEFAULT.as_stylesheet()) self.mapper.setCurrentIndex(row) mn = self.dialog.masternodes_widget.masternode_for_row(row) # Disable the sign button if the masternode can't be signed (for whatever reason). status_text = '%s can be activated' % mn.alias can_sign = True try: self.manager.check_can_sign_masternode(mn.alias) except Exception as e: status_text = str(e) can_sign = False self.status_edit.setText(_(status_text)) self.sign_button.setEnabled(can_sign) def sign_announce(self): """Set the masternode's vin and sign an announcement.""" self.mapper.submit() self.dialog.sign_announce(str(self.alias_edit.text()))
class EditForm(QWidget, Ui_EditForm): def __init__(self, current_index, model): super().__init__() # uic.loadUi('editForm.ui', self) self.setupUi(self) # self.db = database self.db_map = QDataWidgetMapper(self) self.db_map.setModel(model) self.db_map.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.db_map.addMapping(self.lineEdit_name, 1) self.db_map.addMapping(self.lineEdit_inv_number, 2) self.db_map.addMapping(self.textEdit_comments, 3) self.db_map.addMapping(self.checkBox_on_balance, model.fieldIndex('is_on_balance')) relModel_status = model.relationModel(5) self.comboBox_status.setModel(relModel_status) self.comboBox_status.setModelColumn( relModel_status.fieldIndex("status_name")) self.db_map.setItemDelegate(QSqlRelationalDelegate(self)) self.db_map.addMapping(self.comboBox_status, 5) relModel_type = model.relationModel(6) self.comboBox_type.setModel(relModel_type) self.comboBox_type.setModelColumn( relModel_type.fieldIndex("goods_type_name")) self.db_map.setItemDelegate(QSqlRelationalDelegate(self)) self.db_map.addMapping(self.comboBox_type, 6) relModel_subtype = model.relationModel(7) self.comboBox_subtype.setModel(relModel_subtype) self.comboBox_subtype.setModelColumn( relModel_subtype.fieldIndex("goods_subtype_name")) self.db_map.setItemDelegate(QSqlRelationalDelegate(self)) self.db_map.addMapping(self.comboBox_subtype, 7) relModel_location = model.relationModel(8) self.comboBox_location.setModel(relModel_location) self.comboBox_location.setModelColumn( relModel_location.fieldIndex("location_name")) self.db_map.setItemDelegate(QSqlRelationalDelegate(self)) self.db_map.addMapping(self.comboBox_location, 8) relModel_responsible = model.relationModel(9) self.comboBox_responsible.setModel(relModel_responsible) self.comboBox_responsible.setModelColumn( relModel_responsible.fieldIndex("FIO")) self.db_map.setItemDelegate(QSqlRelationalDelegate(self)) self.db_map.addMapping(self.comboBox_responsible, 9) self.pushBtn_save.clicked.connect(self.save_item) self.pushBtn_cancel.clicked.connect(self.cancel) self.pushBtn_next.clicked.connect(self.db_map.toNext) self.pushBtn_prev.clicked.connect(self.db_map.toPrevious) self.pushBtn_close.clicked.connect(self.close) self.db_map.setCurrentIndex(current_index.row()) def save_item(self): self.db_map.submit() def cancel(self): self.db_map.setCurrentIndex(self.db_map.currentIndex())