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 AddressList(MyTreeView): class Columns(IntEnum): TYPE = 0 ADDRESS = 1 LABEL = 2 COIN_BALANCE = 3 FIAT_BALANCE = 4 NUM_TXS = 5 filter_columns = [ Columns.TYPE, Columns.ADDRESS, Columns.LABEL, Columns.COIN_BALANCE ] ROLE_SORT_ORDER = Qt.UserRole + 1000 def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.LABEL) self.wallet = self.parent.wallet self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) for addr_type in AddressTypeFilter.__members__.values( ): # type: AddressTypeFilter self.change_button.addItem(addr_type.ui_text()) self.used_button = QComboBox(self) self.used_button.currentIndexChanged.connect(self.toggle_used) for addr_usage_state in AddressUsageStateFilter.__members__.values( ): # type: AddressUsageStateFilter self.used_button.addItem(addr_usage_state.ui_text()) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.update() self.sortByColumn(self.Columns.TYPE, Qt.AscendingOrder) def get_toolbar_buttons(self): return QLabel(_("Filter:")), self.change_button, self.used_button def on_hide_toolbar(self): self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.update() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_addresses', state) def refresh_headers(self): fx = self.parent.fx if fx and fx.get_fiat_address_config(): ccy = fx.get_currency() else: ccy = _('Fiat') headers = { self.Columns.TYPE: _('Type'), self.Columns.ADDRESS: _('Address'), self.Columns.LABEL: _('Label'), self.Columns.COIN_BALANCE: _('Balance'), self.Columns.FIAT_BALANCE: ccy + ' ' + _('Balance'), self.Columns.NUM_TXS: _('Tx'), } self.update_headers(headers) def toggle_change(self, state: int): if state == self.show_change: return self.show_change = AddressTypeFilter(state) self.update() def toggle_used(self, state: int): if state == self.show_used: return self.show_used = AddressUsageStateFilter(state) self.update() @profiler def update(self): if self.maybe_defer_update(): return current_address = self.current_item_user_role(col=self.Columns.LABEL) if self.show_change == AddressTypeFilter.RECEIVING: addr_list = self.wallet.get_receiving_addresses() elif self.show_change == AddressTypeFilter.CHANGE: addr_list = self.wallet.get_change_addresses() else: addr_list = self.wallet.get_addresses() self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.refresh_headers() fx = self.parent.fx set_address = None addresses_beyond_gap_limit = self.wallet.get_all_known_addresses_beyond_gap_limit( ) for address in addr_list: num = self.wallet.get_address_history_len(address) label = self.wallet.labels.get(address, '') c, u, x = self.wallet.get_addr_balance(address) balance = c + u + x is_used_and_empty = self.wallet.is_used(address) and balance == 0 if self.show_used == AddressUsageStateFilter.UNUSED and ( balance or is_used_and_empty): continue if self.show_used == AddressUsageStateFilter.FUNDED and balance == 0: continue if self.show_used == AddressUsageStateFilter.USED_AND_EMPTY and not is_used_and_empty: continue balance_text = self.parent.format_amount(balance, whitespaces=True) # create item if fx and fx.get_fiat_address_config(): rate = fx.exchange_rate() fiat_balance = fx.value_str(balance, rate) else: fiat_balance = '' labels = [ '', address, label, balance_text, fiat_balance, "%d" % num ] address_item = [QStandardItem(e) for e in labels] # align text and set fonts for i, item in enumerate(address_item): item.setTextAlignment(Qt.AlignVCenter) if i not in (self.Columns.TYPE, self.Columns.LABEL): item.setFont(QFont(MONOSPACE_FONT)) self.set_editability(address_item) address_item[self.Columns.FIAT_BALANCE].setTextAlignment( Qt.AlignRight | Qt.AlignVCenter) # setup column 0 if self.wallet.is_change(address): address_item[self.Columns.TYPE].setText(_('change')) address_item[self.Columns.TYPE].setBackground( ColorScheme.YELLOW.as_color(True)) else: address_item[self.Columns.TYPE].setText(_('receiving')) address_item[self.Columns.TYPE].setBackground( ColorScheme.GREEN.as_color(True)) address_item[self.Columns.LABEL].setData(address, Qt.UserRole) address_path = self.wallet.get_address_index(address) address_item[self.Columns.TYPE].setData(address_path, self.ROLE_SORT_ORDER) address_path_str = self.wallet.get_address_path_str(address) if address_path_str is not None: address_item[self.Columns.TYPE].setToolTip(address_path_str) address_item[self.Columns.FIAT_BALANCE].setData( balance, self.ROLE_SORT_ORDER) # setup column 1 if self.wallet.is_frozen_address(address): address_item[self.Columns.ADDRESS].setBackground( ColorScheme.BLUE.as_color(True)) if address in addresses_beyond_gap_limit: address_item[self.Columns.ADDRESS].setBackground( ColorScheme.RED.as_color(True)) # add item count = self.std_model.rowCount() self.std_model.insertRow(count, address_item) address_idx = self.std_model.index(count, self.Columns.LABEL) if address == current_address: set_address = QPersistentModelIndex(address_idx) self.set_current_idx(set_address) # show/hide columns if fx and fx.get_fiat_address_config(): self.showColumn(self.Columns.FIAT_BALANCE) else: self.hideColumn(self.Columns.FIAT_BALANCE) self.filter() self.proxy.setDynamicSortFilter(True) def create_menu(self, position): from electrum.wallet import Multisig_Wallet is_multisig = isinstance(self.wallet, Multisig_Wallet) can_delete = self.wallet.can_delete_address() selected = self.selected_in_column(self.Columns.ADDRESS) if not selected: return multi_select = len(selected) > 1 addrs = [self.item_from_index(item).text() for item in selected] menu = QMenu() if not multi_select: idx = self.indexAt(position) if not idx.isValid(): return item = self.item_from_index(idx) if not item: return addr = addrs[0] addr_column_title = self.std_model.horizontalHeaderItem( self.Columns.LABEL).text() addr_idx = idx.sibling(idx.row(), self.Columns.LABEL) self.add_copy_menu(menu, idx) menu.addAction(_('Details'), lambda: self.parent.show_address(addr)) persistent = QPersistentModelIndex(addr_idx) menu.addAction(_("Edit {}").format(addr_column_title), lambda p=persistent: self.edit(QModelIndex(p))) #menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr)) if self.wallet.can_export(): menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr)) if not is_multisig and not self.wallet.is_watching_only(): menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr)) menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr)) if can_delete: menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr)) addr_URL = block_explorer_URL(self.config, 'addr', addr) if addr_URL: menu.addAction(_("View on block explorer"), lambda: webopen(addr_URL)) if not self.wallet.is_frozen_address(addr): menu.addAction( _("Freeze"), lambda: self.parent. set_frozen_state_of_addresses([addr], True)) else: menu.addAction( _("Unfreeze"), lambda: self.parent. set_frozen_state_of_addresses([addr], False)) coins = self.wallet.get_spendable_coins(addrs) if coins: menu.addAction(_("Spend from"), lambda: self.parent.utxo_list.set_spend_list(coins)) run_hook('receive_menu', menu, addrs, self.wallet) menu.exec_(self.viewport().mapToGlobal(position)) def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: if is_address(text): try: self.wallet.check_address_for_corruption(text) except InternalAddressCorruption as e: self.parent.show_error(str(e)) raise super().place_text_on_clipboard(text, title=title)
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 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 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 PopupHaloDescriptorWidget(PopupWidget): def __init__(self, parent): super().__init__(parent, 0.25, 0.5) self.setWindowTitle("Halo descriptor") self.__widget_label_title = QLabel("Set the halos for each dimension.", parent=self) self.__halo_model = QStandardItemModel(0, 2) self.__halo_model.setHorizontalHeaderLabels(["Minus", "Plus"]) self.__halo_model.horizontalHeaderItem(0).setToolTip( "Negative halo extent") self.__halo_model.horizontalHeaderItem(1).setToolTip( "Positive halo extent") self.__widget_table = QTableView(self) self.__widget_table.setModel(self.__halo_model) self.__widget_table.setStyleSheet(''' QTableWidget::item:selected:active { background: transparent; border-width: 0px; } ''') self.__widget_table.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # Assume 3 dimension by default for i in range(3): self.add_row() self.__widget_button_add = QPushButton(self) self.__widget_button_add.setIcon(Icon("edit_add.png")) self.__widget_button_add.clicked.connect(self.add_row) self.__widget_button_add.setToolTip("Add a dimension") self.__widget_button_remove = QPushButton(self) self.__widget_button_remove.setIcon(Icon("edit_remove.png")) self.__widget_button_remove.clicked.connect(self.remove_row) self.__widget_button_remove.setToolTip("Remove last dimension") self.__widget_button_ok = QPushButton("Done", parent=self) self.__widget_button_ok.clicked.connect(self.done) hbox_bottom = QHBoxLayout() hbox_bottom.addWidget(self.__widget_button_add) hbox_bottom.addWidget(self.__widget_button_remove) hbox_bottom.addStretch(1) hbox_bottom.addWidget(self.__widget_button_ok) vbox = QVBoxLayout() vbox.addWidget(self.__widget_label_title) vbox.addWidget(self.__widget_table) vbox.addLayout(hbox_bottom) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.setLayout(vbox) def add_row(self): Logger.info("Adding row") minus = QStandardItem() minus.setTextAlignment(Qt.AlignCenter) minus.setText("0") plus = QStandardItem() plus.setTextAlignment(Qt.AlignCenter) plus.setText("0") self.__halo_model.appendRow([minus, plus]) def remove_row(self): Logger.info("Removing row") self.__halo_model.removeRow(self.__halo_model.rowCount() - 1) def done(self): self.close() def get_halos(self): halos = [] try: for i in range(self.__halo_model.rowCount()): minus = int(self.__halo_model.item(i, 0).text()) plus = int(self.__halo_model.item(i, 1).text()) if minus < 0 or plus < 0: raise RuntimeError( "Invalid halo boundary (%i, %i) in dimension %s: halo boundaries must be positive numbers." % (minus, plus, i)) halos += [[minus, None if plus is 0 else plus]] except ValueError as e: raise RuntimeError(str(e)) return Halos(halos)
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 LogDialogClass(QtWidgets.QDialog, Ui_Dialog): def __init__(self): super(LogDialogClass, self).__init__() self.setupUi(self) self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(['日志时间', '日志信息']) # 实例化表格视图,设置模型为自定义的模型 self.tableView = QTableView() self.tableView.setModel(self.model) self.tableView.horizontalHeader().setStretchLastSection(True) # self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.tableView.setColumnWidth(0, 130) self.tableView.verticalHeader().hide() self.tableView.horizontalHeader().setDefaultAlignment( QtCore.Qt.AlignLeft) # 设置布局 horizontalLayout layout = QVBoxLayout(self, spacing=0) layout.setContentsMargins(0, 0, 0, 30) layout.addWidget(self.tableView) """ layout.addWidget(self.pushButton) layout.addWidget(self.pushButton_2) layout.addWidget(self.label) """ self.setLayout(layout) threadSocket = threading.Thread(target=self.Initsocket, args=()) threadSocket.start() self.pushButton_clrear.clicked.connect(self.ClearAllMessage) self.pushButton_export.clicked.connect(self.LogExport) def Initsocket(self): serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serverSocket.bind((logsocketAddress, logsocketPort)) serverSocket.listen(5) # 监听 print('starting....') while True: conn, addr = serverSocket.accept() # 接收客户端信号 print(conn) print('client addr', addr) print('ready to read msg') client_msg = conn.recv(1024) # 收消息 print('client msg: %s' % client_msg) decodejson = json.loads(client_msg) print(type(decodejson)) print(decodejson) strType = decodejson['type'] strMsg = decodejson['msg'] if (strType == 'OutputMessage'): self.SendMessage(strMsg) elif (strType == 'ClearAllMessage'): self.ClearAllMessage() elif (strType == 'CloseWindow'): self.CloseWindow() break conn.close() serverSocket.close() print('The end....') def SendMessage(self, msg): # 第iRow+1行 iRow = self.model.rowCount() item10 = QStandardItem( time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())) self.model.setItem(iRow, 0, item10) item11 = QStandardItem(msg) self.model.setItem(iRow, 1, item11) def ClearAllMessage(self): irowCount = self.model.rowCount() print(irowCount) while (irowCount > 0): self.model.removeRow(irowCount - 1) irowCount = irowCount - 1 def CloseWindow(self): self.pushButton_close.click() def LogExport(self): fileName_choose, filetype = QFileDialog.getSaveFileName( self, "文件保存", "C:/", # 起始路径 "All Files (*);;Text Files (*.txt)") if fileName_choose == "": return print("\n你选择要保存的文件为:") print(fileName_choose) print("文件筛选器类型: ", filetype) irowCount = self.model.rowCount() icolumn = self.model.columnCount() print(irowCount) print(icolumn) # 获取表头文字 strLog = '' for icol1 in range(icolumn): aItem = self.model.horizontalHeaderItem(icol1) # 获取表头的项数据 strLog = strLog + aItem.text() + "\t\t\t" # //以TAB见隔开 print(strLog) strLog = strLog + '\n' File.Write(fileName_choose, strLog) for irow in range(irowCount): str = "" for icol in range(icolumn): item = self.model.item(irow, icol) print('行:', irow) print('列:', icol) print(item.text()) str = str + item.text() + ("\t\t") File.Append(fileName_choose, str + "\r\n")
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 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.__ColCount = 6 #列数=6 self.itemModel = QStandardItemModel(5, self.__ColCount, self) # 数据模型,10行6列 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 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) #先禁用tableView self.__buildStatusBar() ## ==============自定义功能函数============ 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 __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.__ColCount - 1 #最后一列的列号 for i in range(rowCnt - 1): lineText = allLines[i + 1].strip() #一行的文字,\t分隔 strList = lineText.split("\t") #分割为字符串列表 for j in range(self.__ColCount - 1): #不含最后一列 item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) #设置模型的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=QDir.currentPath() #获取当前路径 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 aFile.close() for strLine in allLines: self.ui.plainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.tableView.setEnabled(True) #tableView可用 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) @pyqtSlot() ##保存文件 def on_actSave_triggered(self): ## curPath=QDir.currentPath() #获取当前路径 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 = [] # QStandardItem 对象列表 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_actInsert_triggered(self): itemlist = [] # QStandardItem 对象列表 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_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.__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) ## =============自定义槽函数=============================== def do_curChanged(self, current, previous): if (current != None): #当前模型索引有效 text = "当前单元格:%d行,%d列" % (current.row(), current.column()) self.LabCellPos.setText(text) 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 Q0Measurement(Display): def ui_filename(self): return "q0.ui" def __init__(self, parent=None, args=None): super(Q0Measurement, self).__init__(parent=parent, args=args) self.pathHere = path.dirname(sys.modules[self.__module__].__file__) # Set up calibration data window self.calibrationLiquidLevelCanvas = MplCanvas() self.calibrationLineFitCanvas = MplCanvas() self.calibrationResultsWindow = None self.setupCalibrationDataWindow() # Set up RF data window self.rfLiquidLevelCanvas = MplCanvas() self.rfLineFitCanvas = MplCanvas() self.rfResultsWindow = None self.setupRfDataWindow() self.settingsWindow = Display(ui_filename=self.getPath("settings.ui")) self.setupSettingsWindow() heaterLineEdits = self.settingsWindow.ui.heaterSettingRepeater.findChildren( QLineEdit) self.initialCalibrationHeatLoadLineEdit: QLineEdit = findWidget( "initialCalibrationHeatLoad", heaterLineEdits) self.initialCalibrationHeatLoadLineEdit.setValidator( QIntValidator(8, 48)) # TODO implement custom liveplot (archiver + append callback) self.liveSignalsWindow = Display( ui_filename=self.getPath("signals.ui")) self.ui.liveSignalsButton.clicked.connect( partial(self.showDisplay, self.liveSignalsWindow)) self.plots = TimePlotObjects( liquidLevelPlot=self.liveSignalsWindow.ui.liquidLevelPlot, pressurePlot=self.liveSignalsWindow.ui.pressurePlot, heaterPlot=self.liveSignalsWindow.ui.heaterPlot, valvePlot=self.liveSignalsWindow.ui.valvePlot, rfPlot=self.liveSignalsWindow.ui.rfPlot, radiationPlot=self.liveSignalsWindow.ui.radiationPlot, temperaturePlot=self.liveSignalsWindow.ui.temperaturePlot) self.calibrationOptionModel = QStandardItemModel(self) self.calibrationOptionsWindow = Display( ui_filename=self.getPath("options.ui")) self.setupCalibrationOptionsWindow() self.calibrationSelection = {} self.calibrationStatus = None self.setupLabels() self.calibrationGroupBox = None self.rfGroupBox = None self.setupFrames() self.selectWindow = Display(ui_filename=self.getPath("cmSelection.ui")) self.ui.cmSelectButton.clicked.connect( partial(self.showDisplay, self.selectWindow)) self.pathToAmplitudeWindow = self.getPath("amplitude.ui") # maps cryomodule names to their checkboxes self.cryomoduleRadioButtons = {} # type: Dict[str, QRadioButton] # maps cryomodule names to their buttons self.cryomoduleButtons = {} # type: Dict[str, QPushButton] # maps checkboxes to their buttons self.cryomoduleRadioButtonMap = { } # type: Dict[QRadioButton, QPushButton] # maps cryomodule names to the cavity display self.buttonDisplays = {} # type: Dict[str, Display] # maps cyomodule names to desired cavity amplitudes self.desiredCavAmpLineEdits = {} # type: Dict[str, List[QLineEdit]] self.maxAmplitudeLabels: Dict[str, PyDMLabel] = {} # maps cryomodule names to cavity groupboxes self.cavityGroupBoxes = {} # type: Dict[str, List[QGroupBox]] # maps cryomodule names to select all cavities checkbox self.selectAllCavitiesCheckboxes = {} # type: Dict[str, QCheckBox] self.selectedDisplayCM: Optional[str] = None self.selectedCM: Optional[str] = None self.sectors = [[], [], [], []] # type: List[List[str]] self.radioButtonSectorMap: Dict[QRadioButton, int] = {} self.buttonGroup = QButtonGroup(self) self.populateRadioButtons() for sector in self.sectors: self.calibrationOptionsWindow.ui.cryomoduleComboBox.addItems( sector) self.calibrationOptionsWindow.ui.cavityComboBox.addItem("ALL") for i in range(1, 9): self.calibrationOptionsWindow.ui.cavityComboBox.addItem(str(i)) self.calibrationSanityCheck = QMessageBox() self.setupSanityCheck(self.calibrationSanityCheck, self.calibrationStatus) self.setupButtons() self.calibration = None self.valveParams = {} self.selectedCryomoduleObject: Q0Cryomodule = None def setupLiveSignals(self): self.plots.clearCurves() self.plots.valvePlot.addYChannel(self.selectedCryomoduleObject.valvePV) def setupCalibrationOptionsWindow(self): self.calibrationOptionsWindow.ui.cryomoduleComboBox.currentTextChanged.connect( self.populateCryomoduleCalibrationOptions) self.calibrationOptionsWindow.ui.cavityComboBox.currentTextChanged.connect( self.populateCavityCalibrationOptions) self.calibrationOptionsWindow.ui.optionView.setModel( self.calibrationOptionModel) self.calibrationOptionsWindow.ui.optionView.selectionModel( ).selectionChanged.connect(self.selectCalibration) self.calibrationOptionsWindow.ui.loadButton.clicked.connect( self.loadCalibration) def setupRfDataWindow(self): self.rfResultsWindow = Display(ui_filename=self.getPath("results.ui"), macros={"label": "dLL/dt Slope"}) self.rfResultsWindow.ui.dataLayout.addWidget(self.rfLiquidLevelCanvas) self.rfResultsWindow.ui.lineFitLayout.addWidget(self.rfLineFitCanvas) def setupCalibrationDataWindow(self): self.calibrationResultsWindow = Display( ui_filename=self.getPath("results.ui"), macros={"label": "dLL/dt Slope"}) self.calibrationResultsWindow.ui.dataLayout.addWidget( self.calibrationLiquidLevelCanvas) self.calibrationResultsWindow.ui.lineFitLayout.addWidget( self.calibrationLineFitCanvas) def getPath(self, fileName): return path.join(self.pathHere, fileName) # This is some convoluted bullshit def selectCalibration(self): self.calibrationSelection[ "CM"] = self.calibrationOptionsWindow.ui.cryomoduleComboBox.currentText( ) calibrationTableView = self.calibrationOptionsWindow.ui.optionView # type: QTableView row = calibrationTableView.selectionModel().selectedRows().pop().row() for column in range(self.calibrationOptionModel.columnCount()): data = self.calibrationOptionModel.index(row, column).data() header = self.calibrationOptionModel.horizontalHeaderItem( column).text() self.calibrationSelection[header] = data # self.calibrationStatus.setStyleSheet("color: blue;") self.calibrationStatus.setText( "CM {CM} calibration from {START} selected but not loaded".format( START=self.calibrationSelection["Start"], CM=self.calibrationSelection["CM"])) self.calibrationOptionsWindow.ui.loadButton.setEnabled(True) def loadCalibration(self): linacName = CM_LINAC_MAP[self.calibrationSelection["CM"]] cryomodule = Q0_LINAC_OBJECTS[linacName] self.calibration: CalibDataSession = cryomodule.addCalibDataSessionFromGUI( self.calibrationSelection) redrawAxis(self.calibrationLiquidLevelCanvas, title="Liquid Level vs. Time", xlabel="Unix Time (s)", ylabel="Downstream Liquid Level (%)") redrawAxis(self.calibrationLineFitCanvas, title="Liquid Level Rate of Change vs. Heat Load", xlabel="Heat Load (W)", ylabel="dLL/dt (%/s)") for run in self.calibration.dataRuns: self.calibrationLiquidLevelCanvas.axes.plot(run.timeStamps, run.data, label=run.label) self.calibrationLiquidLevelCanvas.axes.plot( run.timeStamps, [run.slope * x + run.intercept for x in run.timeStamps]) self.calibrationLineFitCanvas.axes.plot( self.calibration.runElecHeatLoadsAdjusted, self.calibration.adjustedRunSlopes, marker="o", linestyle="None", label="Heater Calibration Data") slopeStr = "{slope} %/(s*W)".format(slope=self.calibration.calibSlope) self.calibrationResultsWindow.ui.slope.setText(slopeStr) self.calibrationLineFitCanvas.axes.plot( self.calibration.runElecHeatLoadsAdjusted, [ self.calibration.calibSlope * x for x in self.calibration.runElecHeatLoadsAdjusted ], label=slopeStr) self.calibrationLineFitCanvas.axes.legend(loc='best') self.calibrationLiquidLevelCanvas.axes.legend(loc='best') self.calibrationStatus.setStyleSheet("color: green;") self.calibrationStatus.setText( "CM {CM} calibration from {START} loaded".format( START=self.calibrationSelection["Start"], CM=self.calibrationSelection["CM"])) self.rfGroupBox.setEnabled(True) def setupCalibrationTable(self): self.calibrationOptionModel.clear() parent = path.abspath(path.join(self.pathHere, pardir)) cmName = self.calibrationOptionsWindow.ui.cryomoduleComboBox.currentText( ) calibrationFolder = path.join(path.join(parent, "calibrations"), "cm{NAME}".format(NAME=cmName)) return cmName, calibrationFolder def populateCryomoduleCalibrationOptions(self): cmName, calFolderPath = self.setupCalibrationTable() calibrationFile = path.join( calFolderPath, FULL_CALIBRATION_FILENAME_TEMPLATE.format(CM=cmName)) if not path.isfile(calibrationFile): return self.populateCalibrationTable(calibrationFile) def populateCavityCalibrationOptions(self): cavity = self.calibrationOptionsWindow.ui.cavityComboBox.currentText() if cavity == "ALL": self.populateCryomoduleCalibrationOptions() return cmName, calFolderPath = self.setupCalibrationTable() calibrationFile = path.join( calFolderPath, CAVITY_CALIBRATION_FILENAME_TEMPLATE.format(CM=cmName, CAV=cavity)) if not path.isfile(calibrationFile): print(calibrationFile) return self.populateCalibrationTable(calibrationFile) def populateCalibrationTable(self, calibrationFilePath): with open(calibrationFilePath) as calibrationFile: data: List[dict] = json.load(calibrationFile) header = list(data[0].keys()) self.calibrationOptionModel.setHorizontalHeaderLabels(header) for entry in data: items = [] for column in header: items.append(QStandardItem(entry[column])) self.calibrationOptionModel.appendRow(items) self.calibrationOptionsWindow.ui.optionView.resizeColumnsToContents() def setupFrames(self): groupBoxes = {} # type: Dict[str, QGroupBox] for groupBox in self.ui.dialogues.findChildren(QGroupBox): if groupBox.accessibleName(): groupBoxes[groupBox.accessibleName()] = groupBox self.calibrationGroupBox = groupBoxes["calibrationGroupBox"] self.rfGroupBox = groupBoxes["rfGroupBox"] # For some reason, I need to disable these here vs in designer or the # conditional enabling doesn't work self.calibrationGroupBox.setEnabled(False) self.rfGroupBox.setEnabled(False) def setupLabels(self): name2label = {} # type: Dict[str, QLabel] for label in self.ui.dialogues.findChildren(QLabel): name2label[label.accessibleName()] = label self.calibrationStatus = name2label["calibrationLabel"] def setupButtons(self): name2button = {} # type: Dict[str, QPushButton] # Get all the buttons from my template repeater and figure out which # one's which with the accessible names (set in dialogues.json) for button in self.ui.dialogues.findChildren(QPushButton): name2button[button.accessibleName()] = button name2button["newCalibrationButton"].clicked.connect( self.calibrationSanityCheck.show) name2button["loadCalibrationButton"].clicked.connect( partial(self.showDisplay, self.calibrationOptionsWindow)) name2button["calibrationDataButton"].clicked.connect( partial(self.showDisplay, self.calibrationResultsWindow)) def setupSettingsWindow(self): self.settingsWindow.ui.valvePosSearchStart.setDateTime(datetime.now()) self.settingsWindow.ui.valvePosSearchEnd.setDateTime(datetime.now() - timedelta( hours=24)) self.ui.settingsButton.clicked.connect( partial(self.showDisplay, self.settingsWindow)) def populateRadioButtons(self): displays: List[PyDMEmbeddedDisplay] = [ self.selectWindow.ui.cryomodulesL0B, self.selectWindow.ui.cryomodulesL1B, self.selectWindow.ui.cryomodulesL2B, self.selectWindow.ui.cryomodulesL3B ] for sector, display in enumerate(displays): display.loadWhenShown = False groupbox: QVBoxLayout = display.findChildren(QVBoxLayout).pop() repeater: PyDMTemplateRepeater = groupbox.itemAt(0).widget() pairs: List[QHBoxLayout] = repeater.findChildren(QHBoxLayout) for pair in pairs: button: QPushButton = pair.itemAt(1).widget() name = button.text().split()[1] self.cryomoduleButtons[name] = button button.clicked.connect( partial(self.openAmplitudeWindow, name, sector)) radioButton: QRadioButton = pair.itemAt(0).widget() self.cryomoduleRadioButtons[name] = radioButton self.cryomoduleRadioButtonMap[radioButton] = button self.buttonGroup.addButton(radioButton) radioButton.toggled.connect( partial(self.cryomoduleRadioButtonToggled, name)) self.sectors[sector].append(name) self.radioButtonSectorMap[radioButton] = sector def setupSanityCheck(self, sanityCheckWindow, statusLabel): def takeMeasurement(decision): if "No" in decision.text(): print("Measurement canceled") return else: print("Taking new measurement") self.showDisplay(self.liveSignalsWindow) statusLabel.setStyleSheet("color: blue;") statusLabel.setText("Starting Procedure") self.takeNewCalibration() sanityCheckWindow.setWindowTitle("Sanity Check") sanityCheckWindow.setText( "Are you sure? This will take multiple hours") sanityCheckWindow.setIcon(QMessageBox.Warning) sanityCheckWindow.setStandardButtons(QMessageBox.Yes | QMessageBox.No) sanityCheckWindow.setDefaultButton(QMessageBox.No) sanityCheckWindow.buttonClicked.connect(takeMeasurement) @Slot() def takeNewCalibration(self): self.selectedCryomoduleObject.takeNewCalibration( int(self.initialCalibrationHeatLoadLineEdit.text())) @Slot() def showDisplay(self, display): # type: (QWidget) -> None display.show() # brings the display to the front display.raise_() # gives the display focus display.activateWindow() @Slot() # TODO needs to check all cavities def cavityToggled(self, cm): # type: (str) -> None statusList = list( map(lambda groupbox: groupbox.isChecked(), self.cavityGroupBoxes[cm])) allChecked = reduce( (lambda isChecked1, isChecked2: isChecked1 and isChecked2), statusList) if statusList.count(statusList[0]) != len(statusList): self.selectAllCavitiesCheckboxes[cm].setCheckState(1) else: self.selectAllCavitiesCheckboxes[cm].setCheckState( 0 if not allChecked else 2) self.updateOutputBasedOnDefaultConfig(cm, allChecked) @Slot() # TODO use AMAX/ops limit def checkIfAllCavitiesAtDefault(self, cm, updateOutput=True): # type: (str, bool) -> bool isDefault = True for idx, lineEdit in enumerate(self.desiredCavAmpLineEdits[cm]): if lineEdit.text(): try: amplitude = float(lineEdit.text()) maxAmp = float(self.maxAmplitudeLabels[cm][idx].text()) if amplitude > maxAmp: lineEdit.clear() elif amplitude != maxAmp: isDefault = False except ValueError: lineEdit.clear() isDefault = False else: isDefault = False if updateOutput: self.updateOutputBasedOnDefaultConfig(cm, isDefault) return isDefault def updateOutputBasedOnDefaultConfig(self, cm, isDefault): starredName = "{CM}*".format(CM=cm) self.selectedDisplayCM = cm if isDefault else starredName self.updateSelectedText() @Slot() def openAmplitudeWindow(self, cm, sector): # type: (str, int) -> None # Put this here to speed things up (it was suuuuuuuper slow trying to do # this on startup) if cm not in self.buttonDisplays: displayCM = Display(ui_filename=self.pathToAmplitudeWindow, macros={ "cm": cm, "area": "L{SECTOR}B".format(SECTOR=sector) }) repeater = displayCM.ui.cavityRepeater lineEdits = [] groupBoxes = [] amaxLabels = [] for cav in range(8): item = repeater.layout().itemAt(cav) # type: QWidgetItem displayCav = item.widget() # type: Display lineEdit = displayCav.ui.desiredAmplitude # type: QLineEdit validator = QDoubleValidator(0.0, 21.0, 2, lineEdit) validator.setNotation(QDoubleValidator.StandardNotation) lineEdit.setValidator(validator) amaxLabel = displayCav.ui.amaxLabel try: maxAmplitude = float(amaxLabel.text()) except (TypeError, ValueError): maxAmplitude = 0 lineEdit.setText(str(maxAmplitude)) lineEdit.textChanged.connect( partial(self.checkIfAllCavitiesAtDefault, cm)) lineEdits.append(lineEdit) groupBox = displayCav.ui.cavityGroupbox # type: QGroupBox groupBox.toggled.connect(partial(self.cavityToggled, cm)) groupBoxes.append(groupBox) amaxLabels.append(amaxLabel) restoreDefaultButton: QPushButton = displayCav.ui.restoreDefaultButton restoreDefaultButton.clicked.connect( partial(self.restoreDefault, lineEdit, displayCav.ui.amaxLabel)) self.desiredCavAmpLineEdits[cm] = lineEdits self.buttonDisplays[cm] = displayCM self.cavityGroupBoxes[cm] = groupBoxes self.maxAmplitudeLabels[cm] = amaxLabels selectAllCheckbox = displayCM.ui.selectAllCheckbox # type: QCheckBox self.selectAllCavitiesCheckboxes[cm] = selectAllCheckbox selectAllCheckbox.stateChanged.connect( partial(self.selectAllCavitiesToggled, cm)) self.buttonDisplays[cm].show() @Slot() def selectAllCavitiesToggled(self, cm): state = self.selectAllCavitiesCheckboxes[cm].checkState() if state == 0: for cavityGroupbox in self.cavityGroupBoxes[cm]: cavityGroupbox.setChecked(False) elif state == 2: for cavityGroupbox in self.cavityGroupBoxes[cm]: cavityGroupbox.setChecked(True) @Slot() def restoreDefault(self, desiredAmplitude: QLineEdit, amaxLabel: PyDMLabel): try: maxAmplitude = float(amaxLabel.text()) except (ValueError, TypeError): maxAmplitude = 0 desiredAmplitude.setText(str(maxAmplitude)) def updateSelectedText(self): if not self.selectedDisplayCM: self.ui.cmSelectionLabel.setStyleSheet("color: red;") self.ui.cmSelectionLabel.setText("No Cryomodules Selected") self.calibrationGroupBox.setEnabled(False) self.rfGroupBox.setEnabled(False) else: self.ui.cmSelectionLabel.setStyleSheet("color: green;") self.ui.cmSelectionLabel.setText(self.selectedDisplayCM) self.calibrationGroupBox.setEnabled(True) @Slot() # TODO check if all checkboxes in sector are clicked def cryomoduleRadioButtonToggled(self, cryomodule): # type: (str) -> None radioButton = self.cryomoduleRadioButtons[cryomodule] button = self.cryomoduleButtons[cryomodule] if radioButton.isChecked(): button.setEnabled(True) isDefault = (self.checkIfAllCavitiesAtDefault(cryomodule, False) if cryomodule in self.desiredCavAmpLineEdits else True) self.selectedDisplayCM = cryomodule + ("*" if not isDefault else "") self.selectedCM = cryomodule linacIdx = CM_LINAC_MAP[self.selectedCM] self.selectedCryomoduleObject = Q0_LINAC_OBJECTS[ linacIdx].cryomodules[self.selectedCM] linacIdx = CM_LINAC_MAP[cryomodule] cryomoduleObj = Q0_LINAC_OBJECTS[linacIdx].cryomodules[cryomodule] self.plots.updateChannels(cryomoduleObj) else: button.setEnabled(False) self.updateSelectedText() self.calibrationOptionsWindow.cryomoduleComboBox.setCurrentText( self.selectedCM) @Slot() def selectAllSectorCryomodules(self, selectAllCheckbox, sector): # type: (QCheckBox, int) -> None sectorLabel = "L{SECTOR}B".format(SECTOR=sector) if selectAllCheckbox.checkState() == 2: for name in self.sectors[sector]: self.cryomoduleRadioButtons[name].setChecked(True) self.selectedDisplayCM.discard(name) if (sectorLabel + "*") not in self.selectedDisplayCM: self.selectedDisplayCM.add(sectorLabel) elif selectAllCheckbox.checkState() == 0: for name in self.sectors[sector]: self.cryomoduleRadioButtons[name].setChecked(False) self.selectedDisplayCM.discard(sectorLabel) self.selectedDisplayCM.discard(sectorLabel + "*") self.updateSelectedText()
class MyWindow(QMainWindow): def __init__(self): super(MyWindow, self).__init__() self.lz = [] self.ts = 0 self.zahlenListe = [] dir = os.path.dirname(sys.argv[0]) self.settingsfile = "%s/%s" % (dir, "Lotto.conf") self.zahlen = "%s/%s" % (dir, "zahlen.txt") print(self.settingsfile) self.settings = QSettings(self.settingsfile, QSettings.IniFormat) self.setStyleSheet(stylesheet(self)) self.lottolink = 'https://www.dielottozahlende.net/lotto-6-aus-49' self.mysuper = 5 self.model = QStandardItemModel(self) self.model.setRowCount(7) self.tableview = QTableView(self) self.tableview.setSortingEnabled(False) self.tableview.setGridStyle(1) if int(sys.version[0]) > 2: self.tableview.setFixedHeight(149) else: self.tableview.setFixedHeight(171) self.tableview.setSizeAdjustPolicy(QAbstractScrollArea.AdjustIgnored) self.tableview.horizontalHeader().setStretchLastSection(True) self.tableview.verticalHeader().setStretchLastSection(False) self.tableview.setCornerButtonEnabled(True) self.tableview.setShowGrid(True) self.tableview.setModel(self.model) self.tableview.hideRow(6) self.tableview.hideColumn(13) self.pushButtonLoad = QPushButton() self.pushButtonLoad.setText("Zahlen holen") self.pushButtonLoad.setIcon(QIcon.fromTheme("view-refresh")) self.pushButtonLoad.clicked.connect(self.getLotto) self.pushButtonLoad.setFixedWidth(110) self.pushButtonLoad.setFixedHeight(24) self.zahlenAction = QAction(QIcon.fromTheme("edit"), "Editor", self, triggered=self.edit_Tipps, shortcut="F5") self.addAction(self.zahlenAction) self.superAction = QAction(QIcon.fromTheme("edit"), "Superzahl", self, triggered=self.setMySuper, shortcut="F6") self.addAction(self.superAction) self.infoAction = QAction(QIcon.fromTheme("help-info"), "Information", self, triggered=self.showInfo, shortcut="F1") self.addAction(self.infoAction) self.lbl = QLabel() self.hbox = QHBoxLayout() self.hbox.addWidget(self.pushButtonLoad) grid = QVBoxLayout() grid.setSpacing(10) grid.addLayout(self.hbox) grid.addWidget(self.tableview) grid.addWidget(self.lbl) mywidget = QWidget() mywidget.setLayout(grid) self.setCentralWidget(mywidget) self.readSettings() self.tableview.resizeColumnsToContents() self.tableview.resizeRowsToContents() self.setHeaders() print("Wilkommen bei Lotto") self.statusBar().showMessage( "%s %s" % ("Willkommen bei LottoCheck", " *** F5 Lottozahlen ändern *** F6 Superzahl ändern"), 0) def findTableItems(self): model = self.tableview.model() self.tableview.selectionModel().clearSelection() print(self.zahlenListe) for column in range(12): start = model.index(0, column) for zahl in self.zahlenListe: matches = model.match(start, Qt.DisplayRole, str(zahl), 1, Qt.MatchExactly) if matches: index = matches[0] self.tableview.selectionModel().select( index, QItemSelectionModel.Select) def saveNumbers(self): print(self.model.columnCount(), "Columns") textData = "" fileName, _ = QFileDialog.getSaveFileName(self, "Open File", "~/lottozahlen.csv", "CSV Files (*.csv)") if fileName: print("%s %s" % (fileName, "saved")) f = open(fileName, 'w') for col in range(self.model.columnCount()): textData += str(self.model.horizontalHeaderItem(col).text()) textData += "\t" textData += "\n" for row in range(self.model.rowCount() - 1): for col in range(self.model.columnCount()): textData += str(self.model.data(self.model.index(row, col))) textData += "\t" textData += "\n" f.write(textData) f.close() def edit_Tipps(self): self.edWin = Editor() with open(self.zahlen, 'r') as f: text = f.read() self.edWin.tipp_editor.setPlainText(text) f.close() self.edWin.isModified = False def showInfo(self): link = "<p><a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'> \ Axel Schneider</a></p>" message = "<h2>LottoCheck 1.0</h2><h4>6 aus 49</h4>created by " + link + " with PyQt5<br>©September 2019<br>" \ + "<br>Copyright © 2017 The Qt Company Ltd and other contributors." \ + "<br>Qt and the Qt logo are trademarks of The Qt Company Ltd." \ + "<br><br>F5 = Tipps ändern" \ + "<br>F6 = Superzahl ändern" self.msgbox(message) def msgbox(self, message): msg = QMessageBox(1, "Information", message, QMessageBox.Ok) msg.exec_() def getLotto(self): if not self.lz == []: print("values already here", self.lz) self.compare() else: self.lottolink = "https://www.lotto.de/lotto-6aus49/lottozahlen" print("getting Values") source = requests.get(self.lottolink).text soup = bsoup(source, 'lxml') lottoliste = [] for td in soup.find_all(class_='LottoBall__circle'): lottoliste.append(td.text) result = lottoliste self.zahlenListe = result[:6] self.lz = result theSuper = lottoliste[6] print("Gewinnzahlen:\n", self.zahlenListe) self.ts = theSuper print("theSuper", self.ts) for i in range(6): self.model.setData(self.model.index(i, 12), result[i]) self.model.item(i, 12).setTextAlignment(Qt.AlignCenter) self.compare() def getSpiel77(self): self.lottolink = "https://www.lotto.de/lotto-6aus49/lottozahlen" source = requests.get(self.lottolink).text soup = bsoup(source, 'lxml') result = soup.find(class_='WinningNumbersAdditionalGame__text').text print("Spiel 77: ", result) super6 = soup.find(class_='WinningNumbersAdditionalGame__text' ).parent.find_next_siblings()[0].text print("Super 6: ", super6) date = soup.find(class_="WinningNumbers__date").text self.lbl.setText(self.lbl.text() + "\n" + date + "\n\n" + result.replace("Spiel 77", "Spiel 77: ") + "\n" + super6.replace("Super 6", "Super 6: ")) def compare(self): ### compare all tipps print("self.lz: ", self.lz) self.lz = [int(x) for x in self.lz[:6]] print(self.mysuper, self.lz) self.lbl.clear() tipp = [] for x in range(len(self.tliste)): t = [] tipp = [int(x) for x in self.tliste[x]] # print(tipp) for a in self.lz: if int(a) in tipp: print(a, "in tipp", str(x + 1)) t.append(a) rtext = "" print("len(t) ", len(t)) if len(t) == 2 and self.mysuper == self.ts: rtext += self.lbl.text() rtext += '\ngewonnen in Tipp ' rtext += str(int(x) + 1) rtext += " : " rtext += str(t) rtext += " *** " rtext += str(len(t)) rtext += "er ***" rtext += ' + Superzahl' self.lbl.setText(rtext) elif len(t) > 2: if self.mysuper == self.ts: rtext += self.lbl.text() rtext += '\ngewonnen in Tipp ' rtext += str(int(x) + 1) rtext += " : " rtext += str(t) rtext += " *** " rtext += str(len(t)) rtext += "er ***" rtext += ' + Superzahl' self.lbl.setText(rtext) else: rtext += self.lbl.text() rtext += '\ngewonnen in Tipp ' rtext += str(int(x) + 1) rtext += " : " rtext += str(t) rtext += " *** " rtext += str(len(t)) rtext += "er ***" self.lbl.setText(rtext) if self.lbl.text() == "": self.lbl.setText("leider nichts gewonnen ...\n") self.statusBar().showMessage( "%s %s %s %s" % ("Gewinnzahlen: ", (', '.join(str(x) for x in self.lz)), " *** Superzahl: ", str(self.ts)), 0) self.getSpiel77() self.findTableItems() def setHeaders(self): self.tableview.horizontalHeader().setVisible(True) self.tableview.verticalHeader().setVisible(False) for x in range(self.model.columnCount() - 1): self.model.setHeaderData(x, Qt.Horizontal, "%s %s" % ("Tipp", (x + 1))) self.model.setHeaderData(self.model.columnCount() - 1, Qt.Horizontal, "Gewinnzahlen") self.tableview.setAlternatingRowColors(True) self.tableview.resizeColumnsToContents() self.tableview.resizeRowsToContents() def closeEvent(self, event): print("Goodbye ...") self.writeSettings() def setMySuper(self): s = int(self.mysuper) dlg = QInputDialog() ms, ok = dlg.getInt(self, 'Superzahl:', "", s, 0, 9, 1, Qt.Dialog) if ok: self.mysuper = ms print("Superzahl =", self.mysuper) def readSettings(self): if self.settings.contains("mysuper"): self.mysuper = self.settings.value("mysuper") else: self.setMySuper() print("Superzahl:", self.mysuper) self.tliste = [] with open(self.zahlen, 'r') as f: text = f.read() f.close() for line in text.splitlines(): self.tliste.append(line.split(",")) self.model.setColumnCount(len(self.tliste) + 1) for x in range(0, len(self.tliste)): tipp = self.tliste[x] for i in range(len(tipp)): self.model.setData(self.model.index(i, x), tipp[i]) self.model.item(i, x).setTextAlignment(Qt.AlignCenter) def writeSettings(self): self.settings.setValue("mysuper", self.mysuper)
class SchemaWidget(QWidget): def __init__(self, connection_helper): super().__init__() self.connection_helper = connection_helper self.model = QStandardItemModel() self.edit_cell_value = None self.schema = None self.model.itemChanged.connect(self.edit_cell) self.column_labels = ["Field", "Type", "Unsigned", "Zerofill", "Allow Null", "Key", "Default", "Extra"] # need index form for adding new keys. Not a separate table..just a button # need columns resized self.init_ui() self.refresh() def init_ui(self): uic.loadUi(ui_file, self) self.RefreshButton.clicked.connect(self.refresh) self.AddRowButton.clicked.connect(self.add_row) self.RemoveRowButton.clicked.connect(self.remove_row) self.SchemaTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.SchemaTable.setSelectionMode(QAbstractItemView.SingleSelection) def add_row(self): print('') def remove_row(self): reply = QMessageBox.question(self, 'Wait!', f"Are you sure you want to delete this column?", QMessageBox.Yes|QMessageBox.No) if reply == QMessageBox.Yes: rows = self.SchemaTable.selectionModel().selectedRows() for row in rows: row_index = row.row() column_name = self.model.item(row_index, 0).text() self.connection_helper.drop_table_column(None, column_name) self.refresh() def edit_cell(self, item): row = item.row() row_values = {} table_column = self.model.item(row, 0).text() simple_type = self.schema['columns'][table_column]['Simple_Type'] for column_index in range(self.model.columnCount()): column_header = self.model.horizontalHeaderItem(column_index).text() item = self.model.item(row, column_index) if item.isCheckable(): value = True if item.checkState() == 2 else False else: value = item.data(Qt.EditRole) row_values[column_header] = value result = self.connection_helper.modify_table_column(None, row_values, simple_type) if isinstance(result, str): QMessageBox.about(self, 'Oops!', f'You have an error: \n {result}') self.refresh() def refresh(self): self.model.clear() self.schema = self.connection_helper.get_standardized_schema(None, None) self.model.setHorizontalHeaderLabels(self.column_labels) row_index = 0 for key, val in self.schema['columns'].items(): items = [] standard_item = QStandardItem() standard_item.setData(QVariant(key), Qt.EditRole) items.append(standard_item) standard_item = QStandardItem() standard_item.setData(QVariant(val['Type'].upper()), Qt.EditRole) items.append(standard_item) standard_item = QStandardItem() if val['Simple_Type'] != 'number': standard_item.setCheckable(False) else: standard_item.setCheckable(True) if val['Unsigned'] is True: standard_item.setCheckState(Qt.CheckState.Checked) items.append(standard_item) standard_item = QStandardItem() if val['Simple_Type'] != 'number': standard_item.setCheckable(False) else: standard_item.setCheckable(True) if val['Zerofill'] is True: standard_item.setCheckState(Qt.CheckState.Checked) items.append(standard_item) standard_item = QStandardItem() if val['Null'] is True: standard_item.setCheckState(Qt.CheckState.Checked) standard_item.setCheckable(True) items.append(standard_item) standard_item = QStandardItem() standard_item.setEditable(False) standard_item.setData(QVariant(val['Key']), Qt.EditRole) items.append(standard_item) standard_item = QStandardItem() standard_item.setData(QVariant(val['Default']), Qt.EditRole) items.append(standard_item) standard_item = QStandardItem() standard_item.setData(QVariant(val['Extra']), Qt.EditRole) items.append(standard_item) self.model.insertRow(row_index, items) row_index += 1 self.SchemaTable.setModel(self.model) self.SchemaTable.resizeColumnsToContents() def update(self): self.refresh()
class HealthMonitorWindow(QDialog, Ui_HealthMonitor): def __init__(self, parent): super().__init__(parent, get_modeless_dialog_flags()) self.setupUi(self) self.ipcon_available = False self.button_save_report_to_csv_file.clicked.connect( self.save_report_to_csv_file) self.button_close.clicked.connect(self.hide) self.fixed_column_names = [ 'Name', 'UID', 'Position', 'FW Version', 'Metric Errors' ] self.dynamic_column_names = [] self.metric_errors = {} # by uid self.old_values = {} # by uid, by metric name self.tree_view_model = QStandardItemModel(self) self.tree_view_proxy_model = DevicesProxyModel(self) self.tree_view_proxy_model.setSourceModel(self.tree_view_model) self.tree_view.setModel(self.tree_view_proxy_model) self.tree_view.setSortingEnabled(True) self.tree_view.header().setSortIndicator(2, Qt.AscendingOrder) self.tree_view.setExpandsOnDoubleClick(False) self.delayed_refresh_tree_view_timer = QTimer(self) self.delayed_refresh_tree_view_timer.timeout.connect( self.delayed_refresh_tree_view) self.delayed_refresh_tree_view_timer.setInterval(100) inventory.info_changed.connect( lambda: self.delayed_refresh_tree_view_timer.start()) self.update_metric_values_timer = QTimer(self) self.update_metric_values_timer.timeout.connect( lambda: self.update_metric_values()) self.update_metric_values_timer.setInterval(1000) self.update_metric_values_timer.start() self.refresh_tree_view() self.update_ui_state() def delayed_refresh_tree_view(self): self.delayed_refresh_tree_view_timer.stop() if self.isVisible(): self.refresh_tree_view() def refresh_tree_view(self): sis = self.tree_view.header().sortIndicatorSection() sio = self.tree_view.header().sortIndicatorOrder() self.tree_view_model.clear() self.tree_view_model.setHorizontalHeaderLabels(self.fixed_column_names) self.dynamic_column_names = [] column_offset = len(self.fixed_column_names) def create_and_append_row(info, parent): try: metric_names = info.plugin.get_health_metric_names() except: metric_names = [] fw_version = QStandardItem( get_version_string(info.firmware_version_installed, replace_unknown='?')) if info.firmware_version_installed < info.firmware_version_latest: font = fw_version.font() font.setBold(True) fw_version.setFont(font) row = [ QStandardItem(info.name), QStandardItem(info.uid), QStandardItem(info.position.title()), fw_version, QStandardItem(str(self.metric_errors.get(info.uid, 0))) ] for metric_name in metric_names: try: i = self.dynamic_column_names.index(metric_name) except: self.dynamic_column_names.append(metric_name) i = len(self.dynamic_column_names) - 1 self.tree_view_model.setHorizontalHeaderItem( column_offset + i, QStandardItem(metric_name)) while len(row) <= column_offset + i: row.append(QStandardItem()) item = row[column_offset + i] old_timestamp, old_value = self.old_values.get( info.uid, {}).get(metric_name, (None, None)) item.setText(str(old_value if old_value != None else '-')) if old_timestamp != None and old_timestamp + SETTLE_DURATION >= time.monotonic( ): font = item.font() if not font.bold(): font.setBold(True) item.setFont(font) for item in row: item.setFlags(item.flags() & ~Qt.ItemIsEditable) parent.appendRow(row) return row def recurse_on_device(info, parent): if not isinstance(info, DeviceInfo): return row = create_and_append_row(info, parent) for child in info.connections_values(): recurse_on_device(child, row[0]) for info in inventory.get_infos(): if not isinstance(info, DeviceInfo): continue # if a device has a reverse connection, it will be handled as a child below if info.reverse_connection != None: continue row = create_and_append_row(info, self.tree_view_model) for child in info.connections_values(): recurse_on_device(child, row[0]) self.tree_view.setAnimated(False) self.tree_view.expandAll() self.tree_view.setAnimated(True) self.tree_view.setSortingEnabled(True) self.tree_view.header().setSortIndicator(sis, sio) self.tree_view.header().setStretchLastSection(False) self.tree_view.header().setSectionResizeMode( QHeaderView.ResizeToContents) self.update_metric_values() def get_health_metric_values_async(self, uid, index, metric_values): if self.tree_view_model.itemFromIndex(index) == None: # FIXME: item was removed in the meantime? return column_offset = len(self.fixed_column_names) for metric_name, metric_value in metric_values.items(): try: i = self.dynamic_column_names.index(metric_name) except: # FIXME: column for this metric was removed in the meantime? continue sibling = index.sibling(index.row(), column_offset + i) if not sibling.isValid(): # FIXME: item for this metric was removed in the meantime? continue item = self.tree_view_model.itemFromIndex(sibling) if item == None: # FIXME: item for this metric was removed in the meantime? continue self.update_item_text(uid, item, metric_name, metric_value) metric_name = 'Metric Errors' sibling = index.sibling(index.row(), self.fixed_column_names.index(metric_name)) item = self.tree_view_model.itemFromIndex(sibling) if item == None: # FIXME: item was removed in the meantime? return self.update_item_text(uid, item, metric_name, self.metric_errors.get(uid, 0)) def update_item_text(self, uid, item, metric_name, new_value): new_timestamp = time.monotonic() old_timestamp, old_value = self.old_values.get(uid, {}).get( metric_name, (None, None)) new_value_str = str(new_value) if item.text() != new_value_str: item.setText(new_value_str) if old_value != new_value: if uid not in self.old_values: self.old_values[uid] = { metric_name: (new_timestamp, new_value) } else: self.old_values[uid][metric_name] = (new_timestamp, new_value) font = item.font() if not font.bold(): font.setBold(True) item.setFont(font) elif old_timestamp + SETTLE_DURATION < new_timestamp: font = item.font() if font.bold(): font.setBold(False) item.setFont(font) def get_health_metric_values_error(self, uid, index): if uid in self.metric_errors: self.metric_errors[uid] += 1 else: self.metric_errors[uid] = 1 if self.tree_view_model.itemFromIndex(index) == None: # FIXME: item was removed in the meantime? return metric_name = 'Metric Errors' sibling = index.sibling(index.row(), self.fixed_column_names.index(metric_name)) item = self.tree_view_model.itemFromIndex(sibling) if item == None: # FIXME: item was removed in the meantime? return self.update_item_text(uid, item, metric_name, self.metric_errors[uid]) def update_metric_values(self, parent=None): if not self.isVisible(): return self.update_metric_values_timer.stop() if parent == None: parent = self.tree_view_model.invisibleRootItem() def make_async_call(info, uid, index): async_call( info.plugin.get_health_metric_values, None, lambda metric_values: self.get_health_metric_values_async( uid, index, metric_values), lambda: self.get_health_metric_values_error(uid, index)) # FIXME: avoid getter burst! for r in range(parent.rowCount()): child = parent.child(r, 0) index = child.index() uid = parent.child(r, 1).text() info = inventory.get_info(uid) if info == None: # FIXME: unknown UID, remove row or mark it as broken? continue make_async_call(info, uid, index) self.update_metric_values(parent=child) async_call(lambda: None, None, self.update_metric_values_timer.start, None) def collect_metric_values(self, parent=None, indent=''): if parent == None: parent = self.tree_view_model.invisibleRootItem() rows = [] for r in range(parent.rowCount()): row = [] for c in range(parent.columnCount()): child = parent.child(r, c) if child == None: text = '' else: text = child.text() font = child.font() if c == 0: text = indent + text if font.bold(): text += ' <!>' row.append(text) rows.append(row) rows += self.collect_metric_values(parent=parent.child(r, 0), indent=indent + ' ') return rows def save_report_to_csv_file(self): date = datetime.now().replace(microsecond=0).isoformat().replace( 'T', '_').replace(':', '-') filename = get_save_file_name( self, 'Save Report To CSV File', os.path.join(get_home_path(), 'brickv_health_report_{0}.csv'.format(date))) if len(filename) == 0: return c = 0 header = [] while True: item = self.tree_view_model.horizontalHeaderItem(c) if item == None: break header.append(item.text()) c += 1 rows = [header] + self.collect_metric_values() try: with open(filename, 'w', newline='') as f: csv.writer(f).writerows(rows) except Exception as e: QMessageBox.critical( self, 'Save Report To CSV File', 'Could not save report to CSV file:\n\n' + str(e), QMessageBox.Ok) def update_ui_state(self): pass def set_ipcon_available(self, ipcon_available): self.ipcon_available = ipcon_available self.update_ui_state()