Пример #1
0
class cMainWindow(QMainWindow):
    def __init__(self):
        super(cMainWindow, self).__init__()
        loadUi('MainWindow.ui', self)
        self.mModel = Model.cModel()
        self.mainList.setModel( self.mModel )
        self.treeView.setModel( self.mModel )

        self.mMapper = QDataWidgetMapper()
        self.mMapper.setModel( self.mModel )
        self.mMapper.setOrientation( Qt.Vertical )
        self.mMapper.addMapping( self.nameLineEdit, 0)
        self.mMapper.addMapping( self.weaponComboBox, 1, b"currentText" )
        self.mMapper.addMapping( self.shiledSpinBox, 2)

        self.mainList.selectionModel().currentChanged.connect( self.CombattantSelected )

        self.shiledSpinBox.valueChanged.connect( self.SubmitToModel )
        self.weaponComboBox.currentIndexChanged.connect( self.SubmitToModel )

        weaponList = "Fist", "Dagger", "Sword", "Pike"
        self.weaponComboBox.addItems( weaponList )
    # --------------------------------


    def CombattantSelected(self, iIndex):
        self.mMapper.setRootIndex( iIndex )
        self.mMapper.toFirst()
    # --------------------------------


    def  SubmitToModel(self, iValue):
        self.mMapper.submit()
    # --------------------------------
Пример #2
0
def schema_ui_map(schema, model, form):
    """Construct a QDataWidgetMapper from the given ``schema`` class.
    (Function 4)

    :param schema: The schema to create field-to-widget mappings from.
    :param model: The model that the QDataWidgetMapper observes.
    :param form: The UI widget containing stuff to bind to. It is also set as
                 the parent for the widget mapper.
    """
    assert isinstance(model, QAbstractItemModel)
    mapper = QDataWidgetMapper(form)
    mapper.setModel(model)

    s = schema()

    for i, (name, field) in enumerate(s.fields.items()):
        try:
            widget_classes = _widget_type(type(field))
            widget = form.findChild(widget_classes, name)
            if not widget:
                raise ValueError
            prop = _widget_property(type(widget))
            log.debug("adding map from (`%s', col = %d) to %s (prop = `%s')",
                      name, i, widget, prop)
            mapper.addMapping(widget, i, bytes(prop, encoding='utf8'))
            assert mapper.mappedWidgetAt(i) == widget
        except KeyError:
            log.error("unknown field type %s", type(field))
        except ValueError:  # FIXME: is this the correct exception type?
            log.error("failed to find widget for field `%s'", name)

    mapper.toFirst()
    return mapper
Пример #3
0
    def __init__(self, tag_number):
        super().__init__()
        print('processing query...')
        qry = QSqlQuery(db)
        query = 'SELECT name, ename, startno, starttime FROM name WHERE ecard = %i OR ecard2 = %i' % (
            tag_number, tag_number)
        qry.prepare(query)
        qry.exec()

        model = QSqlQueryModel()
        model.setQuery(qry)
        print(model.rowCount())
        mapper = QDataWidgetMapper()
        form = QFormLayout()
        layout = QVBoxLayout()

        first_name = QLineEdit()
        start_number = QLineEdit()
        form.addRow(QLabel("Startnummer"), start_number)
        form.addRow(QLabel("Fornavn"), first_name)
        mapper.setModel(model)
        mapper.addMapping(first_name, 0)
        mapper.addMapping(start_number, 2)
        mapper.toFirst()
        layout.addLayout(form)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        #controls = QHBoxLayout()
        '''
Пример #4
0
class JPMainTableModel(QtSql.QSqlRelationalTableModel):
    # _tp中存放需要添加到数据映射器中的控件类型
    # 要添加的控件,必须用字段名命名(大小写敏感)
    _tp = (QtWidgets.QLineEdit, QtWidgets.QDateEdit, QtWidgets.QComboBox,
           QtWidgets.QTextEdit, QtWidgets.QCheckBox, QtWidgets.QSpinBox)

    def __init__(self,
                 parent: QWidget,
                 tableName: str,
                 filter: str = None,
                 db=QtSql.QSqlDatabase()):
        '''用于窗体模式进行数据编辑时的主窗体数据模型。\n
        会自动增加数据映射器,但是外键字段要使用addComboBoxData方法增加列表文字。
        最后要调用tofirst()方法定位编辑的记录。\n
        注:数据映射器不能增删记录,只能编辑
        '''
        super().__init__(parent=parent, db=db)
        self.parent = parent
        self.setTable(tableName)
        if filter:
            self.setFilter(filter)
        self.select()
        rec = self.record()
        self.mapper = QDataWidgetMapper(parent)
        self.mapper.setModel(self)
        self.mapper.setItemDelegate(_JPRelationalDelegate(parent, self.mapper))
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        for i in range(rec.count()):
            widget = parent.findChild(self._tp, rec.fieldName(i))
            if widget:
                if not isinstance(widget, QComboBox):
                    self.mapper.addMapping(widget, i)

    def toFirst(self):
        # 定位到模型中第一条记录
        self.mapper.toFirst()

    def addComboBoxData(self,
                        fieldName: str,
                        dataList: list,
                        displayColumn: int = 0,
                        modelColumn: int = 1):
        '''给模型中添加一个QComboBox控件的数据源。\n
        dataList为行来源数据源,列表对象.\n
        displayColumn为Combobox中要显示文字位于列表中的列号(首列为0)\n
        modelColumn为要保存到模型中数据在列表中的列号(首列为0)\n
        '''
        widget = self.parent.findChild(QComboBox, fieldName)
        if widget is not None:
            widget.setModel(
                _JPComboBoxModel(widget, dataList, displayColumn, modelColumn))
            self.mapper.addMapping(widget, self.fieldIndex(fieldName))

    def saveData(self):
        pass
Пример #5
0
class TaskDetails(DetailScreen):
    """ Displays all current Research Plans """
    def __init__(self, data_context):
        super().__init__(data_context)

        form_layout = QFormLayout()
        self.source = LinkedLineEdit(
            self.data_context.sources_model,
            SourcesModelColumns.AUTOCOMPLETE,
            SourcesModelColumns.POINTER,
        )
        self.source.link_updated.connect(self.link_updated)
        form_layout.addRow(QLabel("Source:"), self.source)

        self.description = QTextEdit()
        form_layout.addRow(QLabel("Description:"), self.description)

        self.result = ResultWidget()
        form_layout.addRow(QLabel("Results:"), self.result)

        form_group = QGroupBox("Task")
        form_group.setLayout(form_layout)

        layout = QVBoxLayout()
        layout.addWidget(form_group)

        # Don't add this, we just want to get/set the value
        self.link = QLineEdit()

        self.setLayout(layout)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.data_context.data_model)
        self.mapper.addMapping(self.source, TreeModelCols.TEXT)
        self.mapper.addMapping(self.description, TreeModelCols.DESCRIPTION,
                               b"plainText")
        self.mapper.addMapping(self.result, TreeModelCols.RESULT)
        self.mapper.addMapping(self.link, TreeModelCols.LINK)
        self.result.result_changed.connect(self.mapper.submit)
        self.mapper.currentIndexChanged.connect(
            lambda _: self.source.set_link_visible(self.link.text() != ""))
        self.data_context.data_model.dataChanged.connect(
            lambda _, __: self.source.set_link_visible(self.link.text() != ""))
        self.mapper.toFirst()

    def link_updated(self, text: str):
        """ Called when the link needs updating from the LineEdit """
        self.link.setText(text)
        self.mapper.submit()
Пример #6
0
class PlanDetails(DetailScreen):
    """ Displays all current Research Plans """

    def __init__(self, data_context):
        super(PlanDetails, self).__init__(data_context)

        form_layout = QFormLayout()
        self.ancestor = LinkedLineEdit(
            self.data_context.individuals_model,
            IndividualsModelColumns.AUTOCOMPLETE,
            IndividualsModelColumns.POINTER,
        )
        self.ancestor.link_updated.connect(self.link_updated)
        form_layout.addRow(QLabel("Ancestor:"), self.ancestor)

        self.goal = QTextEdit()
        form_layout.addRow(QLabel("Goal:"), self.goal)

        form_group = QGroupBox("Plan")
        form_group.setLayout(form_layout)

        layout = QVBoxLayout()
        layout.addWidget(form_group)

        # Don't add this, we just want to get/set the value
        self.link = QLineEdit()

        self.setLayout(layout)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.data_context.data_model)
        self.mapper.addMapping(self.ancestor, TreeModelCols.TEXT)
        self.mapper.addMapping(self.goal, TreeModelCols.DESCRIPTION, b"plainText")
        self.mapper.addMapping(self.link, TreeModelCols.LINK)
        self.mapper.currentIndexChanged.connect(
            lambda _: self.ancestor.set_link_visible(self.link.text() != "")
        )
        self.data_context.data_model.dataChanged.connect(
            lambda _, __: self.ancestor.set_link_visible(self.link.text() != "")
        )
        self.mapper.toFirst()

    def link_updated(self, text: str):
        """ Called when the link needs updating from the LineEdit """
        self.link.setText(text)
        self.mapper.submit()
Пример #7
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("")
Пример #8
0
class EmployeeEditView(QWidget, Ui_FormEditDeleteEmployee):
    def __init__(self, employee_model, employee_controller, main_window):
        super().__init__()
        self.setupUi(self)
        self.employee_model: EmployeeModel = employee_model
        self.employee_controller: EmployeeController = employee_controller
        self.main_window: MainWindowView = main_window
        self.mapper = QDataWidgetMapper()
        self.set_employee_editor()

    def show_editor(self, s=None):
        # load role combobox
        self.load_employee_positions_combobox()

        # Set the selected employee to the editor
        i = self.is_selected()
        if i & i >= 0:
            self.mapper.setCurrentIndex(i)
        self.show()

    def clear_fields(self):
        self.lineEditEmployeeID.clear()
        self.dteEditEmployeeDate.clear()
        self.spinEditEmployeeSalary.clear()
        self.cmbEditEmployeeRole.clear()
        self.load_employee_positions_combobox()

    def load_employee_positions_combobox(self):
        positions = self.employee_model.get_employee_positions()
        self.cmbEditEmployeePosition.addItem("")
        self.cmbEditEmployeePosition.addItems(positions)

    def is_selected(self, s=None) -> int:
        # print(self.selection_model.hasSelection())
        # print(self.selection_model.isRowSelected(0))
        index = self.main_window.tblEmployees.selectionModel().currentIndex().row()

        return index

    def set_employee_editor(self, index=0):
        self.btnEditEmployeePrevious.clicked.connect(self.mapper.toPrevious)
        self.btnEditEmployeeNext.clicked.connect(self.mapper.toNext)
        self.btnEditEmployeeSave.clicked.connect(self.update_button_action)
        self.btnEditEmployeeDelete.clicked.connect(self.delete_button_action)
        self.mapper.setModel(self.main_window.employee_sql_query_model)
        self.mapper.addMapping(self.lineEditEmployeeID, 0)
        self.mapper.addMapping(self.lineEditEmployeeName, 1)
        self.mapper.addMapping(self.cmbEditEmployeePosition, 2)
        self.mapper.addMapping(self.spinEditEmployeeSalary, 3)
        self.mapper.addMapping(self.dteEditEmployeeDate, 4)

        # self.set_student_table(self.model)
        # if index > 0:
        #     self.mapper.setCurrentIndex(index)
        self.mapper.toFirst()

    def update_button_action(self, saved):
        employee_id: int = int(self.lineEditEmployeeID.text())
        employee_name: str = self.lineEditEmployeeName.text()
        employee_role: str = self.cmbEditEmployeePosition.currentText()
        employee_salary: float = float(self.spinEditEmployeeSalary.cleanText())
        employee_date: str = self.dteEditEmployeeDate.text()

        employee: Employee = Employee(employee_name, employee_role, employee_salary, employee_date)

        self.employee_controller.update_employee(employee, employee_id)

    def delete_button_action(self):
        dialog_alert_view: DialogAlertView = DialogAlertView()
        employee_id = int(self.lineEditEmployeeID.text())

        dialog_alert_view.show_dialog(True, 4)
        self.employee_controller.delete_employee(employee_id)
class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # Set up the model.
        self.setupModel()

        # Set up the widgets.
        nameLabel = QLabel("Na&me:")
        nameEdit = QLineEdit()
        addressLabel = QLabel("&Address:")
        addressEdit = QTextEdit()
        typeLabel = QLabel("&Type:")
        typeComboBox = QComboBox()
        self.nextButton = QPushButton("&Next")
        self.previousButton = QPushButton("&Previous")
        nameLabel.setBuddy(nameEdit)
        addressLabel.setBuddy(addressEdit)
        typeLabel.setBuddy(typeComboBox)
        typeComboBox.setModel(self.typeModel)

        # Set up the mapper.
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(nameEdit, 0)
        self.mapper.addMapping(addressEdit, 1)
        self.mapper.addMapping(typeComboBox, 2, 'currentIndex')

        # Set up connections and layouts.
        self.previousButton.clicked.connect(self.mapper.toPrevious)
        self.nextButton.clicked.connect(self.mapper.toNext)
        self.mapper.currentIndexChanged.connect(self.updateButtons)

        layout = QGridLayout()
        layout.addWidget(nameLabel, 0, 0, 1, 1)
        layout.addWidget(nameEdit, 0, 1, 1, 1)
        layout.addWidget(self.previousButton, 0, 2, 1, 1)
        layout.addWidget(addressLabel, 1, 0, 1, 1)
        layout.addWidget(addressEdit, 1, 1, 2, 1)
        layout.addWidget(self.nextButton, 1, 2, 1, 1)
        layout.addWidget(typeLabel, 3, 0, 1, 1)
        layout.addWidget(typeComboBox, 3, 1, 1, 1)
        self.setLayout(layout)

        self.setWindowTitle("Delegate Widget Mapper")
        self.mapper.toFirst()
 
    def setupModel(self):
        items = ("Home", "Work", "Other")
        self.typeModel = QStringListModel(items, self)

        self.model = QStandardItemModel(5, 3, self)

        names = ("Alice", "Bob", "Carol", "Donald", "Emma")
        addresses = ("<qt>123 Main Street<br/>Market Town</qt>",
                     "<qt>PO Box 32<br/>Mail Handling Service"
                     "<br/>Service City</qt>",
                     "<qt>The Lighthouse<br/>Remote Island</qt>",
                     "<qt>47338 Park Avenue<br/>Big City</qt>",
                     "<qt>Research Station<br/>Base Camp<br/>Big Mountain</qt>")
        types = ("0", "1", "2", "0", "2")
        
        for row, name in enumerate(names):
            item = QStandardItem(name)
            self.model.setItem(row, 0, item)
            item = QStandardItem(addresses[row])
            self.model.setItem(row, 1, item)
            item = QStandardItem(types[row])
            self.model.setItem(row, 2, item)
 
    def updateButtons(self, row):
        self.previousButton.setEnabled(row > 0)
        self.nextButton.setEnabled(row < self.model.rowCount() - 1)
Пример #10
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)
vbox = QVBoxLayout()

vbox.addWidget(table_view)
vbox.addWidget(spin_box)
vbox.addWidget(line_edit)

window.setLayout(vbox)

###

mapper = QDataWidgetMapper()        # <--
mapper.setModel(my_model)           # <--
mapper.addMapping(spin_box, 0)      # <--
mapper.addMapping(line_edit, 1)     # <--
mapper.toFirst()                    # <--

def update_selection(selected, deselected):                 # <--
    index = table_view.selectionModel().currentIndex()      # <--
    mapper.setCurrentIndex(index.row())                     # <--
    print("Index: ", index.row())

table_view.selectionModel().selectionChanged.connect(update_selection)   # <--

###

window.show()

# The mainloop of the application. The event handling starts from this point.
# The exec_() method has an underscore. It is because the exec is a Python keyword. And thus, exec_() was used instead.
exit_code = app.exec_()
Пример #12
0
class MovieInfoView(QWidget):
    ID_DESC = 0
    ID_CHECK = 1
    ID_CTRL = 2

    def __init__(self):
        super().__init__()
        self.initWidgets()
        self.mapWidget2Model()

    def initWidgets(self):
        from collections import OrderedDict
        self.controls = OrderedDict()
        self.controls['path'] = ['Path:', QLineEdit()]
        self.controls['title'] = ['Title:', QLineEdit()]
        self.controls['originaltitle'] = ['Original Title:', QLineEdit()]
        self.controls['rating'] = ['Rating:', RatingWidget()]
        self.controls['year'] = ['Year:', QLineEdit()]
        self.controls['releasedate'] = ['Release Date:', QLineEdit()]
        self.controls['id'] = ['ID:', QLineEdit()]
        self.controls['studio'] = ['Studio:', QLineEdit()]
        self.controls['set'] = ['Movie Set:', QLineEdit()]
        self.controls['plot'] = ['Plot:', QPlainTextEdit()]
        self.controls['genre'] = ['Genre:', GenreWidget()]
        self.controls['actor'] = ['Actor:', GenreWidget()]

        left = QGridLayout()
        row = 0
        for _, ctrl in self.controls.items():
            check = QCheckBox()
            check.stateChanged.connect(self.onChecked)
            ctrl.insert(self.ID_CHECK, check)
            left.addWidget(ctrl[self.ID_CHECK], row, 0,
                           Qt.AlignTop | Qt.AlignRight)
            left.addWidget(QLabel(ctrl[self.ID_DESC]), row, 1,
                           Qt.AlignTop | Qt.AlignRight)
            left.addWidget(ctrl[self.ID_CTRL], row, 2)
            row += 1

        right = QVBoxLayout()
        self.poster = CoverWidget('poster')
        self.fanart = CoverWidget('fanart', False)
        right.addWidget(self.poster)
        right.addWidget(self.fanart)

        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addLayout(left)
        layout.addLayout(right)
        self.setLayout(layout)

    def mapWidget2Model(self):
        self.mapper = QDataWidgetMapper(self)
        self.model = MovieInfoModel()
        self.mapper.setModel(self.model)

        index = 0
        for key, ctrl in self.controls.items():
            if 'genre' == key or 'actor' == key or 'rating' == key:
                self.mapper.addMapping(ctrl[self.ID_CTRL], index, b'Value')
            else:
                self.mapper.addMapping(ctrl[self.ID_CTRL], index)
            index += 1
        self.mapper.addMapping(self.poster, index)
        index += 1
        self.mapper.addMapping(self.fanart, index)
        self.mapper.setItemDelegate(MovieInfoDelegate())

    def onChecked(self, state):
        columnFilter = []
        for key, val in self.controls.items():
            if val[self.ID_CHECK].isChecked():
                columnFilter.append(key)

        self.model.setColumnFilter(columnFilter)

    def setMovieInfo(self, movieinfo, bypassFilter):
        if not movieinfo: return
        self.model.setMovieInfo(movieinfo, bypassFilter)
        self.mapper.toFirst()

    def clearMovieInfo(self, forceClear=True, keepColumnFilter=False):
        self.model.clearMovieInfo(forceClear, keepColumnFilter)
        if not keepColumnFilter:
            for _, val in self.controls.items():
                val[self.ID_CHECK].setCheckState(Qt.Unchecked)

        self.mapper.toFirst()

    def saveMovieInfo(self):
        import traceback
        #print('updateMovie')
        try:
            self.model.saveMovieInfo()
        except:
            traceback.print_exc()
Пример #13
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))
Пример #14
0
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)
Пример #15
0
class DBControl(QObject, SqlalchemyDBControl, DB_Util1):
    def __init__(self, parent=None):
        super().__init__()

        import Client

        self.mw: Client.MainWindow = parent

        self.__initDB()
        self.__initUI()

    def __initDB(self):
        self._initDB()
        self._createDB()
        self._createModel()
        self._selectModel()

    # <editor-fold desc="qtdb">
    def _initDB(self):
        self.orm_db = self.create_session()
        self.qt_db = QSqlDatabase.addDatabase('QSQLITE')
        self.qt_db.setDatabaseName(self.db_path)
        if not self.qt_db.open():
            print("数据库连接失败")
            return False

        return self.qt_db

    def _createDB(self):
        self.create_table()
        print(self.qt_db.database().tables())

    def _createModel(self):
        def createModel(tbName):
            model = QSqlTableModel()
            # model.setEditStrategy(QSqlTableModel.OnFieldChange)
            model.setTable(tbName)
            model.select()
            setattr(
                self, tbName + "_model", model
            )  # here will create [self.watching_show_model ... ] and other model
            return model

        def createView(title, model, delegate=None):
            view = QQTableView(self.mw)
            view.setModel(model)
            view.setItemDelegateForColumn(
                0, delegate) if delegate is not None else None
            view.REMOVE_SIGNAL.connect(self.del_watching)
            return view

        def createTab(title):
            tab_form = self.mw.repo_tabWidget
            new_tab = QWidget()
            layout = QHBoxLayout(new_tab)
            layout.setContentsMargins(1, 1, 1, 1)
            tab_form.addTab(new_tab, title)
            return layout

        def createItem(title):
            comb = self.mw.filter_cb

            comb.addItem(title)

        tables = self.qt_db.database().tables()
        for tableName in tables:
            if tableName[-4:] == "show":
                # print(tableName)
                model = createModel(tableName)
                delegate = URLDelegate(self)
                view_ = createView(tableName, model, delegate)
                new_tab = createTab(tableName)
                _ = createItem(tableName)
                new_tab.addWidget(view_)
        # modeln
        self.filterModel = QSqlTableModel()
        # model1
        self.urlTableModel = QSqlTableModel()
        self.urlTableModel.setTable(WEBSITE_TABLE_NAME)
        # model2
        self.unameTableModel = QSqlTableModel()
        self.unameTableModel.setTable(USER_TABLE_NAME) if isinstance(
            self.unameTableModel, QSqlTableModel) else None
        # model3
        self.upwdQueryModel = QSqlQueryModel(self)
        """

        ###self.url_mapper = QDataWidgetMapper()  # 数据映射
        ###self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) # 提交策略
        ###self.url_mapper.setModel(self.urlQueryModel)  # 映射的模型源
        ###self.url_mapper.addMapping(self.mw.web_site_cb,0, b"currentIndex")
        ###self.mw.web_site_cb.setModel(self.urlQueryModel)


        # model4
        self.realationModel = QSqlRelationalTableModel(self)
        self.realationModel.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.realationModel.setTable(REPOSITORIES_TABLE_NAME)
        self.realationModel.setRelation(1, QSqlRelation(WEBSITE_TABLE_NAME, 'id', 'url'))
        # TW_TITLE = [""]
        # for i in range(len(TW_TITLE)):
        #     self.realationModel.setHeaderData(i + 1, Qt.Horizontal, TW_TITLE[i])

        self.realationModel.select()
        """

    def _selectModel(self):

        # <editor-fold desc="1">
        self.mw.web_site_cb.setModel(self.urlTableModel)

        # self.mw.web_user_cb.setModelColumn(1)
        # </editor-fold>

        # <editor-fold desc="2">
        self.mw.web_user_cb.setModel(self.unameTableModel)
        self.mw.web_user_cb.setModelColumn(1)
        # </editor-fold>

        # <editor-fold desc="3">
        self.upwd_mapper = QDataWidgetMapper()  # 数据映射
        self.upwd_mapper.setModel(self.upwdQueryModel)  # 映射的模型源
        self.upwd_mapper.addMapping(self.mw.web_pwd_le, 0)
        ## self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit) # 提交策略
        # </editor-fold>

        # <editor-fold desc="4">
        self.mw.filter_tv.setModel(self.filterModel)
        self.mw.filter_tv.setItemDelegateForColumn(0, URLDelegate())
        # </editor-fold>

    # </editor-fold>

    def __initUI(self):
        self._pre_url_ = "---"
        self._pre_uname_ = "---"

        # 1 .
        self.mw.web_site_cb.activated.connect(self.on_web_uname_query)
        self.mw.web_user_cb.activated.connect(self.on_web_upwd_query)

    def on_web_site_url_query(self):
        print("查网址")
        # self.urlTableModel.setQuery(QSqlQuery(self.ORM2SQL(select([WebSite.url]))))
        self.reloadTableModel(self.urlTableModel, False)
        self.mw.web_site_cb.setModelColumn(1)
        # 如果没有item, setCurrentIndex(0) #qtbug 是不起作用的, index还是-1
        self.mw.web_site_cb.setCurrentIndex(0)
        self.on_web_uname_query()

    def on_web_uname_query(self, index=None):
        """
        网址索引改变的时候触发.
        :return:
        """

        print("查用户")
        c_url = self.get_c_url()
        curl_id = self.get_curl_id(c_url)

        self.mw.web_pwd_le.setText("")
        # 有结果
        if curl_id is not None:
            print("查到用户")
            self.unameTableModel.setFilter(f"""user_info.url_id = {curl_id}""")
            self.reloadTableModel(self.unameTableModel)

            self.mw.web_user_cb.setCurrentIndex(0)
            self.on_web_upwd_query()
        # else:

    def on_web_upwd_query(self):
        print("查密码")
        c_url, c_uname, c_upwd, curl_id = self.get_c_all()

        self.upwdQueryModel.setQuery(
            QSqlQuery(
                self.ORM2SQL(
                    select([UserTable.upwd]).where(
                        and_(UserTable.url_id == curl_id,
                             UserTable.uname == c_uname)))))
        # 设置密码UI
        self.upwd_mapper.toFirst()

        # loadtask

        self._set_pre_cb_text(c_url, c_uname)

    # -------------user------------- ↓
    def create_or_update_webInfo(self):
        c_url, c_uname, c_upwd, curl_id = self.get_c_all()
        if curl_id is None:
            model = self.urlTableModel

            row = model.rowCount()
            ret = model.insertRows(row, 1)
            print('insertRows=%s' % str(ret), model.columnCount())
            record_count = model.record().count()
            print(record_count)
            for col in range(model.columnCount()):
                index = model.index(row, col)
                # record = model.record(row)
                # field = record.field(col)
                field_col = self.urlTableModel.fieldIndex("url")
                if col == field_col:
                    model.setData(index, c_url)
            self.urlTableModel.submit()
            self.mw.web_site_cb.setModelColumn(1)
            # self.urlTableModel.select() # qt bug
            # web_obj = WebSite(url=c_url)
            # self.orm_db.add(web_obj)
            # self.orm_db.flush()
            # curl_id = web_obj.id

            curl_id = model.index(row, 0).data()
        # 法一: 双主键,  有则更新 , 无则创建
        # self.orm_db.merge(User(uname=c_uname, upwd=c_upwd, url_id=curl_id))
        # self.orm_db.commit()
        # 改变索引
        # self.reloadTableModel(self.urlTableModel)
        # self.reloadTableModel(self.unameTableModel)

        ## 法二
        model = self.unameTableModel
        row = model.rowCount()
        ret = model.insertRows(row, 1)
        print('insertRows=%s' % str(ret), model.columnCount())
        for col in range(model.columnCount()):
            index = model.index(row, col)

            if col == 0:
                model.setData(index, curl_id)
            elif col == 1:
                model.setData(index, c_uname)
            elif col == 2:
                model.setData(index, c_upwd)
            elif col == 3:
                model.setData(index, "{}")

        self.unameTableModel.submitAll()

    def delete_webInfo(self):
        """

        :return:
        """

        c_url, c_uname, c_upwd, curl_id = self.get_c_all()
        # 找到网址
        if curl_id is not None:
            # 删网址
            if c_uname == '' and c_upwd == '':
                obj = self.orm_db.query(WebSiteTable).filter_by(
                    url=c_url).one()
                self.orm_db.delete(obj)
                self.orm_db.commit()
                self.on_web_site_url_query()

            # 删账户
            else:
                try:
                    obj = self.orm_db.query(UserTable).filter_by(
                        uname=c_uname, upwd=c_upwd, url_id=curl_id).one()
                    self.orm_db.delete(obj)
                    self.orm_db.commit()
                    self.mw.web_pwd_le.setText("")
                    self.reloadTableModel(self.unameTableModel, False)

                    # self.mw.web_user_cb.setCurrentIndex(0)
                except:
                    pass

    # -------------user------------- ↑

    # -------------table query------------- ↓
    def get_watching(self):
        # try:
        WatchIterator = github.get_watching(self)
        self.mw.thread_pools.spawn(self.get_watching_querydb, WatchIterator)

    def get_watching_querydb(self, WatchIterator):
        for watched_repo in WatchIterator:
            query_field = "/" + watched_repo.full_name
            WatchingTable_obj: WatchingTable = self.orm_db.query(
                WatchingTable).filter_by(query_field=query_field).first()
            if WatchingTable_obj is None:
                uname = self.get_c_uname()
                self.orm_db.add(
                    WatchingTable(query_field=query_field, uname=uname))
                self.orm_db.commit()
                model: QSqlTableModel = self.watching_show_model
                model.select()  # TODO:重新载入, 可能可以改成局部刷新.
            else:
                pass

    def del_watching(self, tv, data_dict):
        data = data_dict.get("data")  # type:list
        del_watching_repo = data[0]
        print(f"{del_watching_repo}")
        print(self.get_c_tableName())
        if self.get_c_tableName() == WATCHING_TABLE_NAME:
            print(f"delete")
            github.del_watching(del_watching_repo)
        else:
            pass

    # TODO:查数据库 ,可能用协程

    def re_select_model(self):
        model = self.get_c_model()
        model.select()

    def filterAll(self):
        """
        过滤
        :return:
        """
        query_fields = self.mw.filter_le.text().strip()  # 小注释 : e.g."py test "
        query_field_list = query_fields.split(" ")  # 小注释 : space split
        tableName = self.mw.filter_cb.currentText()

        # 小注释 : 单表
        if tableName != "All":
            TableClass = getTable(tableName)  ##type:BaseComment
            self.filterModel.setQuery(
                QSqlQuery(
                    self.ORM2SQL(
                        select([TableClass]).where(
                            or_(*tuple(
                                map(
                                    lambda query_field: TableClass.comment.
                                    like(f'%{query_field}%'),
                                    query_field_list))
                                # 小注释 :
                                # TableClass.comment.like(f'%{query_field_list[0]}%'),
                                # TableClass.comment.like(f'%{query_field_list[1]}%'),
                                # TableClass.comment.like(f'%{query_field_list[2]}%'),
                                )))))
        # 小注释 : 多表 union
        else:
            tw = self.mw.repo_tabWidget
            tabCount = tw.count()
            end = tabCount - 1
            sql = ""
            for i in range(tabCount):
                tableName = tw.tabText(i)
                condition = " OR ".join(
                    list(
                        map(
                            lambda query_field:
                            f"""{tableName}.comment LIKE '%{query_field}%' """,
                            query_field_list)))
                sql += f"""SELECT * From {tableName} WHERE {condition}"""
                if i != end:
                    sql += " UNION ALL " if self.mw.filter_ckBox.isChecked(
                    ) else " UNION "
            # print(sql)
            self.filterModel.setQuery(QSqlQuery(sql))

    # -------------table query------------- ↑

    def ORM2SQL(self, statement):
        """

        :param statement:
        :return:
        """
        query = statement.compile(dialect=sqlite.dialect())
        query_str = str(query)
        query_paras: dict = query.params
        query_raw_sql = query_str.replace('?', r"%r") % tuple(
            query_paras.values())
        # print("==query_raw_sql==↓:")
        # print(query_raw_sql)
        # print("==query_raw_sql==↑:")
        return query_raw_sql
Пример #16
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
Пример #17
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()

        form = QFormLayout()

        self.track_id = QSpinBox()
        self.track_id.setDisabled(True)
        self.name = QLineEdit()
        self.album = QComboBox()
        self.media_type = QComboBox()
        self.genre = QComboBox()
        self.composer = QLineEdit()

        self.milliseconds = QSpinBox()
        self.milliseconds.setRange(0, 2147483647)
        self.milliseconds.setSingleStep(1)

        self.bytes = QSpinBox()
        self.bytes.setRange(0, 2147483647)
        self.bytes.setSingleStep(1)

        self.unit_price = QDoubleSpinBox()
        self.unit_price.setRange(0, 999)
        self.unit_price.setSingleStep(0.01)
        self.unit_price.setPrefix("$")

        form.addRow(QLabel("Track ID"), self.track_id)
        form.addRow(QLabel("Track name"), self.name)
        form.addRow(QLabel("Composer"), self.composer)
        form.addRow(QLabel("Milliseconds"), self.milliseconds)
        form.addRow(QLabel("Bytes"), self.bytes)
        form.addRow(QLabel("Unit Price"), self.unit_price)

        self.model = QSqlTableModel(db=db)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model)

        self.mapper.addMapping(self.track_id, 0)
        self.mapper.addMapping(self.name, 1)
        self.mapper.addMapping(self.composer, 5)
        self.mapper.addMapping(self.milliseconds, 6)
        self.mapper.addMapping(self.bytes, 7)
        self.mapper.addMapping(self.unit_price, 8)

        self.model.setTable("Track")
        self.model.select()

        self.mapper.toFirst()

        self.setMinimumSize(QSize(400, 400))

        controls = QHBoxLayout()

        prev_rec = QPushButton("Previous")
        prev_rec.clicked.connect(self.mapper.toPrevious)

        next_rec = QPushButton("Next")
        next_rec.clicked.connect(self.mapper.toNext)

        save_rec = QPushButton("Save Changes")
        save_rec.clicked.connect(self.mapper.submit)

        controls.addWidget(prev_rec)
        controls.addWidget(next_rec)
        controls.addWidget(save_rec)

        layout.addLayout(form)
        layout.addLayout(controls)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
Пример #18
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
Пример #19
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
Пример #20
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)
Пример #21
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)
Пример #22
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)
Пример #23
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)
Пример #24
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)
Пример #25
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()))

    """ 
Пример #26
0
class SettingsController(QObject, LogMixin):

    settingsClosed = pyqtSignal()    # send after model or backend data has been updated

    def __init__(self, parent):
        """
        Initiate settings editing

        Signals
        * settingsClosed

        :param parent: parent window of settings dialog
        :return:
        """
        super().__init__(parent)
        self._parent = parent
        print("controller/SettingsController parent: ", self._parent, " -> self: ", self) if oPB.PRINTHIER else None

        self.logger.debug("Initialize settings dialog")

        self.model = None              # data models
        self.datamapper = None             # QDataWidgetMapper object for field mapping
        self._modelDataChanged = False  # is connect via model_data_changed function to itemChanged Signal of QStandardItemModel, will be reset in close_project()

        # create main window and logic
        self.ui = SettingsDialog(self._parent)

        # build special button groups for False/True choice
        self.optionGroupSrvVersion = SpecialOptionButtonGroup(self.ui.rdOpsiSrvNew, self.ui.rdOpsiSrvOld,
                                                              [self.ui.rdSUDOWithPass, self.ui.rdSUDOWithoutPass],
                                                              [self.ui.inpRootPass])

        self.optionGroupSUDO = SpecialOptionButtonGroup(self.ui.rdSUDOWithPass, self.ui.rdSUDOWithoutPass)

        self.optionGroupEditorTyp = SpecialOptionButtonGroup(self.ui.rdEditorInternal, self.ui.rdEditorExternal,
                                                             [self.ui.chkSyntaxHighlight, self.ui.chkCodeFolding],
                                                             [self.ui.btnExternalEditor, self.ui.inpExternalEditor])

        self.optionGroupDepotFuncs = SpecialOptionButtonGroup(self.ui.chkUseDepotFunctions, None, [],
                                                              [self.ui.inpInstallCommand, self.ui.inpInstSetupCommand,
                                                               self.ui.inpUninstallCommand, self.ui.inpUploadCommand])

        self.optionGroupProxy = SpecialOptionButtonGroup(self.ui.chkUseProxy, None,
                                                         [self.ui.inpProxyServer, self.ui.inpProxyPort,
                                                          self.ui.inpProxyUser, self.ui.inpProxyPass], [])

        self.optionGroupSSHKeyFile = SpecialOptionButtonGroup(self.ui.chkUseKeyFile, None,
                                                              [self.ui.btnSetKeyFile, self.ui.inpKeyFile], [])

        self.optionGroupLogFile = SpecialOptionButtonGroup(self.ui.chkWriteLog, None,
                                                              [self.ui.btnLogFile, self.ui.inpLogFile, self.ui.cmbLogLevel], [])

        self.generate_model()
        self.connect_signals()

        # open modal dialog
        self.ui.tabWidget.setCurrentIndex(0)

    def generate_model(self):
        """Create data models and assign field mappings"""
        self.logger.debug("Generate configuration model")
        self.model = QtGui.QStandardItemModel(self.ui)
        self.model.setItem(0, 0, QtGui.QStandardItem(ConfigHandler.cfg.opsi_server))
        self.model.setItem(0, 1, QtGui.QStandardItem(ConfigHandler.cfg.opsi_user))
        self.model.setItem(0, 2, QtGui.QStandardItem(ConfigHandler.cfg.opsi_pass))
        self.model.setItem(0, 3, QtGui.QStandardItem(ConfigHandler.cfg.root_pass))
        self.model.setItem(0, 4, QtGui.QStandardItem(ConfigHandler.cfg.usenetdrive))
        self.model.setItem(0, 5, QtGui.QStandardItem(ConfigHandler.cfg.age))
        self.model.setItem(0, 6, QtGui.QStandardItem(ConfigHandler.cfg.sudo))
        self.model.setItem(0, 7, QtGui.QStandardItem(ConfigHandler.cfg.sshport))
        self.model.setItem(0, 8, QtGui.QStandardItem(ConfigHandler.cfg.usekeyfile))
        self.model.setItem(0, 9, QtGui.QStandardItem(ConfigHandler.cfg.keyfilename))
        self.model.setItem(0, 10, QtGui.QStandardItem(ConfigHandler.cfg.packagemaintainer))
        self.model.setItem(0, 11, QtGui.QStandardItem(ConfigHandler.cfg.mailaddress))
        self.model.setItem(0, 12, QtGui.QStandardItem(ConfigHandler.cfg.dev_dir))
        self.model.setItem(0, 13, QtGui.QStandardItem(ConfigHandler.cfg.buildcommand))
        self.model.setItem(0, 14, QtGui.QStandardItem(ConfigHandler.cfg.installcommand))
        self.model.setItem(0, 15, QtGui.QStandardItem(ConfigHandler.cfg.uninstallcommand))
        self.model.setItem(0, 16, QtGui.QStandardItem(ConfigHandler.cfg.showoutput))
        self.model.setItem(0, 17, QtGui.QStandardItem(ConfigHandler.cfg.reload_for_at))
        self.model.setItem(0, 18, QtGui.QStandardItem(ConfigHandler.cfg.wol_lead_time))
        self.model.setItem(0, 19, QtGui.QStandardItem(ConfigHandler.cfg.uploadcommand))
        self.model.setItem(0, 20, QtGui.QStandardItem(ConfigHandler.cfg.instsetupcommand))
        self.model.setItem(0, 21, QtGui.QStandardItem(ConfigHandler.cfg.use_depot_funcs))
        self.model.setItem(0, 22, QtGui.QStandardItem(ConfigHandler.cfg.use_extended_changelog))
        self.model.setItem(0, 23, QtGui.QStandardItem(ConfigHandler.cfg.scripteditor))
        self.model.setItem(0, 24, QtGui.QStandardItem(ConfigHandler.cfg.chlog_block_marker))
        self.model.setItem(0, 25, QtGui.QStandardItem(ConfigHandler.cfg.editor_intern))
        self.model.setItem(0, 26, QtGui.QStandardItem(ConfigHandler.cfg.editor_use_styling))
        self.model.setItem(0, 27, QtGui.QStandardItem(ConfigHandler.cfg.editor_use_folding))
        self.model.setItem(0, 28, QtGui.QStandardItem(ConfigHandler.cfg.chlog_on_build))
        self.model.setItem(0, 29, QtGui.QStandardItem(ConfigHandler.cfg.chlog_on_save))
        self.model.setItem(0, 30, QtGui.QStandardItem(ConfigHandler.cfg.no_error_msg))
        self.model.setItem(0, 31, QtGui.QStandardItem(ConfigHandler.cfg.no_warning_msg))
        self.model.setItem(0, 32, QtGui.QStandardItem(ConfigHandler.cfg.no_info_msg))
        self.model.setItem(0, 33, QtGui.QStandardItem(ConfigHandler.cfg.no_at_warning_msg))
        self.model.setItem(0, 34, QtGui.QStandardItem(ConfigHandler.cfg.language))
        self.model.setItem(0, 35, QtGui.QStandardItem(ConfigHandler.cfg.useproxy))
        self.model.setItem(0, 36, QtGui.QStandardItem(ConfigHandler.cfg.updatecheck))
        self.model.setItem(0, 37, QtGui.QStandardItem(ConfigHandler.cfg.proxy_server))
        self.model.setItem(0, 38, QtGui.QStandardItem(ConfigHandler.cfg.proxy_port))
        self.model.setItem(0, 39, QtGui.QStandardItem(ConfigHandler.cfg.proxy_user))
        self.model.setItem(0, 40, QtGui.QStandardItem(ConfigHandler.cfg.proxy_pass))
        self.model.setItem(0, 41, QtGui.QStandardItem(ConfigHandler.cfg.log_always))
        self.model.setItem(0, 42, QtGui.QStandardItem(ConfigHandler.cfg.log_file))
        self.model.setItem(0, 43, QtGui.QStandardItem(ConfigHandler.cfg.log_level))

        self.logger.debug("Create data widget mapper")
        self.datamapper = QDataWidgetMapper(self.ui)
        self.datamapper.setModel(self.model)
        self.datamapper.addMapping(self.ui.inpConfigServer, 0)
        self.datamapper.addMapping(self.ui.inpOpsiUser, 1)
        self.datamapper.addMapping(self.ui.inpOpsiPass, 2)
        self.datamapper.addMapping(self.ui.inpRootPass, 3)
        self.datamapper.addMapping(self.ui.chkUseNetworkDrive, 4, "checked")
        self.datamapper.addMapping(self.optionGroupSrvVersion, 5, "checked")
        self.datamapper.addMapping(self.optionGroupSUDO, 6, "checked")
        self.datamapper.addMapping(self.ui.inpSSHPort, 7)
        self.datamapper.addMapping(self.optionGroupSSHKeyFile, 8, "checked")
        self.datamapper.addMapping(self.ui.inpKeyFile, 9)
        self.datamapper.addMapping(self.ui.inpMaintainer, 10)
        self.datamapper.addMapping(self.ui.inpMailAddress, 11)
        self.datamapper.addMapping(self.ui.inpDevFolder, 12)
        self.datamapper.addMapping(self.ui.inpBuildCommand, 13)
        self.datamapper.addMapping(self.ui.inpInstallCommand, 14)
        self.datamapper.addMapping(self.ui.inpUninstallCommand, 15)
        self.datamapper.addMapping(self.ui.chkShowOutput, 16, "checked")
        self.datamapper.addMapping(self.ui.chkAlwaysReload, 17, "checked")
        self.datamapper.addMapping(self.ui.inpWOLLeadTime, 18)
        self.datamapper.addMapping(self.ui.inpUploadCommand, 19)
        self.datamapper.addMapping(self.ui.inpInstSetupCommand, 20)
        #self.datamapper.addMapping(self.settings.chkUseDepotFunctions, 21, "checked")
        self.datamapper.addMapping(self.optionGroupDepotFuncs, 21, "checked")
        self.datamapper.addMapping(self.ui.chkExtendedEditor, 22, "checked")
        self.datamapper.addMapping(self.ui.inpExternalEditor, 23)
        self.datamapper.addMapping(self.ui.inpBlockMarker, 24)
        self.datamapper.addMapping(self.optionGroupEditorTyp, 25, "checked")
        self.datamapper.addMapping(self.ui.chkSyntaxHighlight, 26, "checked")
        self.datamapper.addMapping(self.ui.chkCodeFolding, 27, "checked")
        self.datamapper.addMapping(self.ui.chkForceEntryBuild, 28, "checked")
        self.datamapper.addMapping(self.ui.chkForceEntrySave, 29, "checked")
        self.datamapper.addMapping(self.ui.chkMsgError, 30, "checked")
        self.datamapper.addMapping(self.ui.chkMsgWarning, 31, "checked")
        self.datamapper.addMapping(self.ui.chkMsgInfo, 32, "checked")
        self.datamapper.addMapping(self.ui.chkMsgAT, 33, "checked")
        self.datamapper.addMapping(self.ui.cmbLanguage, 34, "currentText")
        self.datamapper.addMapping(self.optionGroupProxy, 35, "checked")
        self.datamapper.addMapping(self.ui.chkUpdates, 36, "checked")
        self.datamapper.addMapping(self.ui.inpProxyServer, 37)
        self.datamapper.addMapping(self.ui.inpProxyPort, 38)
        self.datamapper.addMapping(self.ui.inpProxyUser, 39)
        self.datamapper.addMapping(self.ui.inpProxyPass, 40)
        self.datamapper.addMapping(self.optionGroupLogFile, 41, "checked")
        self.datamapper.addMapping(self.ui.inpLogFile, 42)
        self.datamapper.addMapping(self.ui.cmbLogLevel, 43)
        self.datamapper.toFirst()

    def connect_signals(self):
        """Connect signals"""

        self.logger.debug("Connect signals")
        self.model.itemChanged.connect(self.model_data_changed)

        self.ui.btnSave.clicked.connect(self.save_config)
        self.ui.dataChanged.connect(self.datamapper.submit)
        self.ui.settingsAboutToBeClosed.connect(self.close_dialog)

        self.ui.rdOpsiSrvNew.clicked.connect(self.set_model_data)
        self.ui.rdOpsiSrvOld.clicked.connect(self.set_model_data)
        self.ui.rdSUDOWithPass.clicked.connect(self.set_model_data)
        self.ui.rdSUDOWithoutPass.clicked.connect(self.set_model_data)
        self.ui.rdEditorInternal.clicked.connect(self.set_model_data)
        self.ui.rdEditorExternal.clicked.connect(self.set_model_data)
        self.ui.chkUseDepotFunctions.clicked.connect(self.set_model_data)
        self.ui.chkUseProxy.clicked.connect(self.set_model_data)
        self.ui.chkUseKeyFile.clicked.connect(self.set_model_data)
        self.ui.chkWriteLog.clicked.connect(self.set_model_data)

    @pyqtSlot()
    def model_data_changed(self):
        """Update model changed marker"""
        self.logger.debug("Model data changed")
        self._modelDataChanged = True

    @pyqtSlot()
    def set_model_data(self):
        """Whenever a special radio button or checkbox is clicked,
        the corresponding model data element will be set accordingly.

        This has to be done like so, because radio buttons and checkboxes are not directly linked
        to the model, but via a SpecialOptionButtonGroup object.
        """
        self.logger.debug("Set model data values from button: " + self.sender().objectName())

        # radio buttons
        if self.sender().objectName() == "rdOpsiSrvNew":
            if self.ui.rdOpsiSrvNew.isChecked():
                self.model.item(0, 5).setText("True")

        if self.sender().objectName() == "rdOpsiSrvOld":
            if self.ui.rdOpsiSrvOld.isChecked():
                self.model.item(0, 5).setText("False")

        if self.sender().objectName() == "rdSUDOWithPass":
            if self.ui.rdSUDOWithPass.isChecked():
                self.model.item(0, 6).setText("True")

        if self.sender().objectName() == "rdSUDOWithoutPass":
            if self.ui.rdSUDOWithoutPass.isChecked():
                self.model.item(0, 6).setText("False")

        if self.sender().objectName() == "rdEditorInternal":
            if self.ui.rdEditorInternal.isChecked():
                self.model.item(0, 25).setText("True")

        if self.sender().objectName() == "rdEditorExternal":
            if self.ui.rdEditorExternal.isChecked():
                self.model.item(0, 25).setText("False")

        # check boxes
        if self.sender().objectName() == "chkUseKeyFile":
            if self.ui.chkUseKeyFile.isChecked():
                self.model.item(0, 8).setText("True")
            else:
                self.model.item(0, 8).setText("False")

        if self.sender().objectName() == "chkUseDepotFunctions":
            if self.ui.chkUseDepotFunctions.isChecked():
                self.model.item(0, 21).setText("True")
            else:
                self.model.item(0, 21).setText("False")

        if self.sender().objectName() == "chkUseProxy":
            if self.ui.chkUseProxy.isChecked():
                self.model.item(0, 35).setText("True")
            else:
                self.model.item(0, 35).setText("False")

        if self.sender().objectName() == "chkWriteLog":
            if self.ui.chkWriteLog.isChecked():
                self.model.item(0, 41).setText("True")
            else:
                self.model.item(0, 41).setText("False")

    def update_backend_data(self):
        self.logger.debug("Update config backend")
        ConfigHandler.cfg.opsi_server = self.model.item(0, 0).text()
        ConfigHandler.cfg.opsi_user = self.model.item(0, 1).text()
        ConfigHandler.cfg.opsi_pass =  self.model.item(0, 2).text()
        ConfigHandler.cfg.root_pass = self.model.item(0, 3).text()
        ConfigHandler.cfg.usenetdrive = self.model.item(0, 4).text().title()
        ConfigHandler.cfg.age = self.model.item(0, 5).text().title()
        ConfigHandler.cfg.sudo = self.model.item(0, 6).text().title()
        ConfigHandler.cfg.cfg.sshport = self.model.item(0, 7).text()
        ConfigHandler.cfg.usekeyfile = self.model.item(0, 8).text().title()
        ConfigHandler.cfg.keyfilename = self.model.item(0, 9).text()
        ConfigHandler.cfg.packagemaintainer = self.model.item(0, 10).text()
        ConfigHandler.cfg.mailaddress = self.model.item(0, 11).text()
        ConfigHandler.cfg.dev_dir = self.model.item(0, 12).text()
        ConfigHandler.cfg.buildcommand = self.model.item(0, 13).text()
        ConfigHandler.cfg.installcommand = self.model.item(0, 14).text()
        ConfigHandler.cfg.uninstallcommand = self.model.item(0, 15).text()
        ConfigHandler.cfg.showoutput = self.model.item(0, 16).text().title()
        ConfigHandler.cfg.reload_for_at = self.model.item(0, 17).text().title()
        ConfigHandler.cfg.wol_lead_time = self.model.item(0, 18).text()
        ConfigHandler.cfg.uploadcommand = self.model.item(0, 19).text()
        ConfigHandler.cfg.instsetupcommand = self.model.item(0, 20).text()
        ConfigHandler.cfg.use_depot_funcs = self.model.item(0, 21).text().title()
        ConfigHandler.cfg.use_extended_changelog = self.model.item(0, 22).text().title()
        ConfigHandler.cfg.scripteditor = self.model.item(0, 23).text()
        ConfigHandler.cfg.chlog_block_marker = self.model.item(0, 24).text()
        ConfigHandler.cfg.editor_intern = self.model.item(0, 25).text().title()
        ConfigHandler.cfg.editor_use_styling = self.model.item(0, 26).text().title()
        ConfigHandler.cfg.editor_use_folding = self.model.item(0, 27).text().title()
        ConfigHandler.cfg.chlog_on_build = self.model.item(0, 28).text().title()
        ConfigHandler.cfg.chlog_on_save = self.model.item(0, 29).text().title()
        ConfigHandler.cfg.no_error_msg = self.model.item(0, 30).text().title()
        ConfigHandler.cfg.no_warning_msg = self.model.item(0, 31).text().title()
        ConfigHandler.cfg.no_info_msg = self.model.item(0, 32).text().title()
        ConfigHandler.cfg.no_at_warning_msg = self.model.item(0, 33).text().title()
        ConfigHandler.cfg.language = self.model.item(0, 34).text()
        ConfigHandler.cfg.useproxy = self.model.item(0, 35).text().title()
        ConfigHandler.cfg.updatecheck = self.model.item(0, 36).text().title()
        ConfigHandler.cfg.proxy_server = self.model.item(0, 37).text()
        ConfigHandler.cfg.proxy_port = self.model.item(0, 38).text()
        ConfigHandler.cfg.proxy_user = self.model.item(0, 39).text()
        ConfigHandler.cfg.proxy_pass = self.model.item(0, 40).text()
        ConfigHandler.cfg.log_always = self.model.item(0, 41).text().title()
        ConfigHandler.cfg.log_file = self.model.item(0, 42).text()
        ConfigHandler.cfg.log_level = self.model.item(0, 43).text()

    def close_dialog(self):
        """Close settings dialog"""
        ignoreChanges = True
        if self._modelDataChanged == True:
            retval = QMessageBox.question(None, translate("settingsController", "Question"), translate("settingsController", "There are unsaved changes! Do you really want to continue?"), QMessageBox.Yes, QMessageBox.No)
            if retval == QMessageBox.No:
                self.logger.debug("Unsaved changes have been ignored.")
                ignoreChanges = False

        if ignoreChanges:
            self.logger.debug("Close settings dialog")
            self.ui.close()
            self.logger.debug("Emit signal settingsClosed")
            self.settingsClosed.emit()

    @pyqtSlot()
    def save_config(self):
        """Get field values and initiate saving of configuration"""
        if self._modelDataChanged:
            self.update_backend_data()
            ConfigHandler.cfg.save()
            self._modelDataChanged = None

        self.close_dialog()
Пример #27
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()
Пример #28
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()))