def __init__(self): start = time.time() self.app = QApplication([]) super().__init__() self.tableModel = TableModel('Id', 'Num', 'Str') self.tableModel.addRow((-1, 0, 'Test .addItem()')) self.tableModel.addRows([(_, random.uniform(-5, 5), f'{_}_str_{_}') for _ in range(1000)]) self.sortModel = SortFilterProxyModel(self.tableModel) self.sortModel.sortend.connect(self.sortEnd) self.rootContext().setContextProperty('sortModel', self.sortModel) self.tableModel2 = TableModel('Dt', 'Name', 'LastName') self.tableModel2.addRows([(self.rndDt(), self.rndWorld(), self.rndWorld()) for _ in range(1000)]) self.sortModel2 = SortFilterProxyModel(self.tableModel2) self.sortModel2.sortend.connect(self.sortEnd) self.rootContext().setContextProperty('sortModel2', self.sortModel2) self.load('main.qml') self.footer = self.rootObjects()[0].findChild(QObject, 'footer') self.footer.setProperty( 'text', f'Initialization in {time.time()-start:.2f} sec') self.app.exec_()
def page(self): """Pages query results""" if not self.paginator: return self.model = None # if data is not fetched from paginator yet we must recreate model # because we dont know beforehead if data will arrive. # otherwise we can end up in situation when paginator is already # fetched (might be partially), model is None and # no new data will arrive in for loop (paginator.feeder) # this potential situation leads to empty model in view if not self.paginator.fetched: self.model = TableModel(columns=self.paginator.headers()) # let's save current state of the cursor savedCursor = self.cursor() try: # set the cursor to the wait cursor self.setCursor(QtCore.Qt.WaitCursor) # feed the model for row in self.paginator.feeder(self.__is_forward(self.sender)): # we must be ensured that model is changed when # actual data arrives only if not self.model: self.model = TableModel(columns=self.paginator.headers()) # data self.model.input_data.append(row[0]) # row number self.model.rows.append(row[1]) # return the cursor to the previous state self.setCursor(savedCursor) except (self.db_provider.Error, self.db_provider.Warning) as err: # return the cursor to the previous state self.setCursor(savedCursor) # unset current page self.lblCurrentPage.setText("") self.message_box("Error!", str(err), QMessageBox.Critical) # clean the model self.tbvResults.setModel(None) return False if not self.model: return False # clean the model self.__update_model_in_view() # update last query result time and page number self.__update_time_and_page() if self.__is_forward(self.sender): self.tbvResults.selectRow(0) else: self.tbvResults.selectRow(self.model.rowCount(None) - 1) return True
def __init__(self, app, parent=None): #GUI Initialisierien super(Controller, self).__init__(parent) self.view = Ui_Wienwahl() self.view.setupUi(self) self.app = app #Shortcuts erstellen self.createShortcuts() #Menue verlinken self.linkMenu() #Init self.model = TableModel() self.db = Database() self.filename = None self.view.tableView.setSortingEnabled(True) self.undoStack = QUndoStack() self.view.tableView.setItemDelegate(ItemDelegate(self.undoStack))
class Models: Bot = TableModel.factory("databot_bot") Intent = TableModel.factory("databot_intent") Entity = TableModel.factory("databot_entity") Variable = TableModel.factory("databot_variable") Rule = TableModel.factory("databot_rule") User = TableModel.factory("databot_user")
class Main(QQmlApplicationEngine): def __init__(self): start = time.time() self.app = QApplication([]) super().__init__() self.tableModel = TableModel('Id', 'Num', 'Str') self.tableModel.addRow((-1, 0, 'Test .addItem()')) self.tableModel.addRows([(_, random.uniform(-5, 5), f'{_}_str_{_}') for _ in range(1000)]) self.sortModel = SortFilterProxyModel(self.tableModel) self.sortModel.sortend.connect(self.sortEnd) self.rootContext().setContextProperty('sortModel', self.sortModel) self.tableModel2 = TableModel('Dt', 'Name', 'LastName') self.tableModel2.addRows([(self.rndDt(), self.rndWorld(), self.rndWorld()) for _ in range(1000)]) self.sortModel2 = SortFilterProxyModel(self.tableModel2) self.sortModel2.sortend.connect(self.sortEnd) self.rootContext().setContextProperty('sortModel2', self.sortModel2) self.load('main.qml') self.footer = self.rootObjects()[0].findChild(QObject, 'footer') self.footer.setProperty( 'text', f'Initialization in {time.time()-start:.2f} sec') self.app.exec_() def rndDt(self): return datetime.fromtimestamp(random.randint(1, int(time.time()))) def rndWorld(self): chrs = 'abcdefghiklmnopqrstvxyz' return chrs[random.randint(0, len(chrs) - 1)].upper() + ''.join( random.choice(chrs) for _ in range(random.randint(4, 10))) def sortEnd(self, items, time): self.footer.setProperty('text', f'Sorting {items} rows in {time:.2f} sec')
class MainForm(QWidget, FORM_CLASS): def __init__(self, parent=None): # initialization super().__init__(parent) self.setupUi(self) self.__add_custom_tableview() self.leRowsPerPage.setText("001000") self.conn = None self.model = None self.db_provider = None # paginator self.paginator = None # describe DB providers here # order needs to be maintained to ensure that SQLite is the first one self.providers = {"SQLite": "sqlite3", "PostgreSQL": "psycopg2"} # add items to the list self.cmbProvider.addItems(self.providers.keys()) # connect signals self.pbCheck.clicked.connect(self.check_connection) self.pbExecute.clicked.connect(self.execute_query) self.pbClose.clicked.connect(self.close_all) self.leConnection.editingFinished.connect(self.reset_conn) self.cmbProvider.currentIndexChanged.connect(self.provider_changed) self.pbForth.clicked.connect(self.page) self.pbBack.clicked.connect(self.page) # signals and slots for CustomTableView self.tbvResults.top_reached_signal.connect(self.pbBack.click) self.tbvResults.bottom_reached_signal.connect(self.pbForth.click) def __add_custom_tableview(self) -> bool: """ Removes standard QTableView, adds custom CustomTableView to the form. """ self.verticalLayout_2.removeWidget(self.tbvResults) self.tbvResults.deleteLater() self.tbvResults = None self.tbvResults = CustomTableView(self.gpbResults) self.tbvResults.setFrameShape(QtWidgets.QFrame.Panel) self.tbvResults.setObjectName("tbvResults") self.tbvResults.horizontalHeader().setVisible(True) self.verticalLayout_2.addWidget(self.tbvResults) self.verticalLayout_2.insertWidget(0, self.tbvResults) return True def close_all(self): # finish up the connection self.reset_conn() self.close() def keyPressEvent(self, *args, **kwargs): """ Overriding of parent's (Qt) method, that's why camelCase used. Ctrl+Enter executes query. """ # check if Ctrl+Enter|Return pressed if (args[0].key() == QtCore.Qt.Key_Enter or args[0].key() == QtCore.Qt.Key_Return ) and args[0].modifiers() == QtCore.Qt.ControlModifier: # execute query self.execute_query() elif args[0].key() == QtCore.Qt.Key_Escape: self.pbClose.clicked.emit() else: # regular reaction return QWidget.keyPressEvent(self, *args, **kwargs) @pyqtSlot() def check_connection(self, user: bool = True) -> bool: """Check button handler.""" try: self.conn = self.try_to_connect() except ( ModuleNotFoundError, RuntimeError, ValueError, self.db_provider.Error, self.db_provider.Warning, ) as err: self.message_box( "Error!", f"Connection can not be established due to: {str(err)}", QMessageBox.Critical, ) return False else: if user: self.message_box( "Success!", "Connection established", QMessageBox.Information, ) return True def __import_provider(self, provider_name: str): """Trying to import module for the provider and return it.""" return importlib.import_module(str(self.providers[provider_name])) def __is_sqlite_db(self) -> bool: """Checks if DB provider is SQLite""" return self.db_provider.__name__ == "sqlite3" def __is_db_in_memory(self, db_type: str = ":memory:") -> bool: """ Checks if database connection is of type :memory:. Makes sense for SQLite only. """ return db_type == ":memory:" def __is_file(self, path_str: str = "") -> bool: """Checks if the path is a file.""" return os.path.isfile(path_str) def __create_sqlite_file(self, file_name: str = ""): """ Ckecks if user wants to create new SQLite file. Otherwise rises an exception. """ question = ( f"The file {file_name} does not exist! Do you want to create it?") res = self.message_box( "Attention!", question, QMessageBox.Warning, buttons=QMessageBox.Ok | QMessageBox.Cancel, ) if res != QMessageBox.Ok: raise RuntimeError("no such file!") def try_to_connect(self): """ Connects to the database with the connection string provided by the user. """ if self.conn: return self.conn # it's unknown what type of provider will user choose, so import here self.db_provider = self.__import_provider( self.cmbProvider.currentData(0)) db_conn_str = self.leConnection.text().strip() if not db_conn_str: raise ValueError("no connection string provided!") # since SQLite DB is a file we need to check if there is such file # or user wants to create new one if (self.__is_sqlite_db() and not self.__is_db_in_memory(db_conn_str) and not self.__is_file(db_conn_str)): # Exception might be risen here self.__create_sqlite_file(db_conn_str) return self.db_provider.connect(db_conn_str) def __is_query_exists(self) -> bool: """Checks if query text is present.""" if self.teQuery.toPlainText().strip(): return True self.message_box("Error!", "No query provided", QMessageBox.Critical) return False @pyqtSlot() def execute_query(self): """Handles 'Execute' button.""" if not self.check_connection(False) or not self.__is_query_exists(): return False # let's try to create paginator object and execute query inside of it try: self.paginator = QueryPaginator( rows_num=int(self.leRowsPerPage.displayText().strip()), connection=self.conn, query=self.teQuery.toPlainText().strip(), ) except ( ValueError, self.db_provider.Error, self.db_provider.Warning, ) as err: self.lblCurrentPage.setText("") self.message_box("Error!", str(err), QMessageBox.Critical) return False # model is created when forth or back button pressed # in order to create model we must emit signal self.pbForth.clicked.emit() def __is_forward(self, sender) -> bool: """Checks if direction is forward""" if sender().objectName() == BACK_BUTTON_NAME: return False return True @pyqtSlot() def page(self): """Pages query results""" if not self.paginator: return self.model = None # if data is not fetched from paginator yet we must recreate model # because we dont know beforehead if data will arrive. # otherwise we can end up in situation when paginator is already # fetched (might be partially), model is None and # no new data will arrive in for loop (paginator.feeder) # this potential situation leads to empty model in view if not self.paginator.fetched: self.model = TableModel(columns=self.paginator.headers()) # let's save current state of the cursor savedCursor = self.cursor() try: # set the cursor to the wait cursor self.setCursor(QtCore.Qt.WaitCursor) # feed the model for row in self.paginator.feeder(self.__is_forward(self.sender)): # we must be ensured that model is changed when # actual data arrives only if not self.model: self.model = TableModel(columns=self.paginator.headers()) # data self.model.input_data.append(row[0]) # row number self.model.rows.append(row[1]) # return the cursor to the previous state self.setCursor(savedCursor) except (self.db_provider.Error, self.db_provider.Warning) as err: # return the cursor to the previous state self.setCursor(savedCursor) # unset current page self.lblCurrentPage.setText("") self.message_box("Error!", str(err), QMessageBox.Critical) # clean the model self.tbvResults.setModel(None) return False if not self.model: return False # clean the model self.__update_model_in_view() # update last query result time and page number self.__update_time_and_page() if self.__is_forward(self.sender): self.tbvResults.selectRow(0) else: self.tbvResults.selectRow(self.model.rowCount(None) - 1) return True def __update_model_in_view(self): """Updates model in view.""" self.tbvResults.setModel(None) self.tbvResults.setModel(self.model) self.tbvResults.selectRow(0) def __update_time_and_page(self): """Updates execution time and page number""" self.lblUpdateTime.setText( datetime.now().strftime("%Y-%m-%d %H:%M:%S")) self.lblCurrentPage.setText(str(self.paginator.current_page)) @pyqtSlot() def reset_conn(self): """Resets connection""" if self.conn: self.conn.close() self.conn = None @pyqtSlot(int) def provider_changed(self, index): """Handles provider change in the providers list box. Resets conn.""" self.reset_conn() def message_box(self, text, informative, icon, buttons=QMessageBox.Ok): """Wraps up the QMessageBox""" msg = QMessageBox(self) msg.setStandardButtons(buttons) msg.setDefaultButton(QMessageBox.Ok) msg.setText(text) msg.setInformativeText(informative) msg.setIcon(icon) return msg.exec_()
self.process.setText(_translate("MainWindow", "Process")) if __name__ == "__main__": import sys import pandas as pd # test data df = pd.DataFrame({ 'a': ['Mary', 'Jim', 'John'], 'b': [100, 200, 300], 'c': ['a', 'b', 'c'] }) # Instanziazione app e mainwindow app = QtWidgets.QApplication(sys.argv) tablemodel = TableModel(df) mainwindow = MainWindow(tablemodel) # Visualizzazione mainwindow #mainwindow.show() #inizializzazione schermata inziale mainwindow.openFirstWindow() #altro... tablemodel.provastampa() #chiusura programma sys.exit(app.exec_())
class Controller(QMainWindow): def __init__(self, app, parent=None): #GUI Initialisierien super(Controller, self).__init__(parent) self.view = Ui_Wienwahl() self.view.setupUi(self) self.app = app #Shortcuts erstellen self.createShortcuts() #Menue verlinken self.linkMenu() #Init self.model = TableModel() self.db = Database() self.filename = None self.view.tableView.setSortingEnabled(True) self.undoStack = QUndoStack() self.view.tableView.setItemDelegate(ItemDelegate(self.undoStack)) def createShortcuts(self): QShortcut(QKeySequence("CTRL+Q"), self, self.exit) QShortcut(QKeySequence("CTRL+C"), self, self.copy) QShortcut(QKeySequence("CTRL+V"), self, self.paste) QShortcut(QKeySequence("CTRL+Z"), self, self.undo) QShortcut(QKeySequence("CTRL+Y"), self, self.redo) QShortcut(QKeySequence("CTRL+X"), self, self.cut) def linkMenu(self): self.view.actionExit.triggered.connect(self.exit) self.view.actionOpen.triggered.connect(self.open) self.view.actionNew.triggered.connect(self.new) self.view.actionSave.triggered.connect(self.save) self.view.actionSaveAs.triggered.connect(self.saveAs) self.view.actionAddNewRow.triggered.connect(self.addNewRow) self.view.actionDuplicateRow.triggered.connect(self.duplicateRow) self.view.actionDeleteRow.triggered.connect(self.deleteRow) self.view.actionSaveToDB.triggered.connect(self.saveToDB) self.view.actionLoadFromDB.triggered.connect(self.loadFromDB) self.view.actionGenerateProjection.triggered.connect( self.generateProjection) self.view.actionUndo.triggered.connect(self.undo) self.view.actionRedo.triggered.connect(self.redo) self.view.actionCopy.triggered.connect(self.copy) self.view.actionPaste.triggered.connect(self.paste) self.view.actionCut.triggered.connect(self.cut) def open(self): self.view.statusBar.showMessage("Opening file...", 2000) self.fileName = QFileDialog.getOpenFileName(self, "Open CSV", QDir.homePath(), "CSV Files (*.csv)") csv = CSVManager.importCSV(self, self.fileName[0]) self.model.update(csv[0], csv[1]) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def new(self): self.view.statusBar.showMessage("Creating new file...", 750) csvheader = [["#"], ["Col1"], ["Col2"]] csvdata = [["1", "Data1", "Data2"]] self.model.update(csvheader, csvdata) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def save(self): self.view.statusBar.showMessage("Saving to file...", 2000) if self.fileName is None: self.fileName = QFileDialog.getSaveFileName( self, "Save CSV", QDir.homePath(), "CSV Files (*.csv)") CSVManager.exportCSV(self, self.fileName[0], self.model.getDataForExport()) def saveAs(self): self.view.statusBar.showMessage("Saving to file...", 2000) self.fileName = QFileDialog.getSaveFileName(self, "Save CSV", QDir.homePath(), "CSV Files (*.csv)") CSVManager.exportCSV(self, self.fileName[0], self.model.getDataForExport()) def exit(self): self.view.statusBar.showMessage("Exiting...", 2000) sys.exit() def addNewRow(self): self.view.statusBar.showMessage("Adding new row...", 1000) self.model.insertRow() def duplicateRow(self): self.view.statusBar.showMessage("Duplicating rows...", 1000) selected = self.view.tableView.selectedIndexes() self.model.duplicateRow(selected) def deleteRow(self): self.view.statusBar.showMessage("Deleting rows...", 1000) selected = self.view.tableView.selectedIndexes() self.model.deleteRow(selected) def copy(self): if len(self.view.tableView.selectionModel().selectedIndexes()) != 0: clipboard = QApplication.clipboard() selected_index = self.view.tableView.selectionModel( ).selectedIndexes()[0] selected_text = str(self.model.data(selected_index)) clipboard.setText(selected_text) def paste(self): if len(self.view.tableView.selectionModel().selectedIndexes()) != 0: clipboard = QApplication.clipboard() index = self.view.tableView.selectionModel().selectedIndexes()[0] command = EditCommand(self.model, index) command.newValue(str(clipboard.text())) self.undoStack.beginMacro("Paste") self.undoStack.push(command) self.undoStack.endMacro() self.view.tableView.reset() def cut(self): self.copy() index = self.view.tableView.selectionModel().selectedIndexes()[0] command = EditCommand(self.model, index) command.newValue("") self.undoStack.beginMacro("Cut") self.undoStack.push(command) self.undoStack.endMacro() self.view.tableView.reset() def undo(self): print() self.undoStack.undo() self.view.tableView.reset() def redo(self): self.undoStack.redo() self.view.tableView.reset() def saveToDB(self): export = self.model.getDataForExport() export = [export[0]] + export[1] self.db.save_to_db(export, self.view.statusBar) def loadFromDB(self): data = self.db.read_from_db(self.view.statusBar) self.model.update(data[0], data[1:]) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def generateProjection(self): pro = self.db.generateProjection(self.view.statusBar) if pro is not False: pro_header = [["Partei"], ["Stimmen in %"]] self.model.update(pro_header, pro) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model)
QMessageBox.warning(self, 'Error', 'Empty username or password!', QMessageBox.Ok) return userRegister = getLogFromDb(log, passwd) if userRegister is not None: QMessageBox.warning(self, 'Error', 'Error, username exists enter another one.', QMessageBox.Ok) return addNewUser(log, passwd) model.layoutChanged.emit() self.refreshView() QMessageBox.information(self, 'Success', f'Account created {log}!', QMessageBox.Ok) def save(self): saveTasks(model.datatable) model.layoutChanged.emit() tasks = readData(self.user) model.update(tasks) self.refreshView() if __name__ == '__main__': app = QApplication([]) connect() model = tm.TableModel() window = ToDo() window.show() sys.exit(app.exec_())
class Controller(QMainWindow): def __init__(self, app, parent=None): #GUI Initialisierien super(Controller, self).__init__(parent) self.view = Ui_Wienwahl() self.view.setupUi(self) self.app = app #Shortcuts erstellen self.createShortcuts() #Menue verlinken self.linkMenu() #Init self.model = TableModel() self.db = Database() self.filename = None self.view.tableView.setSortingEnabled(True) self.undoStack = QUndoStack() self.view.tableView.setItemDelegate(ItemDelegate(self.undoStack)) def createShortcuts(self): QShortcut(QKeySequence("CTRL+Q"), self, self.exit) QShortcut(QKeySequence("CTRL+C"), self, self.copy) QShortcut(QKeySequence("CTRL+V"), self, self.paste) QShortcut(QKeySequence("CTRL+Z"), self, self.undo) QShortcut(QKeySequence("CTRL+Y"), self, self.redo) QShortcut(QKeySequence("CTRL+X"), self, self.cut) def linkMenu(self): self.view.actionExit.triggered.connect(self.exit) self.view.actionOpen.triggered.connect(self.open) self.view.actionNew.triggered.connect(self.new) self.view.actionSave.triggered.connect(self.save) self.view.actionSaveAs.triggered.connect(self.saveAs) self.view.actionAddNewRow.triggered.connect(self.addNewRow) self.view.actionDuplicateRow.triggered.connect(self.duplicateRow) self.view.actionDeleteRow.triggered.connect(self.deleteRow) self.view.actionSaveToDB.triggered.connect(self.saveToDB) self.view.actionLoadFromDB.triggered.connect(self.loadFromDB) self.view.actionGenerateProjection.triggered.connect(self.generateProjection) self.view.actionUndo.triggered.connect(self.undo) self.view.actionRedo.triggered.connect(self.redo) self.view.actionCopy.triggered.connect(self.copy) self.view.actionPaste.triggered.connect(self.paste) self.view.actionCut.triggered.connect(self.cut) def open(self): self.view.statusBar.showMessage("Opening file...", 2000) self.fileName = QFileDialog.getOpenFileName(self,"Open CSV", QDir.homePath(), "CSV Files (*.csv)") csv = CSVManager.importCSV(self, self.fileName[0]) self.model.update(csv[0],csv[1]) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def new(self): self.view.statusBar.showMessage("Creating new file...", 750) csvheader = [["#"],["Col1"],["Col2"]] csvdata = [["1","Data1","Data2"]] self.model.update(csvheader, csvdata) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def save(self): self.view.statusBar.showMessage("Saving to file...", 2000) if self.fileName is None: self.fileName = QFileDialog.getSaveFileName(self,"Save CSV", QDir.homePath(), "CSV Files (*.csv)") CSVManager.exportCSV(self, self.fileName[0], self.model.getDataForExport()) def saveAs(self): self.view.statusBar.showMessage("Saving to file...", 2000) self.fileName = QFileDialog.getSaveFileName(self,"Save CSV", QDir.homePath(), "CSV Files (*.csv)") CSVManager.exportCSV(self, self.fileName[0], self.model.getDataForExport()) def exit(self): self.view.statusBar.showMessage("Exiting...", 2000) sys.exit() def addNewRow(self): self.view.statusBar.showMessage("Adding new row...", 1000) self.model.insertRow() def duplicateRow(self): self.view.statusBar.showMessage("Duplicating rows...", 1000) selected = self.view.tableView.selectedIndexes() self.model.duplicateRow(selected) def deleteRow(self): self.view.statusBar.showMessage("Deleting rows...", 1000) selected = self.view.tableView.selectedIndexes() self.model.deleteRow(selected) def copy(self): if len(self.view.tableView.selectionModel().selectedIndexes()) != 0: clipboard = QApplication.clipboard() selected_index = self.view.tableView.selectionModel().selectedIndexes()[0] selected_text = str(self.model.data(selected_index)) clipboard.setText(selected_text) def paste(self): if len(self.view.tableView.selectionModel().selectedIndexes()) != 0: clipboard = QApplication.clipboard() index = self.view.tableView.selectionModel().selectedIndexes()[0] command = EditCommand(self.model, index) command.newValue(str(clipboard.text())) self.undoStack.beginMacro("Paste") self.undoStack.push(command) self.undoStack.endMacro() self.view.tableView.reset() def cut(self): self.copy() index = self.view.tableView.selectionModel().selectedIndexes()[0] command = EditCommand(self.model, index) command.newValue("") self.undoStack.beginMacro("Cut") self.undoStack.push(command) self.undoStack.endMacro() self.view.tableView.reset() def undo(self): print() self.undoStack.undo() self.view.tableView.reset() def redo(self): self.undoStack.redo() self.view.tableView.reset() def saveToDB(self): export = self.model.getDataForExport() export = [export[0]]+export[1] self.db.save_to_db(export, self.view.statusBar) def loadFromDB(self): data = self.db.read_from_db(self.view.statusBar) self.model.update(data[0], data[1:]) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model) def generateProjection(self): pro = self.db.generateProjection(self.view.statusBar) if pro is not False: pro_header = [["Partei"],["Stimmen in %"]] self.model.update(pro_header, pro) self.view.tableView.reset() self.view.tableView.repaint() self.view.tableView.setModel(self.model)