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 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 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 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 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 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()))