class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setTable() self.setLayout() self.setCentralWidget(self.widget) self.resize(600,400) def setTable(self): self.search = QLineEdit() self.search.textChanged.connect(self.setFilter) self.table = QTableView() self.model = QSqlRelationalTableModel(db=db) self.model.setTable('album') self.table.setModel(self.model) index = self.model.fieldIndex("Title") self.model.setSort(index, Qt.DescendingOrder) self.model.setRelation(2, QSqlRelation("artist", "ArtistId","Name")) self.model.select() def setLayout(self): self.layout = QVBoxLayout() self.layout.addWidget(self.search) self.layout.addWidget(self.table) self.widget = QWidget() self.widget.setLayout(self.layout) def setFilter(self, word): filterLastName = f'Name LIKE "%{word}%"' self.model.setFilter(filterLastName)
def createTable(self): """ Create the table using model/view architecture. """ # Create the model model = QSqlRelationalTableModel() model.setTable('accounts') # Set up relationship for foreign keys model.setRelation(model.fieldIndex('country_id'), QSqlRelation('countries', 'id', 'country')) table_view = QTableView() table_view.setModel(model) table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # Populate the model with data model.select() # Main layout main_v_box = QVBoxLayout() main_v_box.addWidget(table_view) self.setLayout(main_v_box)
class AccountManager(QWidget): def __init__(self): super().__init__() self.initialize_ui() def initialize_ui(self): self.setMinimumSize(1000, 600) self.setWindowTitle('Account Manager GUI') self.createConnection() self.createTable() self.setupWidgets() self.show() def createConnection(self): database = QSqlDatabase.addDatabase("QSQLITE") database.setDatabaseName("files/accounts.db") if not database.open(): print("Unable to open data source file.") sys.exit(1) # Error code 1 - signifies error # Check if tables we need exist in the database tables_needed = {'accounts', 'countries'} tables_not_found = tables_needed - set(database.tables()) if tables_not_found: QMessageBox.critical( None, "Error", f"The following tables are missing from the database: {tables_not_found}" ) sys.exit(1) def createTable(self): """ Set up the model, headers and populate the model. """ self.model = QSqlRelationalTableModel() self.model.setTable('accounts') self.model.setRelation(self.model.fieldIndex('country_id'), QSqlRelation('countries', 'id', 'country')) self.model.setHeaderData(self.model.fieldIndex('id'), Qt.Horizontal, "ID") self.model.setHeaderData(self.model.fieldIndex('employee_id'), Qt.Horizontal, "Employee ID") self.model.setHeaderData(self.model.fieldIndex('first_name'), Qt.Horizontal, "First") self.model.setHeaderData(self.model.fieldIndex('last_name'), Qt.Horizontal, "Last") self.model.setHeaderData(self.model.fieldIndex('email'), Qt.Horizontal, "E-mail") self.model.setHeaderData(self.model.fieldIndex('department'), Qt.Horizontal, "Dept.") self.model.setHeaderData(self.model.fieldIndex('country_id'), Qt.Horizontal, "Country") # populate the model with data self.model.select() def setupWidgets(self): """ Create instances of widgets, the table view and set layouts. """ icons_path = "icons" title = QLabel("Account Management System") title.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) title.setStyleSheet("font: bold 24px") add_product_button = QPushButton("Add Employee") add_product_button.setIcon( QIcon(os.path.join(icons_path, "add_user.png"))) add_product_button.setStyleSheet("padding: 10px") add_product_button.clicked.connect(self.addItem) del_product_button = QPushButton("Delete") del_product_button.setIcon( QIcon(os.path.join(icons_path, "trash_can.png"))) del_product_button.setStyleSheet("padding: 10px") del_product_button.clicked.connect(self.deleteItem) # set up sorting combobox sorting_options = [ "Sort by ID", "Sort by Employee ID", "Sort by First Name", "Sort by Last Name", "Sort by Department", "Sort by Country" ] sort_name_cb = QComboBox() sort_name_cb.addItems(sorting_options) sort_name_cb.currentTextChanged.connect(self.setSortingOrder) buttons_h_box = QHBoxLayout() buttons_h_box.addWidget(add_product_button) buttons_h_box.addWidget(del_product_button) buttons_h_box.addStretch() buttons_h_box.addWidget(sort_name_cb) # Widget to contain editing buttons edit_buttons = QWidget() edit_buttons.setLayout(buttons_h_box) # Create table view and set model self.table_view = QTableView() self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_view.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_view.setSelectionMode(QTableView.SingleSelection) self.table_view.setSelectionBehavior(QTableView.SelectRows) # Instantiate the delegate delegate = QSqlRelationalDelegate(self.table_view) self.table_view.setItemDelegate(delegate) # Main layout main_v_box = QVBoxLayout() main_v_box.addWidget(title, Qt.AlignLeft) main_v_box.addWidget(edit_buttons) main_v_box.addWidget(self.table_view) self.setLayout(main_v_box) def addItem(self): """ Add a new record to the last row of the table. """ last_row = self.model.rowCount() self.model.insertRow(last_row) id = 0 query = QSqlQuery() query.exec_("SELECT MAX(id) FROM ACCOUNTS") if query.next(): print(query.value(0)) id = int(query.value(0)) def deleteItem(self): """ Delete an entire row from the table. """ current_item = self.table_view.selectedIndexes() for index in current_item: self.model.removeRow(index.row()) self.model.select() def setSortingOrder(self, text): """ Sort the rows in table. """ # mode = 0 if text == "Sort by ID": self.model.setSort(self.model.fieldIndex('id'), Qt.AscendingOrder) # self.model.setSort(self.model.fieldIndex('id'), mode if Qt.DescendingOrder else Qt.AscendingOrder) elif text == "Sort by Employee ID": self.model.setSort(self.model.fieldIndex('employee_id'), Qt.AscendingOrder) elif text == "Sort by First Name": self.model.setSort(self.model.fieldIndex('first_name'), Qt.AscendingOrder) elif text == "Sort by Last Name": self.model.setSort(self.model.fieldIndex('last_name'), Qt.AscendingOrder) elif text == "Sort by Department": self.model.setSort(self.model.fieldIndex('department'), Qt.AscendingOrder) elif text == "Sort by Country": self.model.setSort(self.model.fieldIndex('country'), Qt.AscendingOrder) self.model.select()
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.tableView) # 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(100) ## ==============自定义功能函数============ def __getFieldNames(self): ##获取所有字段名称 emptyRec = self.tabModel.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.tabModel = QSqlRelationalTableModel(self, self.DB) #数据表 self.tabModel.setTable("studInfo") #设置数据表 self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit ) #数据保存方式,OnManualSubmit , OnRowChange self.tabModel.setSort(self.tabModel.fieldIndex("studID"), Qt.AscendingOrder) #排序 if (self.tabModel.select() == False): #查询数据失败 QMessageBox.critical( self, "错误信息", "打开数据表错误,错误信息\n" + self.tabModel.lastError().text()) return self.__getFieldNames() #获取字段名和序号 ##字段显示名 self.tabModel.setHeaderData(self.fldNum["studID"], Qt.Horizontal, "学号") self.tabModel.setHeaderData(self.fldNum["name"], Qt.Horizontal, "姓名") self.tabModel.setHeaderData(self.fldNum["gender"], Qt.Horizontal, "性别") self.tabModel.setHeaderData(self.fldNum["departID"], Qt.Horizontal, "学院") self.tabModel.setHeaderData(self.fldNum["majorID"], Qt.Horizontal, "专业") ## 设置代码字段的查询关系数据表 self.tabModel.setRelation(self.fldNum["departID"], QSqlRelation("departments", "departID", "department")) #学院 self.tabModel.setRelation(self.fldNum["majorID"], QSqlRelation("majors", "majorID", "major")) #专业 self.selModel = QItemSelectionModel(self.tabModel) #关联选择模型 ##selModel当前项变化时触发currentChanged信号 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) #设置选择模型 delgate = QSqlRelationalDelegate(self.ui.tableView) self.ui.tableView.setItemDelegate(delgate) #为关系型字段设置缺省代理组件 self.tabModel.select() #必须重新查询数据 ##更新actions和界面组件的使能状态 self.ui.actOpenDB.setEnabled(False) self.ui.actRecAppend.setEnabled(True) self.ui.actRecInsert.setEnabled(True) self.ui.actRecDelete.setEnabled(True) self.ui.actFields.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") #添加 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_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) #设置刚插入的行为当前选择行 @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_actFields_triggered(self): emptyRec = self.tabModel.record() #获取空记录,只有字段名 str = '' for i in range(emptyRec.count()): str = str + emptyRec.fieldName(i) + '\n' QMessageBox.information(self, "所有字段名", str) ## =============自定义槽函数=============================== def do_currentChanged(self, current, previous): ##更新actPost和actCancel 的状态 self.ui.actSubmit.setEnabled(self.tabModel.isDirty()) #有未保存修改时可用 self.ui.actRevert.setEnabled(self.tabModel.isDirty())
def __init__(self, parent=None): super().__init__(parent) horizontalLayout = QHBoxLayout() self.dayView = QTableView() self.dayView.setFrameShape(QFrame.Box) self.dayView.horizontalHeader().setStretchLastSection(True) self.dayView.verticalHeader().setVisible(False) horizontalLayout.addWidget(self.dayView) verticalLayout = QVBoxLayout() self.calendarWidget = QCalendarWidget() self.calendarWidget.setMinimumSize(QSize(250, 200)) self.calendarWidget.setMaximumSize(QSize(250, 200)) self.calendarWidget.setMinimumDate(QDate(2017, 1, 1)) self.calendarWidget.setMaximumDate(QDate(2030, 1, 1)) self.calendarWidget.selectionChanged.connect(self.dataChange) self.calendarWidget.setSelectedDate(QDate.currentDate()) verticalLayout.addWidget(self.calendarWidget) titleFV = QLabel('Food View') verticalLayout.addWidget(titleFV) self.filterLine = QLineEdit() self.filterLine.setMaximumSize(QSize(200, 25)) self.filterLine.textChanged.connect(self.filterChange) buttonAdd = QPushButton(QIcon("images/add.png"), '', None) buttonAdd.setMaximumSize(QSize(20, 30)) buttonAdd.clicked.connect(self.addFood) buttonDell = QPushButton(QIcon("images/del.png"), '', None) buttonDell.setMaximumSize(QSize(20, 30)) buttonDell.clicked.connect(self.delFood) lineEditLayout = QHBoxLayout() lineEditLayout.addWidget(self.filterLine) lineEditLayout.addWidget(buttonAdd) lineEditLayout.addWidget(buttonDell) verticalLayout.addLayout(lineEditLayout) self.foodView = QTableView() self.foodView.setMinimumSize(QSize(0, 0)) self.foodView.setMaximumSize(QSize(250, 1000)) self.foodView.verticalHeader().setVisible(False) self.foodView.horizontalHeader().setStretchLastSection(True) verticalLayout.addWidget(self.foodView) horizontalLayout.addLayout(verticalLayout) self.setLayout(horizontalLayout) model_in = QSqlRelationalTableModel() model_in.setEditStrategy(QSqlTableModel.OnFieldChange) model_in.setTable("intake_food") id_food = model_in.fieldIndex("id_food") date = model_in.fieldIndex("food_date") mass = model_in.fieldIndex("mass") # Set model, hide ID column model_in.setRelation(id_food, QSqlRelation("food", "id", "name")) model_in.setHeaderData(id_food, Qt.Horizontal, "Food") model_in.setHeaderData(date, Qt.Horizontal, "Date") model_in.setHeaderData(mass, Qt.Horizontal, "Mass") if not model_in.select(): self.showError(model_in.lastError()) return self.proxyModel_in = QSortFilterProxyModel() self.proxyModel_in.setSourceModel(model_in) self.proxyModel_in.setFilterKeyColumn(2) self.dayView.setItemDelegate(FlipProxyDelegate()) self.dayView.setModel(self.proxyModel_in) self.dayView.setColumnHidden(0, True) self.dayView.setColumnHidden(2, True) self.dayView.setSelectionMode(QAbstractItemView.SingleSelection) self.dayView.setContextMenuPolicy(Qt.CustomContextMenu) self.dayView.customContextMenuRequested.connect(self.ShowContextMenu) # filter day food by calendar widget self.dataChange() self.model_f = QSqlRelationalTableModel() self.model_f.setEditStrategy(QSqlTableModel.OnFieldChange) self.model_f.setTable("food") self.model_f.setHeaderData(1, Qt.Horizontal, "Food") self.model_f.setHeaderData(2, Qt.Horizontal, "Rate") if not self.model_f.select(): self.showError(self.model_f.lastError()) return self.proxyModel_f = QSortFilterProxyModel() self.proxyModel_f.setSourceModel(self.model_f) self.proxyModel_f.setFilterKeyColumn(1) self.foodView.setModel(self.proxyModel_f) self.foodView.setColumnHidden(0, True) self.foodView.setSelectionMode(QAbstractItemView.SingleSelection) self.foodView.setColumnWidth(1, 150) self.foodView.setColumnWidth(2, 90)
class APISFilm(QDialog, FORM_CLASS): FIRST, PREV, NEXT, LAST = range(4) OBLIQUE, VERTICAL = range(2) def __init__(self, iface, dbm, imageRegistry, apisLayer, parent=None): """Constructor.""" super(APISFilm, self).__init__(parent) self.iface = iface self.dbm = dbm self.imageRegistry = imageRegistry self.apisLayer = apisLayer self.parent = parent self.setupUi(self) # Initial window size/pos last saved. Use default values for first time if GetWindowSize("film"): self.resize(GetWindowSize("film")) if GetWindowPos("film"): self.move(GetWindowPos("film")) self.printingOptionsDlg = None self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat) self.editMode = False self.addMode = False self.initalLoad = True #self.uiInitalEntryQgsDate.setCalendarPopup(False) #self.uiLastChangesQgsDate.setCalendarPopup(False) # Signals/Slot Connections self.rejected.connect(self.onReject) self.uiOkBtn.clicked.connect(self.onAccept) self.uiCancelBtn.clicked.connect(self.cancelEdit) self.uiSaveBtn.clicked.connect(self.saveEdits) self.uiFilmSelectionBtn.clicked.connect(self.openFilmSelectionDialog) self.uiNewFilmBtn.clicked.connect(self.openNewFilmDialog) self.uiSearchFilmBtn.clicked.connect(self.openSearchFilmDialog) self.uiEditWeatherBtn.clicked.connect(self.openEditWeatherDialog) self.uiExportPdfBtn.clicked.connect(self.exportDetailsPdf) self.uiShowFlightPathBtn.clicked.connect(lambda: self.openFlightPathDialog([self.uiCurrentFilmNumberEdit.text()])) # For LaLe Mode if self.settings.value("APIS/disable_site_and_findspot", "0") != "1": self.uiListSitesOfFilmBtn.setEnabled(True) self.uiListSitesOfFilmBtn.clicked.connect(self.openSiteSelectionListDialog) else: self.uiListSitesOfFilmBtn.setEnabled(False) self.uiListImagesOfFilmBtn.clicked.connect(self.openImageSelectionListDialog) self.uiExtractGpsFromImagesBtn.clicked.connect(self.extractGpsFromImages) self.uiWeatherCodeEdit.textChanged.connect(self.generateWeatherCode) self.uiFilmModeCombo.currentIndexChanged.connect(self.onFilmModeChanged) self.uiEditProjectTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("projekt", self.uiProjectSelectionCombo)) self.uiEditCopyrightTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("copyright", self.uiCopyrightCombo)) # self.uiEditProjectTableBtn.clicked.connect(lambda: VersionToCome()) # self.uiEditCopyrightTableBtn.clicked.connect(lambda: VersionToCome()) # init Project Btn self.uiAddProjectBtn.clicked.connect(self.addProject) self.uiRemoveProjectBtn.clicked.connect(self.removeProject) # Setup Sub-Dialogs self.filmSelectionDlg = APISFilmNumberSelection(self) self.newFilmDlg = APISFilmNew(parent=self) self.searchFilmDlg = APISFilmSearch(self.dbm, self) # (self.iface, self.dbm) self.editWeatherDlg = APISWeather(self.iface, self.dbm, self) self.flightPathDlg = APISFlightPath(self.iface, self.dbm, self.apisLayer, self) self.siteSelectionListDlg = APISSiteSelectionList(self.iface, self.dbm, self.imageRegistry, self.apisLayer, self) self.imageSelectionListDlg = APISImageSelectionList(self.iface, self.dbm, self.imageRegistry, self.apisLayer, parent=self) self.systemTableEditorDlg = None # Setup film model self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("film") self.model.select() while (self.model.canFetchMore()): self.model.fetchMore() self.setupMapper() self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None) self.setupComboBox(self.newFilmDlg.uiProducerCombo, "hersteller", 2, None) self.setupNavigation() self.mapper.toFirst() self.initalLoad = False def setupMapper(self): self.mapper = QDataWidgetMapper(self) self.mapper.currentIndexChanged.connect(self.onCurrentIndexChanged) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setItemDelegate(FilmDelegate()) self.mapper.setModel(self.model) self.mandatoryEditors = [self.uiImageCountEdit, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiFilmModeCombo] self.disableEditorsIfOblique = [self.uiCameraNumberEdit, self.uiCalibratedFocalLengthEdit] # LineEdits & PlainTextEdits self.intValidator = QIntValidator() self.doubleValidator = QDoubleValidator() self.lineEditMaps = { "filmnummer": { "editor": self.uiCurrentFilmNumberEdit }, "hersteller": { "editor": self.uiProducerEdit }, "anzahl_bilder": { "editor": self.uiImageCountEdit, "validator": self.intValidator }, "militaernummer": { "editor": self.uiMilitaryNumberEdit }, "militaernummer_alt": { "editor": self.uiOldMilitaryNumberEdit }, "form1": { "editor": self.uiFormat1Edit }, "form2": { "editor": self.uiFormat2Edit }, "kalibrierungsnummer": { "editor": self.uiCameraNumberEdit }, "kammerkonstante": { "editor": self.uiCalibratedFocalLengthEdit, "validator": self.doubleValidator }, "kassettennummer": { "editor": self.uiCassetteEdit }, "art_ausarbeitung": { "editor": self.uiFilmMakeEdit }, "fotograf": { "editor": self.uiPhotographerEdit }, "pilot": { "editor": self.uiPilotEdit }, "flugzeug": { "editor": self.uiAirplaneEdit }, "abflug_flughafen": { "editor": self.uiDepartureAirportEdit }, "ankunft_flughafen": { "editor": self.uiArrivalAirportEdit }, "flugzeit": { "editor": self.uiFlightDurationEdit }, "wetter": { "editor": self.uiWeatherCodeEdit }, "kommentar": { "editor": self.uiCommentsPTxt } } for key, item in self.lineEditMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) if "validator" in item: item["editor"].setValidator(item["validator"]) #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"])) item["editor"].textChanged.connect(self.onLineEditChanged) #Text #self.mapper.addMapping(self.uiCommentsPTxt, self.model.fieldIndex("kommentar")) # Date and Times self.mapper.addMapping(self.uiFlightDate, self.model.fieldIndex("flugdatum")) #self.mapper.addMapping(self.uiFlightQgsDate, self.model.fieldIndex("flugdatum")) self.mapper.addMapping(self.uiInitalEntryDate, self.model.fieldIndex("datum_ersteintrag")) #self.mapper.addMapping(self.uiInitalEntryQgsDate, self.model.fieldIndex("datum_ersteintrag")) self.mapper.addMapping(self.uiLastChangesDate, self.model.fieldIndex("datum_aenderung")) #self.mapper.addMapping(self.uiLastChangesQgsDate, self.model.fieldIndex("datum_aenderung")) self.mapper.addMapping(self.uiDepartureTime, self.model.fieldIndex("abflug_zeit")) self.mapper.addMapping(self.uiArrivalTime, self.model.fieldIndex("ankunft_zeit")) self.uiDepartureTime.timeChanged.connect(self.onFlightTimeChanged) self.uiArrivalTime.timeChanged.connect(self.onFlightTimeChanged) # ComboBox without Model self.mapper.addMapping(self.uiFilmModeCombo, self.model.fieldIndex("weise")) self.uiFilmModeCombo.editTextChanged.connect(self.onLineEditChanged) completer = QCompleter(self.uiFilmModeCombo.model()) self.uiFilmModeCombo.setCompleter(completer) self.uiFilmModeCombo.lineEdit().setValidator(InListValidator([self.uiFilmModeCombo.itemText(i) for i in range(self.uiFilmModeCombo.count())], self.uiFilmModeCombo.lineEdit(), None, self)) # ComboBox with Model self.comboBoxMaps = { "archiv": { "editor": self.uiArchiveCombo, "table": "hersteller", "modelcolumn": 2, "depend": None }, "kamera": { "editor": self.uiCameraCombo, "table": "kamera", "modelcolumn": 0, "depend": [{"form1": self.uiFormat1Edit}, {"form2": self.uiFormat2Edit}] }, "filmfabrikat": { "editor": self.uiFilmMakeCombo, "table": "film_fabrikat", "modelcolumn": 0, "depend": [{"art": self.uiFilmMakeEdit}] }, "target": { "editor": self.uiTargetCombo, "table": "target", "modelcolumn": 0, "depend": None }, "copyright": { "editor": self.uiCopyrightCombo, "table": "copyright", "modelcolumn": 0, "depend": None } } for key, item in self.comboBoxMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) self.setupComboBox(item["editor"], item["table"], item["modelcolumn"], item["depend"]) item["editor"].editTextChanged.connect(self.onLineEditChanged) self.mapper.addMapping(self.uiProjectList, self.model.fieldIndex("projekt")) def fixComboBoxDropDownListSizeAdjustemnt(self, cb): scroll = 0 if cb.count() <= cb.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent) iconWidth = cb.iconSize().width() max = 0 for i in range(cb.count()): width = cb.view().fontMetrics().width(cb.itemText(i)) if max < width: max = width QMessageBox.information(self, "info", "scroll: {0}, max: {1}, icon: {2}".format(scroll, max, iconWidth)) #cb.view().setMinimumWidth(scroll + max) def setupComboBox(self, editor, table, modelColumn, depend): model = QSqlRelationalTableModel(self, self.dbm.db) model.setTable(table) model.removeColumn(0) model.select() tv = QTableView() editor.setView(tv) tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) tv.setSelectionMode(QAbstractItemView.SingleSelection) tv.setSelectionBehavior(QAbstractItemView.SelectRows) tv.setAutoScroll(False) editor.setModel(model) editor.setModelColumn(modelColumn) editor.setInsertPolicy(QComboBox.NoInsert) tv.resizeColumnsToContents() tv.resizeRowsToContents() tv.verticalHeader().setVisible(False) tv.horizontalHeader().setVisible(True) #tv.setMinimumWidth(tv.horizontalHeader().length()) tv.horizontalHeader().setStretchLastSection(True) #tv.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) tv.resizeColumnsToContents() scroll = 0 if editor.count() <= editor.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent) tv.setMinimumWidth(tv.horizontalHeader().length() + scroll) #self.fixComboBoxDropDownListSizeAdjustemnt(editor) #editor.resize(tv.horizontalHeader().sizeHint()) completer = QCompleter(editor.model()) editor.setCompleter(completer) #editor.setAutoCompletion(True) editor.lineEdit().setValidator(InListValidator([editor.itemText(i) for i in range(editor.count())], editor.lineEdit(), depend, self)) if depend: editor.currentIndexChanged.connect(partial(self.updateDepends, editor, depend)) def updateDepends(self, editor, depend): for dep in depend: for key, value in dep.items(): idx = editor.model().createIndex(editor.currentIndex(), editor.model().fieldIndex(key)) value.setText(str(editor.model().data(idx))) #QMessageBox.warning(None, "Test", str(idx)) def setupNavigation(self): self.uiFirstFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.FIRST)) self.uiPreviousFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.PREV)) self.uiNextFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.NEXT)) self.uiLastFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.LAST)) self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.intRecordValidator = QIntValidator(1, self.model.rowCount()) self.uiCurrentFilmCountEdit.setValidator(self.intRecordValidator) self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1)) self.uiCurrentFilmCountEdit.editingFinished.connect(lambda: self.loadRecordById(int(self.uiCurrentFilmCountEdit.text()) - 1)) # QMessageBox.warning(None, "Test", str(self.mapper.itemDelegate())) def enableItemsInLayout(self, layout, enable): for i in range(layout.count()): if layout.itemAt(i).widget(): layout.itemAt(i).widget().setEnabled(enable) def loadRecordByNavigation(self, mode): #self.mapper.submit() #self.submitChanges() self.initalLoad = True if mode == APISFilm.FIRST: self.mapper.toFirst() elif mode == APISFilm.PREV: self.mapper.toPrevious() elif mode == APISFilm.NEXT: self.mapper.toNext() elif mode == APISFilm.LAST: self.mapper.toLast() self.initalLoad = False def loadRecordById(self, id): #self.submitChanges self.initalLoad = True self.mapper.setCurrentIndex(id) self.initalLoad = False def loadRecordByKeyAttribute(self, attribute, value): #self.model.setFilter(attribute + " = '" + value + "'") #self.model.select() # self.mapper.toFirst() query = QSqlQuery(self.dbm.db) #qryStr = "select {0} from film where {0} = '{1}' limit 1".format(attribute, value) #qryStr = "SELECT rowid FROM film WHERE {0} = '{1}' limit 1".format(attribute, value) qryStr = "SELECT" \ " (SELECT COUNT(*)" \ " FROM film AS t2" \ " WHERE t2.rowid < t1.rowid" \ " ) + (" \ " SELECT COUNT(*)" \ " FROM film AS t3" \ " WHERE t3.rowid = t1.rowid AND t3.rowid < t1.rowid" \ " ) AS rowNum" \ " FROM film AS t1" \ " WHERE {0} = '{1}'" \ " ORDER BY t1.rowid ASC".format(attribute, value) query.exec_(qryStr) #QMessageBox.warning(None, "Test", str(query.size()) + ',' + str(query.numRowsAffected())) query.first() fn = query.value(0) if fn is not None: self.loadRecordById(fn) return True else: # Film does not exist QMessageBox.warning(None, "Film Nummer", str("Der Film mit der Nummer {0} existiert nicht!".format(value))) return False #self.model.setFilter('') #self.model.select() #while (self.model.canFetchMore()): #self.model.fetchMore() def submitChanges(self): self.mapper.submit() def onCurrentIndexChanged(self): self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1)) self.onFilmModeChanged() def onFlightTimeChanged(self): dTime = self.uiDepartureTime.time() aTime = self.uiArrivalTime.time() flightDuration = dTime.secsTo(aTime) self.uiFlightDurationEdit.setText(str(flightDuration / 60)) def disableIfOblique(self, isOblique): for editor in self.disableEditorsIfOblique: editor.setDisabled(isOblique) def onFilmModeChanged(self): if self.uiFilmModeCombo.currentText() == u'schräg': self.disableIfOblique(True) else: self.disableIfOblique(False) def onLineEditChanged(self): sender = self.sender() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: sender.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(sender.metaObject().className())) self.editorsEdited.append(sender) def onComboBoxChanged(self, editor): pass def addProject(self): editor = self.uiProjectList value = self.uiProjectSelectionCombo.currentText() notInList = True for row in range(editor.count()): if value == editor.item(row).data(0): notInList = False break if notInList: editor.addItem(value) editor.sortItems() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) def removeProject(self): editor = self.uiProjectList editor.takeItem(self.uiProjectList.currentRow()) if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) def onAccept(self): ''' Check DB Save options when pressing OK button Update Plugin Status ''' self.accept() def onReject(self): ''' Run some actions when the user closes the dialog ''' if self.editMode: res = self.cancelEdit() if res: self.close() else: self.show() else: self.close() def closeEvent(self, e): # Write window size and position to QSettings if self.editMode: self.onReject() else: SetWindowSizeAndPos("film", self.size(), self.pos()) e.accept() def extractGpsFromImages(self): key = self.uiCurrentFilmNumberEdit.text() e2p = Exif2Points(self.iface, key) layer = e2p.run() if layer: self.apisLayer.requestShapeFile(layer, groupName="Flugwege", addToCanvas=True) def exportDetailsPdf(self): if self.printingOptionsDlg is None: self.printingOptionsDlg = APISPrintingOptions(self) self.printingOptionsDlg.setWindowTitle("Druck Optionen: Film") self.printingOptionsDlg.configure(False, False, visPersonalDataChk=True) self.printingOptionsDlg.show() if self.printingOptionsDlg.exec_(): printPersonalData = self.printingOptionsDlg.printPersonalData() APISPrinterQueue([{'type': APISTemplatePrinter.FILM, 'idList': [self.uiCurrentFilmNumberEdit.text()], 'options': {'personalData': printPersonalData}}], OutputMode.MergeNone, openFile=self.printingOptionsDlg.uiOpenFilesChk.isChecked(), openFolder=self.printingOptionsDlg.uiOpenFolderChk.isChecked(), dbm=self.dbm, parent=self) def openSearchFilmDialog(self): """Run method that performs all the real work""" # show the dialog self.searchFilmDlg.show() #self.filmSelectionDlg.uiFilmNumberEdit.setFocus() # Run the dialog event loop and See if OK was pressed if self.searchFilmDlg.exec_(): # QMessageBox.warning(None, "FilmNumber", self.searchFilmDlg.generateSearchQuery()) model = QSqlRelationalTableModel(self, self.dbm.db) model.setTable("film") searchMode, searchFilter = self.searchFilmDlg.generateSearchFilter() # QMessageBox.information(self, "info", searchFilter) model.setFilter(searchFilter) model.select() rc = model.rowCount() while (model.canFetchMore()): model.fetchMore() rc = model.rowCount() query = QSqlQuery(self.dbm.db) searchQuery = "select filmnummer, substr(filmnummer, 3, 8) as 'ohne_hersteller', flugdatum, anzahl_bilder, weise, art_ausarbeitung, militaernummer, militaernummer_alt from film where {0}".format(searchFilter) query.exec_(searchQuery) querySize = 0 while(query.next()): querySize += 1 query.seek(-1) # if model.rowCount(): if querySize > 0: # open film selection list dialog searchListDlg = APISFilmSelectionList(self.iface, model, self.dbm, self.imageRegistry, parent=self) searchListDlg.uiFilmCountLbl.setText(str(rc)) searchListDlg.uiFilmCountDescriptionLbl.setText(u"Film gefunden" if model.rowCount() == 1 else u"Filme gefunden") searchListDlg.uiFilmSearchModeLbl.setText(searchMode) res = searchListDlg.loadFilmListBySqlQuery(query) if res and searchListDlg.exec_(): #QMessageBox.warning(None, "FilmNumber", unicode(searchListDlg.filmNumberToLoad)) self.loadRecordByKeyAttribute("filmnummer", searchListDlg.filmNumberToLoad) else: QMessageBox.warning(self, u"Film Suche", u"Keine Ergebnisse mit den angegebenen Suchkriterien.") self.openSearchFilmDialog() #QMessageBox.warning(None, "FilmNumber", u"{0}, rows: {1}".format(self.searchFilmDlg.generateSearchQuery(), model.rowCount())) # Get Search String/Query #if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()): #self.openFilmSelectionDialog() def openFilmSelectionDialog(self): """Run method that performs all the real work""" self.filmSelectionDlg.show() self.filmSelectionDlg.uiFilmNumberEdit.setFocus() if self.filmSelectionDlg.exec_(): if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()): self.openFilmSelectionDialog() def openNewFilmDialog(self): """Run method that performs all the real work""" self.newFilmDlg.show() if self.newFilmDlg.exec_(): self.addNewFilm(self.newFilmDlg.flightDate(), self.newFilmDlg.useLastEntry(), self.newFilmDlg.producer(), self.newFilmDlg.producerCode()) def openEditWeatherDialog(self): self.editWeatherDlg.setWeatherCode(self.uiWeatherCodeEdit.text()) self.editWeatherDlg.show() if self.editWeatherDlg.exec_(): self.uiWeatherCodeEdit.setText(self.editWeatherDlg.weatherCode()) #self.uiWeatherPTxt.setPlainText(self.editWeatherDlg.weatherDescription()) def generateWeatherCode(self): weatherDescription = self._generateWeatherCode(self.uiWeatherCodeEdit.text()) self.uiWeatherPTxt.setPlainText(weatherDescription) def _generateWeatherCode(self, weatherCode): categories = ["Low Cloud Amount", "Visibility Kilometres", "Low Cloud Height", "Weather", "Remarks Mission", "Remarks Weather"] query = QSqlQuery(self.dbm.db) pos = 0 help = 0 weatherDescription = "" for c in weatherCode: qryStr = "select description from wetter where category = '{0}' and code = '{1}' limit 1".format(categories[pos - help], c) query.exec_(qryStr) query.first() fn = query.value(0) if pos <= 5: weatherDescription += categories[pos] + ': ' + fn if pos < 5: weatherDescription += '\n' else: weatherDescription += '; ' + fn if pos >= 5: help += 1 pos += 1 return weatherDescription def openSystemTableEditorDialog(self, table, updateEditor): if self.dbm: self.systemTableEditorDlg = APISAdvancedInputDialog(self.dbm, table, False, parent=self) if self.systemTableEditorDlg.tableExists: if self.systemTableEditorDlg.exec_(): # See if OK was pressed # rec = self.systemTableEditorDlg.getRecord() # Update updateEditor # self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None) self.updateComboBox(updateEditor) else: QMessageBox.warning(self, "Tabelle nicht vorhanden", "Die Tabelle {0} ist in der APIS Datenbank nicht vorhanden".format(table)) else: QMessageBox.warning(self, "Warning Database", "Die APIS Datenbank konnte nicht gefunden werden.") def updateComboBox(self, updateEditor): updateEditor.model().select() tv = updateEditor.view() tv.resizeRowsToContents() tv.resizeColumnsToContents() scroll = 0 if updateEditor.count() <= updateEditor.maxVisibleItems() else QApplication.style().pixelMetric( QStyle.PM_ScrollBarExtent) tv.setMinimumWidth(tv.horizontalHeader().length() + scroll) updateEditor.setCurrentIndex(updateEditor.count() - 1) if updateEditor.validator(): updateEditor.lineEdit().setValidator( InListValidator([updateEditor.itemText(i) for i in range(updateEditor.count())], updateEditor.lineEdit(), None, self)) def openFlightPathDialog(self, filmList, toClose=None): self.flightPathDlg.viewFilms(filmList) # DEBUG self.flightPathDlg.show() if self.flightPathDlg.exec_(): #TODO load Data in TOC, Close Windows if toClose: toClose.close() self.close() def openSiteSelectionListDialog(self): if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL: fromTable = "luftbild_senk_fp" elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE: fromTable = "luftbild_schraeg_fp" query = QSqlQuery(self.dbm.db) query.prepare("SELECT fundortnummer, flurname, katastralgemeinde, fundgewinnung, sicherheit FROM fundort WHERE fundortnummer IN (SELECT DISTINCT fo.fundortnummer FROM fundort fo, {0} WHERE fo.geometry IS NOT NULL AND {0}.geometry IS NOT NULL AND {0}.filmnummer = '{1}' AND Intersects({0}.geometry, fo.geometry) AND fo.ROWID IN (SELECT ROWID FROM SpatialIndex WHERE f_table_name = 'fundort' AND search_frame = {0}.geometry)) ORDER BY katastralgemeindenummer, land, fundortnummer_nn".format(fromTable, self.uiCurrentFilmNumberEdit.text())) query.exec_() info = u"gefunden, die vom Film {0} abgedeckt/geschnitten werden.".format(self.uiCurrentFilmNumberEdit.text()) res = self.siteSelectionListDlg.loadSiteListBySpatialQuery(query, info) if res: self.siteSelectionListDlg.show() if self.siteSelectionListDlg.exec_(): pass def openImageSelectionListDialog(self): if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL: fromTable = 'luftbild_senk_cp' spatialIndicator = 'massstab' elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE: fromTable = 'luftbild_schraeg_cp' spatialIndicator = 'radius' query = QSqlQuery(self.dbm.db) query.prepare("SELECT cp.bildnummer AS bildnummer, cp.filmnummer AS filmnummer, cp.{2} AS mst_radius, f.weise AS weise, f.art_ausarbeitung AS art FROM {0} AS cp, film AS f WHERE cp.filmnummer = '{1}' AND f.filmnummer = '{1}'".format(fromTable, self.uiCurrentFilmNumberEdit.text(), spatialIndicator)) query.exec_() res = self.imageSelectionListDlg.loadImageListBySqlQuery(query) if res: self.imageSelectionListDlg.show() if self.imageSelectionListDlg.exec_(): pass def addNewFilm(self, flightDate, useLastEntry, producer, producerCode): self.initalLoad = True self.addMode = True self.startEditMode() row = self.model.rowCount() self.mapper.submit() while (self.model.canFetchMore()): self.model.fetchMore() self.model.insertRow(row) if useLastEntry: #copy last row for c in range(1, self.model.columnCount()): value = self.model.data(self.model.createIndex(row - 1, c)) self.model.setData(self.model.createIndex(row, c), value) editor = self.mapper.mappedWidgetAt(c) if editor and not (value == 'NULL' or value == ''): cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): pass else: editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className())) self.editorsEdited.append(editor) self.mapper.setCurrentIndex(row) self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.uiFlightDate.setDate(flightDate) #self.uiFlightQgsDate.setDate(flightDate) self.uiProducerEdit.setText(producer) self.uiArchiveCombo.lineEdit().setText(producer) if not useLastEntry: self.uiWeatherCodeEdit.setText("9990X") #now = QDateTime.currentDateTime() now = QDate.currentDate() self.uiInitalEntryDate.setDate(now) #self.uiInitalEntryQgsDate.setDateTime(now) self.uiLastChangesDate.setDate(now) #self.uiLastChangesQgsDate.setDateTime(now) self.uiFilmModeCombo.setEnabled(True) #Filmnummer hh = producerCode yyyy = flightDate.toString("yyyy") mm = flightDate.toString("MM") query = QSqlQuery(self.dbm.db) qryStr = "select max(filmnummer_nn) from film where filmnummer_hh_jjjj_mm = '{0}{1}{2}' limit 1".format(hh, yyyy, mm) query.exec_(qryStr) query.first() fn = query.value(0) if isinstance(fn, int): nn = str(fn + 1).zfill(2) else: nn = "01" self.uiCurrentFilmNumberEdit.setText("{0}{1}{2}{3}".format(hh, yyyy, mm, nn)) self.initalLoad = False def removeNewFilm(self): self.initalLoad = True row = self.mapper.currentIndex() self.model.removeRow(row) self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() self.uiTotalFilmCountLbl.setText(str(self.model.rowCount())) self.mapper.toLast() self.initalLoad = False def saveEdits(self): # Check Mandatory fields flag = False for mEditor in self.mandatoryEditors: cName = mEditor.metaObject().className() if cName == 'QLineEdit': value = mEditor.text() elif cName == 'QComboBox': value = mEditor.lineEdit().text() if value.strip() == "": flag = True mEditor.setStyleSheet("{0} {{background-color: rgb(240, 160, 160);}}".format(cName)) if mEditor not in self.editorsEdited: self.editorsEdited.append(mEditor) else: if mEditor in self.editorsEdited: mEditor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(cName)) #else: #mEditor.setStyleSheet("") if flag: QMessageBox.warning(self, self.tr(u"Benötigte Felder Ausfüllen"), self.tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind.")) return False #saveToModel currIdx = self.mapper.currentIndex() #now = QDateTime.currentDateTime() now = QDate.currentDate() self.uiLastChangesDate.setDate(now) #self.uiLastChangesQgsDate.setDateTime(now) res = self.mapper.submit() if not res: sqlError = self.mapper.model().lastError() QMessageBox.information(self, "Submit", u"Error: {0}, {1}".format(res, sqlError.text())) while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.setCurrentIndex(currIdx) self.endEditMode() return True def cancelEdit(self): if self.editMode: result = QMessageBox.question(self, self.tr(u"Änderungen wurden vorgenommen!"), self.tr(u"Möchten Sie die Änerungen speichern?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) #save or not save if result == QMessageBox.Yes: res = self.saveEdits() if res: return True else: return False elif result == QMessageBox.No: if self.addMode: self.removeNewFilm() self.mapper.setCurrentIndex(self.mapper.currentIndex()) self.endEditMode() return True def startEditMode(self): self.editMode = True self.enableItemsInLayout(self.uiTopHorizontalLayout, False) self.enableItemsInLayout(self.uiBottomHorizontalLayout, False) self.uiOkBtn.setEnabled(False) self.uiSaveBtn.setEnabled(True) self.uiCancelBtn.setEnabled(True) self.editorsEdited = [] def endEditMode(self): self.editMode = False self.addMode = False self.enableItemsInLayout(self.uiTopHorizontalLayout, True) self.enableItemsInLayout(self.uiBottomHorizontalLayout, True) self.uiOkBtn.setEnabled(True) self.uiSaveBtn.setEnabled(False) self.uiCancelBtn.setEnabled(False) for editor in self.editorsEdited: cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): editor.setStyleSheet("{0} {{background-color: rgb(218, 218, 218);}}".format(cName)) else: editor.setStyleSheet("") self.editorsEdited = [] self.uiFilmModeCombo.setEnabled(False) def showEvent(self, evnt): # QMessageBox.information(self, "info", "db requires update: {0}".format(self.dbm.dbRequiresUpdate)) if self.dbm.dbRequiresUpdate: self.initalLoad = True for editor in [self.uiArchiveCombo, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiCopyrightCombo, self.uiProjectSelectionCombo, self.newFilmDlg.uiProducerCombo]: self.updateComboBox(editor) currIdx = self.mapper.currentIndex() self.model.select() while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.setCurrentIndex(currIdx) self.dbm.dbRequiresUpdate = False self.initalLoad = False
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1200, 800) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget.setGeometry(QtCore.QRect(0, 0, 1200, 800)) self.tabWidget.setObjectName("tabWidget") # TAB 1 self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") self.tabWidget.addTab(self.tab, "") # Admin site integration self.webView = QtWebEngineWidgets.QWebEngineView(self.tab) self.webView.setUrl(QtCore.QUrl("http://185.188.182.76:8000/admin")) self.webView.resize(1200, 800) self.webView.setObjectName("webView") # TAB 2 self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") # Desktop Database integration self.devices_table = QtWidgets.QTableView(self.tab_2) self.devices_table.setGeometry(QtCore.QRect(0, 0, 1200, 800)) self.devices_table.setObjectName("tableView") self.devices_table_UI() self.add_record() # !!! last_month_day = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1] today = strftime("%d", gmtime()) if last_month_day == today: self.add_record() self.tabWidget.addTab(self.tab_2, "") MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) MainWindow.setWindowIcon(QtGui.QIcon('label.ico')) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(1) QtCore.QMetaObject.connectSlotsByName(MainWindow) def devices_table_UI(self): conn = sqlite3.connect("database.db") c = conn.cursor() c.execute( "CREATE TABLE IF NOT EXISTS devices(id INTEGER PRIMARY KEY AUTOINCREMENT, mac_address TEXT, os_version TEXT, architecture TEXT, locale TEXT, timezone TEXT, last_update TEXT)" ) c.close() self.devices_model = QSqlRelationalTableModel(db=createConnection()) self.devices_model.setTable('devices') self.devices_model.select() # self.drivers_table.setEditTriggers(QAbstractItemView.CurrentChanged) self.devices_table.setModel(self.devices_model) self.devices_table.hideColumn(self.devices_model.fieldIndex('id')) # Делаем ресайз колонок по содержимому self.devices_table.resizeColumnsToContents() def add_record(self): rec = self.devices_model.record() data = [ get_mac(), # mac-address platform.platform(), platform.machine(), locale.getdefaultlocale()[0], str(timezone / 3600.0), strftime("%Y-%m-%d %H:%M:%S", gmtime()) ] for i in range(len(data)): rec.setValue(rec.field(i + 1).name(), data[i]) self.devices_model.insertRecord(-1, rec) self.devices_model.submit() self.devices_model.select() self.devices_table.resizeColumnsToContents() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Polydroid Desktop")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "AdminSite")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Desktop DB"))
class bill(QMainWindow, QWidget): def __init__(self): super().__init__() self.initialize() def initialize(self): # set geometry, window title self.setMinimumSize(1350, 600) self.setWindowTitle("Smart Billing") self.Connection() self.createTable() # show menu bar self.MenuBar() self.Tab() self.show() def Connection(self): """ create the connection to the sqlite3 and open the database""" # setup the connection to sqlite3 and open the billing database # if database not present create one database = QSqlDatabase.addDatabase("QSQLITE") database.setDatabaseName("billing.db") if not database.open(): print("Unable to connect") sys.exit(1) # fail to connect to the database # tables needed for billing application table_need = {'items', 'billBook'} # table that are not found table_not_found = table_need - set(database.tables()) # if tables are not found it give a critical message and exits if table_not_found: QMessageBox.critical( None, "Error", f'Following database tables are not found:{table_not_found}') sys.exit(1) def MenuBar(self): """ this create the main menu""" # create print action print_act = QAction("print", self) print_act.setShortcut("Ctrl+P") print_act.setIcon(QIcon("icons/018-printer.png")) print_act.setEnabled(False) print_act.triggered.connect(self.Print) # create exit action exit_act = QAction("exit", self) exit_act.setShortcut("Ctrl+Q") exit_act.setIcon(QIcon("icons/008-logout.png")) exit_act.triggered.connect(self.closeEvent) # create save action save_act = QAction("save", self) save_act.setShortcut("Ctrl+S") save_act.setIcon(QIcon("icons/004-folder.png")) save_act.triggered.connect(self.Save) # create search_bill_act action search_bill_act = QAction("Search Bill", self) search_bill_act.setShortcut("Ctrl+F") search_bill_act.setIcon(QIcon("icons/015-magnifier.png")) search_bill_act.triggered.connect(self.Find_Bill) # create insert item action and set the current tab index to 1 because Items index is 1 insert_act = QAction("Insert item", self) insert_act.setShortcut("Ctrl+I") insert_act.setIcon(QIcon("icons/007-download.png")) insert_act.triggered.connect(self.Change_to_item) # create bill book action and set the current tab index to 2 because bill book index is 2 billBook_act = QAction("Bill Book", self) billBook_act.setShortcut("Ctrl+B") billBook_act.setIcon(QIcon("icons/open-book.png")) billBook_act.triggered.connect(self.Change_to_billBook) # create color_act action color_act = QAction("color", self) color_act.setShortcut("Ctrl+Shift+C") color_act.setIcon(QIcon("icons/001-painter-palette.png")) color_act.triggered.connect(self.Color) # create font action font_act = QAction("font", self) font_act.setShortcut("Ctrl+Shift+F") font_act.setIcon(QIcon("icons/006-font.png")) font_act.triggered.connect(self.Font) # create help menu # create About action about_act = QAction("About", self) about_act.setIcon(QIcon("icons/023-information-button.png")) about_act.triggered.connect(self.About) # feedback action feedback_act = QAction("Feedback", self) feedback_act.setIcon(QIcon("icons/022-feedback.png")) feedback_act.triggered.connect(self.FeedBack) # create main menu and add sub menu and action # create menu menu = self.menuBar() menu.setNativeMenuBar(False) # create file menu file = menu.addMenu("File") file.addAction(print_act) file.addAction(save_act) file.addAction(exit_act) # create tools menu tools = menu.addMenu("Tools") # insert search bill action tools.addAction(search_bill_act) # insert insert item tools.addAction(insert_act) # insert bill book action tools.addAction(billBook_act) # create format Format = menu.addMenu("Format") # add font to format menu Format.addAction(font_act) Format.addAction(color_act) # create help menu help_menu = menu.addMenu("help") # add about_act to help help_menu.addAction(about_act) help_menu.addAction(feedback_act) def Tab(self): """ create the tab for bill, insert, analysis""" # create the tab self.tab = QTabWidget(self) # create the tab object bill, insert_item, analysis self.bill_tab = QWidget() self.insert_tab = QWidget() self.billBook_tab = QWidget() # add the tab objects to tab self.tab.addTab(self.bill_tab, "Bill") self.tab.addTab(self.insert_tab, "Items") self.tab.addTab(self.billBook_tab, "Bill Book") # call the the tabs self.billwidget() self.insertwidget() self.billBook() # create the main self.main_layout = QWidget() self.setCentralWidget(self.main_layout) self.tab_layout = QHBoxLayout() self.tab_layout.addWidget(self.tab) self.main_layout.setLayout(self.tab_layout) def billwidget(self): # buyer information # buyers name self.buyer_name = QLineEdit() self.buyer_name.resize(100, 100) self.buyer_name.setPlaceholderText("Janath Jsk") # customizing the line edit self.buyer_name.setStyleSheet("color: rgb(120, 60, 5)") # buyer_name clear button buyer_name_clear = QPushButton() buyer_name_clear.setIcon(QIcon("icons/005-cancel.png")) buyer_name_clear.setIconSize(QSize(19, 19)) buyer_name_clear.clicked.connect(self.buyer_name.clear) # buyers mobile number self.buyer_mobile = QLineEdit() self.buyer_mobile.resize(100, 100) self.buyer_mobile.setInputMask("000-000-0000") # buyer mobile clear buyer_mobile_clear = QPushButton() buyer_mobile_clear.setIcon(QIcon("icons/005-cancel.png")) buyer_mobile_clear.setIconSize(QSize(19, 19)) buyer_mobile_clear.clicked.connect(self.buyer_mobile.clear) buyer_mobile_clear.setObjectName("clear") # buyers address self.buyers_address = QTextEdit() # buyer address clear address_clear_bt = QPushButton() address_clear_bt.setIcon(QIcon("icons/005-cancel.png")) address_clear_bt.setIconSize(QSize(19, 19)) address_clear_bt.clicked.connect(self.buyers_address.clear) # create main layout and set as central widget bill_layout = QVBoxLayout() # create layout and add to main layout form_layout = QFormLayout() form_layout.setSpacing(0) # horizontal layout for buyer name and clear name_h_layout = QHBoxLayout() name_h_layout.addWidget(self.buyer_name) name_h_layout.addWidget(buyer_name_clear) # add name horizontal to form layout form_layout.addRow("Name", name_h_layout) # create horizontal layout for mobile number and clear button mobile_h_layout = QHBoxLayout() mobile_h_layout.addWidget(self.buyer_mobile) mobile_h_layout.addWidget(buyer_mobile_clear) # add mobile horizontal layout in form layout form_layout.addRow("Mobile Number", mobile_h_layout) # add address and clear button address_layout = QHBoxLayout() address_layout.addWidget(self.buyers_address) address_layout.addWidget(address_clear_bt) # add address and address clear button to form layout form_layout.addRow("Address", address_layout) # create buyer information box buyer_information_gp = QGroupBox("Buyer Information") # set the form layout as buyer information layout buyer_information_gp.setLayout(form_layout) # add buyer information box to bill_layout bill_layout.addWidget(buyer_information_gp) bill_layout.addStretch() # create the combo box for selecting the item from the sqlite3 table items # create item_dict and store the quantity and price in item_dict self.items_dict = {} # create the item query for getting data from items table items_query = QSqlQuery() items_query.exec_("SELECT name, quantity, price FROM items") # store the selected data in items_dict while items_query.next(): self.items_dict[items_query.value(0)] = (items_query.value(1), items_query.value(2)) # create item list and store the items_dict keys items_list = list(self.items_dict.keys()) # create the combo for selecting the item and when index was changed connect to Quantity to enable the quantity # box and set the range self.items_combo = QComboBox() self.items_combo.addItems(items_list) self.items_combo.currentIndexChanged.connect(self.Quantity) # create the spin box to enter the quatity self.item_quantity = QSpinBox() self.item_quantity.setEnabled(False) # create the form layout item and quantity information item_form = QFormLayout() item_form.addRow("Item Name: ", self.items_combo) item_form.addRow("Quantity: ", self.item_quantity) # create the add push button to add the item in bill add_bt = QPushButton("Add to Bill") add_bt.clicked.connect(self.AddToBill) # create horizontal layout for button bt_h_l = QHBoxLayout() bt_h_l.addStretch() bt_h_l.addWidget(add_bt) bt_h_l.addStretch() # create the vertical layout for item information box item_v_l = QVBoxLayout() item_v_l.addLayout(item_form) item_v_l.addLayout(bt_h_l) # create the group box for item information items_inf = QGroupBox("Add items") items_inf.setLayout(item_v_l) # add item information group to bill_layout bill_layout.addWidget(items_inf) # items buyed self.bill_model = QStandardItemModel() self.bill_table = QTableView() self.bill_table.SelectionMode(3) self.bill_table.setModel(self.bill_model) # set the column count for bill_model self.bill_model.setColumnCount(4) # strech the column of bill_table self.bill_table.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # set the horizontal header labels header = ["ITEMS", "QUANTITY", "PRICE", "TOTAL"] self.bill_model.setHorizontalHeaderLabels(header) # create grid layout bill1_layout = QGridLayout() bill1_layout.addLayout(bill_layout, 0, 0) bill1_layout.addWidget(self.bill_table, 0, 1) # set bill_tab layout as bill_layout self.bill_tab.setLayout(bill1_layout) def Quantity(self, text): """ after enter the item it first set the range of quantity box and set enable""" self.item_quantity.setRange(1, self.items_dict[text][0]) self.item_quantity.setEnabled(True) def AddToBill(self): pass def createTable(self): # create the sql item table model # create item model self.itemTable = QSqlRelationalTableModel() # set items table as table for item table mode self.itemTable.setTable('items') # set header names self.itemTable.setHeaderData(self.itemTable.fieldIndex('id'), Qt.Horizontal, "ITEM ID") self.itemTable.setHeaderData(self.itemTable.fieldIndex('name'), Qt.Horizontal, "ITEM NAME") self.itemTable.setHeaderData(self.itemTable.fieldIndex('quantity'), Qt.Horizontal, "STOCK") self.itemTable.setHeaderData(self.itemTable.fieldIndex('price'), Qt.Horizontal, "PRICE") self.itemTable.select() # create bill book model self.billBookTable = QSqlRelationalTableModel() # set billbook table as table for bill book model self.billBookTable.setTable('billBook') # set the header name self.billBookTable.setHeaderData(self.billBookTable.fieldIndex('id'), Qt.Horizontal, 'BILL NO') self.billBookTable.setHeaderData(self.billBookTable.fieldIndex('name'), Qt.Horizontal, "NAME") self.billBookTable.setHeaderData( self.billBookTable.fieldIndex('number'), Qt.Horizontal, "MOBILE NO") self.billBookTable.setHeaderData( self.billBookTable.fieldIndex('items'), Qt.Horizontal, "ITEMS") self.billBookTable.setHeaderData( self.billBookTable.fieldIndex('amount'), Qt.Horizontal, "AMOUNT") self.billBookTable.select() def insertwidget(self): """ create table """ # table view and create sql model and set sql mode has table view mode title = QLabel("Items") title.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) title.setStyleSheet("font: bold 24px") self.items_view = QTableView() self.items_view.setModel(self.itemTable) self.items_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # set the selection mode and behavior for item_view self.items_view.setSelectionMode(QTableView.SingleSelection) self.items_view.setSelectionBehavior(QTableView.SelectRows) # create delegate for item_view delegate = QSqlRelationalDelegate(self.items_view) self.items_view.setItemDelegate(delegate) # push button # add row button additem_button = QPushButton("Add item") additem_button.setIcon(QIcon("icons/007-download.png")) additem_button.setIconSize(QSize(10, 10)) additem_button.clicked.connect(self.additem) # delete row push button deleteitem_bt = QPushButton("delete item") deleteitem_bt.setIcon(QIcon("icons/005-cancel.png")) deleteitem_bt.setIconSize(QSize(10, 10)) deleteitem_bt.clicked.connect(self.deleteitem) # create vertical layout for push button push_layout = QHBoxLayout() push_layout.addWidget(additem_button) push_layout.addStretch() push_layout.addWidget(deleteitem_bt) # create horizontal layout for table and push button tab_layout = QVBoxLayout() tab_layout.addWidget(title, Qt.AlignCenter) push_w = QWidget() push_w.setLayout(push_layout) tab_layout.addWidget(push_w) tab_layout.addWidget(self.items_view) # set tab layout as tab widget layout self.insert_tab.setLayout(tab_layout) def billBook(self): """ show the bills """ title = QLabel("Bill Book") title.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) title.setStyleSheet("font: bold 24px") self.Book_view = QTableView() self.Book_view.setModel(self.billBookTable) # strech the horizontal header only self.Book_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # set selection behavior to select the entire row self.Book_view.setSelectionBehavior(QTableView.SelectRows) bill_V_l = QVBoxLayout() bill_V_l.addWidget(title) bill_V_l.addWidget(self.Book_view) self.billBook_tab.setLayout(bill_V_l) def Change_to_billBook(self): self.tab.setCurrentIndex(2) def Print(self): pass def closeEvent(self, event): """ exit the application""" quit_msg = QMessageBox.question(self, "Quit", "You are sure to exit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if quit_msg == QMessageBox.Yes: event.accept() else: event.ignore() def Font(self): """ open the font dialog box and user able to select font """ font, ok = QFontDialog.getFont() if ok: self.setFont(font) def Save(self): pass def Find_Bill(self): pass def Change_to_item(self): """ change to items tab""" self.tab.setCurrentIndex(1) def Color(self): pass def About(self): QMessageBox.about(self, "About", "Smart Billing created by Janath Jsk") def additem(self): print(1) last = self.itemTable.rowCount() print(last) print(2) self.itemTable.insertRow(last) print(3) id = 0 query = QSqlQuery() query.exec_("SELECT MAX (id) FROM items") print(4) if query.next(): id = int(query.value(0)) print(5) def deleteitem(self): current = self.items_view.selectedIndexes() for index in current: self.itemTable.removeRow(index.row()) self.itemTable.select() def FeedBack(self): url = "https://ut4vq9uuz4l.typeform.com/to/SjBbjdId" webbrowser.open_new_tab(url)
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.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(100) def __getFieldNames(self): emptyRec = self.tabModel.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.tabModel = QSqlRelationalTableModel(self, self.DB) self.tabModel.setTable("studInfo") self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.tabModel.setSort(self.tabModel.fieldIndex("studID"), Qt.AscendingOrder) if (self.tabModel.select() == False): QMessageBox.critical( self, "错误信息", "打开数据表错误,错误信息\n" + self.tabModel.lastError().text()) return self.__getFieldNames() self.tabModel.setHeaderData(self.fldNum["studID"], Qt.Horizontal, "学号") self.tabModel.setHeaderData(self.fldNum["name"], Qt.Horizontal, "姓名") self.tabModel.setHeaderData(self.fldNum["gender"], Qt.Horizontal, "性别") self.tabModel.setHeaderData(self.fldNum["departID"], Qt.Horizontal, "学院") self.tabModel.setHeaderData(self.fldNum["majorID"], Qt.Horizontal, "专业") self.tabModel.setRelation( self.fldNum["departID"], QSqlRelation("departments", "departID", "department")) self.tabModel.setRelation(self.fldNum["majorID"], QSqlRelation("majors", "majorID", "major")) self.selModel = QItemSelectionModel(self.tabModel) self.selModel.currentChanged.connect(self.do_currentChanged) self.ui.tableView.setModel(self.tabModel) self.ui.tableView.setSelectionModel(self.selModel) delgate = QSqlRelationalDelegate(self.ui.tableView) self.ui.tableView.setItemDelegate(delgate) self.tabModel.select() self.ui.actOpenDB.setEnabled(False) self.ui.actRecAppend.setEnabled(True) self.ui.actRecInsert.setEnabled(True) self.ui.actRecDelete.setEnabled(True) self.ui.actFields.setEnabled(True) @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_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_actFields_triggered(self): emptyRec = self.tabModel.record() str = '' for i in range(emptyRec.count()): str = str + emptyRec.fieldName(i) + '\n' QMessageBox.information(self, "所有字段名", str) def do_currentChanged(self, current, previous): self.ui.actSubmit.setEnabled(self.tabModel.isDirty()) self.ui.actRevert.setEnabled(self.tabModel.isDirty())
class APISAdvancedInputDialog(QDialog): def __init__(self, dbm, tableName, showEntriesCombo, modelColumnName=None, excludeEntries=None, parent=None): super(APISAdvancedInputDialog, self).__init__(parent) self.dbm = dbm self.tableName = tableName self.modelColumnName = modelColumnName self.showEntriesCombo = showEntriesCombo self.excludeEntries = excludeEntries self.valueToBeAdded = None self.editors = None self.record = None self.tableExists = False if self.prepairEditorsAndRecord(): self.setupForm() else: pass # something went wrong preping def prepairEditorsAndRecord(self): if not DbHasTable(self.dbm.db, self.tableName): return False self.tableExists = True self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable(self.tableName) self.model.select() while (self.model.canFetchMore()): self.model.fetchMore() self.record = self.model.record() self.editors = [] for fIdx in range(self.record.count()): field = self.record.field(fIdx) if field.name() != "ogc_fid": self.editors.append({ 'name': field.name(), 'type': field.type(), 'lineEdit': QLineEdit() }) return True def setupForm(self): layout = QFormLayout() if self.showEntriesCombo: self.uiAvailableEntriesCombo = QComboBox() # populate (but exlude if exclude has elements) if self.excludeEntries and len(self.excludeEntries) > 0: self.model.setFilter("{0} NOT IN ({1})".format( self.modelColumnName, ",".join("'{0}'".format(i) for i in self.excludeEntries))) # QMessageBox.information(self, "info", "{0} NOT IN ({1})".format(self.modelColumnName, ",".join("'{0}'".format(i) for i in self.excludeEntries))) # self.model.select() self.model.removeColumn(0) self.setupComboBox(self.uiAvailableEntriesCombo, self.model.fieldIndex(self.modelColumnName)) layout.addRow(self.uiAvailableEntriesCombo) self.uiAddBtn = QPushButton("Hinzufügen") if self.uiAvailableEntriesCombo.count() < 1: self.uiAddBtn.setEnabled(False) self.uiAddBtn.clicked.connect(self.addInputToSelection) layout.addRow(self.uiAddBtn) for editor in self.editors: # QMessageBox.information(self, "info", "{}".format((editor["name"]))) if editor["name"] != "ogc_fid": label = QLabel(editor["name"]) # QMessageBox.information(None, "info", "{}".format(editor["type"])) if editor["type"] == QVariant.Int: intVal = QIntValidator() intVal.setBottom(0) editor['lineEdit'].setValidator(intVal) layout.addRow(label, editor['lineEdit']) editor['lineEdit'].textEdited.connect(self.onTextEdited) self.uiSubmitBtn = QPushButton("Speichern") self.uiSubmitBtn.setEnabled(False) self.uiSubmitBtn.clicked.connect(self.saveInputAsQSqlRecord) layout.addRow(self.uiSubmitBtn) self.setLayout(layout) self.setWindowTitle("APIS Input Dialog") self.adjustSize() def onTextEdited(self, text): for editor in self.editors: if len(editor['lineEdit'].text().replace(" ", "")) == 0: self.uiSubmitBtn.setEnabled(False) return self.uiSubmitBtn.setEnabled(True) def addInputToSelection(self): self.setValueToBeAdded(self.uiAvailableEntriesCombo.currentText()) self.accept() def setValueToBeAdded(self, value): self.valueToBeAdded = value def getValueToBeAdded(self): return self.valueToBeAdded def saveInputAsQSqlRecord(self): for editor in self.editors: self.record.setValue(editor["name"], editor['lineEdit'].text()) if not self.record.isEmpty(): result = self.model.insertRowIntoTable(self.record) if result: self.setValueToBeAdded( self.record.field(self.modelColumnName).value()) self.accept() else: QMessageBox.warning( self, "DB Fehler", "Der folgende Feheler ist aufgetreten: {}".format( self.model.lastError().text())) self.reject() else: self.reject() def setupComboBox(self, editor, modelColumn): tv = QTableView() editor.setView(tv) tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) tv.setSelectionMode(QAbstractItemView.SingleSelection) tv.setSelectionBehavior(QAbstractItemView.SelectRows) tv.setAutoScroll(False) editor.setModel(self.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)
class APISSharding(QDialog, FORM_CLASS): shardingEditsSaved = pyqtSignal(bool) def __init__(self, iface, dbm, parent=None): """Constructor.""" super(APISSharding, self).__init__(parent) self.iface = iface self.dbm = dbm self.setupUi(self) # Initial window size/pos last saved. Use default values for first time if GetWindowSize("sharding"): self.resize(GetWindowSize("sharding")) self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat) self.editMode = False self.addMode = False self.initalLoad = True # Signals/Slot Connections self.rejected.connect(self.onReject) #self.uiButtonBox.rejected.connect(self.onReject) self.uiOkBtn.clicked.connect(self.onAccept) self.uiCancelBtn.clicked.connect(self.cancelEdit) self.uiSaveBtn.clicked.connect(self.saveEdits) mViewPictures = QMenu() aViewPicturesPreview = mViewPictures.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'image.png')), "in Vorschau") aViewPicturesPreview.triggered.connect(self.viewPictures) aViewPicturesFolder = mViewPictures.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'image.png')), "in Ordner") aViewPicturesFolder.triggered.connect(self.openPictures) self.uiViewPicturesTBtn.setMenu(mViewPictures) self.uiViewPicturesTBtn.clicked.connect( self.uiViewPicturesTBtn.showMenu) mViewSketches = QMenu() aViewSketchesPreview = mViewSketches.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'sketch.png')), "in Vorschau") aViewSketchesPreview.triggered.connect(self.viewSketches) aViewSketchesFolder = mViewSketches.addAction( QIcon( os.path.join(QSettings().value("APIS/plugin_dir"), 'ui', 'icons', 'sketch.png')), "in Ordner") aViewSketchesFolder.triggered.connect(self.openSketches) self.uiViewSketchesTBtn.setMenu(mViewSketches) self.uiViewSketchesTBtn.clicked.connect( self.uiViewSketchesTBtn.showMenu) self.initalLoad = False def openSharding(self, siteNumber, shardingNumber): self.initalLoad = True self.siteNumber = siteNumber self.shardingNumber = shardingNumber #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber, shardingNumber))) # Setup sharding model self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("begehung") self.model.setFilter("fundortnummer='{0}' AND begehung='{1}'".format( self.siteNumber, self.shardingNumber)) res = self.model.select() self.setupMapper() self.mapper.toFirst() self.setKgNameAndCode() self.initalLoad = False def setKgNameAndCode(self): query = QSqlQuery(self.dbm.db) qryStr = u"select CASE WHEN katastralgemeinde IS NULL AND katastralgemeindenummer IS NULL THEN '--' ELSE katastralgemeindenummer || ' - ' || katastralgemeinde END AS kg FROM fundort WHERE fundortnummer = '{0}'".format( self.siteNumber) query.exec_(qryStr) query.first() self.uiCadastralCommunityEdit.setText(query.value(0)) def setupMapper(self): self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setItemDelegate(ShardingDelegate()) self.mapper.setModel(self.model) self.mandatoryEditors = [self.uiShardingDate] # LineEdits & PlainTextEdits self.intValidator = QIntValidator() self.doubleValidator = QDoubleValidator() self.lineEditMaps = { "fundortnummer": { "editor": self.uiSiteNumberEdit }, "begehung": { "editor": self.uiShardingNumberEdit }, "name": { "editor": self.uiNameEdit }, "parzelle": { "editor": self.uiPlotPTxt }, "sichtbarkeit": { "editor": self.uiVisibilityEdit }, "verbleib": { "editor": self.uiWhereaboutsEdit }, "funde": { "editor": self.uiFindsPTxt }, "morphologie": { "editor": self.uiMorphologyPTxt }, "sonstiges": { "editor": self.uiMiscellaneousPTxt } } for key, item in self.lineEditMaps.items(): self.mapper.addMapping(item["editor"], self.model.fieldIndex(key)) if "validator" in item: item["editor"].setValidator(item["validator"]) #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"])) item["editor"].textChanged.connect(self.onLineEditChanged) # Date and Times self.mapper.addMapping(self.uiShardingDate, self.model.fieldIndex("datum")) # ComboBox without Model self.mapper.addMapping(self.uiShardingTypeCombo, self.model.fieldIndex("begehtyp")) self.uiShardingTypeCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiShardingTypeCombo.setAutoCompletion(True) self.uiShardingTypeCombo.lineEdit().setValidator( InListValidator([ self.uiShardingTypeCombo.itemText(i) for i in range(self.uiShardingTypeCombo.count()) ], self.uiShardingTypeCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionPlantCoverCombo, self.model.fieldIndex("zustand_bewuchs")) self.uiConditionPlantCoverCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionPlantCoverCombo.setAutoCompletion(True) self.uiConditionPlantCoverCombo.lineEdit().setValidator( InListValidator([ self.uiConditionPlantCoverCombo.itemText(i) for i in range(self.uiConditionPlantCoverCombo.count()) ], self.uiConditionPlantCoverCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionLightCombo, self.model.fieldIndex("zustand_licht")) self.uiConditionLightCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionLightCombo.setAutoCompletion(True) self.uiConditionLightCombo.lineEdit().setValidator( InListValidator([ self.uiConditionLightCombo.itemText(i) for i in range(self.uiConditionLightCombo.count()) ], self.uiConditionLightCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionSoilCombo, self.model.fieldIndex("zustand_boden")) self.uiConditionSoilCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionSoilCombo.setAutoCompletion(True) self.uiConditionSoilCombo.lineEdit().setValidator( InListValidator([ self.uiConditionSoilCombo.itemText(i) for i in range(self.uiConditionSoilCombo.count()) ], self.uiConditionSoilCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionMoistureCombo, self.model.fieldIndex("zustand_feuchtigkeit")) self.uiConditionMoistureCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionMoistureCombo.setAutoCompletion(True) self.uiConditionMoistureCombo.lineEdit().setValidator( InListValidator([ self.uiConditionMoistureCombo.itemText(i) for i in range(self.uiConditionMoistureCombo.count()) ], self.uiConditionMoistureCombo.lineEdit(), None, self)) # ComboBox without Model self.mapper.addMapping(self.uiConditionRainCombo, self.model.fieldIndex("zustand_abgeregnet")) self.uiConditionRainCombo.editTextChanged.connect( self.onLineEditChanged) # FIXME Pyqt5 AutoCompletion #self.uiConditionRainCombo.setAutoCompletion(True) self.uiConditionRainCombo.lineEdit().setValidator( InListValidator([ self.uiConditionRainCombo.itemText(i) for i in range(self.uiConditionRainCombo.count()) ], self.uiConditionRainCombo.lineEdit(), None, self)) def onLineEditChanged(self): sender = self.sender() if not self.editMode and not self.initalLoad: self.startEditMode() if not self.initalLoad: sender.setStyleSheet( "{0} {{background-color: rgb(153, 204, 255);}}".format( sender.metaObject().className())) self.editorsEdited.append(sender) def onAccept(self): ''' Check DB Save options when pressing OK button Update Plugin Status ''' # Save Settings SetWindowSize("sharding", self.size()) self.accept() def onReject(self): ''' Run some actions when the user closes the dialog ''' if self.editMode: res = self.cancelEdit() if res: SetWindowSize("sharding", self.size()) self.close() else: self.show() else: SetWindowSize("sharding", self.size()) self.close() def addNewSharding(self, siteNumber): self.initalLoad = True self.siteNumber = siteNumber # get new sharding number query = QSqlQuery(self.dbm.db) qryStr = "SELECT CASE WHEN max(begehung) IS NULL THEN 1 ELSE max(begehung)+1 END begehungNeu FROM begehung WHERE fundortnummer='{0}'".format( self.siteNumber) query.exec_(qryStr) query.first() self.shardingNumber = query.value(0) self.model = QSqlRelationalTableModel(self, self.dbm.db) self.model.setTable("begehung") self.model.setFilter("fundortnummer='{0}'".format(self.siteNumber)) res = self.model.select() #self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() row = self.model.rowCount() #QMessageBox.information(None, "begehung", "{0}".format(row)) self.model.insertRow(row) #QMessageBox.information(None, "begehung", "{0}".format(self.model.rowCount())) self.setupMapper() self.mapper.toLast() self.addMode = True self.startEditMode() # self.mapper.submit() # self.model.insertRow(row) # self.mapper.setCurrentIndex(row) self.uiSiteNumberEdit.setText(self.siteNumber) self.uiShardingNumberEdit.setText(str(self.shardingNumber)) now = QDate.currentDate() self.uiShardingDate.setDate(now) self.setKgNameAndCode() #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber,nn))) self.initalLoad = False def removeNewSharding(self): self.initalLoad = True row = self.mapper.currentIndex() self.model.removeRow(row + 1) self.model.submitAll() while (self.model.canFetchMore()): self.model.fetchMore() self.mapper.toLast() self.initalLoad = False def saveEdits(self): #Check Mandatory fields flag = False for mEditor in self.mandatoryEditors: cName = mEditor.metaObject().className() if cName == 'QDateEdit': value = mEditor.date().toString("yyyy-MM-dd") elif cName == 'QLineEdit': value = mEditor.text() elif cName == 'QComboBox': if mEditor.isEditable(): value = mEditor.lineEdit().text() else: if mEditor.currentIndex == -1: value = '' else: value = '1' if value.strip() == "": flag = True mEditor.setStyleSheet( "{0} {{background-color: rgb(240, 160, 160);}}".format( cName)) if mEditor not in self.editorsEdited: self.editorsEdited.append(mEditor) else: if mEditor in self.editorsEdited: mEditor.setStyleSheet( "{0} {{background-color: rgb(153, 204, 255);}}".format( cName)) #else: #mEditor.setStyleSheet("") if flag: QMessageBox.warning( self, self.tr(u"Benötigte Felder Ausfüllen"), self. tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind." )) return False #saveToModel currIdx = self.mapper.currentIndex() #QMessageBox.information(None, "begehung", "{0}".format(currIdx)) #now = QDate.currentDate() #self.uiLastChangesDate.setDate(now) self.mapper.submit() self.mapper.setCurrentIndex(currIdx) # emit signal self.shardingEditsSaved.emit(True) self.endEditMode() return True def cancelEdit(self): currIdx = self.mapper.currentIndex() if self.editMode: result = QMessageBox.question( self, self.tr(u"Änderungen wurden vorgenommen!"), self.tr(u"Möchten Sie die Änerungen speichern?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) #save or not save if result == QMessageBox.Yes: res = self.saveEdits() if res: return True else: return False elif result == QMessageBox.No: if self.addMode: #self.close() self.done(1) self.removeNewSharding() self.endEditMode() return True else: self.mapper.setCurrentIndex(currIdx) self.endEditMode() return True def startEditMode(self): self.editMode = True self.uiOkBtn.setEnabled(False) self.uiSaveBtn.setEnabled(True) self.uiCancelBtn.setEnabled(True) self.editorsEdited = [] self.uiShardingDate.setReadOnly(not self.addMode) if self.uiShardingDate.isReadOnly(): self.uiShardingDate.setStyleSheet( "background-color: rgb(218, 218, 218);") else: self.uiShardingDate.setStyleSheet("") def endEditMode(self): self.editMode = False self.addMode = False self.uiOkBtn.setEnabled(True) self.uiSaveBtn.setEnabled(False) self.uiCancelBtn.setEnabled(False) self.uiShardingDate.setReadOnly(not self.addMode) self.uiShardingDate.setStyleSheet( "background-color: rgb(218, 218, 218);") for editor in self.editorsEdited: cName = editor.metaObject().className() if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly(): editor.setStyleSheet( "{0} {{background-color: rgb(218, 218, 218);}}".format( cName)) else: editor.setStyleSheet("") self.editorsEdited = [] def viewPictures(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_foto_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType self.loadInImageViewer(path) def openPictures(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_foto_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType if not OpenFileOrFolder(path): QMessageBox.information( self, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path)) def viewSketches(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_sketch_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType self.loadInImageViewer(path) def openSketches(self): dirName = self.settings.value("APIS/insp_image_dir") folderNameType = self.settings.value("APIS/insp_image_sketch_dir") folderNameSite = self.getFolderNameSite(self.siteNumber) path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType if not OpenFileOrFolder(path): QMessageBox.information( None, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path)) def getFolderNameSite(self, siteNumber): query = QSqlQuery(self.dbm.db) #qryStr = u"SELECT trim(katastralgemeinde) || ' ' || trim(katastralgemeindenummer) || '.' || substr('000' || fundortnummer_nn_legacy, -3, 3) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'".format(siteNumber) query.prepare( u"SELECT land || '\\' || CASE WHEN land = 'AUT' THEN replace(replace(replace(replace(lower(trim(katastralgemeinde)), '.',''), '-', ' '), '(', ''), ')', '') || ' ' ELSE '' END || substr('000000' || fundortnummer_nn, -6, 6) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'" .format(siteNumber)) query.exec_() query.first() return query.value(0) def loadInImageViewer(self, path): dir = QDir(path) if dir.exists(): entryList = dir.entryList(['*.jpg'], QDir.Files) if len(entryList) > 0: # load in thumb viewer # QMessageBox.information(None, u"Begehung", u",".join(entryList)) imagePathList = [] for image in entryList: imagePathList.append(path + u'\\' + image) widget = APISThumbViewer() widget.load(imagePathList) widget.show() if widget.exec_(): pass # app.exec_() else: QMessageBox.information( self, u"Begehung", u"Es wurden keine Dateien [*.jpg] für diesen Fundort gefunden." ) else: QMessageBox.information( self, u"Begehung", u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path))