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)
Beispiel #3
0
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("")
Beispiel #4
0
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()))
Beispiel #5
0
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)
Beispiel #6
0
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()
Beispiel #7
0
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)
Beispiel #9
0
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
Beispiel #10
0
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))
Beispiel #11
0
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)
Beispiel #13
0
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)
Beispiel #14
0
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)
Beispiel #15
0
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))
Beispiel #16
0
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
Beispiel #18
0
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)
Beispiel #20
0
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)
Beispiel #21
0
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:&nbsp;Query&nbsp;the&nbsp;database&nbsp;according&nbsp;to&nbsp;data&nbsp;types&nbsp;and&nbsp;name&nbsp;or&nbsp;DOI.</h3>'
            '<ul>'
            '<li>Search&nbsp;the&nbsp;exact&nbsp;compound&nbsp;name&nbsp;in&nbsp;"<em>Exact&nbsp;Match</em>". Search&nbsp;the&nbsp;element&nbsp;or&nbsp;part&nbsp;of&nbsp;compound&nbsp;name&nbsp;in&nbsp;"<em>Generic&nbsp;Match</em>".&nbsp;</li>'
            '<li>Click the "<em>Home</em>" or "<em>All</em>" button to view the full database</li>'
            '<li>Refer&nbsp;to&nbsp;"<em>Correctness</em>"&nbsp;column&nbsp;for&nbsp;database&nbsp;evaluation&nbsp;details.&nbsp;</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:&nbsp;Statistical&nbsp;analysis&nbsp;of&nbsp;the&nbsp;database.</h3>'
            '<ul>'
            '<li><em>Pie&nbsp;chart</em>&nbsp;shows&nbsp;the&nbsp;proportion&nbsp;of&nbsp;data&nbsp;records.</li>'
            '<li><em>Stacked&nbsp;bar&nbsp;chart</em>&nbsp;shows&nbsp;the&nbsp;data&nbsp;types&nbsp;for&nbsp;each&nbsp;compound. First&nbsp;input&nbsp;the&nbsp;compound&nbsp;name,&nbsp;click&nbsp;"<em>Add</em>"&nbsp;and&nbsp;then&nbsp;"<em>Generate</em>"&nbsp;data&nbsp;for&nbsp;overview.&nbsp;</li>'
            '<li><em>Histogram&nbsp;</em>shows&nbsp;the&nbsp;distribution&nbsp;of&nbsp;each&nbsp;data&nbsp;type.</li>'
            '<li><em>Venn&nbsp;diagram</em>&nbsp;shows&nbsp;the&nbsp;correlation&nbsp;of&nbsp;each&nbsp;data&nbsp;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)
Beispiel #22
0
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()))

    """ 
Beispiel #23
0
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)
Beispiel #24
0
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()))
Beispiel #25
0
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)
Beispiel #26
0
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()))
Beispiel #27
0
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())