def filling_table_shifts(month: str, stItModel: QtGui.QStandardItemModel): try: dictMonth = load_data_file(month + '.txt') # except (FileNotFoundError, EOFError): # # диалоговое окно с информацией о отсутствии смен в текущем месяце create_dialog_message(splash, 'Нет смен в выбраном месяце.', 'Попробуйте выбрать другой месяц.') # если файл существует то заполняем таблицу смен except _pickle.UnpicklingError: # create_dialog_message(splash, 'Файл повреждён!!!', 'Требуется восстановление файла') else: # index = QtCore.QModelIndex() # просто индекс stItModel.removeColumns(0, stItModel.columnCount(index), parent=index) # shiftsNameList = list(dictMonth.keys()) # список названий смен stItModel.setHorizontalHeaderLabels(shiftsNameList) date_list = [] # список для временного хранения данных по сменам for key_dateMonth in dictMonth.keys( ): # цикл для заполнения списка данных по сменам date_list.append(dictMonth[key_dateMonth] ) # заполняем список с данными по сменам for j in range(stItModel.columnCount(index)): # цикл по колонкам for row in range(stItModel.rowCount(index)): # цикл по строкам stItModel.setItem(row, j, QtGui.QStandardItem( date_list[j][row])) # заполнение таблицы
class QmyFormTable(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_QWFormTable() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.__dlgSetHeaders = None self.setAutoFillBackground(True) self.setCentralWidget(self.ui.tableView) self.ui.tableView.setAlternatingRowColors(True) ## self.ui.tableView.verticalHeader().setDefaultSectionSize(25) #缺省行高 ## self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) #单选 ## self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems) #单元格选择 #构建Model/View self.itemModel = QStandardItemModel(10, 5, self) #数据模型,10行5列 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 self.ui.tableView.setModel(self.itemModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #设置选择模型 def __del__(self): ##析构函数 print("QmyFormTable 对象被删除了") ## ==============自定义功能函数============ ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##设置表格大小 def on_actSetSize_triggered(self): dlgTableSize = QmyDialogSize() #局部变量,构建时不能传递self dlgTableSize.setIniSize(self.itemModel.rowCount(), self.itemModel.columnCount()) ret = dlgTableSize.exec() if (ret == QDialog.Accepted): rows, cols = dlgTableSize.getTableSize() self.itemModel.setRowCount(rows) self.itemModel.setColumnCount(cols) @pyqtSlot() ##设置表头标题 def on_actSetHeader_triggered(self): if (self.__dlgSetHeaders == None): self.__dlgSetHeaders = QmyDialogHeaders(self) count = len(self.__dlgSetHeaders.headerList()) if (count != self.itemModel.columnCount()): strList = [] for i in range(self.itemModel.columnCount()): text = str( self.itemModel.headerData(i, Qt.Horizontal, Qt.DisplayRole)) strList.append(text) self.__dlgSetHeaders.setHeaderList(strList) ret = self.__dlgSetHeaders.exec() if (ret == QDialog.Accepted): strList2 = self.__dlgSetHeaders.headerList() self.itemModel.setHorizontalHeaderLabels(strList2)
def __init__(self): super(Window, self).__init__() self.filter_button = QPushButton("Filter") self.filter_button.setCheckable(True) self.filter_button.setChecked(True) self.filter_button.clicked.connect(self.on_button_clicked) self.view = QTableView() self.view.setGeometry(100, 100, 500, 500) self.view.horizontalHeader().setStretchLastSection(True) button_layout = QHBoxLayout() button_layout.addStretch() button_layout.addWidget(self.filter_button) layout = QVBoxLayout(self) layout.addLayout(button_layout) layout.addWidget(self.view) header = FilterHeader(self.view) self.view.setHorizontalHeader(header) self.view.verticalHeader().setVisible(False) #model = QStandardItemModel(self.view) model = QStandardItemModel(5, 7, self.view) for i in range(5): for j in range(7): item = QStandardItem(str(i + j)) model.setItem(i, j, item) model.setHorizontalHeaderLabels( "One Two Three Four Five Six Seven".split()) self.view.setModel(model) header.setFilterBoxes(model.columnCount()) header.filterActivated.connect(self.handleFilterActivated)
def fillTable(self): table = self.stageResults[2] if not self.tableView: tableView = QTableView() model = QStandardItemModel(len(table), 4) model.setHeaderData(0, Qt.Horizontal, "Трійка") model.setHeaderData(1, Qt.Horizontal, "Кут") model.setHeaderData(2, Qt.Horizontal, "Точка") model.setHeaderData(3, Qt.Horizontal, "Дія над точкою") tableView.setModel(model) self.tableView = tableView self.tableLayout.addWidget(tableView) model = self.tableView.model() if len(table) > model.rowCount(): model.insertRows(model.rowCount() - 1, len(table) - model.rowCount(), QModelIndex()) if len(table) < model.rowCount(): model.removeRows(model.rowCount() - 1, model.rowCount() - len(table), QModelIndex()) for row in range(model.rowCount()): triple = str(table[row][0][0]) +\ "-" + str(table[row][0][1]) +\ "-" + str(table[row][0][2]) angle = "<π" if table[row][1] else "⩾π" point = table[row][2] action = "Додати" if table[row][1] else "Видалити" data = [triple, angle, point, action] for col in range(model.columnCount()): index = model.index(row, col) model.setData(index, data[col])
class QmyFormTable(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_QWFormTable() self.ui.setupUi(self) self.__dlgSetHeaders = None self.setAutoFillBackground(True) self.setCentralWidget(self.ui.qTableView) self.itemModel = QStandardItemModel(10, 5, self) self.selectionModel = QItemSelectionModel(self.itemModel) self.ui.qTableView.setModel(self.itemModel) self.ui.qTableView.setSelectionModel(self.selectionModel) def __del__(self): print("QmyFormTable 对象被删除了") @pyqtSlot() def on_qAction1_triggered(self): dlgTableSize = QmyDialogSize() dlgTableSize.setIniSize(self.itemModel.rowCount(), self.itemModel.columnCount()) ret = dlgTableSize.exec() if (ret == QDialog.Accepted): rows, cols = dlgTableSize.getTableSize() self.itemModel.setRowCount(rows) self.itemModel.setColumnCount(cols) @pyqtSlot() def on_qAction2_triggered(self): if (self.__dlgSetHeaders == None): self.__dlgSetHeaders = QmyDialogHeaders(self) count = len(self.__dlgSetHeaders.headerList()) if (count != self.itemModel.columnCount()): strList = [] for i in range(self.itemModel.columnCount()): text = str( self.itemModel.headerData(i, Qt.Horizontal, Qt.DisplayRole)) strList.append(text) self.__dlgSetHeaders.setHeaderList(strList) ret = self.__dlgSetHeaders.exec() if (ret == QDialog.Accepted): strList2 = self.__dlgSetHeaders.headerList() self.itemModel.setHorizontalHeaderLabels(strList2)
def buildTable(self, headers, datas): model = QStandardItemModel() model.setHorizontalHeaderLabels(headers) for xindex, row in enumerate(datas): for yindex, column in enumerate(headers): item = QStandardItem(str(datas[xindex][yindex])) model.setItem(xindex, yindex, item) print(model.columnCount()) return model
class ReaderExcelThread(QThread): standarModel_signal = pyqtSignal(QStandardItemModel) # sqlTableModel_signal = pyqtSignal(QSqlTableModel) progressRate_signal = pyqtSignal(str) finished_signal = pyqtSignal() # ''' # 读取表格的方式分为两种: # 1.读取后直接使用,即直接设置并返回为QStandardItemModel # 2.读取后放到缓存数据库,从数据库中取数据,返回QSqlTableModel # ''' def __init__(self, file_name, operate_way=1): super().__init__() self.file_name = file_name self.operate_way = operate_way self.model = QStandardItemModel() def run(self): # 这里读取数据返回列表便于表格中数据的更新 self.progressRate_signal.emit("数据载入准备中...") data_list = read_excel(self.file_name) if data_list == -1: return print('start work!') cnt = len(data_list) for i, rows in enumerate(data_list): row = [QStandardItem(str(cell)) for cell in rows] self.model.appendRow(row) percent = int(i / cnt * 100 + 0.5) self.progressRate_signal.emit("数据载入进度:{}%".format(percent)) #自动填满,这样更加美观(不过增加了后期数据处理难度!) while self.model.rowCount() < 22: self.model.insertRows(self.model.rowCount(), 1) while self.model.columnCount() < 15: self.model.insertColumns(self.model.columnCount(), 1) #数据加载完成 self.progressRate_signal.emit("数据载入进度:100%") self.standarModel_signal.emit(self.model) print('send finised') self.finished_signal.emit()
class JSONEditor(QDialog): def __init__(self, parent=None): super(JSONEditor, self).__init__(parent) self.settings = None self.model = QStandardItemModel(self) self.tableView = QTableView(self) self.tableView.setModel(self.model) self.tableView.horizontalHeader().setStretchLastSection(True) self.pushButtonWrite = QPushButton(self) self.pushButtonWrite.setText("Salva Impostazioni") self.pushButtonWrite.clicked.connect(self.on_pushButtonWrite_clicked) self.layoutVertical = QVBoxLayout(self) self.layoutVertical.addWidget(self.tableView) self.layoutVertical.addWidget(self.pushButtonWrite) self.settings = self.loadJSON() def loadJSON(self): settings = json.load(open("emailsender_settings.json")) for k, v in settings.items(): v = json.dumps(v) items = [QStandardItem(k), QStandardItem(v)] self.model.appendRow(items) self.model.setHeaderData(0, Qt.Horizontal, "Parametro") self.model.setHeaderData(1, Qt.Horizontal, "Valore") return settings def writeJSON(self): fields = [] for rowNumber in range(self.model.rowCount()): fields.append([ self.model.data(self.model.index(rowNumber, columnNumber), Qt.DisplayRole) for columnNumber in range(self.model.columnCount()) ]) for f in fields: try: self.settings[f[0]] = json.loads(f[1]) except: QMessageBox.critical(self, "Impostazioni", "Errore nella riga {}".format(f[1])) break else: json.dump(self.settings, open("emailsender_settings.json", 'w')) self.close() @pyqtSlot() def on_pushButtonWrite_clicked(self): self.writeJSON()
class Example(QWidget): def __init__(self): super().__init__() self.setGeometry(300, 300, 350, 250) self.setWindowTitle("Actresses") self.initData() self.initUI() def initData(self): self.model = QStandardItemModel() labels = ("Name", "Place", "Born") self.model.setHorizontalHeaderLabels(labels) for i in range(len(data)): name = QStandardItem(data[i][0]) place = QStandardItem(data[i][1]) born = QStandardItem(data[i][2]) self.model.appendRow((name, place, born)) def initUI(self): tv = QTreeView(self) tv.setRootIsDecorated(False) tv.setModel(self.model) behavior = QAbstractItemView.SelectRows tv.setSelectionBehavior(behavior) self.label = QLabel(self) layout = QVBoxLayout() layout.addWidget(tv) layout.addWidget(self.label) self.setLayout(layout) tv.clicked.connect(self.onClicked) def onClicked(self, idx): row = idx.row() cols = self.model.columnCount() data = [] for col in range(cols): item = self.model.item(row, col) data.append(item.text()) self.label.setText((", ".join(data)))
def __init__(self): super(_Window, self).__init__() self.view = QTableView() layout = QVBoxLayout(self) layout.addWidget(self.view) header = FilterHeader(self.view) self.view.setHorizontalHeader(header) model = QStandardItemModel(self.view) model.setHorizontalHeaderLabels('One Two Three Four Five'.split()) model.appendRow(QStandardItem([1, 2, 3, 4, 5])) self.view.setModel(model) header.setFilterBoxes(model.columnCount()) header.filterActivated.connect(self.handleFilterActivated)
def getIndexFromCaption(self, model: QStandardItemModel, caption: str): """ 获取指定列标题的索引. :param model: tableView模型 :param caption: 列标题 :return: 返回找到索引值,未找到返回-1 """ for index in range(model.columnCount()): text = model.headerData(index, Qt.Horizontal) if text == caption: return index return -1
def execute_query(self): """ Executing a query on click Execute button :return: void """ try: self.conn.row_factory = sqlite3.Row cursor = self.conn.cursor() cursor.execute("PRAGMA max_page_count = %s" % __max_page_count__) cursor.execute("PRAGMA page_size = %s" % __page_size__) if not len(self.query.toPlainText()): raise sqlite3.OperationalError("Can\'t execute empty query") model = QStandardItemModel() self.results.setModel(model) cursor.execute(self._query_decorator()) self._update_page() row = cursor.fetchone() if isinstance(row, sqlite3.Row): if not model.columnCount(): model.setColumnCount(len(row.keys())) model.setHorizontalHeaderLabels(row.keys()) while row: r = list() for name in row: item = QStandardItem(name.__str__()) item.setEditable(False) r.append(item) model.appendRow(r) row = cursor.fetchone() self.results.setModel(model) else: self.conn.commit() except sqlite3.OperationalError as e: QMessageBox.critical( self, 'Operational Error', '%s. %s' % (e.__str__(), "Please check the documentation https://www.sqlite.org/lang.html to correct the query." )) except Exception as e: QMessageBox.critical(self, 'Error', e.__str__()) raise e else: QMessageBox.information(self, 'Executed', 'It\'s Ok. Done!')
def exportCSV(self): if self.focusWidget().__class__.__name__ != 'QTableView': print('Not TableView') return exportModel = QStandardItemModel(self) exportModel = self.focusWidget().model() if not exportModel: return nrOfRows = exportModel.rowCount() nrOfCols = exportModel.columnCount() exportCSVStr = StringIO() for ch in range(nrOfCols): exportCSVStr.write(exportModel.horizontalHeaderItem(ch).text()) exportCSVStr.write('\t') exportCSVStr.write('\n') for i in range(nrOfRows): for c in range(nrOfCols): endData = exportModel.data(exportModel.index(i, c)).encode(encoding='iso-8859-1', errors='ignore') exportCSVStr.write(str(endData, 'iso-8859-1').replace('\r', '')) exportCSVStr.write('\t') exportCSVStr.write('\n') if not self.exportCSV_: pyperclip.copy(exportCSVStr.getvalue()) return text, okPressed = QInputDialog.getText(self, "Get text", "File Name:", QLineEdit.Normal, "") if okPressed and text != '': file = open(text+'.csv', 'w', encoding='iso-8859-1') file.write(exportCSVStr.getvalue()) file.close()
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.qSplitter) self.__ColCount = 6 self.itemModel = QStandardItemModel(5, self.__ColCount, self) self.selectionModel = QItemSelectionModel(self.itemModel) self.selectionModel.currentChanged.connect(self.do_curChanged) self.__lastColumnTitle = "测井取样" self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.ui.qTableView.setModel(self.itemModel) self.ui.qTableView.setSelectionModel(self.selectionModel) oneOrMore = QAbstractItemView.ExtendedSelection self.ui.qTableView.setSelectionMode(oneOrMore) itemOrRow = QAbstractItemView.SelectItems self.ui.qTableView.setSelectionBehavior(itemOrRow) self.ui.qTableView.verticalHeader().setDefaultSectionSize(22) self.ui.qTableView.setAlternatingRowColors(True) self.ui.qTableView.setEnabled(False) self.qLabel1 = QLabel("当前单元格:", self) self.qLabel1.setMinimumWidth(180) self.qLabel2 = QLabel("单元格内容:", self) self.qLabel2.setMinimumWidth(150) self.qLabel3 = QLabel("当前文件:", self) self.ui.qStatusBar.addWidget(self.qLabel1) self.ui.qStatusBar.addWidget(self.qLabel2) self.ui.qStatusBar.addPermanentWidget(self.qLabel3) def __iniModelFromStringList(self, allLines): rowCnt = len(allLines) self.itemModel.setRowCount(rowCnt - 1) headerText = allLines[0].strip() headerList = headerText.split("\t") self.itemModel.setHorizontalHeaderLabels(headerList) self.__lastColumnTitle = headerList[len(headerList) - 1] lastColNo = self.__ColCount - 1 for i in range(rowCnt - 1): lineText = allLines[i + 1].strip() strList = lineText.split("\t") for j in range(self.__ColCount - 1): item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) item = QStandardItem(self.__lastColumnTitle) item.setFlags(self.__lastColumnFlags) item.setCheckable(True) if (strList[lastColNo] == "0"): item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i, lastColNo, item) def __setCellAlignment(self, align=Qt.AlignHCenter): if (not self.selectionModel.hasSelection()): return selectedIndex = self.selectionModel.selectedIndexes() count = len(selectedIndex) for i in range(count): index = selectedIndex[i] item = self.itemModel.itemFromIndex(index) item.setTextAlignment(align) @pyqtSlot() def on_qAction1_triggered(self): # 打开文件 curPath = os.getcwd() filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.qLabel3.setText("当前文件:" + filename) self.ui.qPlainTextEdit.clear() aFile = open(filename, 'r') allLines = aFile.readlines() aFile.close() for strLine in allLines: self.ui.qPlainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.qTableView.setEnabled(True) self.ui.qAction2.setEnabled(True) self.ui.qAction3.setEnabled(True) self.ui.qAction4.setEnabled(True) self.ui.qAction5.setEnabled(True) self.ui.qAction6.setEnabled(True) @pyqtSlot() def on_qAction2_triggered(self): # 另存文件 curPath = os.getcwd() filename, flt = QFileDialog.getSaveFileName( self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.on_qAction3_triggered() aFile = open(filename, "w") aFile.write(self.ui.qPlainTextEdit.toPlainText()) aFile.close() @pyqtSlot() def on_qAction4_triggered(self): # 添加行 itemList = [] for i in range(self.__ColCount - 1): item = QStandardItem("0") itemList.append(item) item = QStandardItem(self.__lastColumnTitle) item.setCheckable(True) item.setFlags(self.__lastColumnFlags) itemList.append(item) self.itemModel.appendRow(itemList) curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_qAction5_triggered(self): # 插入行 itemlist = [] for i in range(self.__ColCount - 1): item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) item.setFlags(self.__lastColumnFlags) item.setCheckable(True) item.setCheckState(Qt.Checked) itemlist.append(item) curIndex = self.selectionModel.currentIndex() self.itemModel.insertRow(curIndex.row(), itemlist) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_qAction6_triggered(self): # 删除行 curIndex = self.selectionModel.currentIndex() self.itemModel.removeRow(curIndex.row()) @pyqtSlot() def on_qAction7_triggered(self): # 居左 self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() def on_qAction8_triggered(self): # 居中 self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter) @pyqtSlot() def on_qAction9_triggered(self): # 居右 self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) def on_qAction10_triggered(self, checked): # 粗体 if (not self.selectionModel.hasSelection()): return selectedIndex = self.selectionModel.selectedIndexes() count = len(selectedIndex) for i in range(count): index = selectedIndex[i] item = self.itemModel.itemFromIndex(index) font = item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() def on_qAction3_triggered(self): # 模型数据 self.ui.qPlainTextEdit.clear() lineStr = "" for i in range(self.itemModel.columnCount() - 1): item = self.itemModel.horizontalHeaderItem(i) lineStr = lineStr + item.text() + "\t" item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1) lineStr = lineStr + item.text() self.ui.qPlainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): lineStr = "" for j in range(self.itemModel.columnCount() - 1): item = self.itemModel.item(i, j) lineStr = lineStr + item.text() + "\t" item = self.itemModel.item(i, self.__ColCount - 1) if (item.checkState() == Qt.Checked): lineStr = lineStr + "1" else: lineStr = lineStr + "0" self.ui.qPlainTextEdit.appendPlainText(lineStr) def do_curChanged(self, current, previous): if (current != None): text = "当前单元格:%d行,%d列" % (current.row(), current.column()) self.qLabel1.setText(text) item = self.itemModel.itemFromIndex(current) self.qLabel2.setText("单元格内容:" + item.text()) font = item.font() self.ui.qAction10.setChecked(font.bold())
class AnalysisWindowDemo(QWidget): def __init__(self): super(AnalysisWindowDemo, self).__init__() self.initUI() def initUI(self): self.setWindowTitle('分析预测') self.setWindowIcon(QIcon('../image/对比分析.png')) #需要的数据 self.RMSE = None self.y_predict = None self.plt = plt # 创建一个展示板 self.figure = self.plt.figure() self.canvas = FigureCanvas(self.figure) self.predict_button = QPushButton('预测') self.draw_button = QPushButton('绘图') self.output_button = QPushButton('导出') # self.input_button = QPushButton('导入') # 显示用于分析的数据 self.table_view = QTableView() self.table_view.setModel(QStandardItemModel(100, 100)) self.status_bar = QStatusBar() # 设置布局 hlayout = QHBoxLayout() hlayout.addWidget(self.predict_button) hlayout.addWidget(self.draw_button) hlayout.addWidget(self.output_button) # hlayout.addWidget(self.input_button) hlayout.addStretch() hlayout.setSpacing(15) hlayout1 = QHBoxLayout() hlayout1.addWidget(self.table_view) layout = QVBoxLayout() layout.addItem(hlayout) layout.addItem(hlayout1) layout.addWidget(self.canvas) layout.addWidget(self.status_bar) layout.setStretch(0, 1) layout.setStretch(1, 5) layout.setStretch(2, 5) layout.setStretch(3, 1) self.setLayout(layout) # 绑定信号 self.draw_button.clicked.connect(self.onClickDraw) self.predict_button.clicked.connect(self.onClickPredict) self.output_button.clicked.connect(self.onClickOutput) #显示预测的结果 def onClickPredict(self): if self.y_predict is None: return self.predict_button.setEnabled(False) self.model = QStandardItemModel() dtl = DTL() data_list = dtl.DataFrame_to_list(self.y_predict) for rows in data_list: row = [QStandardItem(str(cell)) for cell in rows] self.model.appendRow(row) RMSE = ['old_RMSE:', self.RMSE[0], 'now_RMSE:', self.RMSE[1]] row = [QStandardItem(str(cell)) for cell in RMSE] #突出显示RMSE row[1].setBackground(QColor(255, 255, 0)) row[1].setForeground(QColor(255, 0, 0)) row[-1].setBackground(QColor(255, 255, 0)) row[-1].setForeground(QColor(255, 0, 0)) self.model.appendRow(row) self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) #绘制可视化图形 def onClickDraw(self): if self.y_predict is None: return self.plt = plt #这里开始就按照matlibplot的方式绘图 try: # 中文乱码处理 self.plt.rcParams['font.sans-serif'] = ['SimHei'] self.plt.rcParams['axes.unicode_minus'] = False #数据 index = random.sample(self.y_predict.index.tolist(), 10) y_list = self.y_predict['y'].tolist() data = [item for i, item in enumerate(y_list) if i in index] y_old_predict_list = self.y_predict['y'].tolist() data1 = [ item for i, item in enumerate(y_old_predict_list) if i in index ] y_now_predict_list = self.y_predict['y'].tolist() data2 = [ item for i, item in enumerate(y_now_predict_list) if i in index ] index.sort() x = [str(i) for i in index] # self.plt.plot(x, data, marker='.', mec='g', label='y') self.plt.plot(x, data1, marker='o', mec='b', label='y_old_predict') self.plt.plot(x, data2, marker='*', mec='r', label='y_now_predict') # label显示 self.plt.legend() # x轴数值标记,这个一定要在后面加上 self.plt.xticks(x) #确定y轴数值范围 minx = min(min(y_old_predict_list), min(y_now_predict_list)) maxx = max(max(y_now_predict_list), max(y_old_predict_list)) self.plt.ylim(minx - 100, maxx + 500) # # 标上数值 # for x, y in enumerate(data1): # plt.text(x, y + 100, '%s' % y, ha='center') # # for x, y in enumerate(data2): # plt.text(x, y + 500, '%s' % y, ha='center') # 设置标题 self.plt.title("预测结果对比") # 按照matlibplot的方式绘制之后,在窗口上绘制 self.canvas.draw() except Exception as e: print(e) self.draw_button.setEnabled(False) #导出数据分析结果 def onClickOutput(self): if self.y_predict is None: return #输出表格中结果 file_path, self.save = QFileDialog.getSaveFileName( self, '保存文件', '../result', 'ALL Files(*);;xlsx(*.xlsx);;xls(*.xls);;csv(*.csv)') if file_path == '': return wb = workbook.Workbook() wb.encoding = 'utf-8' wa = wb.active # 文件中写入数据 try: rows = self.model.rowCount() columns = self.model.columnCount() for i in range(rows): item = [] for j in range(columns): item.append(self.model.index(i, j).data()) wa.append(item) wb.save(file_path) except Exception as e: print(e) return try: self.plt.savefig('{}_img.svg'.format( file_path.split('.', maxsplit=1)[0])) except: pass self.status_bar.showMessage('导出完毕!', 5000) print('导出完毕!')
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setCentralWidget(self.ui.splitter) self.__buildStatusBar() self.COL_COUNT = 6 #常数,列数=6 self.itemModel = QStandardItemModel(5, self.COL_COUNT, self) # 数据模型,10行6列 ## headerList=["测深(m)","垂深(m)","方位(°)","总位移(m)","固井质量","测井取样"] ## self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头文字 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 self.selectionModel.currentChanged.connect(self.do_currentChanged) self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.__lastColumnTitle = "测井取样" #为tableView设置数据模型 self.ui.tableView.setModel(self.itemModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #设置选择模型 oneOrMore = QAbstractItemView.ExtendedSelection self.ui.tableView.setSelectionMode(oneOrMore) #可多选 itemOrRow = QAbstractItemView.SelectItems self.ui.tableView.setSelectionBehavior(itemOrRow) #单元格选择 self.ui.tableView.verticalHeader().setDefaultSectionSize(22) #缺省行高 self.ui.tableView.setEnabled(False) #先禁用tableView ## self.__resetTable(5) #创建自定义代理组件并设置 self.spinCeShen = QmyFloatSpinDelegate(0, 10000, 0, self) #用于 测深 self.spinLength = QmyFloatSpinDelegate(0, 6000, 2, self) #垂深,总位移 self.spinDegree = QmyFloatSpinDelegate(0, 360, 1, self) #用于 方位 self.ui.tableView.setItemDelegateForColumn(0, self.spinCeShen) #测深 self.ui.tableView.setItemDelegateForColumn(1, self.spinLength) #垂深 self.ui.tableView.setItemDelegateForColumn(3, self.spinLength) #总位移 self.ui.tableView.setItemDelegateForColumn(2, self.spinDegree) #方位角 qualities = ["优", "良", "合格", "不合格"] self.comboDelegate = QmyComboBoxDelegate(self) self.comboDelegate.setItems(qualities, False) #不可编辑 self.ui.tableView.setItemDelegateForColumn(4, self.comboDelegate) #固井质量 ## ==============自定义功能函数============ def __buildStatusBar(self): ##构建状态栏 self.LabCellPos = QLabel("当前单元格:", self) self.LabCellPos.setMinimumWidth(180) self.ui.statusBar.addWidget(self.LabCellPos) self.LabCellText = QLabel("单元格内容:", self) self.LabCellText.setMinimumWidth(150) self.ui.statusBar.addWidget(self.LabCellText) self.LabCurFile = QLabel("当前文件:", self) self.ui.statusBar.addPermanentWidget(self.LabCurFile) ## def __resetTable(self,tableRowCount): #复位数据表,必须为数值设置0,否则代理组件出错 ## self.itemModel.removeRows(0,self.itemModel.rowCount()) #删除所有行 ## self.itemModel.setRowCount(tableRowCount) #设置新的行数 ## ## for i in range(tableRowCount): #设置最后一列 ## for j in range(self.COL_COUNT-1): ## index=self.itemModel.index(i,j) #获取模型索引 ## item=self.itemModel.itemFromIndex(index) #获取item ## item.setData(0,Qt.DisplayRole) #数值必须初始化为0 ## item.setTextAlignment(Qt.AlignHCenter) ## ## index=self.itemModel.index(i,self.COL_COUNT-1) #获取模型索引 ## item=self.itemModel.itemFromIndex(index) #获取item ## item.setCheckable(True) ## item.setData(self.__lastColumnTitle,Qt.DisplayRole) ## item.setEditable(False) #不可编辑 def __iniModelFromStringList(self, allLines): ##从字符串列表构建模型 rowCnt = len(allLines) #文本行数,第1行是标题 self.itemModel.setRowCount(rowCnt - 1) #实际数据行数 headerText = allLines[0].strip() #第1行是表头,去掉末尾的换行符 "\n" headerList = headerText.split("\t") self.itemModel.setHorizontalHeaderLabels(headerList) self.__lastColumnTitle = headerList[len(headerList) - 1] # 最后一列表头的标题,即“测井取样” lastColNo = self.COL_COUNT - 1 #最后一列的列号 for i in range(rowCnt - 1): lineText = allLines[i + 1].strip() #一行的文字,\t分隔 strList = lineText.split("\t") for j in range(self.COL_COUNT - 1): #不含最后一列 item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) if (strList[lastColNo] == "0"): item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i, lastColNo, item) #设置最后一列的item def __setCellAlignment(self, align=Qt.AlignHCenter): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex = self.selectionModel.selectedIndexes() #列表类型 count = len(selectedIndex) for i in range(count): index = selectedIndex[i] #获取其中的一个模型索引 item = self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 item.setTextAlignment(align) #设置文字对齐方式 ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##“打开文件” def on_actOpen_triggered(self): curPath = os.getcwd() #获取当前路径 filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.LabCurFile.setText("当前文件:" + filename) self.ui.plainTextEdit.clear() aFile = open(filename, 'r') allLines = aFile.readlines() #读取所有行,list类型,每行末尾带有 \n ## for eachLine in aFile: #每次读取一行 ## self.ui.plainTextEdit.appendPlainText(eachLine) aFile.close() for strLine in allLines: self.ui.plainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.actAppend.setEnabled(True) #更新Actions的enable属性 self.ui.actInsert.setEnabled(True) self.ui.actDelete.setEnabled(True) self.ui.actSave.setEnabled(True) self.ui.actModelData.setEnabled(True) self.ui.tableView.setEnabled(True) #启用tableView @pyqtSlot() ##保存文件 def on_actSave_triggered(self): curPath = os.getcwd() #获取当前路径 filename, flt = QFileDialog.getSaveFileName( self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.on_actModelData_triggered() #更新数据到plainTextEdit aFile = open(filename, 'w') #以写方式打开 aFile.write(self.ui.plainTextEdit.toPlainText()) aFile.close() @pyqtSlot() def on_actAppend_triggered(self): #在最后添加一行 itemlist = [] # 列表 for i in range(self.COL_COUNT - 1): item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setCheckable(True) item.setFlags(self.__lastColumnFlags) itemlist.append(item) self.itemModel.appendRow(itemlist) curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() ##插入一行 def on_actInsert_triggered(self): itemlist = [] # 列表 for i in range(self.COL_COUNT - 1): item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) item.setCheckState(Qt.Checked) itemlist.append(item) curIndex = self.selectionModel.currentIndex() #获取当前选中项的模型索引 self.itemModel.insertRow(curIndex.row(), itemlist) #在当前行的前面插入一行 self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() ##删除当前行 def on_actDelete_triggered(self): curIndex = self.selectionModel.currentIndex() #获取当前选择单元格的模型索引 self.itemModel.removeRow(curIndex.row()) # //删除当前行 @pyqtSlot() ##左对齐 def on_actAlignLeft_triggered(self): self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() ##中间对齐 def on_actAlignCenter_triggered(self): self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter) @pyqtSlot() ##右对齐 def on_actAlignRight_triggered(self): self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) ##字体Bold def on_actFontBold_triggered(self, checked): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex = self.selectionModel.selectedIndexes() #列表类型 count = len(selectedIndex) for i in range(count): index = selectedIndex[i] #获取其中的一个模型索引 item = self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 font = item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() ##模型数据显示到plainTextEdit里 def on_actModelData_triggered(self): self.ui.plainTextEdit.clear() lineStr = "" for i in range(self.itemModel.columnCount() - 1): #表头 item = self.itemModel.horizontalHeaderItem(i) lineStr = lineStr + item.text() + "\t" item = self.itemModel.horizontalHeaderItem(self.COL_COUNT - 1) #最后一列 lineStr = lineStr + item.text() self.ui.plainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): lineStr = "" for j in range(self.itemModel.columnCount() - 1): #不包括最后一列 item = self.itemModel.item(i, j) lineStr = lineStr + item.text() + "\t" item = self.itemModel.item(i, self.COL_COUNT - 1) #最后一列 if (item.checkState() == Qt.Checked): lineStr = lineStr + "1" else: lineStr = lineStr + "0" self.ui.plainTextEdit.appendPlainText(lineStr) ## =============自定义槽函数=============================== def do_currentChanged(self, current, previous): if (current != None): #当前模型索引有效 self.LabCellPos.setText( "当前单元格:%d行,%d列" % (current.row(), current.column())) #显示模型索引的行和列号 item = self.itemModel.itemFromIndex(current) #从模型索引获得Item self.LabCellText.setText("单元格内容:" + item.text()) #显示item的文字内容 font = item.font() #获取item的字体 self.ui.actFontBold.setChecked(font.bold()) #更新actFontBold的check状态
class EditSubject(Ui_Dialog): def __init__(self, session, subject=None): super().__init__() self.session = session if subject is None: self.subject = Subject() else: self.subject = subject self.timeslot_model = QStandardItemModel(12, 7) self.timeslot_model.setHorizontalHeaderLabels([ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]) for tp in self.subject.time_places: it = QStandardItem() it.setText(tp.place.name) self.timeslot_model.setItem(tp.slot, int(tp.day), it) def setupUi(self, dialog): super().setupUi(dialog) self.dialog = dialog self.name.setText(self.subject.name) self.abbreviation.setText(self.subject.abbreviation) self.timeslotView.setModel(self.timeslot_model) self.timeslotView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.timeslotView.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.buttonBox.accepted.connect(self.update_subject) def update_subject(self): self.subject.name = self.name.text() self.subject.abbreviation = self.abbreviation.text() self.subject.time_places = [] for i in range(self.timeslot_model.rowCount()): for j in range(self.timeslot_model.columnCount()): it = self.timeslot_model.item(i, j) if it is not None and it.text(): place = self.session.query(Place).filter( Place.name == it.text()).one_or_none() if place is None: messagebox = QMessageBox() messagebox.setWindowTitle("Create new location?") messagebox.setIcon(QMessageBox.Question) messagebox.setText("Create location {0}".format( it.text())) messagebox.setInformativeText( "Location {0} does not exist. Do you want to create it?" .format(it.text())) messagebox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) messagebox.setDefaultButton(QMessageBox.Yes) reply = messagebox.exec() if reply == QMessageBox.Yes: place = Place() place.name = it.text() self.session.add(place) if place is not None: tp = TimePlace() tp.day = DayOfWeek(j) tp.slot = i tp.place = place self.subject.time_places.append(tp) self.session.add(self.subject)
class SubtitleEditor(SubTab): def __init__(self, filePath, subtitleData, parent = None): name = os.path.split(filePath)[1] super(SubtitleEditor, self).__init__(name, parent) self.__initWidgets() self.__initContextMenu() self._settings = SubSettings() self._filePath = filePath self._movieFilePath = None self._subtitleData = subtitleData self.refreshSubtitles() # Some signals self._subtitleData.fileChanged.connect(self.fileChanged) self._subtitleData.subtitlesAdded.connect(self._subtitlesAdded) self._subtitleData.subtitlesRemoved.connect(self._subtitlesRemoved) self._subtitleData.subtitlesChanged.connect(self._subtitlesChanged) self._model.itemChanged.connect(self._subtitleEdited) self.customContextMenuRequested.connect(self.showContextMenu) def __initWidgets(self): minimalSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # List of subtitles subListDelegate = SubListItemDelegate() self._model = QStandardItemModel(0, 3, self) self._model.setHorizontalHeaderLabels([_("Begin"), _("End"), _("Subtitle")]) self._subList = QTableView(self) self._subList.setModel(self._model) self._subList.setItemDelegateForColumn(0, subListDelegate) self._subList.setItemDelegateForColumn(1, subListDelegate) self._subList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self._searchBar = SearchBar(self) self._searchBar.hide() # Top toolbar toolbar = QHBoxLayout() toolbar.setAlignment(Qt.AlignLeft) #toolbar.addWidget(someWidget....) toolbar.addStretch(1) # Main layout grid = QGridLayout() grid.setSpacing(10) grid.setContentsMargins(0, 3, 0, 0) grid.addLayout(toolbar, 0, 0, 1, 1) # stretch to the right grid.addWidget(self._subList, 1, 0) grid.addWidget(self._searchBar, 2, 0) self.setLayout(grid) def __initContextMenu(self): self._contextMenu = QMenu(self) self.setContextMenuPolicy(Qt.CustomContextMenu) af = ActionFactory(self) insertSub = af.create(title = _("&Insert subtitle"), icon = "list-add", connection = self.insertNewSubtitle) self._contextMenu.addAction(insertSub) insertSub = af.create(title = _("&Add subtitle"), icon = "list-add", connection = self.addNewSubtitle) self._contextMenu.addAction(insertSub) removeSub = af.create(title = _("&Remove subtitles"), icon = "list-remove", connection = self.removeSelectedSubtitles) self._contextMenu.addAction(removeSub) def _changeRowBackground(self, rowNo, bg): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): for columnNo in range(self._model.columnCount()): item = self._model.item(rowNo, columnNo) item.setBackground(bg) def _changeItemData(self, item, val, role): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(val, role) def _handleIncorrectItem(self, item): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(False, CustomDataRoles.ErrorFlagRole) bg = item.background() rowNo = item.row() self._changeRowBackground(rowNo, Qt.red) QTimer.singleShot(600, lambda rowNo=rowNo, bg=bg: self._changeRowBackground(rowNo, bg)) def _subtitleEdited(self, item): modelIndex = item.index() column = modelIndex.column() subNo = modelIndex.row() errorFlag = item.data(CustomDataRoles.ErrorFlagRole) if errorFlag is True: self._handleIncorrectItem(item) else: # TODO: timeStart and timeEnd might be displayed in a frame format in a bright future. # Check it and create FrameTime properly in that case. # TODO: Maybe add column numbers to some kind of enum to avoid magic numbers? oldSubtitle = self.subtitles[subNo] newSubtitle = oldSubtitle.clone() if 0 == column: timeStart = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(start = timeStart) elif 1 == column: timeEnd = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(end = timeEnd) elif 2 == column: newSubtitle.change(text = item.text()) command = ChangeSubtitle(self.filePath, oldSubtitle, newSubtitle, subNo) self._subtitleData.execute(command) def _subtitlesAdded(self, path, subNos): if path != self.filePath: return subtitles = self.subtitles for subNo in subNos: row = createRow(subtitles[subNo]) self._model.insertRow(subNo, row) def _subtitlesRemoved(self, path, subNos): if path != self.filePath: return for subNo in subNos: self._model.removeRow(subNo) def _subtitlesChanged(self, path, subNos): if path != self.filePath: return for subNo in subNos: self.refreshSubtitle(subNo) def _createNewSubtitle(self, data, subNo): fps = data.fps # data is passed to avoid unnecessary copies minFrameTime = FrameTime(fps, frames = 1) # calculate correct minimum subtitle start time if subNo > 0: timeStart = data.subtitles[subNo - 1].end + minFrameTime else: timeStart = FrameTime(fps, frames = 0) # calculate correct maximum subtitle end time if subNo < data.subtitles.size(): try: timeEnd = data.subtitles[subNo].start - minFrameTime except SubException: timeEnd = FrameTime(fps, frames = 0) else: timeEnd = timeStart + FrameTime(fps, frames = 50) # add subtitle to DataModel sub = Subtitle(timeStart, timeEnd, "") command = AddSubtitle(self.filePath, subNo, sub) with DisableSignalling(self._subtitleData.subtitlesAdded, self._subtitlesAdded): self._subtitleData.execute(command) # create subtitle graphical representation in editor sub list row = createRow(sub) self._model.insertRow(subNo, row) index = self._model.index(subNo, 2) self._subList.clearSelection() self._subList.setCurrentIndex(index) self._subList.edit(index) def addNewSubtitle(self): data = self.data subNo = data.subtitles.size() indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) + 1 self._createNewSubtitle(data, subNo) def insertNewSubtitle(self): data = self.data subNo = 0 indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) self._createNewSubtitle(data, subNo) def removeSelectedSubtitles(self): indices = self._subList.selectedIndexes() if len(indices) > 0: rows = list(set([index.row() for index in indices])) command = RemoveSubtitles(self.filePath, rows) self._subtitleData.execute(command) if self._model.rowCount() > rows[-1]: self._subList.selectRow(rows[-1]) else: self._subList.selectRow(self._model.rowCount() - 1) def highlight(self): self._searchBar.show() self._searchBar.highlight() def showContextMenu(self): self._contextMenu.exec(QCursor.pos()) def changeInputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.inputEncoding: try: data.encode(encoding) except UnicodeDecodeError: message = QMessageBox( QMessageBox.Warning, _("Decoding error"), _("Cannot decode subtitles to '%s' encoding.\nPlease try different encoding.") % encoding, QMessageBox.Ok, self ) message.exec() except LookupError: message = QMessageBox(QMessageBox.Warning, _("Unknown encoding"), _("Unknown encoding: '%s'") % encoding, QMessageBox.Ok, self ) message.exec() else: # TODO: outputEncoding command = ChangeData(self.filePath, data, _("Input encoding: %s") % encoding) self._subtitleData.execute(command) def changeOutputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.outputEncoding: data.outputEncoding = encoding command = ChangeData(self.filePath, data, _("Output encoding: %s") % encoding) self._subtitleData.execute(command) def changeSubFormat(self, fmt): data = self._subtitleData.data(self.filePath) if data.outputFormat != fmt: data.outputFormat = fmt command = ChangeData(self.filePath, data) self._subtitleData.execute(command) def changeFps(self, fps): data = self.data if data.fps != fps: data.subtitles.changeFps(fps) data.fps = fps command = ChangeData(self.filePath, data, _("FPS: %s") % fps) self._subtitleData.execute(command) def changeVideoPath(self, path): data = self.data if data.videoPath != path: data.videoPath = path command = ChangeData(self.filePath, data, _("Video path: %s") % path) self._subtitleData.execute(command) def offset(self, seconds): data = self.data fps = data.subtitles.fps if fps is None: log.error(_("No FPS for '%s' (empty subtitles)." % self.filePath)) return ft = FrameTime(data.subtitles.fps, seconds=seconds) data.subtitles.offset(ft) command = ChangeData(self.filePath, data, _("Offset by: %s") % ft.toStr()) self._subtitleData.execute(command) def detectFps(self): data = self.data if data.videoPath is not None: fpsInfo = File.detectFpsFromMovie(data.videoPath) if data.videoPath != fpsInfo.videoPath or data.fps != fpsInfo.fps: data.videoPath = fpsInfo.videoPath data.subtitles.changeFps(fpsInfo.fps) data.fps = fpsInfo.fps command = ChangeData(self.filePath, data, _("Detected FPS: %s") % data.fps) self._subtitleData.execute(command) def fileChanged(self, filePath): if filePath == self._filePath: self.refreshSubtitles() def refreshSubtitle(self, subNo): sub = self.subtitles[subNo] self._model.removeRow(subNo) self._model.insertRow(subNo, createRow(sub)) def refreshSubtitles(self): self._model.removeRows(0, self._model.rowCount()) for sub in self.subtitles: self._model.appendRow(createRow(sub)) def updateTab(self): self.refreshSubtitles() def selectedSubtitles(self): rows = self.selectedRows() subtitleList = [self.subtitles[row] for row in rows] return subtitleList def selectedRows(self): indices = self._subList.selectedIndexes() # unique list rows = list(set([index.row() for index in indices])) rows.sort() return rows def selectRow(self, row): self._subList.selectRow(row) @property def filePath(self): return self._filePath @property def movieFilePath(self): return self._movieFilePath @property def data(self): return self._subtitleData.data(self.filePath) @property def subtitles(self): return self.data.subtitles @property def history(self): return self._subtitleData.history(self.filePath) @property def inputEncoding(self): return self.data.inputEncoding @property def outputEncoding(self): return self.data.outputEncoding @property def outputFormat(self): return self.data.outputFormat
class TableDemo(QWidget): def __init__(self, parent=None): super(TableDemo, self).__init__(parent) self.setWindowTitle('TableView Demo') self.resize(600, 500) modelVerticalTitleLabelList = ['A', 'B', 'C', 'D', 'E'] modelHorizontalTitleLabelList = ['甲', '乙', '丙', '丁', '戊', '已'] self.model = QStandardItemModel(5, 5) self.model.setHorizontalHeaderLabels(modelVerticalTitleLabelList) self.model.setVerticalHeaderLabels(modelHorizontalTitleLabelList) for i in range(5): for j in range(5): item = QStandardItem(str(i + j)) self.model.setItem(i, j, item) self.tabletView = QTableView() self.tabletView.setModel(self.model) self.tabletView.horizontalHeader().setStretchLastSection(True) mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabletView) self.testRowColumn() self.setLayout(mainLayout) def testRowColumn(self): # 用rowAt()和columnAt(),返回一个坐标在table中的行和列的序号 x, y = 100, 200 row_at_x = self.tabletView.rowAt(x) column_at_y = self.tabletView.columnAt(y) print('坐标(%d,%d)在表格中是第%d行,第%d列' % (x, y, row_at_x + 1, column_at_y + 1)) # 如果(x,y)不在表格内,函数返回值是-1 # setRowHeight,setColumnWidth:可以设置行高'列宽 self.tabletView.setRowHeight(1, 50) self.tabletView.setColumnWidth(1, 150) # <int> columnWidth():返回指定列的宽度 # <int> rowHeight():返回指定行的高度 print('第(2,2)单元格的列宽,行高为为:%d,%d(像素)' % (self.tabletView.columnWidth(1), self.tabletView.rowHeight(1))) # setSpan():设定指定行和列的行跨度和列跨度 self.tabletView.setSpan(2, 2, 2, 2) # <int> rowSpan():返回指定行的位置的行跨度 # <int> columnSpan:返回指定(row,column)的列跨度 print( '第(3,3)单元格的的行和列跨度为(%dx%d)' % (self.tabletView.columnSpan(2, 2), self.tabletView.rowSpan(2, 2))) # setCornerButtonEnable():设置是否启用左上角的按钮 # 此按钮(用来全选整个表格),默认是启用的 self.tabletView.setCornerButtonEnabled(False) # 此时,左上角的按钮将不再起作用 def contextMenuEvent(self, QContextMenuEvent): # 设置tableView的右键弹出菜单和菜单信号槽 # 如何只在单元格内弹出右键菜单呢?现在在空白地方点击右键也会弹出菜单???????? menu = QMenu(self) hideMenu = menu.addAction('&Hide') hideMenu.triggered.connect(self.hideCurrentColumn) # 设置显示所有被隐藏的列 showhiddenColumnMenu = menu.addAction('显示隐藏列') showhiddenColumnMenu.triggered.connect(self.showAllHiddenColumns) menu.addSeparator() # 设置当前点击的列按照内容自适应列宽度 resizeColumnToCtnsMenu = menu.addAction('宽度适应') resizeColumnToCtnsMenu.triggered.connect( lambda: self.tabletView.resizeColumnToContents( self.tabletView.currentIndex().column())) # 排序当前选择的列 orderCurentColumnMenu = menu.addAction('排序') orderCurentColumnMenu.triggered.connect(self.orderCurrentColum) menu.exec_(QContextMenuEvent.globalPos()) def hideCurrentColumn(self): print('第%d列被隐藏了!' % self.tabletView.currentIndex().column()) self.tabletView.setColumnHidden( self.tabletView.currentIndex().column(), True) def showAllHiddenColumns(self): print('显示所有被隐藏的列') # 遍历所有的列,找到隐藏的列,设置其隐藏为False for i in range(self.model.columnCount()): if self.tabletView.isColumnHidden(i): self.tabletView.setColumnHidden(i, False) print('列%d已被重新显示' % (i + 1)) def orderCurrentColum(self): self.tabletView.setSortingEnabled(True) self.tabletView.sortByColumn(self.tabletView.currentIndex().column(), Qt.AscendingOrder)
class Controller(object): """ The Controller class is for loading the specific guis from the GUI folder. It also implements and fill the required GUI with logic. """ def __init__(self, path: str): # the actual path self.actualPath = path # A IDatabaseManager to communicate with the database self.database = DatabaseManager() # Tries to create the required tables self.database.createTables() # The path to the different GUIs self.pathMainGui = self.actualPath + '/GUI' + '/MainGui.ui' self.pathStartDownload = self.actualPath + '/GUI' + '/StartDownload.ui' self.pathCurrentDownload = self.actualPath + '/GUI' + '/CurrentDownload.ui' self.pathSettings = self.actualPath + '/GUI' + '/Settings.ui' self.pathError = self.actualPath + '/GUI' + '/ErrorMessage.ui' self.pathHelp = self.actualPath + '/GUI' + '/Help.ui' self.pathMoodleSummary = self.actualPath + '/GUI' + '/MoodleSummary.ui' # path to the folder, where temporary files shall be stored self.pathTempFolder = self.actualPath + '/temp/' app = QtWidgets.QApplication(sys.argv) # the main and error window self.MainWindow = None self.ErrorWindow = None # courseData, which was selected from the user self.selectedCourseData = None # The filter (lecturer name, semester, course name) which is selected self.selectedFilter = None # The model of the courseData which is selected self.modelCourseData = None # Will set on True, when the moodle download was started, because # scrapy can only run one time per program run self.startedMoodleCrawler = False # The IFileHandler to handle the CourseData self.fileHandler = FileHandler() # The used ITextAbstraction self.textSummarizer = TextAbstraction(database=self.database) user = self.database.getUser() # check if the program has already a user if user is None: # no user in the database # go to settings self.openSettings() else: # go to main page self.goBackMainPage() sys.exit(app.exec_()) # Guis # Open MainPage def goBackMainPage(self): """ goBackMainPage will start the MainPage and will connect everything with the required functions and print the required information to the gui. """ # close and clean up the old Main Window self.cleanMainWindow() # Load and show the new Main Window self.MainWindow = loadUi(self.pathMainGui) self.MainWindow.showMaximized() self.MainWindow.show() # disable that the user can edit the entries from table for general course information self.MainWindow.tab_courses.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_courses.setSortingEnabled(True) # Fill the table for the general course information with data self.printGeneralCourseInformation() # if some data from the general course information is clicked, show all data for this filter # in tab_data self.MainWindow.tab_courses.clicked.connect( self.selectGeneralCourseInformation) # disable that the user can edit the entries from table for course data self.MainWindow.tab_data.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_data.setSortingEnabled(True) # if an cell was selected in table for course data, mark the whole row self.MainWindow.tab_data.setSelectionBehavior( QAbstractItemView.SelectRows) # if some data from the CourseData is clicked, load the summary to the field text_Abstract self.MainWindow.tab_data.clicked.connect(self.selectCourseData) # Connect the Buttons with functionality # open Window for checking, if it is necessary to download moodle-data self.MainWindow.but_downloadMoodle.clicked.connect( self.openWindowStartDownload) # open Window for storing username and password self.MainWindow.but_settings.clicked.connect(self.openSettings) # open Window for help self.MainWindow.but_help.clicked.connect(self.openHelp) # open Window for get the summary from the last moodle download self.MainWindow.but_moodleSummary.clicked.connect( lambda: self.openMoodleSummary(destination="Main Page")) # search functions self.MainWindow.but_searchAll.clicked.connect( lambda: self.searchData(filter="All")) self.MainWindow.but_searchCell.clicked.connect( lambda: self.searchData(filter="Cell")) # show Text without Text-Mining self.MainWindow.but_withoutTextMiningAll.clicked.connect( lambda: self.showDataWithoutTextMining(filter="All")) self.MainWindow.but_withoutTextMiningCell.clicked.connect( lambda: self.showDataWithoutTextMining(filter="Cell")) # open Data self.MainWindow.but_openData.clicked.connect(self.openData) self.MainWindow.but_openAllData.clicked.connect(self.openAllData) # save Data self.MainWindow.but_saveData.clicked.connect(self.saveData) self.MainWindow.but_saveAllData.clicked.connect(self.saveAllData) # close program self.MainWindow.but_close.clicked.connect(self.quitProgram) # StartDownloadPage def openWindowStartDownload(self): """ open the gui to ask the user, if he really wants to download the moodle data. It will connect everything with the required functions and print the required information to the gui. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathStartDownload) # Check if the Crawler was executed, because you can´t start again a Crawler if (self.startedMoodleCrawler): # Crawler was executed # deactivate the Button for starting the Crawler self.MainWindow.but_startDownload.setEnabled(False) # inform the user that he can not start again the crawler self.MainWindow.label_info.setText( """<html><head/><body><p align="center">Achtung:</p><p align="center">Es ist nur möglich einen Moodledownload pro </p><p align="center">Programmstart auszuführen.</p><p align="center">Falls Sie erneut den Download starten wollen, starten Sie das Porgramm neu!<br/></p></body></html>""" ) else: # Crawler was not executed # get the las date of Crawling lastDateOfCrawling = self.database.getMaxDateOfCrawling() if lastDateOfCrawling is None: # inform the user, that he never start a download process from moodle self.MainWindow.label_info.setText( self.MainWindow.label_info.text().replace( '%String', 'Sie haben noch keinen Download gestartet!')) else: # inform the user, when his last download was self.MainWindow.label_info.setText( self.MainWindow.label_info.text().replace( '%String', lastDateOfCrawling.dateCrawling.strftime( "%H:%M:%S %d.%m.%Y "))) self.MainWindow.show() # connect button to go back to Main Page self.MainWindow.but_abortDownload.clicked.connect(self.goBackMainPage) # connect button to start moodle download self.MainWindow.but_startDownload.clicked.connect( self.openCurrentDownload) def openCurrentDownload(self): """ Will open the current download gui and connect the scrapy logger to the gui. It start also the Crawler, if the user stored all required information. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathCurrentDownload) self.MainWindow.showMaximized() # Activate logger to textbox logTextBox = QTextEditLogger(self.MainWindow) # You can format what is printed to text box logTextBox.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) # You can control the logging level logging.getLogger().setLevel(logging.INFO) # disable button done until the crawler finished self.MainWindow.but_done.setEnabled(False) # the log output is only readable self.MainWindow.plainTextEdit.setReadOnly(True) self.MainWindow.show() # get the moodle user user = self.database.getUser() # Check if a user is in the database or none of his attributes is null if (user is None or not user.username or not user.password): logTextBox.deactivate() self.goBackMainPage() self.errorMessage(e="""Sie haben noch keinen Nutzer angelegt. \n Bitte legen Sie bei \"Einstellungen\" auf dem Startbildschirm, einen Nutzer an!""" ) else: # the user has all attributes # start the moodle crawler crawler = MoodleCrawlerHTWBerlin() crawler.startCrawler(self.database, user.username, user.password) # set the information, that the crawler was started on true self.startedMoodleCrawler = True # move the cursor to the end of the text field self.MainWindow.plainTextEdit.moveCursor(QTextCursor.End) logTextBox.deactivate() # check if the login was sucessfully if not self.database.loginSuccessfully(): self.errorMessage(e=""" Das Passwort oder der Nutzername sind falsch. \n Bitte ändern Sie bei \"Einstellungen\" auf dem Startbildschirm den Nutzer!""" ) self.MainWindow.but_done.setEnabled(True) self.MainWindow.but_done.clicked.connect(self.goBackMainPage) else: # login was a success self.MainWindow.but_done.setEnabled(True) self.MainWindow.but_done.clicked.connect( lambda: self.openMoodleSummary(destination="Text Process")) def openMoodleSummary(self, destination: str = "Main Page"): """ Open the GUI for the getMoodleSummary. And print all informations to the gui. This GUI is for informing the user about what data per course is new, old and could not be downloaded. Also every specific error in the download process will be shown. :param destination: Which GUI shall load after this gui. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathMoodleSummary) # Fill the moodle data summary with data modelMoodleSummaryData = QStandardItemModel() self.MainWindow.tab_numberOfData.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_numberOfData.setSortingEnabled(True) self.MainWindow.tab_numberOfData.setModel(modelMoodleSummaryData) # get the summary from the database moodleSummaryData = self.database.getMoodleSummary() # get the header from the table header = MoodleSummary.getHeader() modelMoodleSummaryData.setHorizontalHeaderLabels(header) for moodleSummaryItem in moodleSummaryData: listOfValues = moodleSummaryItem.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) modelMoodleSummaryData.appendRow(row) # Fill the moodle error data summary with data modelMoodleError = QStandardItemModel() self.MainWindow.tab_errorData.setModel(modelMoodleError) self.MainWindow.tab_errorData.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_errorData.setSortingEnabled(True) # get the error summary from the database moodleErrorData = self.database.getMoodleErrorSummary() # get the header from the table header = MoodleErrorSummary.getHeader() modelMoodleError.setHorizontalHeaderLabels(header) for moodleErrorItem in moodleErrorData: listOfValues = moodleErrorItem.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) modelMoodleError.appendRow(row) self.MainWindow.showMaximized() self.MainWindow.show() if destination == "Main Page": self.MainWindow.but_back.setText("Zurück zur Hauptseite") self.MainWindow.but_back.clicked.connect(self.goBackMainPage) elif destination == "Text Process": self.MainWindow.but_back.clicked.connect(self.openTextProcessing) def openSettings(self): """ open the GUI for settings. It is for saving the user information password and username from moodle. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathSettings) self.MainWindow.show() # get the user from the database user = self.database.getUser() # set passwordline on password, that the password is not readable for the user self.MainWindow.linePassword.setEchoMode(QLineEdit.Password) # check if in the database is an user if user is not None: # in the database is an user # fill the text fields with his information self.MainWindow.lineUsername.setText(user.username) self.MainWindow.linePassword.setText(user.password) else: self.MainWindow.lineUsername.setPlaceholderText('s0111111') self.MainWindow.linePassword.setPlaceholderText( 'Hier dein Passwort') # go back to main page, without saving self.MainWindow.but_abortSettings.clicked.connect(self.goBackMainPage) # go back to main page, with saving self.MainWindow.but_save.clicked.connect(self.saveSettings) def openHelp(self): """ open the help GUI. This is for helping the user to work with the application """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathHelp) self.MainWindow.showMaximized() self.MainWindow.show() # the user can not edit the help text self.MainWindow.helpText.setReadOnly(True) # go back to main page self.MainWindow.but_back.clicked.connect(self.goBackMainPage) # open textProcessing Page def openTextProcessing(self): """ open the GUI CurrentDownload and start the text processing. Also it connects the logger to the edit line. This Gui informs the user about which CourseData will be textually processed. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathCurrentDownload) self.MainWindow.showMaximized() # Activate logger to textbox logTextBox = QTextEditLogger(self.MainWindow) # You can format what is printed to text box logTextBox.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) # You can control the logging level logging.getLogger().setLevel(logging.INFO) # disable button until the text process is finished self.MainWindow.but_done.setEnabled(False) self.MainWindow.plainTextEdit.setReadOnly(True) self.MainWindow.show() # create the text mining logic textProcessing = TextProcessing(database=self.database, path=self.pathTempFolder, textSummarizer=self.textSummarizer) # get the CourseData from the database, which do not have a text abstraction and not raised an error in a past process fileTypes = ['pdf', 'docx', 'pptx', 'html'] dataWithoutTextMining = self.database.getCourseDataWithoutTextMiningForParsing( fileTypes) # i is the position of the course data in the list i = 1 countDataWithoutTextMining = len(dataWithoutTextMining) self.MainWindow.plainTextEdit.appendPlainText( "Es sind insgesamt %d Dateien textuell aufzuarbeiten!".replace( "%d", str(countDataWithoutTextMining))) # start for each data the text mining process for data in dataWithoutTextMining: self.MainWindow.plainTextEdit.appendPlainText( "Beginn mit der %d1. Datei von %d2!".replace( "%d1", str(i)).replace("%d2", str(countDataWithoutTextMining))) textProcessing.textProcessing(data) self.MainWindow.plainTextEdit.appendPlainText( "Fertig mit der %d1. Datei von %d2!".replace( "%d1", str(i)).replace("%d2", str(countDataWithoutTextMining))) i += 1 QtWidgets.QApplication.processEvents() # enable the button for finish this self.MainWindow.but_done.setEnabled(True) # deactivate the logger logTextBox.deactivate() # go back to main page self.MainWindow.but_done.clicked.connect(self.goBackMainPage) def saveSettings(self): """ It tries to save the informations from the settings to the database. If every field is filled save the information to the database and go back to the main page. Otherwise print an error message and do nothing. """ # read the arguments of the user username = self.MainWindow.lineUsername.text() password = self.MainWindow.linePassword.text() if username == "" or password == "": self.errorMessage(e="""Der Nuzername oder das Passwort sind leer. Bitte füllen Sie die Felder aus!""") else: user = User(username=username, password=password) # delete the current user from the database self.database.deleteUsers() # insert the new user self.database.insertObject(user) # go back to main page self.goBackMainPage() def quitProgram(self): """ Tries to delete every file in the temp folder. Only the files, which are not any more in use will be deleted. After this quit the program. """ self.fileHandler.deleteAllFilesInFolder(self.pathTempFolder) sys.exit() def printGeneralCourseInformation(self): """ print the generalCourseInformation to the table tab_courses """ self.modelGeneralCourseInformation = QStandardItemModel() self.MainWindow.tab_courses.setModel( self.modelGeneralCourseInformation) courses = self.database.getGeneralCourseInformation() header = GeneralCourseInformation.getHeader() self.modelGeneralCourseInformation.setHorizontalHeaderLabels(header) # fill the table with the information for course in courses: listOfValues = course.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) self.modelGeneralCourseInformation.appendRow(row) def printCourseData(self, table=""): """ print all CourseData from the table to the table tab_data. :param table: the table which shall be printed """ self.modelCourseData = QStandardItemModel() self.MainWindow.tab_data.setModel(self.modelCourseData) header = CourseDataWithInformation.getHeader() self.modelCourseData.setHorizontalHeaderLabels(header) for course in table: listOfValues = course.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) self.modelCourseData.appendRow(row) def searchData(self, filter: str): """ search for data if filter is all search for all data for search string otherwise for the selected filter after this print the searched data to table tab_data :param filter: filter = "All" if all data shall be searched; filter = "Cell" if only for the specific selected filter data shall be searched """ searchString = self.MainWindow.line_search.text() table = None if filter == 'All': table = self.database.getCourseDataByText( searchString=searchString, filter="") elif filter == 'Cell': if self.selectedFilter: table = self.database.getCourseDataByText( searchString=searchString, filter=self.selectedFilter) else: self.errorMessage( e="""Sie haben keine Zelle ausgewählt. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff""") if table: self.printCourseData(table) def showDataWithoutTextMining(self, filter: str): """ Search for data without text mining and print them to the table tab_data. :param filter: filter = "All" if all data without text-mining shall be searched; filter = "Cell" if only for the specific selected filter data without text-mining shall be searched """ table = None if filter == 'All': table = self.database.getCourseDataWithoutTextMining(filter="") elif filter == 'Cell': if self.selectedFilter: table = self.database.getCourseDataWithoutTextMining( filter=self.selectedFilter) else: self.errorMessage(e="""Sie haben keine Zelle ausgewählt. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff""" ) if table: self.printCourseData(table) def openData(self): """ open the the selected CourseData if None is selected inform the user that he has to select a CourseData in the table """ if self.selectedCourseData is not None: self.fileHandler.openFile(courseData=self.selectedCourseData, path=self.pathTempFolder) else: self.errorMessage(e="""Sie haben keine Datei ausgewählt. \n Bitte drücken Sie in der mittleren Tabelle auf Ihren gewünschte Datei.""" ) def openAllData(self): """ open all Data which are in the tab_data(modle = modelCourseData) printed If no data is printed inform the user that he has to search for CourseData to open a data """ if self.modelCourseData is not None: courseDataID_list = [] self.modelCourseData.columnCount() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem(y).text() if header == "DataID": column = y continue for x in range(self.modelCourseData.rowCount()): index = self.modelCourseData.index(x, column) courseDataID_list.append( self.modelCourseData.itemData(index).get(0)) for courseDataId in courseDataID_list: courseData = self.database.getCourseDataByID(int(courseDataId)) self.fileHandler.openFile(courseData=courseData, path=self.pathTempFolder) else: self.errorMessage( e="""Sie haben keine Dateien gesucht, die Sie auswählen können. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff, um die zugehörigen Dateien anzuzeigen.""" ) def selectGeneralCourseInformation(self, signal): """ Set the selectedFilter on the selected Value, which the user selected. And print all Data for the specific filter to the tab_data """ cell_dict = self.modelGeneralCourseInformation.itemData(signal) self.selectedFilter = cell_dict.get(0) result = self.database.getAllCourseData(filter=self.selectedFilter) self.printCourseData(table=result) def errorMessage(self, e: str): """ open the error Gui and print the error message :param e: the error message """ if self.ErrorWindow is not None: self.ErrorWindow.close() self.ErrorWindow = loadUi(self.pathError) self.ErrorWindow.label_info.setText( self.ErrorWindow.label_info.text().replace('%String', str(e))) self.ErrorWindow.but_ok.clicked.connect(self.ErrorWindow.close) self.ErrorWindow.show() def saveData(self): """ save the selected data to a folder, which the user select. if None is selected inform the user that he has to select a CourseData in the table """ if self.selectedCourseData is not None: saveFolder = QFileDialog.getExistingDirectory( self.MainWindow, "Select Directory") saveFolder += '/' if len(saveFolder) > 0: self.fileHandler.saveFile(courseData=self.selectedCourseData, path=saveFolder) else: self.errorMessage(e="""Sie haben keine Datei ausgewählt. \n Bitte drücken Sie in der mittleren Tabelle auf Ihren gewünschte Datei.""" ) def saveAllData(self): """ save all CourseData which are printed in the tab_data(modle = modelCourseData) If no data is printed inform the user that he has to search for CourseData to open a data """ if self.modelCourseData is not None: saveFolder = str( QFileDialog.getExistingDirectory(self.MainWindow, "Select Directory")) if len(saveFolder) > 0: saveFolder += '/' courseDataID_list = [] self.modelCourseData.columnCount() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem( y).text() if header == "DataID": column = y continue for row in range(self.modelCourseData.rowCount()): index = self.modelCourseData.index(row, column) courseDataID_list.append( self.modelCourseData.itemData(index).get(0)) for courseDataId in courseDataID_list: courseData = self.database.getCourseDataByID( int(courseDataId)) self.fileHandler.saveFile(courseData=courseData, path=saveFolder) else: self.errorMessage( e="""Sie haben keine Dateien gesucht, die Sie auswählen können. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff, um die zugehörigen Dateien anzuzeigen.""" ) def selectCourseData(self, signal): """ set the selectedCourseData on the data which was selected. Print the abstract, the frequency of words and the errors from the data to the text field "text_Abstract" """ row = signal.row() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem(y).text() if header == "DataID": column = y break index = self.modelCourseData.index(row, column) courseDataID = self.modelCourseData.itemData(index).get(0) self.selectedCourseData = self.database.getCourseDataByID( idCourseData=courseDataID) self.MainWindow.text_Abstract.clear() if self.selectedCourseData.abstract is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.abstract) if self.selectedCourseData.abstractWordFrequency is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.abstractWordFrequency) if self.selectedCourseData.error is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.error) self.MainWindow.text_Abstract.setReadOnly(True) def cleanMainWindow(self): """ reset all fields """ if self.MainWindow is not None: self.selectedCourseData = None self.selectedFilter = None self.modelCourseData = None
class DataChangeUI(object): def __init__(self, window, opc_ua_client, view): self.window = window self.opc_ua_client = opc_ua_client self._subhandler = DataChangeHandler() self.subscribed_nodes = [] self.view = view self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(["ObjectName", "VariableName", "Value", "Timestamp"]) self.view.setModel(self.model) # handle subscriptions self._subhandler.data_change_fired.connect(self._update_subscription_model, type=Qt.QueuedConnection) # accept drops self.model.canDropMimeData = self.canDropMimeData self.model.dropMimeData = self.dropMimeData # Context menu self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect(self.showContextMenu) actionDeleteMonitoredItem = QAction("Delete Monitored Item", self.model) actionDeleteMonitoredItem.triggered.connect(self._delete_monitored_item_context) self._contextMenu = QMenu() self._contextMenu.addAction(actionDeleteMonitoredItem) self.view.selectionModel().selectionChanged.connect(self.highlight_node) def highlight_node(self, selection): if isinstance(selection, QItemSelection): if not selection.indexes(): # no selection return idx = self.view.currentIndex() idx = idx.siblingAtColumn(0) it = self.model.itemFromIndex(idx) if not it: return node = it.data() self.window.tree_ui.expand_to_node(node) def canDropMimeData(self, mdata, action, row, column, parent): node = self.opc_ua_client.client.get_node(mdata.text()) if node.get_node_class() == ua.NodeClass.Variable: return True return False def dropMimeData(self, mdata, action, row, column, parent): node = self.opc_ua_client.client.get_node(mdata.text()) self.window.add_monitored_item(node) return True def showContextMenu(self, position): item = self.get_current_item() if item: self._contextMenu.exec_(self.view.viewport().mapToGlobal(position)) def get_current_item(self, col_idx=0): idx = self.view.currentIndex() idx = idx.siblingAtColumn(col_idx) return self.model.itemFromIndex(idx) def _delete_monitored_item_context(self): it = self.get_current_item() if it: index = self.window.ui.tabWidget.currentIndex() self.delete_monitored_item(index, it.data()) def clear(self): self.subscribed_nodes = [] # remove all rows but not header self.model.removeRows(0, self.model.rowCount()) def show_error(self, *args): self.window.show_error(*args) def create_subscription(self): self.opc_ua_client.create_subscription(self._subhandler) def delete_subscription(self, index): self.opc_ua_client.delete_subscription(index) @trycatchslot def add_monitored_item(self, index, node): variable_name = node.get_display_name().Text descriptions = node.get_references(ua.ObjectIds.Aggregates, ua.BrowseDirection.Inverse, ua.NodeClass.Object, True) parent_node = node while not descriptions: parent_node = parent_node.get_parent() descriptions = parent_node.get_references(ua.ObjectIds.Aggregates, ua.BrowseDirection.Inverse, ua.NodeClass.Object, True) parent_nodeid = descriptions[0].NodeId if parent_nodeid in self.opc_ua_client.custom_objects: custom_type = self.opc_ua_client.custom_objects[parent_nodeid] icon = get_icon(custom_type) else: icon = "icons/object.svg" row = [QStandardItem(QIcon(icon), descriptions[0].DisplayName.Text), QStandardItem(variable_name), QStandardItem("No Data yet"), QStandardItem("")] row[0].setData(node) self.model.appendRow(row) self.subscribed_nodes.append(node) try: self.opc_ua_client.create_monitored_items(node, index) row[0].setData(self.window.get_monitored_item_tooltip(), Qt.ToolTipRole) self.model.sort(0, Qt.AscendingOrder) self._color_rows() except Exception as ex: self.window.show_error(ex) idx = self.model.indexFromItem(row[0]) self.model.takeRow(idx.row()) self.subscribed_nodes.remove(node) raise def _color_rows(self): n_rows = self.model.rowCount() if n_rows > 1: change_color = False for row in range(1, n_rows): prev_object_name = self.model.data(self.model.index(row - 1, 0)) curr_object_name = self.model.data(self.model.index(row, 0)) if curr_object_name != prev_object_name: change_color = not change_color if change_color: color = QColor(240, 240, 240) # grey else: color = QColor(255, 255, 255) # white for col in range(self.model.columnCount()): item = self.model.item(row, col) item.setData(QBrush(color), Qt.BackgroundRole) @trycatchslot def delete_monitored_item(self, index, node=None): if not isinstance(node, Node): node = self.window.get_current_node() if node is None: return self.opc_ua_client.remove_monitored_item(node, index) self.subscribed_nodes.remove(node) i = 0 while self.model.item(i): item = self.model.item(i) if item.data() == node: self.model.removeRow(i) i += 1 def _update_subscription_model(self, node, value, status_code, timestamp): i = 0 while self.model.item(i): item = self.model.item(i) if item.data() == node: it = self.model.item(i, 2) it.setText(value) if status_code == ua.StatusCodes.Good: it.setForeground(QBrush(QColor("green"))) elif status_code == ua.StatusCodes.Uncertain: it.setForeground(QBrush(QColor("yellow"))) else: # StatusCode = Bad: it.setForeground(QBrush(QColor("red"))) it_ts = self.model.item(i, 3) it_ts.setText(timestamp) i += 1
class QmyMainWindow(QMainWindow): cellIndexChanged = pyqtSignal(int, int) def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.__dlgSetHeaders = None self.setCentralWidget(self.ui.tableView) ##构建状态栏 self.LabCellPos = QLabel("当前单元格:", self) self.LabCellPos.setMinimumWidth(180) self.ui.statusBar.addWidget(self.LabCellPos) self.LabCellText = QLabel("单元格内容:", self) self.LabCellText.setMinimumWidth(200) self.ui.statusBar.addWidget(self.LabCellText) ##构建Item Model/View self.itemModel = QStandardItemModel(10, 5, self) #数据模型,10行5列 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 self.selectionModel.currentChanged.connect(self.do_currentChanged) ##为tableView设置数据模型 self.ui.tableView.setModel(self.itemModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #设置选择模型 ## self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection) #单选 ## self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems) #单元格选择 ## self.ui.tableView.setAlternatingRowColors(True) ## self.ui.tableView.verticalHeader().setDefaultSectionSize(25)#缺省行高 def __del__(self): ## super().__del__(self) print("QmyMainWindow 对象被删除了") ## ==============自定义功能函数============ ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##设置行数列数对话框 def on_actTab_SetSize_triggered(self): dlgTableSize = QmyDialogSize() #局部变量,构建时不能传递self dlgTableSize.setIniSize(self.itemModel.rowCount(), self.itemModel.columnCount()) ret = dlgTableSize.exec() #模态方式运行对话框 if (ret == QDialog.Accepted): rows, cols = dlgTableSize.getTableSize() self.itemModel.setRowCount(rows) self.itemModel.setColumnCount(cols) @pyqtSlot() ##设置表头标题 def on_actTab_SetHeader_triggered(self): if (self.__dlgSetHeaders == None): #未创建对话框 self.__dlgSetHeaders = QmyDialogHeaders(self) count = len(self.__dlgSetHeaders.headerList()) if (count != self.itemModel.columnCount()): #列数改变了 strList = [] for i in range(self.itemModel.columnCount()): text = str( self.itemModel.headerData(i, Qt.Horizontal, Qt.DisplayRole)) strList.append(text) #现有表格标题 self.__dlgSetHeaders.setHeaderList(strList) ret = self.__dlgSetHeaders.exec() #以模态方式运行对话框 if (ret == QDialog.Accepted): strList2 = self.__dlgSetHeaders.headerList() self.itemModel.setHorizontalHeaderLabels(strList2) @pyqtSlot() ##"定位单元格" def on_actTab_Locate_triggered(self): dlgLocate = QmyDialogLocate(self) dlgLocate.setSpinRange(self.itemModel.rowCount(), self.itemModel.columnCount()) dlgLocate.changeActionEnable.connect(self.do_setActLocateEnable) dlgLocate.changeCellText.connect(self.do_setACellText) self.cellIndexChanged.connect(dlgLocate.do_setSpinValue) dlgLocate.setAttribute(Qt.WA_DeleteOnClose) #对话框关闭时自动删除 dlgLocate.show() ## =============自定义槽函数=============================== def do_currentChanged(self, current, previous): if (current != None): #当前模型索引有效 self.LabCellPos.setText( "当前单元格:%d行,%d列" % (current.row(), current.column())) #显示模型索引的行和列号 item = self.itemModel.itemFromIndex(current) #从模型索引获得Item self.LabCellText.setText("单元格内容:" + item.text()) #显示item的文字内容 self.cellIndexChanged.emit(current.row(), current.column()) ## @pyqtSlot(bool) def do_setActLocateEnable(self, enable): self.ui.actTab_Locate.setEnabled(enable) ## @pyqtSlot(int,int,str) def do_setACellText(self, row, column, text): index = self.itemModel.index(row, column) #获取模型索引 self.selectionModel.clearSelection() #清除现有选择 self.selectionModel.setCurrentIndex( index, QItemSelectionModel.Select) #定位到单元格 self.itemModel.setData(index, text, Qt.DisplayRole) #设置单元格字符串
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建Ui对象 self.ui.setupUi(self) #构造UI self.__ColCount = 6 #列数 self.itemModel = QStandardItemModel( 10, self.__ColCount, self) #创建QStandardItemModel类型的数据模型,指定行列值 ''' setSelectionBehavior() 此属性保存视图使用的选择行为。 此属性保存选择是根据单个项目,行还是列进行的 #QItemSelectionModel() 此属性保存视图在哪种选择模式下运行。 #此属性控制用户是否可以选择一个或多个项目,并且在多个项目选择中控制选择是否必须是连续范围的项目 ''' self.selectionModel = QItemSelectionModel(self.itemModel) self.selectionModel.currentChanged.connect( self.do_curChanged) #单元格选择发生变化时会发射此信号 self.__lastColumnTitle = "" #设置最后一列的标题,可以是空 self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) #设置tableView属性 self.ui.tableView.setModel(self.itemModel) #数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #选择模型 oneOrMore = QAbstractItemView.ExtendedSelection #选择模式->多选模式 self.ui.tableView.setSelectionMode(oneOrMore) #多选模式 itemOrRow = QAbstractItemView.SelectItems #项选择模式->单元格选择 self.ui.tableView.setSelectionBehavior(itemOrRow) #单元格选择 self.ui.tableView.verticalHeader().setDefaultSectionSize(22) self.ui.tableView.setAlternatingRowColors(True) #交替行颜色 self.ui.tableView.setEnabled(False) #设置默认禁用tabelView self.ui.actFontBold.setCheckable(False) self.setCentralWidget(self.ui.splitter) #设置中心组件 # self.setCentralWidget(self.ui.tableView) self.__buildStatusBar() self.spinCeshen = QmyFloatSpinDelegate(0, 10000, 0, self) self.spinLength = QmyFloatSpinDelegate(0, 6000, 2, self) self.spinDegree = QmyFloatSpinDelegate(0, 360, 1, self) self.ui.tableView.setItemDelegateForColumn(0, self.spinCeshen) self.ui.tableView.setItemDelegateForColumn(1, self.spinLength) self.ui.tableView.setItemDelegateForColumn(3, self.spinLength) self.ui.tableView.setItemDelegateForColumn(2, self.spinDegree) qualities = ["优", "良", "合格", "不合格"] self.comboDelegate = QmyComboBoxDelegate(self) self.comboDelegate.setItems(qualities, False) self.ui.tableView.setItemDelegateForColumn(4, self.comboDelegate) ##==========自定义功能函数========== def __buildStatusBar(self): ''' 设置状态栏ui组件 :return: ''' self.LabCellPos = QLabel("当前单元格:", self) self.LabCellPos.setMinimumWidth(180) self.ui.statusBar.addWidget(self.LabCellPos) self.LabCellText = QLabel("单元格内容:", self) self.LabCellText.setMinimumWidth(150) self.ui.statusBar.addWidget(self.LabCellText) self.LabCurFile = QLabel("当前文件:", self) self.ui.statusBar.addWidget(self.LabCurFile) def __iniModelFromStringList(self, allLines): rowCnt = len(allLines) #获取总行数 self.itemModel.setRowCount(rowCnt - 1) #除去表头的数据行数 headerText = allLines[0].strip() #表头去除换行符,文件呢的空格使用Tab代替 headerList = headerText.split("\t") #按照制表符转化为列表 self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头标题 # print(headerList) self.__lastColumnTitle = headerList[len(headerList) - 1] #最后一列的标题 lastColNo = self.__ColCount - 1 #最后一列的列号 for i in range(rowCnt - 1): #除去表头的数据行数 # print(i) lineText = allLines[i + 1].strip() #去除换行符,不包括表头 strList = lineText.split("\t") #按制表符生成列表 for j in range(self.__ColCount - 1): #不包括最后一列 ''' QStandardItem是一个数据结构,他可以存储一个cell的各种信息,比如文本、图标、是否可选、字体、别景色、前景色等等。 并且QStandardItem可以有孩子和兄弟,他是为model提供数据存储的节点。 QTableView:作为表格cell时,有一个作为根节点的QStandardItem,其他节点都是QStandardItem节点的孩子节点,并且都是兄弟节点(这里暂时不考虑多列的情况)。 QTreeView:作为树节点cell时,有一个作为根节点的QStandardItem,其他节点都是他的孩子节点,但是其他节点也可以作为父节点存在(这里暂时不考虑多列的情况)。 ''' item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) #设置最后一行 # print(self.__lastColumnTitle) item = QStandardItem(self.__lastColumnTitle) #将最后一行的表头 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) # print(strList[lastColNo]) if strList[lastColNo] == '0': #对比文本内的数值进行设定,类型是字符串 item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i, lastColNo, item) def __setCellAlignment(self, align=Qt.AlignHCenter): if not self.selectionModel.hasSelection(): return ''' selectedIndexes()返回一个元素为QModelIndex类型的列表,包括所有被选中的单元格的模型索引 ''' selectdIndex = self.selectionModel.selectedIndexes() # print(selectdIndex) count = len(selectdIndex) for i in range(count): index = selectdIndex[i] ''' itemFromIndex(index)返回的是模型索引为index的QStandardItem对象 ''' item = self.itemModel.itemFromIndex(index) item.setTextAlignment(align) ##==========事件处理函数=========== ##==========由connectSlotsByName()自动关联的槽函数==== @pyqtSlot() def on_actOpenFile_triggered(self): curPath = os.getcwd() #获取当前路径 # print(curPath)? #flt是文件过滤器 filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if filename == "": return self.LabCurFile.setText(("当前文件: " + filename)) #设置状态栏文本 self.ui.plainTextEdit.clear() aFile = open(filename, "r") allLines = aFile.readlines() aFile.close() for strLine in allLines: self.ui.plainTextEdit.appendPlainText( strLine.strip()) #按照行添加到plainTextEdit中 self.__iniModelFromStringList(allLines) #设置激活状态 self.ui.tableView.setEnabled(True) self.ui.actAppend.setEnabled(True) self.ui.actInsert.setEnabled(True) self.ui.actDel.setEnabled(True) self.ui.actSaveFile.setEnabled(True) self.ui.actModelData.setEnabled(True) self.ui.actFontBold.setCheckable(True) #设置加粗可用 @pyqtSlot() def on_actAppend_triggered(self): itemlist = [] for i in range(self.__ColCount - 1): #循环一行中的各个列,不包括最后一列 item = QStandardItem("0") #添加0到数据结构中 itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) #将最后一行的表头添加入数据结构 item.setCheckable(True) #可选 item.setFlags(self.__lastColumnFlags) itemlist.append(item) #添加到itemlist内(添加到最后一个) self.itemModel.appendRow(itemlist) curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0) #获取最后一行第一个单元格的模型索引 self.selectionModel.clearSelection() #清除选择 self.selectionModel.setCurrentIndex( curIndex, QItemSelectionModel.Select) #设置在添加后自动选择添加行的第一个单元格(可从状态栏确认) @pyqtSlot() def on_actInsert_triggered(self): ''' 插入行 :return: ''' itemlist = [] for i in range(self.__ColCount - 1): item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) item.setFlags(self.__lastColumnFlags) item.setCheckable(False) #是否可以修改选择 item.setCheckState(Qt.Checked) #是否选中 itemlist.append(item) curIndex = self.selectionModel.currentIndex() #选中项的模型索引,包括行列等其他信息 self.itemModel.insertRow(curIndex.row(), itemlist) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_actDel_triggered(self): ''' 删除行 :return: ''' curIndex = self.selectionModel.currentIndex() self.itemModel.removeRow(curIndex.row()) @pyqtSlot() def on_actAlignLeft_triggered(self): self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() def on_actAlignCenter_triggered(self): self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter) @pyqtSlot() def on_actAlignRight_triggered(self): self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) def on_actFontBold_triggered(self, checked): print("1,checked", checked) if not self.selectionModel.hasSelection(): return selectIndex = self.selectionModel.selectedIndexes() for i in range(len(selectIndex)): index = selectIndex[i] item = self.itemModel.itemFromIndex(index) font = item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() def on_actModelData_triggered(self): self.ui.plainTextEdit.clear() lineStr = "" for i in range(self.itemModel.columnCount() - 1): #不包括最后一列的表头遍历 item = self.itemModel.horizontalHeaderItem(i) #返回行标题的一个数据项对象,i是列号 lineStr = lineStr + item.text() + "\t" #给每个项对象的文本添加Tab制表符 item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1) #最后一列的表头 lineStr = lineStr + item.text() self.ui.plainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): #获取行总数,不包括表头行 lineStr = "" for j in range(self.itemModel.columnCount() - 1): #不包括最后一列的遍历 item = self.itemModel.item(i, j) #按照行列号获取工作区内项对象 lineStr = lineStr + item.text() + "\t" #项对象文本添加制表符 item = self.itemModel.item(i, self.__ColCount - 1) #按照行号获取最后一列的项对象 if item.checkState() == Qt.Checked: #匹配状态是否为选中 lineStr = lineStr + "1" else: lineStr = lineStr + "0" self.ui.plainTextEdit.appendPlainText(lineStr) @pyqtSlot() def on_actSaveFile_triggered(self): ''' 保存文件 :return: ''' curPath = os.getcwd() filename, flt = QFileDialog.getSaveFileName( self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if filename == "": return self.on_actModelData_triggered() aFile = open(filename, "w") aFile.write(self.ui.plainTextEdit.toPlainText()) aFile.close() ##=========自定义槽函数============ def do_curChanged(self, current, previous): ''' 设置状态栏组件显示内容 :param current: :param previous: :return: ''' if current != None: text = " 当前单元格: %d行,%d列" % (current.row() + 1, current.column() + 1) self.LabCellPos.setText(text) item = self.itemModel.itemFromIndex(current) self.LabCellText.setText("单元格内容:" + item.text()) font = item.font() self.ui.actFontBold.setChecked( font.bold()) #设置按钮按下,当font.Bold的值大于50式font.blod()会为True
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建Ui对象 self.ui.setupUi(self) #构造UI self.ui.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.BASE_PATH = os.getcwd() self.itemModel = QStandardItemModel(self) self.item_Model = QStandardItemModel(self) self.ui.checkBox.setChecked(False) self.ui.checkBox.stateChanged.connect(self.__ShowAnswer) self.ui.rab_dan.clicked.connect(lambda: self.__do_setchangeType()) self.ui.rab_duo.clicked.connect(lambda: self.__do_setchangeType()) self.ui.rab_pan.clicked.connect(lambda: self.__do_setchangeType()) self.__CheckedFlags = Qt.Checked def __Excle_init(self): self.excle_book = xlrd.open_workbook(self.Open_File_path) self.excle_sheetnames = self.excle_book.sheet_names() #获取excle的sheet名称 self.__InitModelRaido() # self.__groupbox4_init() def __Excle_api(self, sheetname): self.item_list = [] excle_sheet = self.excle_book.sheet_by_name(sheetname) self.rows = excle_sheet.nrows for i in range(self.rows): original_table = excle_sheet.row_values(i) original_table[0] = "第" + str(original_table[0]) + "题" original_table = [str(j) for j in original_table] self.item_list.append(original_table) # print(self.item_list) self.__InitModelExcle() def __InitModelRaido(self): Count_Row = len(self.excle_sheetnames) for i in range(Count_Row): item = QStandardItem(self.excle_sheetnames[i]) self.itemModel.setItem(0, i, item) def __InitModelExcle(self): Count_Row = len(self.item_list) for i in range(Count_Row): Count_Col = len(self.item_list[i]) #Count_Col是二维列表内的列表的长度 for j in range(Count_Col): item_model = QStandardItem(self.item_list[i][j]) self.item_Model.setItem(i, j, item_model) self.ui.listView.setModel(self.item_Model) def __ShowAnswer(self, state): #接收显示答案复选框的信号并显示答案 if state == Qt.Checked: self.__result = self.item_Model.item(self.__Signal, 7).text() self.ui.label.setText(self.__result) def on_listView_clicked(self, index): # print(index) try: self.ui.textBrowser.clear() self.ui.checkBox.setChecked(False) self.__Signal = index.row() for i in self.ui.groupBox_2.children(): if type(i) == QCheckBox: i.deleteLater() #删除checkBox组件 item = self.item_Model.item(self.__Signal, 2) #获取题目的单元格的QStandardItem对象 self.__Title = item.text() # self.__TYPE = self.item_Model.item(self.__Signal, 2).text() #题目类型的文本 self.ui.textBrowser.setText(self.__Title) #给文本框设置文字 Column = self.item_Model.columnCount() #获取二维列表的长度 for i in range(3, 7): item = self.item_Model.item(self.__Signal, i) #遍历二级列表内的元素 try: anchor = item.text() # print(anchor) checkName = "chk_{}_{}".format(self.__Signal, i) self.__CreateChecked(checkName, anchor) #按照选项个数动态生成生成复选框 except AttributeError: break except AttributeError: return def __CreateChecked(self, checkName, checkText): ''' 创建复选框 :param checkName: 复选框的objectName :param checkText: 复选框的文本内容 :return: ''' self.chk = QCheckBox(self.ui.groupBox_2) #在groupBox_2内实例化复选框 self.chk.setObjectName(checkName) #设置名称 self.ui.verticalLayout.addWidget(self.chk) #添加复选框到布局管理器内,必要的,否则无法正常显示 self.chk.setText(checkText) #设置文本内容 # def __CreateRadio(self,radioName,radioText): # ''' # 创建单选框 # :param checkName: 复选框的objectName # :param checkText: 复选框的文本内容 # :return: # ''' # self.rab = QRadioButton(self.ui.groupBox_4)#在groupBox_2内实例化复选框 # self.rab.setObjectName(radioName)#设置名称 # self.ui.horizontalLayout_3.addWidget(self.rab)#添加复选框到布局管理器内,必要的,否则无法正常显示 # self.rab.setText(radioText)#设置文本内容 @pyqtSlot() def on_actOpen_File_triggered(self): ''' 打开文件按钮 :return: ''' self.__FileName, self.flt = QFileDialog.getOpenFileName( self, "打开一个文件", self.BASE_PATH, "*(*.xlsx)") if self.__FileName == "": return # self.ui.btnInit.setEnabled(True)#打开初始化按钮 self.Open_File_path = self.__FileName #获取文件路径 # print(self.Open_File_path) self.__Excle_init() ##=========自定义槽函数============ # def __groupbox4_init(self): # #动态生成题目类型,即sheet页对应的题目类型 # for i in self.ui.groupBox_4.children(): # if type(i) == QRadioButton: # i.deleteLater() # 删除checkBox组件 # Column = self.itemModel.columnCount() # 获取二维列表的长度 # # for i in range(Column): # item = self.itemModel.item(0, i) # 遍历二级列表内的元素 # # try: # radioText = item.text() # radioName = "rad_{}_{}".format(0, i) # self.__CreateRadio(radioName,radioText) # 按照选项个数动态生成生成复选框 # except AttributeError: # break def __do_setchangeType(self): if self.ui.rab_dan.isChecked(): self.__Excle_api(self.excle_sheetnames[0]) print("1") elif self.ui.rab_duo.isChecked(): self.__Excle_api(self.excle_sheetnames[1]) print("2") elif self.ui.rab_pan.isChecked(): self.__Excle_api(self.excle_sheetnames[2]) print("3")
class ResultsTable(QWidget): def __init__(self, connection_helper): super().__init__() self.connection_helper = connection_helper self.model = QStandardItemModel() self.model.itemChanged.connect(self.edit_cell) # self.database = QSqlDatabase("QPSQL7") # self.database.setHostName('127.0.0.1') # self.database.setUserName('root') # self.database.setPassword('root') # self.database.setPort(5432) # self.database.setDatabaseName('pydb') # self.database.open() # self.sql_model = QSqlTableModel(None, self.database) # self.sql_model.setHeaderData(0, Qt.Horizontal, "id") # self.sql_model.setTable('testing') # print(self.sql_model.selectStatement()) # self.sql_model.select() # print(self.sql_model.selectStatement()) # print(self.sql_model.lastError().text()) # print(self.sql_model.rowCount()) # print(self.sql_model.columnCount()) self.init_ui() def init_ui(self): uic.loadUi(ui_file, self) self.ResultsTable.setSortingEnabled(True) # self.ResultsTable.sortByColumn(0, Qt.AscendingOrder) def edit_cell(self, item): # revert update command if failed to reset cell and display warning message column = item.column() row = item.row() row_values = [self.model.item(row, column).text() for column in range(self.model.columnCount())] column_value = self.model.horizontalHeaderItem(column).text() value = item.data(Qt.EditRole) result = self.connection_helper.update_query(None, column, column_value, row, value, row_values) print(result) def set_headers(self, headers): self.headers = headers for idx, header in enumerate(headers): self.model.setHorizontalHeaderItem(idx, QStandardItem(header)) def set_blank(self): self.set_headers(['Results']) self.set_rows([{'value': 'No Results'}]) def clear(self): self.model.clear() def set_rows(self, rows): for idx, row in enumerate(rows): items = [] for column, item in row.items(): standard_item = QStandardItem() if item is None: font = QFont() font.setItalic(True) font.setBold(True) standard_item.setData(QVariant("NULL"), Qt.EditRole) standard_item.setFont(font) elif isinstance(item, datetime.datetime): standard_item.setData(QDateTime(item), Qt.EditRole) elif isinstance(item, datetime.date): standard_item.setData(QDate(item), Qt.EditRole) elif isinstance(item, str): standard_item.setData(QVariant(item), Qt.EditRole) else: standard_item.setData(QVariant(item), Qt.EditRole) items.append(standard_item) self.model.insertRow(idx, items) def get_sort(self): sort_column = self.ResultsTable.horizontalHeader().sortIndicatorSection() sort_type = self.ResultsTable.horizontalHeader().sortIndicatorOrder() return {'column': sort_column, 'type': sort_type} def update_sort(self, column, type): self.ResultsTable.sortByColumn(column, type) def display(self): self.ResultsTable.setModel(self.model)
class AnalysisView(QWidget): def __init__(self, parent=None): super(QWidget, self).__init__(parent) self.vectorManager = VectorManager() self.nodeManager = NodeManager() self.logentryManager = LogEntryManager.get_instance() self.initUI() def initUI(self): self.setupMainLayout() self.setLayout(self.mainLayout) def setupMainLayout(self): #Log Entries table self.logEntriesTbl = QTableView() self.logEntryModel = QStandardItemModel() self.logEntryModel.setHorizontalHeaderLabels([ 'Host', 'Timestamp', 'Content', 'Source', 'Source Type', 'Associated Vectors' ]) self.logEntriesTbl.setModel(self.logEntryModel) self.logEntriesTbl.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.setupVectorTab() self.tabWidget = QTabWidget() self.tabWidget.addTab(self.logEntriesTbl, "Log Entries") self.tabWidget.addTab(self.vectorTab, "Vector View") # Label for our Vector List vectorLbl = QListWidgetItem() vectorLbl.setText("Vector Databases") vectorLbl.setTextAlignment(Qt.AlignCenter) vectorLbl.setFlags(Qt.NoItemFlags) self.workspace = QHBoxLayout() self.workspace.addWidget(self.tabWidget, 90) # Filtering and search hSpacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Fixed) self.search = QLineEdit() self.search.setFixedWidth(250) self.filterBox = QComboBox() # Container for tab/table controls self.controls = QHBoxLayout() self.controls.addItem(hSpacer) self.controls.addWidget(self.search) self.controls.addWidget(self.filterBox) # Container for all workspace self.mainLayout = QVBoxLayout() self.mainLayout.addLayout(self.controls) self.mainLayout.addLayout(self.workspace) def setupVectorTab(self): self.graph = GraphWidget() self.nodes = QTableView() nodeModel = QStandardItemModel() nodeModel.setHorizontalHeaderLabels([ "Name", "Timestamp", "Description", "Log Entry Refrence", "Log Creator", "Icon", "Source", "Visible" ]) self.nodes.setModel(nodeModel) # self.nodes.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.vectorViews = QHBoxLayout() self.vectorViews.addWidget(self.nodes, 30) self.vectorViews.addWidget(self.graph, 70) hSpacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Fixed) vectorsLable = QLabel("Vectors") self.vectorsCB = QComboBox() self.vectorsCB.currentIndexChanged.connect(self.vectorHandle) self.vectorAdded() # self.unitsCb = QComboBox() # self.interval = QLineEdit() # Graph controls such as orientation, interval units, interval self.graphContols = QHBoxLayout() self.graphContols.addItem(hSpacer) self.graphContols.addWidget(vectorsLable) self.graphContols.addWidget(self.vectorsCB) # self.graphContols.addWidget(self.unitsCb) # self.graphContols.addWidget(self.interval) self.container = QVBoxLayout() self.container.addLayout(self.graphContols) self.container.addLayout(self.vectorViews) self.vectorTab = QWidget() self.vectorTab.setLayout(self.container) def vectorAdded(self): self.vectorsCB.clear() self.vectorsCB.addItem("") vectors = self.vectorManager.getVectors() for vector in vectors: self.vectorsCB.addItem(vector.getName()) def vectorHandle(self, item): vectorname = self.vectorsCB.currentText() vector = self.vectorManager.getVectorByName(vectorname) if vector == None: return # Update node tableview nodeModel = self.nodes.model() nodeModel.removeRows(0, nodeModel.rowCount()) for nodeId in vector.getNodes(): node = self.nodeManager.getNode(nodeId) # "Name", "Timestamp", "Description", "Log Entry Refrence", "Log Creator", "Icon", "Source", "Visible" nodeModel.appendRow([ QStandardItem(node.getName()), QStandardItem(node.getTimeStamp()), QStandardItem(node.getDesc()), QStandardItem(node.getLogEntryRef()), QStandardItem(node.getLogCreator()), QStandardItem(node.getIcon()), QStandardItem(node.getSource()), QStandardItem(node.getVisible()) ]) self.nodes.setModel(nodeModel) # Todo add nodes to graph self.graph.updateGraph(vector) def addLogEntry(self, logentry): host = QStandardItem(logentry.getHost()) timestamp = QStandardItem(logentry.getTimestamp()) content = QStandardItem(logentry.getContent()) source = QStandardItem(logentry.getSource()) sourcetype = QStandardItem(logentry.getSourceType()) testWidget = QtWidgets.QWidget() combobox = CheckableComboBox(testWidget) combobox.itemcheck_callback.connect(self.handelLogEntryChange) vectors = self.vectorManager.getVectors() for vector in vectors: combobox.addItem(vector.name) self.logEntryModel.appendRow([ host, timestamp, content, source, sourcetype, ]) row = self.logEntryModel.rowCount() - 1 col = self.logEntryModel.columnCount() - 1 a = self.logEntryModel.index(row, col) self.logEntriesTbl.setIndexWidget(a, combobox) def handelLogEntryChange(self, item): if item.checkState() == Qt.Checked: vectorName = item.text() row = item.row() logEntryContent = self.logEntryModel.item(row, 2).text() logentry = self.logentryManager.getEntryByContent(logEntryContent) vector = self.vectorManager.getVectorByName(vectorName) self.vectorManager.associateLogEntry(logentry, vector) else: # TODO: Remove association print("uncheck")
class ApkList(DwarfListView): """ Displays installed APKs """ onApkSelected = pyqtSignal(list, name='onApkSelected') def __init__(self, parent=None, show_path=True): super(ApkList, self).__init__(parent=parent) self.adb = Adb() if not self.adb.available(): return self.retrieve_thread = PackageRetrieveThread(self.adb) if self.retrieve_thread is not None: self.retrieve_thread.onAddPackage.connect(self._on_addpackage) if show_path: self.apk_model = QStandardItemModel(0, 2) else: self.apk_model = QStandardItemModel(0, 1) self.apk_model.setHeaderData(0, Qt.Horizontal, 'Name') if show_path: self.apk_model.setHeaderData(1, Qt.Horizontal, 'Path') self.setModel(self.apk_model) self.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.doubleClicked.connect(self._on_apk_selected) if self.retrieve_thread is not None: if not self.retrieve_thread.isRunning(): self.retrieve_thread.start() # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def refresh(self): """ Refresh Packages """ if self.retrieve_thread is not None: if not self.retrieve_thread.isRunning(): self.clear() self.retrieve_thread.start() # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_addpackage(self, package): if package: name = QStandardItem() name.setText(package[0]) if self.apk_model.columnCount() == 2: path = QStandardItem() path.setText(package[1]) self.apk_model.appendRow([name, path]) else: self.apk_model.appendRow([name]) def _on_apk_selected(self, model_index): item = self.apk_model.itemFromIndex(model_index).row() if item != -1: package = self.apk_model.item(item, 0).text() if self.apk_model.columnCount() == 2: path = self.apk_model.item(item, 1).text() self.onApkSelected.emit([package, path]) else: self.onApkSelected.emit([package, None])
class QWTable(QTableView): def __init__(self, parent=None): QTableView.__init__(self, parent) self._name = self.__class__.__name__ icon.set_icons() self.is_connected_item_changed = False self.model = QStandardItemModel() self.set_selection_mode() self.fill_table_model() # defines self.model self.setModel(self.model) self.connect_item_selected(self.on_item_selected) self.clicked.connect(self.on_click) self.doubleClicked.connect(self.on_double_click) #self.connect_item_changed(self.on_item_changed) self.set_style() #def __del__(self): # QTableView.__del__(self) - it does not have __del__ def set_selection_mode(self, smode=QAbstractItemView.ExtendedSelection): logger.debug('Set selection mode: %s' % smode) self.setSelectionMode(smode) def connect_item_changed(self, recipient): self.model.itemChanged.connect(recipient) self.is_connected_item_changed = True def disconnect_item_changed(self, recipient): if self.is_connected_item_changed: self.model.itemChanged.disconnect(recipient) self.is_connected_item_changed = False def connect_item_selected(self, recipient): self.selectionModel().currentChanged[QModelIndex, QModelIndex].connect(recipient) def disconnect_item_selected(self, recipient): self.selectionModel().currentChanged[QModelIndex, QModelIndex].disconnect(recipient) def set_style(self): self.setStyleSheet("QTableView::item:hover{background-color:#00FFAA;}") def fill_table_model(self): self.clear_model() self.model.setHorizontalHeaderLabels( ['col0', 'col1', 'col2', 'col3', 'col4']) self.model.setVerticalHeaderLabels(['row0', 'row1', 'row2', 'row3']) for row in range(0, 4): for col in range(0, 6): item = QStandardItem("itemA %d %d" % (row, col)) item.setIcon(icon.icon_table) item.setCheckable(True) self.model.setItem(row, col, item) if col == 2: item.setIcon(icon.icon_folder_closed) if col == 3: item.setText('Some text') #self.model.appendRow(item) def clear_model(self): rows, cols = self.model.rowCount(), self.model.columnCount() self.model.removeRows(0, rows) self.model.removeColumns(0, cols) def selected_indexes(self): return self.selectedIndexes() def selected_items(self): indexes = self.selectedIndexes() return [self.model.itemFromIndex(i) for i in self.selectedIndexes()] def getFullNameFromItem(self, item): #item = self.model.itemFromIndex(ind) ind = self.model.indexFromItem(item) return self.getFullNameFromIndex(ind) def getFullNameFromIndex(self, ind): item = self.model.itemFromIndex(ind) if item is None: return None self._full_name = item.text() self._getFullName(ind) return self._full_name def _getFullName(self, ind): ind_par = self.model.parent(ind) if (ind_par.column() == -1): item = self.model.itemFromIndex(ind) self.full_name = '/' + self._full_name #logger.debug('Item full name:' + self._full_name) return self._full_name else: item_par = self.model.itemFromIndex(ind_par) self._full_name = item_par.text() + '/' + self._full_name self._getFullName(ind_par) def closeEvent(self, event): # if the x is clicked logger.debug('closeEvent') def on_click(self, index): item = self.model.itemFromIndex(index) msg = 'on_click: item in row:%02d text: %s' % (index.row(), item.text()) logger.debug(msg) def on_double_click(self, index): item = self.model.itemFromIndex(index) msg = 'on_double_click: item in row:%02d text: %s' % (index.row(), item.text()) logger.debug(msg) def on_item_selected(self, ind_sel, ind_desel): item = self.model.itemFromIndex(ind_sel) logger.debug('on_item_selected: "%s" is selected' % (item.text() if item is not None else None)) def on_item_changed(self, item): state = ['UNCHECKED', 'TRISTATE', 'CHECKED'][item.checkState()] logger.debug('abstract on_item_changed: "%s" at state %s' % (self.getFullNameFromItem(item), state)) def process_selected_items(self): selitems = self.selected_items() msg = '%d Selected items:' % len(selitems) for i in selitems: msg += '\n %s' % i.text() logger.info(msg) def key_usage(self): return 'Keys:'\ '\n ESC - exit'\ '\n S - show selected items'\ '\n' def keyPressEvent(self, e): logger.info('keyPressEvent, key=', e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_S: self.process_selected_items() else: logger.info(self.key_usage())
class Table(QWidget): def __init__(self): super(Table, self).__init__() self.setWindowTitle('TableView示例') self.resize(600, 600) self.model = QStandardItemModel(4, 4) ''' QStandardItemModel:'Q标准化模型'类提供了一个用于存储定制数据的通用模型。 'Q标准化模型'可以作为标准Qt数据类型的存储库。 它是模型/视图类之一,也是Qt模型/视图框架的一部分。 'Q标准化模型'提供了一种经典的基于项目的方法来处理模型。 'Q标准化模型'提供了Q标准化模型中的项目。 'Q标准化模型'实现了QAbstractItemModel接口,这意味着该模型可以用于提供支持该接口 的任何视图中的数据(如QListView、QTableView和QTreeView,以及自定义的类型)。 当您需要一个列表或树时,通常会创建一个空的'q标准化模型', 并使用appendRow()将项目添加到模型中,并使用item()来访问项目。 如果您的模型代表一个表,那么您通常将表的维度传递给'q标准化模型'构造函数, 并使用setItem()将条目放置到表中。您还可以使用setRowCount()和setColumnCount()来改变模型的维度。 要插入项,请使用insertRow()或insertColumn(),并删除项目,使用removeRow()或removeColumn()。 ''' tableTittleList = ['行数', '针数', '次数', '收针'] self.model.setHorizontalHeaderLabels(tableTittleList) dataList = [ '5', '7', 'dd', '90', '34', '', '1', '33', '45', '31', '34', '12', '89', '12', '1', '513' ] for [n, (i, j)] in enumerate([(i, j) for i in range(4) for j in range(4)]): item = QStandardItem(dataList[n]) self.model.setItem(i, j, item) self.tabletView = QTableView() self.tabletView.setModel(self.model) # 设置tableView的最后一列会跟随窗口水平伸缩 self.tabletView.horizontalHeader().setStretchLastSection(True) # 设置tableView的所有列都会跟谁窗口伸缩 self.tabletView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.stateLabel = QLabel('Size:(0x0),Mouse:(0,0)') self.setStateLabel() self.tabletView.clicked.connect(self.setStateLabel) # 添加一些按钮:删除行,插入行,清空行, delBtn = QPushButton('删除') insertRowBtn = QPushButton('插入') clrBtn = QPushButton('清除') # 添加2个lineEdit和一个btn 用来查询用户指定的位置的数据 rowLine = QLineEdit() colLine = QLineEdit() findBtn = QPushButton('查询') # 创建一个整数验证器,用来限制输入的数据为0~300的整数 intValidator = QIntValidator() intValidator.setRange(0, 300) # 添加信号槽 rowLine.setValidator(intValidator) colLine.setValidator(intValidator) rowLine.setPlaceholderText('输入查询的行数') colLine.setPlaceholderText('输入要查询的列数') findBtn.clicked.connect( lambda: self.findData(int(rowLine.text()), int(colLine.text()))) # 为按钮添加信号槽 delBtn.clicked.connect(self.removeRow) insertRowBtn.clicked.connect(self.insertRow) clrBtn.clicked.connect(self.clearSelectedItem) btnGridLayout = QGridLayout() btnGridLayout.addWidget(delBtn, 0, 0) btnGridLayout.addWidget(insertRowBtn, 0, 1) btnGridLayout.addWidget(clrBtn, 0, 2) btnGridLayout.addWidget(rowLine, 1, 0) btnGridLayout.addWidget(colLine, 1, 1) btnGridLayout.addWidget(findBtn, 1, 2) # 创建查询框和查询按钮 searchLine = QLineEdit() columnNumLine = QLineEdit() searchBtn = QPushButton('搜索') columnNumLine.setValidator(intValidator) # 为搜索按钮添加槽 searchBtn.clicked.connect( lambda: self.searchData(searchLine.text(), columnNumLine.text())) btnGridLayout.addWidget(searchLine, 2, 0) btnGridLayout.addWidget(columnNumLine, 2, 1) btnGridLayout.addWidget(searchBtn, 2, 2) layout = QVBoxLayout() layout.addWidget(self.tabletView) layout.addLayout(btnGridLayout) layout.addWidget(self.stateLabel) self.setLayout(layout) def setStateLabel(self, p_arg): print(p_arg) '''获取当前tableView的大小和鼠标点击的位置,以及选择和框选区大小''' selectedIndexes = self.tabletView.selectedIndexes() stateList = [ self.model.rowCount(), self.model.columnCount(), self.tabletView.currentIndex().row(), self.tabletView.currentIndex().column() ] self.stateLabel.setText( 'Size:(%dx%d),Mouse:(%d,%d)' % (stateList[0], stateList[1], stateList[2] + 1, stateList[3] + 1)) print(stateList) def insertRow(self): if self.model.rowCount() < 300: if self.model.rowCount() == 0: self.model.setItem(0, QStandardItem('')) else: self.model.insertRow(self.tabletView.currentIndex().row()) print('rowCount = ', self.model.rowCount()) else: QMessageBox.warning(self, '停止', '最大支持300行数据!') self.setStateLabel() def removeRow(self): indexes = self.tabletView.selectedIndexes() rowIndexList = [] for index in indexes: rowIndexList.append(index.row()) rowIndexSet = set(rowIndexList) print(len(indexes), len(rowIndexList), len(rowIndexSet)) self.model.removeRows(self.tabletView.currentIndex().row(), len(rowIndexSet)) self.setStateLabel() def findData(self, n_row, n_col): print('开始查询第{0}行,第{1}列的数据...'.format(n_row, n_col)) index = self.model.index(n_row - 1, n_col - 1) # 检查输入的数据是否超出表格范围,并检查表格内容是否为空 if (n_row - 1) > self.model.rowCount(): QMessageBox.critical(self, '错误', '输入的行数超过表格最大行数') elif (n_col - 1) > self.model.columnCount(): QMessageBox.critical(self, '错误', '输入的列数超过表格最大列数') else: data = self.model.data(index) if data: QMessageBox.information( self, '查询', '({0},{1})位置处的数值是{2}'.format(n_row, n_col, data)) else: QMessageBox.information( self, '查询', '({0},{1})位置处的数值是{2}'.format(n_row, n_col, '空的')) def searchData(self, data, column_num): # 用来在指定的column_num列找那个查找有没有data的item # 如果找到,返回其行数, 如果找不到,告知找不到 column_num = int(column_num) dataItem = QStandardItem(data) indexList = self.model.findItems(data, column=column_num - 1) list = [] for i in range(len(indexList)): list.append(indexList[i].row()) if len(list) == 0: QMessageBox.information( self, '找不到', '在第{0}列中找不到\n任何值是{1}元素'.format(column_num, data)) else: for i in range(len(list)): list[i] = list[i] + 1 dlgText = """在第{0}列中找到了值是'{1}'的元素共<font color = red>{2}</font>个,分别在第{3}列""".format( column_num, data, len(list), list) QMessageBox.information(self, '找到了', dlgText) def clearSelectedItem(self): indexes = self.tabletView.selectedIndexes() for index in indexes: self.model.setItem(index.row(), index.column(), QStandardItem(''))
class UserManager(QMainWindow): def __init__(self): super().__init__() self.initializeUI() def initializeUI(self): """Initialize the window and display its contents to the screen.""" self.setGeometry(100, 100, 500, 300) self.setWindowTitle('1.2 - User Manager') self.setupModelView() self.setupMenu() self.show() def setupModelView(self): """Set up widgets, and standard item model and table view.""" user_gb = QGroupBox("Users") new_user_button = QPushButton(QIcon("images/plus.png"), "Create New User") new_user_button.setMaximumWidth(160) new_user_button.clicked.connect(self.createNewUserDialog) self.list_of_table_headers = ["First Name", "Last Name", "Profile Name", "Location"] self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(self.list_of_table_headers) table_view = QTableView() table_view.setModel(self.model) table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # Set initial row and column values self.model.setRowCount(0) self.model.setColumnCount(4) v_box = QVBoxLayout() v_box.addWidget(new_user_button, Qt.AlignLeft) v_box.addWidget(table_view) user_gb.setLayout(v_box) self.setCentralWidget(user_gb) def setupMenu(self): """Set up menu bar.""" # Create actions for file menu save_act = QAction('Save', self) save_act.setShortcut('Ctrl+S') save_act.triggered.connect(self.saveTableToFile) exit_act = QAction('Exit', self) exit_act.setShortcut('Ctrl+Q') exit_act.triggered.connect(self.close) # Create menubar menu_bar = self.menuBar() # For MacOS users, places menu bar in main window menu_bar.setNativeMenuBar(False) # Create file menu and add actions file_menu = menu_bar.addMenu('File') file_menu.addAction(save_act) file_menu.addSeparator() file_menu.addAction(exit_act) def createNewUserDialog(self): """Set up the dialog box that allows the user to enter new user information.""" self.new_user_dialog = QDialog(self) self.new_user_dialog.setWindowTitle("Create New User") self.new_user_dialog.setModal(True) self.enter_first_line = QLineEdit() self.enter_last_line = QLineEdit() self.display_name_line = QLineEdit() locations_list = ["Select Location...", "Algeria", "Argentina", "Bolivia", "Canada", "Denmark", "Greece", "Iran", "Liberia", "New Zealand", "Qatar", "Uganda"] self.location_cb = QComboBox() self.location_cb.addItems(locations_list) create_button = QPushButton("Create User") create_button.clicked.connect(self.addNewUserToTable) cancel_button = QPushButton("Cancel") cancel_button.clicked.connect(self.new_user_dialog.reject) button_h_box = QHBoxLayout() button_h_box.addWidget(create_button) button_h_box.addSpacing(15) button_h_box.addWidget(cancel_button) # Add widgets to form layout dialog_form = QFormLayout() dialog_form.setFormAlignment(Qt.AlignLeft) dialog_form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) dialog_form.addRow("First name", self.enter_first_line) dialog_form.addRow("Last name", self.enter_last_line) dialog_form.addRow("Display Name", self.display_name_line) dialog_form.addRow("Location", self.location_cb) dialog_form.addItem(button_h_box) self.new_user_dialog.setLayout(dialog_form) # Restrict the size of the dialog in relation to the size of the # dialog_form's sizeHint() self.new_user_dialog.setMaximumSize(dialog_form.sizeHint()) self.new_user_dialog.show() def addNewUserToTable(self): """Add information from input widgets in dialog box to a list. If a widget is empty, append None to the list. Finally, add a new row to the table.""" new_user_info_list = [] if self.enter_first_line.text() != "": new_user_info_list.append(QStandardItem(self.enter_first_line.text())) else: new_user_info_list.append(None) if self.enter_last_line.text() != "": new_user_info_list.append(QStandardItem(self.enter_last_line.text())) else: new_user_info_list.append(None) if self.display_name_line.text() != "": new_user_info_list.append(QStandardItem(self.display_name_line.text())) else: new_user_info_list.append(None) if self.location_cb.currentIndex() != 0: new_user_info_list.append(QStandardItem(self.location_cb.currentText())) else: new_user_info_list.append(None) # Add a new row to the model self.model.appendRow(new_user_info_list) self.new_user_dialog.close() def saveTableToFile(self): """Save user information to a csv file.""" file_name, _ = QFileDialog.getSaveFileName(self, 'Save Table', "", "CSV Files (*.csv)") # If file_name exists and there is at least one row in the table, then save if file_name and self.model.rowCount() != 0: with open(file_name, "w") as csv_wf: user_writer = csv.writer(csv_wf, delimiter=',') user_writer.writerow(self.list_of_table_headers) # Iterate through each row and column in the table for row in # range(self.model.rowCount()): for row in range(self.model.rowCount()): current_row_list = [] for column in range(self.model.columnCount()): item = str(self.model.data(self.model.index(row, column))) current_row_list.append(item) user_writer.writerow(current_row_list)
class HistoryManagerWidget(QWidget): def __init__(self): super().__init__() self.listHistory = [] self.nam = QtNetwork.QNetworkAccessManager() self.setting = QSettings() self.searchLineEdit = QLineEdit() self.tableView = QTableView() self.columnComboBox = QComboBox() self.searchLabel = QLabel() self.searchLabel.setText("Filter") self.model = QStandardItemModel(self) searchHbox = QHBoxLayout() searchHbox.addWidget(self.searchLabel) searchHbox.addWidget(self.searchLineEdit) searchHbox.addWidget(self.columnComboBox) self.header = "Order ID;Order Status;Card ID;Menu ID;Menu Name;Price;Qty;" \ "Item Status;Table Number;Order Time;Modified Time".split(";") self.model.setHorizontalHeaderLabels(self.header) self.tableView.horizontalHeader().setStretchLastSection(True) hboxLayout = QHBoxLayout() self.backButton = QPushButton() self.backButton.setText("Back") self.refreshButton = QPushButton() self.refreshButton.setText("Refresh") self.refreshButton.clicked.connect(self.refresh) self.saveCSVButton = QPushButton() self.saveCSVButton.setText("Save as CSV") self.saveCSVButton.clicked.connect(self.saveCSV) hboxLayout.addWidget(self.backButton) hboxLayout.addWidget(self.refreshButton) hboxLayout.addWidget(self.saveCSVButton) widgetTitleLabel = QLabel() widgetTitleLabel.setAlignment(Qt.AlignCenter) widgetTitleLabel.setText("History Manager") mainLayout = QVBoxLayout() mainLayout.addWidget(widgetTitleLabel) mainLayout.addLayout(searchHbox) mainLayout.addWidget(self.tableView) mainLayout.addLayout(hboxLayout) self.proxy = QSortFilterProxyModel(self) self.proxy.setSourceModel(self.model) self.tableView.setModel(self.proxy) self.columnComboBox.addItems(self.header) self.searchLineEdit.textChanged.connect(self.on_lineEdit_textChanged) self.columnComboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged) self.horizontalHeader = self.tableView.horizontalHeader() self.setLayout(mainLayout) def saveCSV(self): data = "" rows = self.model.rowCount() columns = self.model.columnCount() if rows>0: for title in self.header: data += title data += "," data += "\n" for i in range(rows): for j in range(columns): index = self.model.index(i,j) # print(str(self.model.data(index))) data += str(self.model.data(index)) data += "," data += "\n" name, _ = QFileDialog.getSaveFileName(self, 'Save File', "History SELFO.csv", "csv(*.csv)") if name: file = open(name, 'w') file.write(data) file.close() else: QMessageBox.critical(self, "Error", "No Data") def clear(self): self.listHistory.clear() self.model.clear() self.model.setHorizontalHeaderLabels(self.header) def refresh(self): self.clear() self.doRequestOrderDetail() def populateList(self): for rowName in range(len(self.listHistory)): self.model.invisibleRootItem().appendRow( [QStandardItem("{}".format(self.listHistory[rowName][column])) for column in range(len(self.header)) ] ) self.tableView.resizeColumnsToContents() def closeHistoryManager(self): self.mainWindow.stackedWidget.removeWidget(self) def doRequestOrderDetail(self): url = self.setting.value("baseURL", "") url += "/orderdetail/?sellerID=" + str(self.setting.value("sellerID", "")) \ # + "&itemStatus=" + "placed" req = QtNetwork.QNetworkRequest(QUrl(url)) reply = self.nam.get(req) reply.finished.connect(self.handleResponseOrderDetail) def handleResponseOrderDetail(self): reply = self.sender() er = reply.error() if er == QtNetwork.QNetworkReply.NoError: bytes_string = reply.readAll() data = json.loads(str(bytes_string, 'utf-8')) # print(data) for history in data: # id = history['id'] orderID = history['orderID'] orderStatus = history['orderStatus'] cardID = history['cardID'] # sellerID = history['sellerID'] menuID = history['menuID'] menuName = history['menuName'] itemStatus = history['itemStatus'] price = formatRupiah(history['price']) qty = history['qty'] tableNumber = history['tableNumber'] rawOrderTime = history['orderTime'] orderTime = datetime.datetime.strptime( rawOrderTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S") rawModifiedTime = history['modifiedTime'] if rawModifiedTime is not None: modifiedTime = datetime.datetime.strptime( rawModifiedTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S") else: modifiedTime = "null" historyItem = [orderID, orderStatus, cardID, menuID, menuName, price, qty, itemStatus, tableNumber, orderTime, modifiedTime] self.listHistory.append(historyItem) self.populateList() else: errorMessage = "Error occured: " + str(er) + "\n" + str(reply.errorString()) QMessageBox.critical(self, "Error Order Detail", errorMessage) reply.deleteLater() def on_view_horizontalHeader_sectionClicked(self, logicalIndex): self.logicalIndex = logicalIndex self.menuValues = QMenu(self) self.signalMapper = QSignalMapper(self) self.columnComboBox.blockSignals(True) self.columnComboBox.setCurrentIndex(self.logicalIndex) self.columnComboBox.blockSignals(True) valuesUnique = [ self.model.item(row, self.logicalIndex).text() for row in range(self.model.rowCount()) ] actionAll = QAction("All", self) actionAll.triggered.connect(self.on_actionAll_triggered) self.menuValues.addAction(actionAll) self.menuValues.addSeparator() for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))): action = QAction(actionName, self) self.signalMapper.setMapping(action, actionNumber) action.triggered.connect(self.signalMapper.map) self.menuValues.addAction(action) self.signalMapper.mapped.connect(self.on_signalMapper_mapped) headerPos = self.tableView.mapToGlobal(self.horizontalHeader.pos()) posY = headerPos.y() + self.horizontalHeader.height() posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex) self.menuValues.exec_(QPoint(posX, posY)) def on_actionAll_triggered(self): filterColumn = self.logicalIndex filterString = QRegExp( "", Qt.CaseInsensitive, QRegExp.RegExp ) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) def on_signalMapper_mapped(self, i): stringAction = self.signalMapper.mapping(i).text() filterColumn = self.logicalIndex filterString = QRegExp( stringAction, Qt.CaseSensitive, QRegExp.FixedString ) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) def on_lineEdit_textChanged(self, text): search = QRegExp( text, Qt.CaseInsensitive, QRegExp.RegExp ) self.proxy.setFilterRegExp(search) def on_comboBox_currentIndexChanged(self, index): self.proxy.setFilterKeyColumn(index)