def menu_button(self, main_action_id, ids, widget): ''' Creates an :obj:`.OWButton` with a popup-menu and adds it to the parent ``widget``. ''' id, name, attr_name, attr_value, callback, icon_name = self._expand_id(main_action_id) b = OWButton(parent=widget) m = QMenu(b) b.setMenu(m) b._actions = {} QObject.connect(m, SIGNAL("triggered(QAction*)"), b, SLOT("setDefaultAction(QAction*)")) if main_action_id: main_action = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=b) QObject.connect(m, SIGNAL("triggered(QAction*)"), main_action, SLOT("trigger()")) for id in ids: id, name, attr_name, attr_value, callback, icon_name = self._expand_id(id) a = OWAction(self._plot, icon_name, attr_name, attr_value, callback, parent=m) m.addAction(a) b._actions[id] = a if m.actions(): b.setDefaultAction(m.actions()[0]) elif main_action_id: b.setDefaultAction(main_action) b.setPopupMode(QToolButton.MenuButtonPopup) b.setMinimumSize(40, 30) return b
def show(position, panel, link, cursor): """Shows a context menu. position: The global position to pop up panel: The music view panel, giving access to mainwindow and view widget link: a popplerqt4 LinkBrowse instance or None cursor: a QTextCursor instance or None """ m = QMenu(panel) # selection? -> Copy if panel.widget().view.surface().hasSelection(): m.addAction(panel.actionCollection.music_copy_image) if cursor: a = m.addAction(icons.get("document-edit"), _("Edit in Place")) @a.triggered.connect def edit(): from . import editinplace editinplace.edit(panel.widget(), cursor, position) elif link: a = m.addAction(icons.get("window-new"), _("Open Link in &New Window")) @a.triggered.connect def open_in_browser(): import helpers helpers.openUrl(QUrl(link.url())) a = m.addAction(icons.get("edit-copy"), _("Copy &Link")) @a.triggered.connect def copy_link(): QApplication.clipboard().setText(link.url()) # no actions yet? insert Fit Width/Height if not m.actions(): m.addAction(panel.actionCollection.music_fit_width) m.addAction(panel.actionCollection.music_fit_height) m.addAction(panel.actionCollection.music_zoom_original) m.addSeparator() m.addAction(panel.actionCollection.music_sync_cursor) # help m.addSeparator() a = m.addAction(icons.get("help-contents"), _("Help")) @a.triggered.connect def help(): import userguide userguide.show("musicview") # show it! if m.actions(): m.exec_(position) m.deleteLater()
class TableView(QTableView): def __init__(self, parent): QTableView.__init__(self, parent) # Set the title header self.header_column_count = 0 self.header = HeaderView(Qt.Horizontal, self) self.header.setClickable(True) self.connect(self.header, SIGNAL("right_clicked"), self.displayHeadersActionsMenu) self.setHorizontalHeader(self.header) self.setMouseTracking(True) self.header_menu = QMenu(self) self.setAlternatingRowColors(True) def updateHeadersActions(self): # clean the current actions list: if self.header_column_count == self.header.count(): # column didn't change return self.header_column_count = self.header.count() for action in self.header_menu.actions(): self.removeAction(action) for col in xrange(self.header.count()): col_label = self.model().headerData(col, Qt.Horizontal).toString() action = QAction(col_label, self.header) action.setCheckable(True) action.setChecked(not self.header.isSectionHidden(col)) self.connect(action, SIGNAL("triggered()"), self.updateDisplayedColumns) self.header_menu.addAction(action) def displayHeadersActionsMenu(self, event): self.header_menu.exec_(event.globalPos()) def updateDisplayedColumns(self): for menu_item_no, menu_item in enumerate(self.header_menu.actions()): if menu_item.isChecked(): self.header.showSection(menu_item_no) else: self.header.hideSection(menu_item_no) print self.sizeHint() def parentResizeEvent(self, event): pass
def slotShowContextMenu(self, pos): hit = self.webview.page().currentFrame().hitTestContent(pos) menu = QMenu() if hit.linkUrl().isValid(): a = self.webview.pageAction(QWebPage.CopyLinkToClipboard) a.setIcon(icons.get("edit-copy")) a.setText(_("Copy &Link")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window")) a.triggered.connect( (lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl())) else: if hit.isContentSelected(): a = self.webview.pageAction(QWebPage.Copy) a.setIcon(icons.get("edit-copy")) a.setText(_("&Copy")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))( self.webview.url())) if menu.actions(): menu.exec_(self.webview.mapToGlobal(pos))
def customContextMenu(self, point): popup_menu = self.createStandardContextMenu() # Select the word under the cursor. cursor = self.cursorForPosition(point) cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if self.textCursor().hasSelection(): text = unicode(self.textCursor().selectedText()) if not self.spell_dict.check(text): spell_menu = QMenu('Spelling Suggestions') for word in self.spell_dict.suggest(text): action = SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) popup_menu.exec_(self.mapToGlobal(point))
def menu_sessions(parent): m = QMenu(parent) m.setTitle(_('menu title', '&Session')) m.triggered.connect(slot_session_action) import sessions for name in sessions.sessionNames(): a = m.addAction(name.replace('&', '&&')) a.setObjectName(name) qutil.addAccelerators(m.actions()) return m
def menu_file_open_recent(parent): m = QMenu(parent) m.setTitle(_("Open &Recent")) m.triggered.connect(slot_file_open_recent_action) import recentfiles for url in recentfiles.urls(): f = url.toLocalFile() dirname, basename = os.path.split(f) text = "{0} ({1})".format(basename, util.homify(dirname)) m.addAction(text).url = url qutil.addAccelerators(m.actions()) return m
def menu_file_new_from_template(parent): m = QMenu(parent) m.setTitle(_("New from &Template")) m.triggered.connect(slot_file_new_from_template_action) from snippet import model, actions, snippets groups = {} for name in sorted(model.model().names()): variables = snippets.get(name).variables group = variables.get('template') if group: action = actions.action(name, m) if action: groups.setdefault(group, []).append(action) for group in sorted(groups): for action in groups[group]: m.addAction(action) m.addSeparator() qutil.addAccelerators(m.actions()) return m
def slotShowContextMenu(self, pos): hit = self.webview.page().currentFrame().hitTestContent(pos) menu = QMenu() if hit.linkUrl().isValid(): a = self.webview.pageAction(QWebPage.CopyLinkToClipboard) a.setIcon(icons.get("edit-copy")) a.setText(_("Copy &Link")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl())) else: if hit.isContentSelected(): a = self.webview.pageAction(QWebPage.Copy) a.setIcon(icons.get("edit-copy")) a.setText(_("&Copy")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(self.webview.url())) if menu.actions(): menu.exec_(self.webview.mapToGlobal(pos))
class NgiiDataUtils: """QGIS Plugin Implementation.""" mainMenuTitle = u"NGII" mainMenu = None menuBar = None menuActions = [] toolbarActions = [] def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'NgiiDataUtils_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.pluginIsActive = False self.dockwidget = None def initGui(self): # 메뉴와 툴바에 추가할 항목 정의 menuIcons = ['icon.png'] menuTexts = [u'국토지리정보원 공간정보 중첩 검사'] menuActions = [self.togglePanel] assert (len(menuIcons) == len(menuTexts)) assert (len(menuTexts) == len(menuActions)) # 기존 NGII 메뉴가 있으면 재사용. 없으면 추가 self.addNgiiMenu(menuIcons, menuTexts, menuActions) # self.togglePanel() def addNgiiMenu(self, menuIcons, menuTexts, menuActions): # https://gis.stackexchange.com/questions/227876/finding-name-of-qgis-toolbar-in-python qgisMenuBar = self.iface.mainWindow().menuBar() # 이미 NGII 메뉴 있는지 찾아보기 ngiiMenu = None for action in qgisMenuBar.actions(): if action.text() == self.mainMenuTitle: ngiiMenu = action.menu() break # 없음 만들고 있음 그냥 사용 if ngiiMenu is None: self.mainMenu = QMenu(self.iface.mainWindow()) self.mainMenu.setTitle(self.mainMenuTitle) qgisMenuBar.insertMenu( self.iface.firstRightStandardMenu().menuAction(), self.mainMenu) else: self.mainMenu = ngiiMenu # 이미 NGII 툴바 있는지 찾아보기 ngiiToolbar = None for toolbar in self.iface.mainWindow().findChildren(QToolBar): # if toolbar.objectName() == self.mainMenuTitle: if toolbar.windowTitle() == self.mainMenuTitle: ngiiToolbar = toolbar break # 없음 만들고 있음 그냥 사용 if ngiiToolbar is None: self.toolbar = self.iface.addToolBar(self.mainMenuTitle) self.toolbar.setObjectName(self.mainMenuTitle) else: self.toolbar = ngiiToolbar # 세부 메뉴, 버튼 추가 self.menuActions = [] self.toolbarActions = [] for i in range(0, len(menuTexts)): icon = QIcon( os.path.join(os.path.dirname(__file__), 'icons', menuIcons[i])) text = menuTexts[i] action = QAction(icon, text, self.iface.mainWindow()) self.mainMenu.addAction(action) action.triggered.connect(menuActions[i]) button = self.toolbar.addAction(icon, text, menuActions[i]) self.menuActions.append(action) self.toolbarActions.append(button) def removeNgiiMenu(self): if self.toolbar is not None: # 내가 등록한 툴바 아이템 제거 for action in self.toolbarActions: self.toolbar.removeAction(action) # 더이상 항목이 없으면 부모 제거 if len(self.toolbar.actions()) == 0: self.toolbar.deleteLater() if self.mainMenu is not None: for action in self.menuActions: self.mainMenu.removeAction(action) # print len(self.mainMenu.actions()) if len(self.mainMenu.actions()) == 0: self.mainMenu.deleteLater() #-------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" # print "** CLOSING NgiiDataUtils" # disconnects self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) # remove this statement if dockwidget is to remain # for reuse if plugin is reopened # Commented next statement since it causes QGIS crashe # when closing the docked window: # self.dockwidget = None self.pluginIsActive = False def unload(self): if self.dockwidget: self.iface.removeDockWidget(self.dockwidget) self.removeNgiiMenu() #-------------------------------------------------------------------------- def togglePanel(self): if not self.pluginIsActive: self.pluginIsActive = True # print "** STARTING NgiiDataUtils" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = NgiiDataUtilsDockWidget(self.iface) # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # show the dockwidget self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget) # 좌우로 붙게 수정 self.dockwidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.dockwidget.show() else: if self.dockwidget: self.dockwidget.close()
class MSView(QSplitter): modifiedContext = pyqtSignal(object) def __init__(self, widget, parent=None, **kw): QSplitter.__init__(self, Qt.Horizontal, parent) self.setFocusPolicy(Qt.StrongFocus) self.mainWidget = widget self.addWidget(self.mainWidget) self.showHide = None self.subsidiaryWidget = MSQtCanvas([], "", flags='spectrum')#, subsidiaryWidget=True) self.subsidiaryWidget.pw.plotItem.toolBar.hide() self.subsidiaryWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.subsidiaryWidget, SIGNAL("customContextMenuRequested(const QPoint &)"), self.showContextMenu) self.menu=QMenu(self.subsidiaryWidget) self.menu.addAction("&Hide...") self.connect(self.menu.actions()[0], SIGNAL("triggered()"), self.subsidiaryWidget.hide) self.addWidget(self.subsidiaryWidget) self.subsidiaryWidget.hide() self.barplotdrawn = False self.connect(self.mainWidget, SIGNAL('drawSpectraRequested'), self.drawSpectrum) self.connect(self.mainWidget, SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.drawSpectra) self.connect(self.mainWidget, SIGNAL('drawSpectrumByTime'), self.drawSpectrumByTime) self.connect(self.mainWidget, SIGNAL('hideRequested'), self.subsidiaryWidget.hide) def showContextMenu(self, pos): if self.subsidiaryWidget.pw.plotItem.vb.hasMoved: return self.menu.exec_(QCursor.pos()) @pyqtSlot() def drawSpectrum(self, p): if p is None: return mergedSpectra=p.merge(p.spectra) self.subsidiaryWidget.pw.clear() self.subsidiaryWidget._plotting([mergedSpectra]) self.subsidiaryWidget.pw.setTitle("Merged Spectrum@%s-%s"%(str(p.rtmin), str(p.rtmax))) self.subsidiaryWidget.show() def drawSpectrumByTime(self, t, sample): if not sample or not t: print "unknown error..." return spectra = sample.spectraInRTRange(t.x(), t.x()-2., t.x()+2.) if not spectra: print "No spectrum found at this retention time" return closest = sorted(spectra, key=lambda x: abs(t.x()-x.rtmin))[0] self.subsidiaryWidget.pw.clear() self.subsidiaryWidget._plotting([closest]) self.subsidiaryWidget.pw.setTitle("Spectrum@%s"%(str(closest.rtmin))) self.subsidiaryWidget.show() def drawSpectra(self, inf, sup, sample): if not sample: return spectra = sample.spectraInRTRange((inf+sup)/2., inf, sup) print [s.rtmin for s in spectra]
def registerAction(self, action, menuName, callback=None): """ register an action to the manager's main menu """ if not hasattr(self, '_registeredDbActions'): self._registeredDbActions = {} if callback is not None: invoke_callback = lambda x: self.invokeCallback(callback) if menuName is None or menuName == "": self.addAction(action) if menuName not in self._registeredDbActions: self._registeredDbActions[menuName] = list() self._registeredDbActions[menuName].append(action) if callback is not None: QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback) return True # search for the menu actionMenu = None helpMenuAction = None for a in self.menuBar.actions(): if not a.menu() or a.menu().title() != menuName: continue if a.menu() != self.menuHelp: helpMenuAction = a actionMenu = a break # not found, add a new menu before the help menu if actionMenu is None: menu = QMenu(menuName, self) if helpMenuAction is not None: actionMenu = self.menuBar.insertMenu(helpMenuAction, menu) else: actionMenu = self.menuBar.addMenu(menu) menu = actionMenu.menu() menuActions = menu.actions() # get the placeholder's position to insert before it pos = 0 for pos in range(len(menuActions)): if menuActions[pos].isSeparator() and menuActions[pos].objectName().endswith("_placeholder"): menuActions[pos].setVisible(True) break if pos < len(menuActions): before = menuActions[pos] menu.insertAction(before, action) else: menu.addAction(action) actionMenu.setVisible(True) # show the menu if menuName not in self._registeredDbActions: self._registeredDbActions[menuName] = list() self._registeredDbActions[menuName].append(action) if callback is not None: QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback) return True
class QuestionDlg(QDialog): def __init__(self, parent=None): super(QuestionDlg,self).__init__(parent) # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;") # self.createDb() # return self.db = QSqlDatabase.addDatabase("QSQLITE"); self.db.setDatabaseName("studentNew.db") if not self.db.open(): QMessageBox.warning(None, "错误", "数据库连接失败: %s" % self.db.lastError().text()) sys.exit(1) self.g_curClassName = "" self.deleteTmpdata() self.setWindowFlags(Qt.CustomizeWindowHint) # self.setStyleSheet("border: 2px; border-radius 2px;") # self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet("background-color: rgba(132, 171, 208, 200);") self.tabWidget=QTabWidget(self) self.tabWidget.currentChanged.connect(self.changeTab) # tabWidget.setTabShape(QTabWidget.Triangular) self.tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\ border-style: outset;background-color: rgb(132, 171, 208);\ background: transparent;} \ QTabWidget::tab-bar{border-width:0px;}\ QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \ QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \ QTabBar::tab:selected{border-color:green;background-color:white;color:green;}") # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}") self.btngroup = QButtonGroup() self.popMenu = QMenu(self) entry1 = self.popMenu.addAction("正确") self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight()) entry2 = self.popMenu.addAction("错误") self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong()) entry3 = self.popMenu.addAction("替换") self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent()) # Create the first tab page. self.w1=QWidget() self.w1.setAccessibleName("w1tab") self.genOneTab() # Create the second tab page. self.w2=QWidget() self.w2.setAccessibleName("w2tab") self.genTwoTab() self.tabWidget.addTab(self.w1,"") self.tabWidget.addTab(self.w2,"班级学生信息管理") self.tabWidget.resize(940,700) btnclose = QPushButton(self) btnclose.setToolTip("关闭") btnclose.setText("╳") btnclose.setGeometry(915, 5, 20, 20) btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnclose.clicked.connect(self.close) btnMinimized = QPushButton(self) btnMinimized.setToolTip("最小化") btnMinimized.setText("▁") btnMinimized.setGeometry(890, 5, 20, 20) btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnMinimized.clicked.connect(lambda: self.showMinimized()) self.btnSysMenu = QPushButton(self) # self.btnSysMenu.setText("▼") self.btnSysMenu.setGeometry(865, 5, 20, 20) self.btnSysMenu.setToolTip("系统设置") self.btnSysMenu.clicked.connect(lambda: self.showMinimized()) menufont = QFont("宋体", 10) popMenu = QMenu(self) entry1 = popMenu.addAction("所有学生提问信息清零") entry1.setFont(menufont) self.connect(entry1,SIGNAL('triggered()'), self.initStudent) entry2 = popMenu.addAction("清除本堂课提问人员") entry2.setFont(menufont) self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata) entry3 = popMenu.addAction("关于...") entry3.setFont(menufont) self.connect(entry3,SIGNAL('triggered()'), self.aboutMe) entry4 = popMenu.addAction("导出...") entry4.setFont(menufont) self.connect(entry4,SIGNAL('triggered()'), self.exportNotice) self.btnSysMenu.setMenu(popMenu) self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ") # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);") authorinfo = QLabel(self.tabWidget) # authorinfo.setToolTip("关闭") authorinfo.setText("程序设计:汕头市大华路第一小学 赵小娜,有任何问题请反馈至[email protected]。") authorinfo.setGeometry(20, 665, 470, 26) authorinfo.setFont(QFont('Courier New')) authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:12px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;") self.setWindowTitle("课堂随机提问") self.setWindowIcon(QIcon("image/start.ico")) self.setGeometry(100, 20, 940, 700) # self.changeTab() screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) self.btn_start.setMyarg('start') # print(self.btn_start.getMyarg()) self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) # self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) self.btngroup.buttonClicked[int].connect(self.btns_click) # self.connect(self.btn_start, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click()) def myslot(self, text): # print(text, self.dict_choices) self.g_curbtn = text if self.g_curbtn not in self.dict_choices: self.btnSysMenu.setFocus() return # print(self.btngroup.button(int(self.g_curbtn)).parent()) # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget())) pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos()) width = self.btngroup.button(int(self.g_curbtn)).rect().height() # print("-----", pos, width) pos.setY(pos.y()+width-5) indx = 0 for istate in self.dict_choices[self.g_curbtn]: if istate == '1': self.popMenu.actions()[indx].setEnabled(True) elif istate == '0': self.popMenu.actions()[indx].setEnabled(False) indx += 1 self.popMenu.exec_(pos) self.btnSysMenu.setFocus() # def on_context_menu(self, point): # print(point) # self.popMenu.exec_(self.button.mapToGlobal(point)) def btns_click(self, btnid): # curclassname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) # cur = conn.cursor() today = datetime.date.today() self.g_curbtn = str(btnid).zfill(2) if self.g_curbtn not in self.dict_choices: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(self.g_curbtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", self.g_curClassName) query.bindValue(":stusn", self.g_curbtn) query.bindValue(":datequestion", today) query.exec_() self.dict_choices[self.g_curbtn] = "111" else: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon()) query.exec_("delete from tmprecord where stusn='"+ str(self.g_curbtn) + "'") self.dict_choices.pop(self.g_curbtn) self.btnSysMenu.setFocus() def exportNotice(self): query = QSqlQuery(self.db) query.exec_("select stusn, stuname, classname, rightquestions, wrongquestions from student" ) lstInfo = [["学号","姓名", "班级", "回答正确次数", "回答错误次数"]] while(query.next()): lstInfo.append([query.value(0),query.value(1),query.value(2),query.value(3),query.value(4)]) from xlwt import Workbook,easyxf book = Workbook(encoding='ascii') # 'pattern: pattern solid, fore_colour white;' style = easyxf( 'font: height 280, name 黑体;' 'align: vertical center, horizontal center;' ) style2 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left;') style3 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left, wrap True;') sheet1 = book.add_sheet('学生提问情况汇总',cell_overwrite_ok=True) # sheet1.write(0,7,flagtxt, easyxf('font: height 200, name 黑体;align: vertical center, horizontal right;')) sheet1.write_merge(0,0,0,4, '学生提问情况汇总表',style) sheet1.row(0).height_mismatch = 1 sheet1.row(0).height = 5*256 sheet1.col(0).width = 10*256 sheet1.col(1).width = 25*256 sheet1.col(2).width = 25*256 sheet1.col(3).width = 20*256 sheet1.col(4).width = 20*256 tmprows = 1 for item in lstInfo: stusn = item[0] stuname = item[1] classname = item[2] rightquestions = item[3] wrongquestions = item[4] sheet1.write(tmprows,0,stusn, style2) sheet1.write(tmprows,1,stuname, style2) sheet1.write(tmprows,2,classname, style2) sheet1.write(tmprows,3,rightquestions, style2) sheet1.write(tmprows,4,wrongquestions, style2) tmprows += 1 # print(tmprows) sheet1.header_str = "".encode() sheet1.footer_str = "".encode() # book.save('d:/simple.xls') # print(QDir.home().dirName() , QDir.homePath ()) filename = QDir.homePath () + "\学生提问情况汇总表.xls" try: book.save(filename) except Exception as e: QMessageBox.warning(self, "写入错误", "错误号:"+str(e.errno)+"\n错误描述:"+e.strerror+"\n请关闭已经打开的%s文档!" % filename) QMessageBox.about (self, "导出成功", "请查看文档:%s" % filename) def aboutMe(self): strinfo = """本软件采用python3.4编写,界面采用qt4.8的python绑定。 \n版本所有:汕头市大华路第一小学赵小娜老师。 \n有任何问题请反馈至[email protected]。 """ QMessageBox.information(None, "关于", strinfo) def initStudent(self): query = QSqlQuery(self.db) ret = query.exec_("update student set wrongquestions=0") ret = query.exec_("update student set rightquestions=0") QMessageBox.information(None, "提示", "已清除所有学生的累计提问情况。") def deleteTmpdata(self): query = QSqlQuery(self.db) ret = query.exec_("delete from tmprecord where 1=1" ) if self.g_curClassName != "": QMessageBox.information(None, "提示", "已清除本次软件启动后的所有已提问过的学生。") def changeTab(self): # pass curtab = self.tabWidget.currentIndex() # print(curtab, "-") if curtab == 1: ## when click the second tab page ,then pass. return # cur = conn.cursor() query = QSqlQuery(self.db) ## if current classname is null, then set current tabpage display the first class of classtable if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() self.g_curClassName = query.value(0) self.tabWidget.setTabText(0, self.g_curClassName) # print(1) strwhere = " and classname like '" + self.g_curClassName + "' ORDER BY stusn" self.g_curbtn = "" self.dict_choices = {} self.studentSnlst = [] ## clearn the question data of temp record . ret= query.exec_("delete from tmprecord where 1=1") ret = query.exec_("select stusn, stuname from student where 1=1 " + strwhere) ## now update the global data "self.btngroup" for indx in range(0, 56): self.btngroup.button(indx+1).setText("") self.btngroup.button(indx+1).setMyarg(None) self.btngroup.button(indx+1).setStyleSheet(stylesheetstr_old) self.btngroup.button(indx+1).setIcon(QIcon()) self.btngroup.button(indx+1).setEnabled(False) self.studentSnlst.append([indx+1,]) inum = 0 while (query.next()): inum += 1 self.btngroup.button(inum).setText(query.value(1)) self.btngroup.button(inum).setMyarg(query.value(0)) self.btngroup.button(inum).setStyleSheet(stylesheetstr_old) self.btngroup.button(inum).setIcon(QIcon()) self.btngroup.button(inum).setEnabled(True) # print(inum, len(self.btngroup.buttons())) self.group_animation = groupAnimation(self.studentSnlst, self.btngroup) def mousePressEvent(self, event): # print('a') if event.button() == Qt.RightButton: QDialog.mousePressEvent(self,event) return # print(event.sender(), event.button()) self.offset = event.pos() # print(self.offset) def mouseMoveEvent(self, event): # print('sss') if hasattr(self, 'offset'): x=event.globalX() y=event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x-x_w, y-y_w) else: pass #######======= studentModel ============############### def newStudent(self): # Calc the missing number: row = self.StudentModel.rowCount() if row > 0: oldNumList = [] for i in range(0, row): oldNumList.append(int(self.StudentModel.index(i,2).data())) allNumberList = list(range(1, oldNumList[-1]+1)) for i in range(0, allNumberList[-1]): if oldNumList[i] != allNumberList[i]: missingNum = allNumberList[i] break if len(oldNumList) == len(allNumberList): missingNum = allNumberList[i] +1 else: missingNum = 1 self.StudentModel.insertRow(row) self.StudentView.scrollToBottom() self.StudentModel.setData(self.StudentModel.index(row, 1), self.g_curClassName) self.StudentModel.setData(self.StudentModel.index(row, 2), str(missingNum).zfill(2)) self.StudentModel.setData(self.StudentModel.index(row, 4), 0) self.StudentModel.setData(self.StudentModel.index(row, 5), 0) def removeStudent(self): index = self.StudentView.currentIndex() row = index.row() if QMessageBox.question(self, "删除确认", "是否要删除当前选中记录?", "确定", "取消") == 0: self.StudentModel.removeRows(row, 1) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertStudent(self): self.StudentModel.revertAll() self.StudentModel.database().rollback() def saveStudent(self): self.StudentModel.database().transaction() if self.StudentModel.submitAll(): self.StudentModel.database().commit() # print("save success! ->commit") else: self.StudentModel.revertAll() self.StudentModel.database().rollback() #######======= classModel ============############### def newClass(self): row = self.ClassnameModel.rowCount() self.ClassnameModel.insertRow(row) def removeClass(self): index = self.ClassnameView.currentIndex() row = index.row() curClassname = index.sibling(index.row(),0).data() strwhere = "classname like '" + curClassname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() # print(self.StudentModel.rowCount(), "----", ) if QMessageBox.question(self, "删除确认", "删除班级意味着会删除本班所有人员信息。是否要删除当前选中记录?", "确定", "取消") == 0: self.ClassnameModel.removeRows(row, 1) self.ClassnameModel.submitAll() self.ClassnameModel.database().commit() self.StudentModel.removeRows(0, self.StudentModel.rowCount()) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertClass(self): self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() def saveClass(self): query = QSqlQuery(self.db) # record the old class name lstOldClassName = {} lstOldClassid = [] query.exec_("select rowid, classname from classtable" ) while(query.next()): lstOldClassName[query.value(0)] = query.value(1) lstOldClassid.append(query.value(0)) # print(lstOldClassName) # Update the class Table self.ClassnameModel.database().transaction() if self.ClassnameModel.submitAll(): self.ClassnameModel.database().commit() # print("save success! ->commit") else: QMessageBox.warning(None, "错误", "请检查班级中名称,不能出现同名班级!") self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() # print(lstOldClassid) lstNewClassName = {} query.exec_("select rowid, classname from classtable where rowid in " + str(tuple(lstOldClassid)) ) while(query.next()): lstNewClassName[query.value(0)] = query.value(1) # print(lstOldClassName, '=========') # print(lstNewClassName, '~~~~~~~~~') for i in lstOldClassName: oldclassname = lstOldClassName[i] newclassname = lstNewClassName[i] if oldclassname != newclassname: # print(oldclassname, newclassname, '++++++++') # print("update student set classname=" + newclassname + " where classname='" + oldclassname + "'") query.exec_("update student set classname='" + newclassname + "' where classname='" + oldclassname + "'") self.StudentModel.setFilter("classname = '" + newclassname + "'") self.StudentModel.select() lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) def dbclick(self, indx): if type(indx.sibling(indx.row(),0).data()) != QPyNullVariant: classname = indx.sibling(indx.row(),0).data() strwhere = "classname like '" + classname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.setSort(2, Qt.AscendingOrder) self.StudentModel.select() self.g_curClassName = classname self.tabWidget.setTabText(0, self.g_curClassName) def dbclick2(self, indx): if indx.column() == 2: self.StudentView.setEditTriggers(QAbstractItemView.NoEditTriggers) else: self.StudentView.setEditTriggers(QAbstractItemView.DoubleClicked) def genTwoTab(self, tabtitle=""): # Create the tab title sytle. tabtitle = QLabel() tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("班级学生信息管理") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) # Create the classnameView self.ClassnameView = QTableView() self.ClassnameModel = QSqlTableModel(self.ClassnameView) self.ClassnameModel.setTable("classtable") # self.ClassnameModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.ClassnameModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.ClassnameModel.select() self.ClassnameModel.setHeaderData(0, Qt.Horizontal, "班级名称") # for indx, iheader in enumerate(["classid", "classname"]): # self.ClassnameModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.ClassnameView.setModel(self.ClassnameModel) # self.ClassnameView.setColumnHidden(0, True) # self.ClassnameView.show() self.ClassnameView.verticalHeader().setFixedWidth(30) self.ClassnameView.verticalHeader().setStyleSheet("color: red;font-size:20px; "); self.ClassnameView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 0);}" "QTableView::item:hover {background-color: rgba(100,200,220,100);} ") self.ClassnameView.setStyleSheet("font-size:16px; "); self.ClassnameView.setSelectionMode(QAbstractItemView.SingleSelection) # self.ClassnameView.dataChanged.connect(self.dataChanged) # self.ClassnameView.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # the second list self.StudentView = QTableView() self.StudentModel = QSqlTableModel(self.StudentView) self.StudentModel.setTable("student") # self.StudentModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.StudentModel.setEditStrategy(QSqlTableModel.OnManualSubmit) # self.StudentModel.select() query = QSqlQuery(self.db) strwhere = " 1=1 " if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() firstClassName = query.value(0) strwhere += " and classname like '" + firstClassName + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() for indx, iheader in enumerate(["班级名称", "学生编号", "学生姓名", "答对次数", "答错次数"]): self.StudentModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.StudentView.setModel(self.StudentModel) self.StudentView.setColumnHidden(0, True) # query = QSqlQuery(self.db) lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) # self.StudentView.show() self.StudentView.verticalHeader().setFixedWidth(30) self.StudentView.verticalHeader().setStyleSheet("color: red;font-size:20px; background-color: rgb(250, 250, 200, 100)"); self.StudentView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 250);}" "QTableView::item:hover {background-color: rgba(10,200,100,200);} " ) self.StudentView.setStyleSheet("font-size:16px;") self.StudentView.setSelectionMode(QAbstractItemView.SingleSelection) self.StudentView.doubleClicked.connect(self.dbclick2) btn_lst1_layout = QGridLayout() newusrbtn = QPushButton("新增") savebtn = QPushButton("保存") revertbtn = QPushButton("撤销") removebtn = QPushButton("删除") btn_lst1_layout.addWidget(newusrbtn, 0, 0) btn_lst1_layout.addWidget(savebtn, 0, 1) btn_lst1_layout.addWidget(revertbtn, 1, 0) btn_lst1_layout.addWidget(removebtn, 1, 1) newusrbtn.clicked.connect(self.newClass) savebtn.clicked.connect(self.saveClass) revertbtn.clicked.connect(self.revertClass) removebtn.clicked.connect(self.removeClass) self.ClassnameView.doubleClicked.connect(self.dbclick) btnbox2 = QDialogButtonBox(Qt.Horizontal) newusrbtn2 = QPushButton("新增") savebtn2 = QPushButton("保存") revertbtn2 = QPushButton("撤销") removebtn2 = QPushButton("删除") btnbox2.addButton(newusrbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(savebtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(revertbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(removebtn2, QDialogButtonBox.ActionRole); newusrbtn2.clicked.connect(self.newStudent) savebtn2.clicked.connect(self.saveStudent) revertbtn2.clicked.connect(self.revertStudent) removebtn2.clicked.connect(self.removeStudent) # left list layout lst_layout_1 = QVBoxLayout() lst_layout_1.addWidget(self.ClassnameView) lst_layout_1.addLayout(btn_lst1_layout) lst_layout_2 = QVBoxLayout() lst_layout_2.addWidget(self.StudentView) lst_layout_2.addWidget(btnbox2) lstlayout = QHBoxLayout() lstlayout.setMargin(5) # lstlayout.addLayout(findbox) lstlayout.addLayout(lst_layout_1, 2) lstlayout.setMargin(5) lstlayout.addLayout(lst_layout_2, 5) labelClass = QLabel("") labelClass.setStyleSheet("background-color:rgba(255, 255, 255,0); color:rgba(0,0,0,0);") labelClass.setFixedHeight(40) # labelClass.setFixedWidth(100) # labelClass.setFont(QFont('宋体', 10)) bottomlayout = QHBoxLayout() bottomlayout.addWidget(labelClass) tab2layout = QVBoxLayout() tab2layout.addLayout(titleLayout) tab2layout.addLayout(lstlayout) tab2layout.addLayout(bottomlayout) self.w2.setLayout(tab2layout) self.w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def genOneTab(self): tabtitle = QLabel() # tabtitle.setFixedHeight(40) # tabtitle.setFixedWidth(160) self.btn_start = MyButton("开始") self.choicenum_text = QComboBox() self.choicenum_text.setObjectName('w1combonums') # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');") # Set the title style tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("随堂提问演板") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) btnlayout = QGridLayout() tmpnum = 0 for inum in range(0,56): irow = tmpnum // g_cols icol = tmpnum % g_cols tmpnum += 1 btnlayout.setRowMinimumHeight(irow, 80) tmpbtn = MyButton("") tmpbtn.setMyarg(None) # tmpbtn.setFixedHeight(20) tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)) tmpbtn.setStyleSheet("border: 1px solid rgb(55,55,255,100);background-color: rgba(255,255,255,20);font-size:16px;") self.connect(tmpbtn, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) tmpbtn.setAutoDefault(False) self.btngroup.addButton(tmpbtn, inum+1) # stusn is from 1 start btnlayout.addWidget(tmpbtn, irow, icol) self.btn_start.setIcon(QIcon("image/start.png")) self.btn_start.setStyleSheet("border: 1px solid yellow;") self.btn_start.setFixedHeight(40) self.btn_start.setFixedWidth(100) self.btn_start.setFont(QFont('宋体', 18)) # self.choicenum_text.setFixedHeight(45) # self.choicenum_text.setFixedWidth(60) ## Set the combox number style self.choicenum_text.setFont(QFont('Courier New', 20)) self.choicenum_text.setFixedHeight(45) self.choicenum_text.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\ border-radius: 6px; \ min-width: 2em; ") self.choicenum_text.setEditable(True) self.choicenum_text.lineEdit().setReadOnly(True); self.choicenum_text.lineEdit().setAlignment(Qt.AlignCenter); model = self.choicenum_text.model() for row in list(range(1, 7)): item = QStandardItem(str(row)) item.setTextAlignment(Qt.AlignCenter) item.setForeground(QColor('red')) item.setBackground(QColor(0,200,50, 130)) model.appendRow(item) self.choicenum_text.setCurrentIndex(2) # self.choicenum_text.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}") # self.choicenum_text.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}") bottomlayout = QHBoxLayout() bottomlayout.setSizeConstraint(QLayout.SetFixedSize) bottomlayout.addStretch(10) bottomlayout.addWidget(self.btn_start) bottomlayout.setSpacing(5) bottomlayout.addWidget(self.choicenum_text) tab1layout = QVBoxLayout() tab1layout.addLayout(titleLayout) tab1layout.addLayout(btnlayout) tab1layout.addLayout(bottomlayout) self.w1.setLayout(tab1layout) self.w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def startChoice(self, usernum="", oldbtn=""): # print(oldbtn, 1) if oldbtn == "": self.dict_choices = {} strwhere = " and classname like '" + self.g_curClassName + "'" allstudent = [] lstrecord = [] query = QSqlQuery(self.db) query.exec_("select stusn from tmprecord where 1=1 " + strwhere) while(query.next()): lstrecord.append(query.value(0)) # print(lstrecord, 'record', "select stusn from student where stusn not in " + str(tuple(lstrecord))) query.exec_("select stusn from student where stusn not in " + str(tuple(lstrecord)) + strwhere) while(query.next()): allstudent.append(query.value(0)) if usernum == "": nums = int(self.choicenum_text.currentText()) else: nums = usernum if nums >= len(allstudent): query.exec_("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today allstudent = [] query.exec_("select stusn from student where 1=1 " + strwhere) while(query.next()): allstudent.append(query.value(0)) if oldbtn == "": random.seed() lstchoices = random.sample(allstudent, nums) for ibtn in lstchoices: self.dict_choices[ibtn] = "111" self.group_animation.start() QTimer.singleShot(1200, self.stopmovie) else: random.seed() otherbtn = random.sample(allstudent, 1)[0] # self.btngroup.button(int(otherbtn)).setFocus() self.dict_choices.pop(oldbtn) self.dict_choices[otherbtn] = '111' self.stopmovie() self.btnSysMenu.setFocus() def stopmovie(self): self.group_animation.stop() for isn in self.studentSnlst: # print(isn) self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(isn[0])).setIcon(QIcon()) classname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) today = datetime.date.today() for ibtn in self.dict_choices: self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(ibtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", classname) query.bindValue(":stusn", ibtn) query.bindValue(":datequestion", today) query.exec_() def answerRight(self): # print(self.g_curbtn) value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) query = QSqlQuery(self.db) query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) + 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") ########### if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "011" def answerWrong(self): value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);") query = QSqlQuery(self.db) query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) + 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "101" def resetStudent(self): value = self.g_curbtn if value not in self.dict_choices: return query = QSqlQuery(self.db) if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.startChoice(usernum=1, oldbtn=value) # print("---reset___") # curmenu.actions()[0].setEnabled(True) # curmenu.actions()[1].setEnabled(True) # self.choiceOneStudent(value) def createDb(self): conn = sqlite3.connect("studentNew.db") cur = conn.cursor() sqlstr = 'create table student (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ stuname varchar(20), \ rightquestions integer, \ wrongquestions integer, \ FOREIGN KEY(classname) REFERENCES classtable(classname))' # print(sqlstr) sqlstr2 = 'create table tmprecord (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ datequestion date)' sqlstr3 = 'create table classtable (classname varchar(20) PRIMARY KEY)' cur.execute(sqlstr3) conn.commit() cur.execute(sqlstr2) conn.commit() cur.execute(sqlstr) conn.commit() strdelete = "delete from student where 1=1" cur.execute(strdelete) conn.commit() strdelete = "delete from tmprecord where 1=1" cur.execute(strdelete) conn.commit() # print(sqlstr2) # cur.execute(sqlstr) # conn.commit() # cur.execute(sqlstr2) # conn.commit() # insert example data strsql = "insert into classtable values (?)" cur.execute(strsql, ("三(3)班",)) conn.commit() cur.execute(strsql, ("三(4)班",)) conn.commit() a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"] a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"] strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a03lst))): cur.execute(strsql, (None, "三(3)班", str(i+1).zfill(2), a03lst[i], 0, 0)) conn.commit() strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a04lst))): cur.execute(strsql, (None, "三(4)班", str(i+1).zfill(2), a04lst[i], 0, 0)) conn.commit() cur.close()
class QDataTableView(QTableView): """ This is an actual table of waves. """ def __init__(self, model=None, title="Table", *args): """ Initialize the view. model is the DataTableModel to use. title is the window title. """ QTableView.__init__(self, *args) self._app = QApplication.instance().window if model is None: model = DataTableModel() self.setModel(model) self.setWindowTitle(title) self.setAttribute(Qt.WA_DeleteOnClose) self.setSelectionMode(QAbstractItemView.ContiguousSelection) # contiguous instead of extended so that we can easily insert/delete cells more easily. See note below. self.setEditTriggers(QAbstractItemView.AnyKeyPressed | QAbstractItemView.SelectedClicked | QAbstractItemView.DoubleClicked) self.horizontalHeader().setMovable(True) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showCellContextMenu) self.verticalHeader().setContextMenuPolicy(Qt.CustomContextMenu) self.verticalHeader().customContextMenuRequested.connect(self.showVerticalHeaderMenu) self.setupHorizontalHeaderMenu() def name(self): """Return the name of the table.""" return self.windowTitle() def renameWave(self, wave): """ Create a dialog box to rename a wave. When the dialog box is filled out and submitted, try to rename the wave. """ # Setup dialog box renameWaveDialog = QDialog(self) renameWaveUi = Ui_RenameWaveDialog() renameWaveUi.setupUi(renameWaveDialog) renameWaveUi.oldWaveName.setText(wave.name()) renameWaveDialog.setVisible(True) def saveRename(): """Save button pressed. Do work to save new name.""" newName = wave.validateWaveName(str(renameWaveUi.newWaveNameLineEdit.text())) if str(renameWaveUi.newWaveNameLineEdit.text()) == "": failedMessage = QMessageBox(renameWaveDialog) failedMessage.setText("Cannot use a blank name.") failedMessage.exec_() renameWaveDialog.setVisible(True) elif self._app.waves().goodWaveName(newName) and wave.setName(newName): renameWaveDialog.close() else: failedMessage = QMessageBox() failedMessage.setText("Unable to rename wave.") failedMessage.exec_() renameWaveDialog.setVisible(True) def cancelRename(): """Cancel button pressed.""" renameWaveDialog.close() # connect actions renameWaveUi.buttons.accepted.connect(saveRename) renameWaveUi.buttons.rejected.connect(cancelRename) def removeWave(self, visualIndex): self.model().removeColumn(visualIndex) def addWave(self, wave, visualIndex): if self.model().addColumn(wave): # The wave was added (i.e. it did not already exist in the table) # We need to move the newly added column from the end to where the user clicked self.horizontalHeader().moveSection(self.model().columnCount() - 1, visualIndex + 1) def insertCells(self): """Insert cells into waves based on selected cells in this table.""" # Sort by rows, so that we start at the top of the waves # This is the reason we only do contiguous selections, because # tracking which cells to insert into is really difficult otherwise selectedCells = self.selectedIndexes() selectedCells.sort(None, QModelIndex.row, False) # Disconnect the dataModified signal before changing anything, then connect # it after changing everything. This way, multiple calls are not emitted # in the middle, for no reason. # We create the waves list just in case the selectedCells indexes aren't valid # aftewards. waves = Util.uniqueList(map(lambda x: x.internalPointer(), selectedCells)) for wave in waves: wave.blockSignals(True) for cell in selectedCells: try: cell.internalPointer().insert(cell.row(), "") except: # The cell did not exist (i.e. the wave does not extend this far) # but another wave does, so do not fail completely pass for wave in waves: wave.blockSignals(False) wave.dataModified.emit() wave.lengthChanged.emit() def deleteCells(self): """Delete cells from waves based on selected cells in this table.""" # Sort by rows, inverted, so that we start by deleting at the # bottom of the waves, and don't screw up index values along # the way selectedCells = self.selectedIndexes() selectedCells.sort(None, QModelIndex.row, True) # Disconnect the dataModified signal before changing anything, then connect # it after changing everything. This way, multiple calls are not emitted # in the middle, for no reason. # We create the waves list just in case the selectedCells indexes aren't valid # aftewards. waves = Util.uniqueList(map(lambda x: x.internalPointer(), selectedCells)) for wave in waves: wave.blockSignals(True) for cell in selectedCells: try: cell.internalPointer().pop(cell.row()) except: # The cell did not exist (i.e. the wave does not extend this far) # but another wave does, so do not fail completely pass for wave in waves: wave.blockSignals(False) wave.dataModified.emit() wave.lengthChanged.emit() def showCellContextMenu(self, point): """Display the menu that occurs when right clicking on a table cell.""" clickedCell = self.indexAt(point) if not clickedCell.isValid(): # User clicked on a part of the table without a cell return False cellMenu = QMenu(self) insertCellAction = QAction("Insert Cells", cellMenu) deleteCellAction = QAction("Delete Cells", cellMenu) cellMenu.addAction(insertCellAction) cellMenu.addAction(deleteCellAction) # Connect signals insertCellAction.triggered.connect(self.insertCells) deleteCellAction.triggered.connect(self.deleteCells) # Display menu cellMenu.exec_(self.mapToGlobal(point)) # Disconnect signals insertCellAction.triggered.disconnect(self.insertCells) deleteCellAction.triggered.disconnect(self.deleteCells) def showVerticalHeaderMenu(self, point): """Display the menu that occurs when right clicking on a vertical header.""" rowMenu = QMenu(self) insertRowAction = QAction("Insert Rows", rowMenu) deleteRowAction = QAction("Delete Rows", rowMenu) rowMenu.addAction(insertRowAction) rowMenu.addAction(deleteRowAction) # Connect signals insertRowAction.triggered.connect(self.insertCells) deleteRowAction.triggered.connect(self.deleteCells) # Display menu rowMenu.exec_(self.mapToGlobal(point)) # Disconnect signals insertRowAction.triggered.disconnect(self.insertCells) deleteRowAction.triggered.disconnect(self.deleteCells) def setupHorizontalHeaderMenu(self): self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu) self.horizontalHeader().customContextMenuRequested.connect(self.showHorizontalHeaderMenu) self.horizontalHeaderMenu = QMenu(self.horizontalHeader()) # Create actions self.renameWaveAction = QAction("Rename Wave", self.horizontalHeaderMenu) self.removeWaveAction = QAction("Remove Wave", self.horizontalHeaderMenu) self.addWaveMenu = QMenu("Add Wave", self.horizontalHeaderMenu) # Add actions to menu self.horizontalHeaderMenu.addAction(self.addWaveMenu.menuAction()) self.horizontalHeaderMenu.addAction(self.renameWaveAction) self.horizontalHeaderMenu.addAction(self.removeWaveAction) def showHorizontalHeaderMenu(self, point): """Display the menu that occurs when right clicking on a column header.""" logicalIndex = self.horizontalHeader().logicalIndexAt(point) visualIndex = self.horizontalHeader().visualIndex(logicalIndex) self.selectColumn(logicalIndex) #print "l: " + str(logicalIndex) #print "v: " + str(visualIndex) selectedWave = self.model().waves()[logicalIndex] # Create helper functions, defined for this specific menu location def renameWaveHelper(): self.renameWave(selectedWave) def removeWaveHelper(): #self.removeWave(selectedWave) self.removeWave(visualIndex) def addWaveHelper(wave): self.addWave(wave, visualIndex) def addNewWaveHelper(): wave = Wave(self._app.waves().findGoodWaveName()) self._app.waves().addWave(wave) self.addWave(wave, visualIndex) self.addWaveMenu.clear() # Add "New Wave" entry newWaveAction = QAction("New Wave", self.addWaveMenu) self.addWaveMenu.addAction(newWaveAction) newWaveAction.triggered.connect(addNewWaveHelper) # Get current list of waves for "add wave to table" menu #for wave in self._app.waves().waves().values(): for wave in self._app.model('appWaves').waves(): waveAction = AddWaveAction(wave, self.addWaveMenu) self.addWaveMenu.addAction(waveAction) waveAction.addWaveClicked.connect(addWaveHelper) # Connect actions self.renameWaveAction.triggered.connect(renameWaveHelper) self.removeWaveAction.triggered.connect(removeWaveHelper) self.horizontalHeaderMenu.exec_(self.mapToGlobal(point)) # Disconnect actions. We need to do this or else there will be multiple connections # when we open the menu again, and the old connections will have strange visualIndex values self.renameWaveAction.triggered.disconnect(renameWaveHelper) self.removeWaveAction.triggered.disconnect(removeWaveHelper) for waveAction in self.addWaveMenu.actions(): try: waveAction.addWaveClicked.disconnect(addWaveHelper) except: waveAction.triggered.disconnect(addNewWaveHelper) def reset(self): QTableView.reset(self) self.resizeRowsToContents() self.resizeColumnsToContents() def keyPressEvent(self, event): """Capture certain types of keypress events and handle them different ways.""" # When data has been edited, move to the next row in the column and continue editing. currentIndex = self.currentIndex() #print "row: " + str(currentIndex.row()) + ", col: " + str(currentIndex.column()) if currentIndex.isValid(): if self.state() == QAbstractItemView.EditingState: if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter: Util.debug(3, "DataTableView.keyPressEvent", "Enter key pressed in table") newIndex = self.model().createIndex(currentIndex.row() + 1, currentIndex.column()) self.setCurrentIndex(newIndex) self.edit(newIndex) self.setCurrentIndex(newIndex) return elif event.key() == Qt.Key_Up: Util.debug(3, "DataTableView.keyPressEvent", "Up key pressed in table") newIndex = self.model().createIndex(currentIndex.row() - 1, currentIndex.column()) #print "nrow: " + str(newIndex.row()) + ", ncol: " + str(newIndex.column()) #self.setCurrentIndex(newIndex) self.setState(QAbstractItemView.NoState) elif event.key() == Qt.Key_Down: Util.debug(3, "DataTableView.keyPressEvent", "Down key pressed in table") newIndex = self.model().createIndex(currentIndex.row() + 1, currentIndex.column()) #print "nrow: " + str(newIndex.row()) + ", ncol: " + str(newIndex.column()) #self.setCurrentIndex(newIndex) self.setState(QAbstractItemView.NoState) # Nothing found, so resort to default behavior QTableView.keyPressEvent(self, event)
class Dummy: instance = None def __init__(self, iface): from createunbeffl import application as createunbeffl from importdyna import application as importdyna from exportdyna import application as exportdyna from linkflaechen import application as linkflaechen from tools import application as tools self.plugins = [ createunbeffl.CreateUnbefFl(iface), importdyna.ImportFromDyna(iface), exportdyna.ExportToKP(iface), linkflaechen.LinkFl(iface), tools.QKanTools(iface) ] Dummy.instance = self # Plugins self.instances = [] # QGIS self.iface = iface self.plugin_dir = os.path.dirname(__file__) self.actions = [] actions = self.iface.mainWindow().menuBar().actions() self.menu = None for menu in actions: if menu.text() == 'QKan': self.menu = menu.menu() self.menu_action = menu break self.toolbar = self.iface.addToolBar('QKan') self.toolbar.setObjectName('QKan') def initGui(self): # Create and insert QKan menu after the 3rd menu if self.menu is None: self.menu = QMenu('QKan', self.iface.mainWindow().menuBar()) actions = self.iface.mainWindow().menuBar().actions() prepend = actions[3] self.menu_action = self.iface.mainWindow().menuBar().insertMenu(prepend, self.menu) # Calls initGui on all known QKan plugins for plugin in self.plugins: plugin.initGui() self.sort_actions() def sort_actions(self): # Finally sort all actions self.actions.sort(key=lambda x: x.text().lower()) self.menu.clear() self.menu.addActions(self.actions) def unload(self): from qgis.utils import unloadPlugin # Unload all other instances for instance in self.instances: print('Unloading ', instance.name) if not unloadPlugin(instance.name): print('Failed to unload plugin!') # Remove entries from own menu for action in self.menu.actions(): self.menu.removeAction(action) # Remove entries from Plugin menu and toolbar for action in self.actions: self.iface.removeToolBarIcon(action) # Remove the toolbar del self.toolbar # Remove menu self.iface.mainWindow().menuBar().removeAction(self.menu_action) # Call unload on all loaded plugins for plugin in self.plugins: plugin.unload() def register(self, instance): self.instances.append(instance) self.plugins += instance.plugins def unregister(self, instance): self.instances.remove(instance) for plugin in instance.plugins: self.plugins.remove(plugin) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.__actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.menu.addAction(action) self.actions.append(action) return action
class CFSceneContextMenuMixin: " Encapsulates the context menu handling " def __init__(self): self.menu = None self.individualMenus = {} # Scene menu preparation self.sceneMenu = QMenu() self.sceneMenu.addAction(getIcon("filesvg.png"), "Save as SVG...", self.parent().onSaveAsSVG) self.sceneMenu.addAction(getIcon("filepdf.png"), "Save as PDF...", self.parent().onSaveAsPDF) self.sceneMenu.addAction(getIcon("filepixmap.png"), "Save as PNG...", self.parent().onSaveAsPNG) self.sceneMenu.addSeparator() self.sceneMenu.addAction(getIcon("copymenu.png"), "Copy to clipboard", self.parent().copyToClipboard) # Common menu for all the individually selected items self.commonMenu = QMenu() # self.commonMenu.addAction( # getIcon( "cutmenu.png" ), "Cut (Ctrl+X)", self.onCut ) # self.commonMenu.addAction( # getIcon( "copymenu.png" ), "Copy (Ctrl+C)", self.onCopy ) # self.commonMenu.addSeparator() # self.commonMenu.addAction( # getIcon( "trash.png" ), "Delete (Del)", self.onDelete ) # Non-comment common menu for the individually selected items self.nonCommentCommonMenu = QMenu() # self.nonCommentCommonMenu.addAction( # getIcon( "customcolors.png" ), "Custom colors...", # self.onCustomColors ) # self.nonCommentCommonMenu.addAction( # getIcon( "replacetitle.png" ), "Replace text...", # self.onReplaceText ) # Individual items specific menu: begin ifContextMenu = QMenu() ifContextMenu.addAction(getIcon("switchbranches.png"), "Switch branch layout", self.onSwitchIfBranch) self.individualMenus[IfCell] = ifContextMenu # Individual items specific menu: end # Menu for a group of selected items self.groupMenu = QMenu() # self.groupMenu.addAction( # getIcon( "cfgroup.png" ), "Group...", # self.onGroup ) # self.groupMenu.addAction( # getIcon( "customcolors.png" ), "Custom colors...", # self.onCustomColors ) # self.groupMenu.addSeparator() # self.groupMenu.addAction( # getIcon( "trash.png" ), "Delete (Del)", self.onDelete ) return def onContextMenu(self, event): " Triggered when a context menu should be shown " selectedItems = self.selectedItems() selectionCount = len(selectedItems) if selectionCount == 0: self.sceneMenu.popup(event.screenPos()) return if selectionCount == 1: self.__buildIndividualMenu(selectedItems[0]) else: self.__buildGroupMenu(selectedItems) self.menu.popup(event.screenPos()) return def __buildIndividualMenu(self, item): " Builds a context menu for the given item " self.menu = QMenu() if type(item) in self.individualMenus: individualPart = self.individualMenus[type(item)] self.menu.addActions(individualPart.actions()) self.menu.addSeparator() if not item.isComment(): self.menu.addActions(self.nonCommentCommonMenu.actions()) self.menu.addSeparator() self.menu.addActions(self.commonMenu.actions()) # Note: if certain items need to be disabled then it should be done # here return def __buildGroupMenu(self, items): " Builds a context menu for the group of items " self.menu = QMenu() self.menu.addActions(self.groupMenu.actions()) # Note: if certain items need to be disabled then it should be done # here return def onSwitchIfBranch(self): " If primitive should switch the branches " selectedItems = self.selectedItems() for item in selectedItems: if item.kind == CellElement.IF: item.switchBranches() return def onCustomColors(self): " Custom background and foreground colors " print "Custom colors" def onReplaceText(self): " Replace the code with a title " print "Replace title" def onDelete(self): " Delete the item " print "Delete" def onGroup(self): " Groups items into a single one " print "Group" def onCopy(self): print "Copy" def onCut(self): print "Cut"
class MSMainWindow(QMainWindow): """Gui of the main window""" # MAX_RECENT_FILES = 10 # start putting links spyder numpy scipy et tutti quanti links = ( "http://numpy.scipy.org/", "http://packages.python.org/spyder/", "http://www.riverbankcomputing.co.uk/software/pyqt/intro", ) pluginPath = path.normcase("pluginmanager/plugins/") def __init__(self, availablePlugins): """ Constructor with all the models needed setup menus """ QMainWindow.__init__(self) self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) self.plugins = availablePlugins self.pluginsInst = [] settings = QSettings( "INRA/INSA", "-".join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR]) ) self.recentFiles = list(settings.value("RecentFiles").toStringList()) self.setStyleSheet(stylesheet) self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self) self.addToolBar(0x1, self.pipeline) self._setupModels() self._setupUi() self._setupMenus() def _setupModels(self): """ Warning:Causes segfault when horizontal labels set to True on aura peu etre a la fin un model par sampleList c'est ce qui parait le plus logique """ # drag and drop table sample self.sampleModel = QStandardItemModel(self) self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"]) # treeView1 self.spectraModel = QStandardItemModel(self) # treeview2 self.peakModel = QStandardItemModel(self) # treeview3 self.clusterModel = QStandardItemModel(self) def _setupMenus(self): # file self.fileMenu = QMenu("&File") self.fileMenu.setTearOffEnabled(True) self.op = QMenu("&Open...", self.fileMenu) self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png"))) open_ = QAction("&Open rawfiles", self) open_.setToolTip("Open an mzXML or netCDF file") open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) open_icon = QIcon(path.normcase("gui/icons/fileopen.png")) open_.setIcon(open_icon) self.op.addAction(open_) load_ = QAction("&Open projects...", self) load_.setToolTip("load binary file containing saved objects") load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) load_icon = QIcon(QPixmap(path.normcase("gui/icons/project_open.png"))) load_.setIcon(load_icon) self.op.addAction(load_) self.fileMenu.addMenu(self.op) save_ = QAction("&Save...", self) save_.setToolTip("save the actual application model") save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) save_icon = QIcon(path.normcase("gui/icons/save_all.png")) save_.setIcon(save_icon) self.fileMenu.addAction(save_) pkl = QAction("&load a peaklist", self) # TODO:load peaklist pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P)) pkl.setToolTip("load a peaklist and process it") pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png"))) self.fileMenu.addAction(pkl) convert_ = QAction("&Convert...", self) convert_.setEnabled(False) convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed") convert_icon = QIcon(path.normcase("gui/icons/goto.png")) convert_.setIcon(convert_icon) self.fileMenu.addAction(convert_) a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch") a.setEnabled(False) b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge") b.setToolTip("Merge MRM file") # b.setEnabled(False) self.fileMenu.addSeparator() # # for i in xrange(self.MAX_RECENT_FILES): # a = QAction('', self) # a.setVisible(False) # self.fileMenu.addAction(a) # # for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))): # self.fileMenu.actions()[5+i].setVisible(True) # self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1]) exit_action = QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) exit_action.setIcon(QIcon(QPixmap(path.normcase("gui/icons/exit.png")))) self.fileMenu.addAction(exit_action) self.menuBar().addMenu(self.fileMenu) self.editMenu = QMenu("&Edit") self.editMenu.setTearOffEnabled(True) self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_undo.png")), "&Undo...") self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_redo.png")), "&Redo...") self.editMenu.actions()[0].setEnabled(False) self.editMenu.actions()[1].setEnabled(False) self.editMenu.addSeparator() self.editMenu.addAction(QIcon(path.normcase("gui/icons/run.png")), "&Preferences") self.exportMenu = QMenu("&Export...") self.exportMenu.setIcon(QIcon(path.normcase("gui/icons/file_export.png"))) self.exportMenu.addAction("&Peaklist") self.exportMenu.addAction("&Clusters intensity matrix") self.editMenu.addMenu(self.exportMenu) self.menuBar().addMenu(self.editMenu) # view self.viewMenu = QMenu("&View") self.viewMenu.setTearOffEnabled(True) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/window_duplicate")), "&Cascade View", self.mdiArea.cascadeSubWindows, QKeySequence(Qt.CTRL + Qt.Key_K), ) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/view_icon")), "&Title View", self.mdiArea.tileSubWindows, QKeySequence(Qt.CTRL + Qt.Key_N), ) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/stop_process.png")), "&Close all subWindows", self.mdiArea.closeAllSubWindows, QKeySequence(Qt.CTRL + Qt.Key_W), ) self.plotting = QMenu("&Plotting...") self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png")))) self.plotting.addAction("&3D Plot") # self.plotting.addAction("&Cytoscape web") self.plotting.addAction("&Spectrogram Plot") # self.multiplePlot = QAction("&Visualize Raw/Treated Data", self) # self.multiplePlot.setCheckable(True) # self.multiplePlot.setEnabled(False) # self.sub_plot_.addAction(self.multiplePlot) self.viewMenu.addMenu(self.plotting) self.viewMenu.addSeparator() self.show_hide = QMenu("&Show/Hide") m = self.createPopupMenu() m.setTitle("&Show/Hide") self.viewMenu.addMenu(m) # self.pref = QMenu("&Preferences") # self.pref.addAction(self.multiplePlot) # self.viewMenu.addMenu(self.pref) self.menuBar().addMenu(self.viewMenu) # algorithm self.algoMenu = QMenu("&Algorithm") self.algoMenu.setTearOffEnabled(True) self.preProcessing = QMenu("&PreProcessing(experimental)") self.preProcessing.addAction("&Smoothing raw data...") self.preProcessing.addAction("&Cut off raw data...") self.preProcessing.addAction("&Calibration (mz dimension)") self.preProcessing.addAction("&Resize sample...") self.algoMenu.addMenu(self.preProcessing) self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self) self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png"))) matched = QAction("&MatchedFiltered", self) matched.setIcon(QIcon(path.normcase("gui/icons/RLogo"))) matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm") self.peakPickingMenu.addAction(matched) centwave = QAction("&CentWave", self) centwave.setIcon(QIcon(path.normcase("gui/icons/RLogo"))) centwave.setToolTip("Peak Detection and Integration using CentWave algorithm") self.peakPickingMenu.addAction(centwave) # peak_.setShortcut(.QKeySequence(CTRL + Key_P)) # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png"))) # peak_.setIcon(peak_icon) self.algoMenu.addMenu(self.peakPickingMenu) self.alignment = QMenu("&Alignment") self.alignment.setIcon(QIcon(path.normcase("gui/icons/format_indent_more.png"))) self.alignment.addAction("&Polynomial fitting(exp)") self.alignment.addAction("&DynamicTimeWarping") self.alignment.addAction("&ObiWarp") self.alignment.actions()[2].setEnabled(False) self.algoMenu.addMenu(self.alignment) self.algoMenu.addAction("Normalization") clust_ = QAction("&Clustering", self) clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L)) clust_icon = QIcon(QPixmap(path.normcase("gui/icons/cluster.png"))) clust_.setIcon(clust_icon) self.algoMenu.addAction(clust_) id_ = QAction("&Identification", self) id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I)) id_.setToolTip("Try to identify peaks with several methods") id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png")))) self.algoMenu.addAction(id_) self.menuBar().addMenu(self.algoMenu) # tools self.toolsMenu = QMenu("&Tools") self.toolsMenu.setTearOffEnabled(True) web = QAction("&Web Browser", self) web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png")))) self.toolsMenu.addAction(web) # cyto = QAction("&cytoscape", self) # cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg"))) # cyto.setIcon(cyto_icon) # self.toolsMenu.addAction(cyto) editor = QAction("&Editor", self) editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png")))) self.toolsMenu.addAction(editor) pet = QAction("&Short Periodic Table", self) pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg")))) self.toolsMenu.addAction(pet) self.menuBar().addMenu(self.toolsMenu) # plugins self.pluginMenu = QMenu("&Plugins") self.pluginMenu.setTearOffEnabled(True) instPl = QAction("&Install a plugin", self) instPl.setIcon(QIcon(path.normcase("gui/icons/pluginInstall.png"))) self.pluginMenu.addAction(instPl) self.launchingMenu = QMenu("&Launch PLugins", self) self.launchingMenu.setIcon(QIcon(path.normcase("gui/icons/plugin"))) for plug in self.plugins: # fullname="".join([self.pluginPath, str(plug)]) mod = imp.load_source(self.__module__, plug) if mod.autoActivation: qApp = QApplication.instance() name = getattr(mod, "className") cls = getattr(mod, name) p = cls(qApp.model, self, parent=self) # p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1]) self.pluginsInst.append(p) else: self.launchingMenu.addAction(plug.split("/")[-1]) self.pluginMenu.addMenu(self.launchingMenu) self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin") self.menuBar().addMenu(self.pluginMenu) # about self.aboutMenu = QMenu("&About") self.aboutMenu.setTearOffEnabled(True) metms = QAction(QIcon(path.normcase("gui/icons/deluge.png")), "&about metMS...", self) self.aboutMenu.addAction(metms) pyqt = QAction("&about PyQt4...", self) pyqt_icon = QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png"))) pyqt.setIcon(pyqt_icon) self.aboutMenu.addAction(pyqt) metms = QAction("&metMS Documentation", self) metms_icon = QIcon(QPixmap(path.normcase("gui/icons/deluge.png"))) metms.setIcon(metms_icon) self.aboutMenu.addAction(metms) self.menuBar().addMenu(self.aboutMenu) def _setupUi(self, background=None): """ Make the GUI """ # mdi self.mdiArea = MSMdiArea(self) self.mdiArea.setBackground(QBrush(QPixmap(path.normcase("gui/icons/blac2.png")))) # QColor(Qt.blue).darker())) self.setCentralWidget(self.mdiArea) # sample dock widget self.sampleDockWidget = QDockWidget("Samples", self) # sampleWidget = QWidget() self.sampleTableView = MSDragFromTableView() self.sampleTableView.setModel(self.sampleModel) self.sampleTableView.setSelectionBehavior(1) self.sampleTableView.verticalHeader().hide() self.sampleTableView.verticalHeader().setDefaultSectionSize(15) self.sampleTableView.horizontalHeader().setDefaultSectionSize(150) self.sampleDockWidget.setWidget(self.sampleTableView) # sampleWidget) self.sampleDockWidget.visible = True # workflow dock self.workflowDockWidget = QDockWidget("Visualizer", self) self.workflowDockWidget.visible = True a = QWidget(self) v = QVBoxLayout(a) q = QToolBar() # self.workingSample = QLabel("Working Sample:None") # q.addWidget(self.workingSample) q.addWidget(QLabel("ppm :")) self.ppmEditer = QDoubleSpinBox() self.usePpm = QCheckBox("use ?") q.addWidget(self.ppmEditer) q.addWidget(self.usePpm) q.addSeparator() self.removeButton = QToolButton(self) self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png"))) q.addWidget(self.removeButton) self.markAsGood = QAction(QIcon(path.normcase("gui/icons/button_ok.png")), "mark peak as good", self) self.markAsBad = QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self) self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self) q.addAction(self.markAsGood) q.addAction(self.markAsBad) q.addAction(self.hideItem) v.addWidget(q) self.tabWidget = QTabWidget() self.tab = QWidget() verticalLayout = QVBoxLayout(self.tab) self.treeView = MSToDropTableView() self.treeView.verticalHeader().setDefaultSectionSize(20) self.treeView.setModel(self.spectraModel) self.spectraLabel = QLabel("Sample: None") verticalLayout.addWidget(self.treeView) verticalLayout.addWidget(self.spectraLabel) self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")), "Spectra") self.tab_2 = QWidget() verticalLayout_4 = QVBoxLayout(self.tab_2) self.treeView_2 = MSToDropTableView() # MSTreeView(self.tab_2)# QTableView(self)# self.treeView_2.verticalHeader().setDefaultSectionSize(20) self.treeView_2.setModel(self.peakModel) self.peakLabel = QLabel("Sample: None") verticalLayout_4.addWidget(self.treeView_2) verticalLayout_4.addWidget(self.peakLabel) self.tabWidget.addTab(self.tab_2, QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List") self.tab_3 = QWidget() verticalLayout_5 = QVBoxLayout(self.tab_3) self.treeView_3 = MSToDropTreeView() self.treeView_3.setAnimated(True) self.treeView_3.setModel(self.clusterModel) self.clusterLabel = QLabel("Sample: None") verticalLayout_5.addWidget(self.treeView_3) verticalLayout_5.addWidget(self.clusterLabel) self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters") self.tabWidget.setCurrentIndex(0) for l in (self.spectraLabel, self.peakLabel, self.clusterLabel): l.setAutoFillBackground(True) v.addWidget(self.tabWidget) self.workflowDockWidget.setWidget(a) self.addDockWidget(Qt.DockWidgetArea(0x2), self.workflowDockWidget) from gui.MetBaseGui import MSIsoCalculator self.isoCalc = MSIsoCalculator(self) self.isoCalcDockWidget = QDockWidget("isotopes calculation", self) self.isoCalcDockWidget.setWidget(self.isoCalc) self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget) self.isoCalcDockWidget.setVisible(False) self.isoCalcDockWidget.visible = False from gui.MetBaseGui import FormulaGenerator self.generator = FormulaGenerator(self) self.generatorDockWidget = QDockWidget("formula generator", self) self.generatorDockWidget.setWidget(self.generator) self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget) self.generatorDockWidget.setVisible(False) self.generatorDockWidget.visible = False self.compoundTreeView = MSCompoundTreeView(self) self.compoundDockWidget = QDockWidget("Compounds", self) self.compoundDockWidget.setWidget(self.compoundTreeView) self.addDockWidget(Qt.DockWidgetArea(0x2), self.compoundDockWidget) self.compoundDockWidget.setVisible(False) self.compoundDockWidget.visible = False self.comparativeTableView = QTableView(self) self.comparativeTableView.horizontalHeader().setStretchLastSection(True) self.comparativeTableView.verticalHeader().setDefaultSectionSize(20) self.comparativeDock = QDockWidget("Comparative View", self) self.comparativeDock.setWidget(self.comparativeTableView) self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock) self.comparativeDock.setVisible(False) self.comparativeDock.visible = False self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget) self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget) self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget) # set the end # WARNING: possible that the internal shell widget cause random segfault # with the error of QObject::killTimers...? not sure ! self.shell = QWidget() # InternalShell(namespace={'metms': QApplication.instance()}, # parent=self, # multithreaded=False) self.shellDock = QDockWidget("Python Shell", self) self.shellDock.setWindowIcon(QIcon(path.normcase("gui/icons/stop.png"))) self.shellDock.setWidget(self.shell) self.shellDock.setMinimumWidth(255) self.shellDock.visible = True self.addDockWidget(0x2, self.shellDock) self.addDockWidget(0x2, self.sampleDockWidget) self.tabifyDockWidget(self.shellDock, self.sampleDockWidget) self.pb = QProgressBar(self) self.pb.setMaximumWidth(245) self.stopProcess = QToolButton(self) self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png"))) m = QMenu() # self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName) self.stopProcess.setMenu(m) self.stopProcess.setPopupMode(1) # Menu Button # self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread) self.statusBar().addPermanentWidget(self.stopProcess) self.statusBar().addPermanentWidget(self.pb) def updateStopProcessMenu(self): """ update the menu of the stop process button, based directly on the processes stored by the task manager """ self.stopProcess.menu().clear() for c in QApplication.instance().taskManager: self.stopProcess.menu().addAction(c.title) # QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1]) def addMdiSubWindow(self, plot, title="", showMaximized=False): """ Allow addition of new window in the mdiarea """ win = self.mdiArea.addSubWindow(plot) # print "widget parent", plot.parent() win.setAttribute(Qt.WA_DeleteOnClose) # win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy) # plot.setParent(win) win.setWindowTitle(title) if showMaximized: win.showMaximized() else: win.resize(400, 300) win.show() return win def updateTreeView(self): """ Tree View update switch spectre/chromato """ if self.treeView.model() == self.spectraModel: self.treeView.setModel(self.chromaModel) self.tabWidget.setTabText(0, "Chroma") else: self.treeView.setModel(self.spectraModel) # self.treeView.setSelectionMode(1) self.tabWidget.setTabText(0, "Spectra") def addTreeViewModel(self, model1, model2): """Add a model """ self.chromaModel.appendRow(model1) self.spectraModel.appendRow(model2) def _actionHovered(self, action): """emulate tooltip cause they do not work that much""" tip = action.toolTip() QToolTip.showText(QCursor.pos(), tip) def showErrorMessage(self, title, string): QMessageBox.critical(self, title, string, 0, 0) def showWarningMessage(self, title, string): return QMessageBox.warning(self, title, string, QMessageBox.Ok | QMessageBox.Cancel) def showInformationMessage(self, title, string): QMessageBox.information(self, title, string, 0) def updateProgressBar(self, i): """update the value of the progress bar for all the treatment""" self.pb.setValue(min(i, 100)) def to_indetermined_mode(self): self.pb.setMaximum(0) def to_determined_mode(self): self.pb.setMaximum(100) def showInStatusBar(self, string, time=5000): self.statusBar().showMessage(string, time) def addInterpreterDock(self, shell): self.shellDock = QDockWidget(self) self.shellDock.setWidget(shell) self.shellDock.setWindowTitle("shell") self.addDockWidget(0x2, self.shellDock) def showMetMSInformation(self): QMessageBox.about( self, self.tr("About %1").arg("metMS"), self.tr( """<b>%1 %2</b> <br>metabolite Mass Spectrometry <p>Copyright © 2010 Marco INSA, INRA <br>Licensed under the terms of the CeciLL License <p>Developed and maintained by Marco <br>Bug reports and feature requests: <a href="http://github.com/jerkos/metms">metMS site</a><br> Discussions around the project: <a href="http://groups.google.com/group/spyderlib">Google Group</a> <p>This project is part of the BRIDGE project <p>Python %3, Qt %4, PyQt %5""" ) .arg("metMS") .arg(__version__) .arg(platform.python_version()) .arg(QT_VERSION_STR) .arg(PYQT_VERSION_STR), )
class MSQtCanvas(QWidget, MSDialogController): """ DONE:the current peak is not updated while the user press up and down key on the treeView TODO: think about a mjor redesign of those classes """ #linePlotted = pyqtSignal(object, str) #lineRemoved = pyqtSignal(object) def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data=data self.title=title self.flags=flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx=self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k)#parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01)#antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems=[]#why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data)#initial plotting def getMax(self): localXmin =[] localXmax = [] localYmax = [] for el in self.data: if el is None: continue localXmin.append(min_f(el.x_data)) localXmax.append(max_f(el.x_data)) localYmax.append(max_l(el.y_data)) return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l(np.array(localYmax)) def _plotting(self, data): """ refactor this shit c = Line(chrom.x_data, chrom.y_data, QColor.fromRgbF(*(self.ref.sample.color+(.7,))), parent=self.pw.plotItem.vb, scene=self.pw.scene()) #test scatter plot self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) self.pw.addDataItem(self.scatter) self.scatter.sigClicked.connect(self.requestSpectra) """ if self.flags == 'peak': self.connect(self.pw.plotItem.vb, SIGNAL('showDiffOrSpectra(PyQt_PyObject)'), self.drawSpectra) self.ref = sorted([e for e in data if e is not None], key=lambda x:x.height)[-1] ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) #show labels self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data) #drawing color = QColor.fromRgbF(*self.ref.sample.color +(.5, )) c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color) self.drawnItems[self.ref.sample] = c # peak's pixmap on the ref peak pix= PeakArrowItem(self.ref, pen=color, brush=color, pos=(self.ref.rt, self.ref.height + (self.ref.height * 6) / 100.), angle=-90, parent=self.pw.plotItem.vb) pix.setZValue(1000) self.pw.addItem(pix) #both these connections are emitted #in peak Indicator by effictivamente qApp self.connect(qApp.instance(), SIGNAL("highlightRequested"), c.setHighlighted) self.connect(qApp.instance(), SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) # self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName()) #if qApp.instance().lowMemory: # chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \ # for el in data if el != ref and el is not None] #else: ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \ for el in data if el is not None and el != self.ref] self.drawEics(chromatograms) #initialisation zoom on the peak self.pw.setYRange(0., self.ref.height + (self.ref.height * 12) / 100.) self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20) elif self.flags == 'chroma': ref = [d for d in data if d is not None] if not ref: print "Error, empty data to plot" return self.ref = ref[0] self.textLabels+=self.showTextLabel(self.ref.x_data, self.ref.y_data) self.drawEics(data) else:#spectrum if not data: #print "NOTHING TO PLOT" return self.ref = data[0] for el in data: c=SpectrumItem(el, centroid=True, scene=self.pw.scene()) self.pw.addItem(c) self.drawnItems[el.sample] = c self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), el.sample.shortName()) #just put time information if data: i=0 while data[i] is None and i < len(data): i+=1 self.textLabels+=self.showTextLabel(data[i].x_data, data[i].y_data) #setting the range #warning: autoRange pw function does not work well #on spectrum item maxY = max([el.y_data.max() for el in data]) minX, maxX = min([el.x_data.min() for el in data]), max([el.x_data.max() for el in data]) self.pw.setXRange(minX, maxX, padding=0) self.pw.setYRange(0., maxY, padding=0) def drawEics(self, data): for chrom in data: color = QColor.fromRgbF(*(chrom.sample.color+(.5,))) c=self.pw.plotItem.plot(x=chrom.x_data, y=chrom.y_data, pen=color) #c = Line(chrom.x_data, chrom.y_data, # color, # parent=self.pw.plotItem.vb, # scene=self.pw.scene()) self.drawnItems[chrom.sample] = c #self.pw.addItem(c) #self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), chrom.sample.shortName()) if self.flags != 'peaks': self.pw.autoRange() #=========================================================================== # UI stuffs #=========================================================================== def _setupUi (self): # self.stop = QToolButton() # self.stop.setIcon(QIcon('gui/icons/tools_wizard.png')) # self.stop.setToolTip('Enable or disable the appearance of the contextMenu') layout=QVBoxLayout(self) self.smoothButton=QToolButton() #self.smoothButton.setToolButtonStyle(2) self.smoothButton.setPopupMode(2) self.smoothButton.setToolTip("Smooth the visualized data") #self.smoothButton.setText("Smooth...") self.smoothButton.setIcon(QIcon(os.path.normcase('gui/icons/smooth.png'))) self.smoothMenu = QMenu() self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'), self.smooth) self.smoothButton.setMenu(self.smoothMenu) self.pw.plotItem.toolBar.addWidget(self.smoothButton) self.flipButton=QToolButton() #self.flipButton.setToolButtonStyle(2) self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png'))) self.flipButton.setToolTip("Flip the visualized data") #self.flipButton.setText("Flip...") self.flipButton.setPopupMode(2) self.flipMenu = QMenu() self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip) self.flipButton.setMenu(self.flipMenu) self.pw.plotItem.toolBar.addWidget(self.flipButton) self.annotButton=QToolButton() #self.annotButton.setToolButtonStyle(2) self.annotButton.setPopupMode(2) #self.annotButton.setText("&Annotate...") self.annotButton.setIcon(QIcon(os.path.normcase('gui/icons/attach.png'))) self.annotMenu = QMenu() self.annotMenu.addAction("&Add Annotation") self.annotMenu.addAction("&Remove last Annotation") self.annotMenu.addAction("&Remove All Annotation") self.annotButton.setMenu(self.annotMenu) self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"), self.annotate) self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"), self.removeLastAnnot) self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"), self.removeAllAnnot) self.pw.plotItem.toolBar.addWidget(self.annotButton) self.addPlotButton=QToolButton() #self.addPlotButton.setToolButtonStyle(2) self.addPlotButton.setText("Add...") self.addPlotButton.setIcon(QIcon(os.path.normcase('gui/icons/list_add.png'))) self.addPlotButton.setToolTip("Add a new plot to the current figure") #self.addPlotButton.setText('&Add Plot') self.pw.plotItem.toolBar.addWidget(self.addPlotButton) self.showSpectra=QToolButton() self.showSpectra.setPopupMode(2) #instant popup #self.showSpectra.setToolButtonStyle(2) self.showSpectra.setIcon(QIcon(os.path.normcase('gui/icons/file_export.png'))) #self.showSpectra.setText('&Show /hide...') self.showSpectra.setToolTip('Show/hide ...') self.showMenu=QMenu() self.showTextLabels=QAction("&Show Labels", self.showMenu) self.showTextLabels.setCheckable(True) self.showTextLabels.setChecked(True) self.showMenu.addAction(self.showTextLabels) self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'), self.setTextLabelsVisibility) showSpectrum=QAction("&Merged Spectrum", self.showMenu) showSpectrum.setCheckable(True) if self.flags == 'chroma' or self.flags == 'spectra': showSpectrum.setEnabled(False) self.showMenu.addAction(showSpectrum) self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'), self.drawSpectraRequested) showNonXCMSPeak=QAction("&Show Non XCMS Peak", self.showMenu) showNonXCMSPeak.setCheckable(True) if self.flags == 'spectra': showNonXCMSPeak.setEnabled(False) self.showMenu.addAction(showNonXCMSPeak) self.connect(self.showMenu.actions()[2], SIGNAL('toggled(bool)'), self.setPixmapVisibility) showDataPoints = QAction("&Show DataPoints", self.showMenu) showDataPoints.setCheckable(True) showDataPoints.setChecked(False) self.showMenu.addAction(showDataPoints) self.connect(self.showMenu.actions()[3], SIGNAL('toggled(bool)'), self.setDataPointsVisibility) self.showSpectra.setMenu(self.showMenu) self.pw.plotItem.toolBar.addWidget(self.showSpectra) self.saveToPng = QToolButton() self.saveToPng.setIcon(QIcon(os.path.normcase('gui/icons/thumbnail.png'))) #self.saveToPng.setToolButtonStyle(2) #self.saveToPng.setText("Save to Png...") self.pw.plotItem.toolBar.addWidget(self.saveToPng) self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage) #add bar plot even if we are plotting chroma #cause we can find non xcms peaks self.barPlot = BarPlot(scene=self.pw.sceneObj) #self.barPlot.rotate(-90.) if self.flags == 'peak': self.barPlot.setPeakGroup(self.data) #TODO modify to get this close to us #on the left part xpos = self.barPlot.scene().width()*3.5#-bwidth; ypos = self.barPlot.scene().height()*1.1 self.barPlot.setPos(xpos,ypos) self.barPlot.setZValue(1000) layout.addWidget(self.pw) layout.addWidget(self.pw.plotItem.toolBar) def showTextLabel(self, x, y, secure=25): """ add labels of principle peaks of spectrum or chroma on the plot, return the labels, that we can show hide """ maxis=[]#will contain tuple(rt, intens) indexes=[] #from core.MetObjects import MSAbstractTypes from scipy.ndimage import gaussian_filter1d as gauss z=gauss(y, 1) #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8) i=0 while i <len(z)-1: while z[i+1] >= z[i] and i < len(y)-2: i+=1 maxis.append((x[i], y[i])) indexes.append(i) while z[i+1] <= z[i] and i<len(z)-2: i+=1 i+=1 labels=[] for t in sorted(maxis, key=lambda x:x[1])[-5:]: g=QGraphicsTextItem(str(t[0])) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) font=QApplication.font() font.setPointSizeF(6.5) g.setFont(font) g.setDefaultTextColor(Qt.black) g.setPos(t[0], t[1]) labels.append(g) self.pw.addItem(g) return labels #=============================================================================== #SLOTS #=============================================================================== def redrawAll(self, value): self.pw.clear() self._plotting(self.data) def disHighlightOne(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(False) except KeyError: pass def highlight(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(True) except KeyError: pass #print "sample not found" self.pw.plotItem.update()#works def disHighlight(self): for key in self.drawnItems.iterkeys(): self.drawnItems[key].setHighlighted(False) self.pw.plotItem.update() def setTextLabelsVisibility(self, bool_): for t in self.textLabels: t.setVisible(bool_) def setDataPointsVisibility(self, b): if self.dataPoints is None: if self.flags == 'peak': chrom = self.ref.sample.massExtraction(self.ref.mass(), self.ref.sample.ppm, asChromatogram=True) self.dataPoints = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) else: self.dataPoints = ScatterPlotItem(x=self.ref.x_data, y=self.ref.y_data) if self.flags != 'spectra': self.dataPoints.sigClicked.connect(self.requestSpectra) self.pw.addDataItem(self.dataPoints) self.dataPoints.setVisible(b) def setPixmapVisibility(self, bool_): """ draw other peaks than the xcms peak """ if not self.pixmaps and bool_: ppm = 1. if self.ref.sample.kind=='MRM' else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \ if self.flags == 'peak' else self.ref chrom.findNonXCMSPeaks() for p in chrom.peaks.ipeaks(): if self.flags == 'peak': diff=(p.height*10)/100 if abs(p.height-self.ref.height) < diff: continue #we assume that they are the same peaks pix=PeakIndicator(p, icon='flags') #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted) self.connect(pix, SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) pix.setPos(p.rt, p.height + (p.height * 10) / 100.) pix.setZValue(1000) self.pixmaps.append(pix) self.pw.addItem(pix) if self.pixmaps: for t in self.pixmaps: t.setVisible(bool_) @pyqtSlot() def updateCurrentPeak(self): idx=self.acTree.selectedIndexes()[0] s=self.model.sample(idx.parent().data().toString(), fullNameEntry=False) if s is not None: self.currentPeak=s.peakAt(*map(float, idx.data().toString().split('/'))) def requestSpectra(self, scatter, l): """ idea plot all spectra between a time range and not only with only one spectra """ if not l: return ref = l[0] self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample) @pyqtSlot() def drawSpectraRequested(self, bool_): """ i think this is for plotting merged spectrum """ if bool_: self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak) else: self.hideRequested() def drawSpectra(self, l): self.emit(SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), l[0], l[1], self.ref.sample) @pyqtSlot() def hideRequested(self): self.emit(SIGNAL('hideRequested')) self.showMenu.actions()[1].setChecked(False) @pyqtSlot() def redraw(self): """ this is for updating the view port when hiding or not samples """ chromas =[] for spl in self.model: if spl.checked: if spl in self.drawnItems.keys(): self.drawnItems[spl].setVisible(True) else: chromas.append(spl.chroma[0]) else: self.drawnItems[spl].setVisible(False) self._plotting(chromas) self.pw.plotItem.update()#works def cleanScene(self): """ remove all items in the trash """ for element in self.trashItems: self.pw.sceneObj.removeItem(element) @pyqtSlot() def updateContextMenu(self, line): self.flipMenu.addAction(line) self.smoothMenu.addAction(line) #=============================================================================== # CONTEXT MENU SLOTS #=============================================================================== @pyqtSlot(str) def flip(self, action): spl=self.model.sample(self.fullXmlPath(action.text())) if spl is None: print "can not flip, can not recognize the selected sample" return try: self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1], self.drawnItems[spl].getData()[0]) except KeyError: pass if len(self.data) == 1: #we are flipping the text labels only #if only one dataset is flipped for item in self.textLabels: item.setPos(item.pos().x(), -item.pos().y()) @pyqtSlot(str) def smooth(self, action): """ TODO: would be good to reuse the widget in the menuControl """ from core.MetObjects import MSAbstractTypes class Dial(QDialog): choices =['flat', 'hanning', 'hamming', 'bartlett', 'blackman'] def __init__(self, parent): QDialog.__init__(self, parent) f =QFormLayout(self) self.a =QSpinBox(self) self.a.setValue(30) self.b = QComboBox(self) self.b.addItems(self.choices) self.c= QDialogButtonBox(self) self.c.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) f.addRow("window:" ,self.a) f.addRow("method:", self.b) f.addRow("", self.c) self.connect(self.c, SIGNAL("accepted()"), self.sendData) self.connect(self.c, SIGNAL("rejected()"), self.reinitialize) def sendData(self): self.parent().window = self.a.value() self.parent().method = self.b.currentText() self.close() def reinitialize(self): self.parent().window = None self.parent().method = None self.close() Dial(self).exec_() if self.window and self.method: for spl in self.drawnItems.keys(): if action.text() == spl.shortName(): self.drawnItems[spl].updateData( MSAbstractTypes.averageSmoothing(self.drawnItems[spl].getData()[1],self.window , self.method), self.drawnItems[spl].getData()[0]) @pyqtSlot() def plotEIC(self): if self.flags == 'spectra': #show double combobox #select the good spectra then draw pass else: mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:") if not (mass and ok): return xmlfile = self.fullXmlPath(self.selection[0].data().toString()) if not xmlfile: xmlfile = self.fullXmlPath(self.selection[0].parent().data().toString()) if not xmlfile: print "item clicked not recognized..." return sample = self.model.sample(xmlfile) if sample.kind =='HighRes': error=(sample.ppm/1e6)*float(mass) x, y = massExtraction(sample, float(mass), error) from core.MetObjects import MSChromatogram chrom = MSChromatogram(x_data=x, y_data=y, sample=sample) else: chrom = sample.getChromWithTrans(math.ceil(float(mass))) self.view.addMdiSubWindow(MSQtCanvas([chrom], "EIC %s"%str(mass), labels={'bottom':'RT(s)', 'left':'INTENSITY'})) #=========================================================================== # annotate stuff #=========================================================================== @pyqtSlot() def annotate(self): text, bool_ = QInputDialog.getText(self.view, "Annotation dialog", "Annotation:") g=QGraphicsTextItem(str(text)) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) g.setFlag(QGraphicsItem.ItemIsMovable) g.setTextInteractionFlags(Qt.TextEditorInteraction) font=qApp.instance().font() font.setPointSizeF(10.) g.setFont(font) g.setDefaultTextColor(Qt.blue) g.setPos(500,1e4) self.trashItems.append(g) self.pw.addItem(g) def removeAllAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") return for i in self.trashItems: self.pw.removeItem(i) def removeLastAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") self.pw.removeItem(self.trashItems[-1])
class MSMainWindow(QMainWindow): """Gui of the main window""" #MAX_RECENT_FILES = 10 #start putting links spyder numpy scipy et tutti quanti links=('http://numpy.scipy.org/', 'http://packages.python.org/spyder/', 'http://www.riverbankcomputing.co.uk/software/pyqt/intro') pluginPath=path.normcase('pluginmanager/plugins/') def __init__(self, availablePlugins): """ Constructor with all the models needed setup menus """ QMainWindow.__init__(self) self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) self.plugins = availablePlugins self.pluginsInst=[] settings=QSettings('INRA/INSA', '-'.join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR])) self.recentFiles = list(settings.value("RecentFiles").toStringList()) self.setStyleSheet(stylesheet) self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self) self.addToolBar(0x1,self.pipeline) self._setupModels() self._setupUi() self._setupMenus() def _setupModels(self): """ Warning:Causes segfault when horizontal labels set to True on aura peu etre a la fin un model par sampleList c'est ce qui parait le plus logique """ #drag and drop table sample self.sampleModel = QStandardItemModel(self) self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"]) #treeView1 self.spectraModel = QStandardItemModel(self) #treeview2 self.peakModel = QStandardItemModel(self) #treeview3 self.clusterModel = QStandardItemModel(self) def _setupMenus(self): #file self.fileMenu = QMenu('&File') self.fileMenu.setTearOffEnabled(True) self.op=QMenu("&Open...",self.fileMenu) self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png"))) open_=QAction("&Open rawfiles", self) open_.setToolTip("Open an mzXML or netCDF file") open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) open_icon=QIcon(path.normcase("gui/icons/fileopen.png")) open_.setIcon(open_icon) self.op.addAction(open_) load_=QAction("&Open projects...", self) load_.setToolTip("load binary file containing saved objects") load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) load_icon=QIcon(QPixmap(path.normcase("gui/icons/project_open.png"))) load_.setIcon(load_icon) self.op.addAction(load_) self.fileMenu.addMenu(self.op) save_=QAction("&Save...", self) save_.setToolTip("save the actual application model") save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) save_icon=QIcon(path.normcase("gui/icons/save_all.png")) save_.setIcon(save_icon) self.fileMenu.addAction(save_) pkl = QAction("&load a peaklist", self) #TODO:load peaklist pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P)) pkl.setToolTip("load a peaklist and process it") pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png"))) self.fileMenu.addAction(pkl) convert_=QAction("&Convert...", self) convert_.setEnabled(False) convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed") convert_icon=QIcon(path.normcase("gui/icons/goto.png")) convert_.setIcon(convert_icon) self.fileMenu.addAction(convert_) a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch") a.setEnabled(False) b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge") b.setToolTip("Merge MRM file") #b.setEnabled(False) self.fileMenu.addSeparator() # # for i in xrange(self.MAX_RECENT_FILES): # a = QAction('', self) # a.setVisible(False) # self.fileMenu.addAction(a) # # for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))): # self.fileMenu.actions()[5+i].setVisible(True) # self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1]) exit_action =QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) exit_action.setIcon(QIcon(QPixmap(path.normcase('gui/icons/exit.png')))) self.fileMenu.addAction(exit_action) self.menuBar().addMenu(self.fileMenu) self.editMenu=QMenu("&Edit") self.editMenu.setTearOffEnabled(True) self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_undo.png')), '&Undo...') self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_redo.png')), '&Redo...') self.editMenu.actions()[0].setEnabled(False) self.editMenu.actions()[1].setEnabled(False) self.editMenu.addSeparator() self.editMenu.addAction(QIcon(path.normcase('gui/icons/run.png')), '&Preferences') self.exportMenu = QMenu("&Export...") self.exportMenu.setIcon(QIcon(path.normcase('gui/icons/file_export.png'))) self.exportMenu.addAction("&Peaklist") self.exportMenu.addAction("&Clusters intensity matrix") self.editMenu.addMenu(self.exportMenu) self.menuBar().addMenu(self.editMenu) #view self.viewMenu =QMenu("&View") self.viewMenu.setTearOffEnabled(True) self.viewMenu.addAction(QIcon(path.normcase('gui/icons/window_duplicate')), "&Cascade View", self.mdiArea.cascadeSubWindows, QKeySequence(Qt.CTRL + Qt.Key_K)) self.viewMenu.addAction(QIcon(path.normcase('gui/icons/view_icon')), "&Title View", self.mdiArea.tileSubWindows, QKeySequence(Qt.CTRL + Qt.Key_N)) self.viewMenu.addAction(QIcon(path.normcase("gui/icons/stop_process.png")), "&Close all subWindows", self.mdiArea.closeAllSubWindows, QKeySequence(Qt.CTRL+Qt.Key_W)) self.plotting =QMenu("&Plotting...") self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png")))) self.plotting.addAction("&3D Plot") #self.plotting.addAction("&Cytoscape web") self.plotting.addAction("&Spectrogram Plot") #self.multiplePlot = QAction("&Visualize Raw/Treated Data", self) #self.multiplePlot.setCheckable(True) #self.multiplePlot.setEnabled(False) #self.sub_plot_.addAction(self.multiplePlot) self.viewMenu.addMenu(self.plotting) self.viewMenu.addSeparator() self.show_hide=QMenu("&Show/Hide") m=self.createPopupMenu() m.setTitle("&Show/Hide") self.viewMenu.addMenu(m) #self.pref = QMenu("&Preferences") #self.pref.addAction(self.multiplePlot) #self.viewMenu.addMenu(self.pref) self.menuBar().addMenu(self.viewMenu) #algorithm self.algoMenu= QMenu("&Algorithm") self.algoMenu.setTearOffEnabled(True) self.preProcessing=QMenu("&PreProcessing(experimental)") self.preProcessing.addAction("&Smoothing raw data...") self.preProcessing.addAction("&Cut off raw data...") self.preProcessing.addAction('&Calibration (mz dimension)') self.preProcessing.addAction("&Resize sample...") self.algoMenu.addMenu(self.preProcessing) self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self) self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png"))) matched = QAction("&MatchedFiltered", self) matched.setIcon(QIcon(path.normcase('gui/icons/RLogo'))) matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm") self.peakPickingMenu.addAction(matched) centwave=QAction("&CentWave", self) centwave.setIcon(QIcon(path.normcase('gui/icons/RLogo'))) centwave.setToolTip("Peak Detection and Integration using CentWave algorithm") self.peakPickingMenu.addAction(centwave) #peak_.setShortcut(.QKeySequence(CTRL + Key_P)) # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png"))) #peak_.setIcon(peak_icon) self.algoMenu.addMenu(self.peakPickingMenu) self.alignment = QMenu("&Alignment") self.alignment.setIcon(QIcon(path.normcase('gui/icons/format_indent_more.png'))) self.alignment.addAction("&Polynomial fitting(exp)") self.alignment.addAction("&DynamicTimeWarping") self.alignment.addAction("&ObiWarp") self.alignment.actions()[2].setEnabled(False) self.algoMenu.addMenu(self.alignment) self.algoMenu.addAction("Normalization") clust_ = QAction("&Clustering", self) clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L)) clust_icon=QIcon(QPixmap(path.normcase("gui/icons/cluster.png"))) clust_.setIcon(clust_icon) self.algoMenu.addAction(clust_) id_ = QAction("&Identification", self) id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I)) id_.setToolTip("Try to identify peaks with several methods") id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png")))) self.algoMenu.addAction(id_) self.menuBar().addMenu(self.algoMenu) #tools self.toolsMenu =QMenu("&Tools") self.toolsMenu.setTearOffEnabled(True) web = QAction("&Web Browser", self) web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png")))) self.toolsMenu.addAction(web) #cyto = QAction("&cytoscape", self) #cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg"))) #cyto.setIcon(cyto_icon) #self.toolsMenu.addAction(cyto) editor = QAction("&Editor", self) editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png")))) self.toolsMenu.addAction(editor) pet=QAction("&Short Periodic Table", self) pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg")))) self.toolsMenu.addAction(pet) self.menuBar().addMenu(self.toolsMenu) #plugins self.pluginMenu = QMenu('&Plugins') self.pluginMenu.setTearOffEnabled(True) instPl= QAction("&Install a plugin", self) instPl.setIcon(QIcon(path.normcase('gui/icons/pluginInstall.png'))) self.pluginMenu.addAction(instPl) self.launchingMenu = QMenu("&Launch PLugins", self) self.launchingMenu.setIcon(QIcon(path.normcase('gui/icons/plugin'))) for plug in self.plugins: #fullname="".join([self.pluginPath, str(plug)]) mod=imp.load_source(self.__module__, plug) if mod.autoActivation: qApp=QApplication.instance() name=getattr(mod, 'className') cls=getattr(mod, name) p=cls(qApp.model, self, parent=self) #p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1]) self.pluginsInst.append(p) else: self.launchingMenu.addAction(plug.split('/')[-1]) self.pluginMenu.addMenu(self.launchingMenu) self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin") self.menuBar().addMenu(self.pluginMenu) #about self.aboutMenu= QMenu("&About") self.aboutMenu.setTearOffEnabled(True) metms = QAction(QIcon(path.normcase('gui/icons/deluge.png')), "&about metMS...", self) self.aboutMenu.addAction(metms) pyqt = QAction("&about PyQt4...", self) pyqt_icon =QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png"))) pyqt.setIcon(pyqt_icon) self.aboutMenu.addAction(pyqt) metms = QAction("&metMS Documentation", self) metms_icon =QIcon(QPixmap(path.normcase("gui/icons/deluge.png"))) metms.setIcon(metms_icon) self.aboutMenu.addAction(metms) self.menuBar().addMenu(self.aboutMenu) def _setupUi(self, background=None): """ Make the GUI """ #mdi self.mdiArea = MSMdiArea(self) self.mdiArea.setBackground(QBrush(QPixmap(path.normcase('gui/icons/blac2.png'))))#QColor(Qt.blue).darker())) self.setCentralWidget(self.mdiArea) #sample dock widget self.sampleDockWidget = QDockWidget("Samples", self) #sampleWidget = QWidget() self.sampleTableView = MSDragFromTableView() self.sampleTableView.setModel(self.sampleModel) self.sampleTableView.setSelectionBehavior(1) self.sampleTableView.verticalHeader().hide() self.sampleTableView.verticalHeader().setDefaultSectionSize(15) self.sampleTableView.horizontalHeader().setDefaultSectionSize(150) self.sampleDockWidget.setWidget(self.sampleTableView)#sampleWidget) self.sampleDockWidget.visible=True #workflow dock self.workflowDockWidget = QDockWidget("Visualizer", self) self.workflowDockWidget.visible = True a=QWidget(self) v=QVBoxLayout(a) q=QToolBar() #self.workingSample = QLabel("Working Sample:None") #q.addWidget(self.workingSample) q.addWidget(QLabel("ppm :")) self.ppmEditer=QDoubleSpinBox() self.usePpm=QCheckBox("use ?") q.addWidget(self.ppmEditer) q.addWidget(self.usePpm) q.addSeparator() self.removeButton=QToolButton(self) self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png"))) q.addWidget(self.removeButton) self.markAsGood=QAction(QIcon(path.normcase("gui/icons/button_ok.png")),"mark peak as good", self) self.markAsBad=QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self) self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self) q.addAction(self.markAsGood) q.addAction(self.markAsBad) q.addAction(self.hideItem) v.addWidget(q) self.tabWidget = QTabWidget() self.tab = QWidget() verticalLayout = QVBoxLayout(self.tab) self.treeView = MSToDropTableView() self.treeView.verticalHeader().setDefaultSectionSize(20) self.treeView.setModel(self.spectraModel) self.spectraLabel = QLabel("Sample: None") verticalLayout.addWidget(self.treeView) verticalLayout.addWidget(self.spectraLabel) self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")),"Spectra") self.tab_2 = QWidget() verticalLayout_4 = QVBoxLayout(self.tab_2) self.treeView_2 = MSToDropTableView()#MSTreeView(self.tab_2)# QTableView(self)# self.treeView_2.verticalHeader().setDefaultSectionSize(20) self.treeView_2.setModel(self.peakModel) self.peakLabel = QLabel("Sample: None") verticalLayout_4.addWidget(self.treeView_2) verticalLayout_4.addWidget(self.peakLabel) self.tabWidget.addTab(self.tab_2,QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List") self.tab_3 = QWidget() verticalLayout_5 = QVBoxLayout(self.tab_3) self.treeView_3 = MSToDropTreeView() self.treeView_3.setAnimated(True) self.treeView_3.setModel(self.clusterModel) self.clusterLabel = QLabel("Sample: None") verticalLayout_5.addWidget(self.treeView_3) verticalLayout_5.addWidget(self.clusterLabel) self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters") self.tabWidget.setCurrentIndex(0) for l in (self.spectraLabel, self.peakLabel, self.clusterLabel): l.setAutoFillBackground(True) v.addWidget(self.tabWidget) self.workflowDockWidget.setWidget(a) self.addDockWidget(Qt.DockWidgetArea(0x2),self.workflowDockWidget) from gui.MetBaseGui import MSIsoCalculator self.isoCalc = MSIsoCalculator(self) self.isoCalcDockWidget=QDockWidget('isotopes calculation', self) self.isoCalcDockWidget.setWidget(self.isoCalc) self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget) self.isoCalcDockWidget.setVisible(False) self.isoCalcDockWidget.visible=False from gui.MetBaseGui import FormulaGenerator self.generator=FormulaGenerator(self) self.generatorDockWidget=QDockWidget('formula generator', self) self.generatorDockWidget.setWidget(self.generator) self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget) self.generatorDockWidget.setVisible(False) self.generatorDockWidget.visible=False self.compoundTreeView = MSCompoundTreeView(self) self.compoundDockWidget = QDockWidget("Compounds", self) self.compoundDockWidget.setWidget(self.compoundTreeView) self.addDockWidget(Qt.DockWidgetArea(0x2),self.compoundDockWidget) self.compoundDockWidget.setVisible(False) self.compoundDockWidget.visible=False self.comparativeTableView = QTableView(self) self.comparativeTableView.horizontalHeader().setStretchLastSection(True) self.comparativeTableView.verticalHeader().setDefaultSectionSize(20) self.comparativeDock = QDockWidget("Comparative View", self) self.comparativeDock.setWidget(self.comparativeTableView) self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock) self.comparativeDock.setVisible(False) self.comparativeDock.visible = False self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget) self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget ) self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget) #set the end #WARNING: possible that the internal shell widget cause random segfault #with the error of QObject::killTimers...? not sure ! self.shell = QWidget()#InternalShell(namespace={'metms': QApplication.instance()}, # parent=self, # multithreaded=False) self.shellDock = QDockWidget("Python Shell", self) self.shellDock.setWindowIcon(QIcon(path.normcase('gui/icons/stop.png'))) self.shellDock.setWidget(self.shell) self.shellDock.setMinimumWidth(255) self.shellDock.visible=True self.addDockWidget(0x2, self.shellDock) self.addDockWidget(0x2, self.sampleDockWidget) self.tabifyDockWidget(self.shellDock, self.sampleDockWidget) self.pb = QProgressBar(self) self.pb.setMaximumWidth(245) self.stopProcess = QToolButton(self) self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png"))) m = QMenu() #self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName) self.stopProcess.setMenu(m) self.stopProcess.setPopupMode(1) #Menu Button #self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread) self.statusBar().addPermanentWidget(self.stopProcess) self.statusBar().addPermanentWidget(self.pb) def updateStopProcessMenu(self): """ update the menu of the stop process button, based directly on the processes stored by the task manager """ self.stopProcess.menu().clear() for c in QApplication.instance().taskManager: self.stopProcess.menu().addAction(c.title) #QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1]) def addMdiSubWindow(self, plot, title="", showMaximized=False): """ Allow addition of new window in the mdiarea """ win=self.mdiArea.addSubWindow(plot) #print "widget parent", plot.parent() win.setAttribute(Qt.WA_DeleteOnClose) #win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy) #plot.setParent(win) win.setWindowTitle(title) if showMaximized: win.showMaximized() else: win.resize(400, 300) win.show() return win def updateTreeView(self): """ Tree View update switch spectre/chromato """ if self.treeView.model() == self.spectraModel: self.treeView.setModel(self.chromaModel) self.tabWidget.setTabText(0, "Chroma") else: self.treeView.setModel(self.spectraModel) #self.treeView.setSelectionMode(1) self.tabWidget.setTabText(0, "Spectra") def addTreeViewModel (self,model1, model2): """Add a model """ self.chromaModel.appendRow(model1) self.spectraModel.appendRow(model2) def _actionHovered(self, action): """emulate tooltip cause they do not work that much""" tip = action.toolTip() QToolTip.showText(QCursor.pos(), tip) def showErrorMessage(self, title, string): QMessageBox.critical(self, title, string, 0, 0) def showWarningMessage(self, title, string): return QMessageBox.warning(self, title, string, QMessageBox.Ok|QMessageBox.Cancel) def showInformationMessage(self, title, string): QMessageBox.information(self, title, string, 0) def updateProgressBar(self, i): """update the value of the progress bar for all the treatment""" self.pb.setValue(min(i, 100)) def to_indetermined_mode(self): self.pb.setMaximum(0) def to_determined_mode(self): self.pb.setMaximum(100) def showInStatusBar(self, string, time=5000): self.statusBar().showMessage(string, time) def addInterpreterDock(self, shell): self.shellDock = QDockWidget(self) self.shellDock.setWidget(shell) self.shellDock.setWindowTitle("shell") self.addDockWidget(0x2, self.shellDock) def showMetMSInformation(self): QMessageBox.about(self, self.tr("About %1").arg("metMS"), self.tr("""<b>%1 %2</b> <br>metabolite Mass Spectrometry <p>Copyright © 2010 Marco INSA, INRA <br>Licensed under the terms of the CeciLL License <p>Developed and maintained by Marco <br>Bug reports and feature requests: <a href="http://github.com/jerkos/metms">metMS site</a><br> Discussions around the project: <a href="http://groups.google.com/group/spyderlib">Google Group</a> <p>This project is part of the BRIDGE project <p>Python %3, Qt %4, PyQt %5""") \ .arg("metMS").arg(__version__) \ .arg(platform.python_version()).arg(QT_VERSION_STR) \ .arg(PYQT_VERSION_STR))
def registerAction(self, action, menuName, callback=None): """ register an action to the manager's main menu """ if not hasattr(self, '_registeredDbActions'): self._registeredDbActions = {} if callback is not None: invoke_callback = lambda x: self.invokeCallback(callback) if menuName is None or menuName == "": self.addAction(action) if menuName not in self._registeredDbActions: self._registeredDbActions[menuName] = list() self._registeredDbActions[menuName].append(action) if callback is not None: QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback) return True # search for the menu actionMenu = None helpMenuAction = None for a in self.menuBar.actions(): if not a.menu() or a.menu().title() != menuName: continue if a.menu() != self.menuHelp: helpMenuAction = a actionMenu = a break # not found, add a new menu before the help menu if actionMenu is None: menu = QMenu(menuName, self) if helpMenuAction is not None: actionMenu = self.menuBar.insertMenu(helpMenuAction, menu) else: actionMenu = self.menuBar.addMenu(menu) menu = actionMenu.menu() menuActions = menu.actions() # get the placeholder's position to insert before it pos = 0 for pos in range(len(menuActions)): if menuActions[pos].isSeparator() and menuActions[pos].objectName( ).endswith("_placeholder"): menuActions[pos].setVisible(True) break if pos < len(menuActions): before = menuActions[pos] menu.insertAction(before, action) else: menu.addAction(action) actionMenu.setVisible(True) # show the menu if menuName not in self._registeredDbActions: self._registeredDbActions[menuName] = list() self._registeredDbActions[menuName].append(action) if callback is not None: QObject.connect(action, SIGNAL("triggered(bool)"), invoke_callback) return True
class CFSceneContextMenuMixin: " Encapsulates the context menu handling " def __init__(self): self.menu = None self.individualMenus = {} # Scene menu preparation self.sceneMenu = QMenu() self.sceneMenu.addAction(getIcon('filesvg.png'), 'Save as SVG...', self.parent().onSaveAsSVG) self.sceneMenu.addAction(getIcon('filepdf.png'), 'Save as PDF...', self.parent().onSaveAsPDF) self.sceneMenu.addAction(getIcon('filepixmap.png'), 'Save as PNG...', self.parent().onSaveAsPNG) self.sceneMenu.addSeparator() self.sceneMenu.addAction(getIcon('copymenu.png'), 'Copy to clipboard', self.parent().copyToClipboard) # Common menu for all the individually selected items self.commonMenu = QMenu() #self.commonMenu.addAction( # getIcon( "cutmenu.png" ), "Cut (Ctrl+X)", self.onCut ) #self.commonMenu.addAction( # getIcon( "copymenu.png" ), "Copy (Ctrl+C)", self.onCopy ) #self.commonMenu.addSeparator() #self.commonMenu.addAction( # getIcon( "trash.png" ), "Delete (Del)", self.onDelete ) # Non-comment common menu for the individually selected items self.nonCommentCommonMenu = QMenu() #self.nonCommentCommonMenu.addAction( # getIcon( "customcolors.png" ), "Custom colors...", # self.onCustomColors ) #self.nonCommentCommonMenu.addAction( # getIcon( "replacetitle.png" ), "Replace text...", # self.onReplaceText ) # Individual items specific menu: begin ifContextMenu = QMenu() ifContextMenu.addAction(getIcon("switchbranches.png"), "Switch branch layout", self.onSwitchIfBranch) self.individualMenus[IfCell] = ifContextMenu # Individual items specific menu: end # Menu for a group of selected items self.groupMenu = QMenu() #self.groupMenu.addAction( # getIcon( "cfgroup.png" ), "Group...", # self.onGroup ) #self.groupMenu.addAction( # getIcon( "customcolors.png" ), "Custom colors...", # self.onCustomColors ) #self.groupMenu.addSeparator() #self.groupMenu.addAction( # getIcon( "trash.png" ), "Delete (Del)", self.onDelete ) return def onContextMenu(self, event): " Triggered when a context menu should be shown " selectedItems = self.selectedItems() selectionCount = len(selectedItems) if selectionCount == 0: self.sceneMenu.popup(event.screenPos()) return if selectionCount == 1: self.__buildIndividualMenu(selectedItems[0]) else: self.__buildGroupMenu(selectedItems) self.menu.popup(event.screenPos()) return def __buildIndividualMenu(self, item): " Builds a context menu for the given item " self.menu = QMenu() if type(item) in self.individualMenus: individualPart = self.individualMenus[type(item)] self.menu.addActions(individualPart.actions()) self.menu.addSeparator() if not item.isComment(): self.menu.addActions(self.nonCommentCommonMenu.actions()) self.menu.addSeparator() self.menu.addActions(self.commonMenu.actions()) # Note: if certain items need to be disabled then it should be done # here return def __buildGroupMenu(self, items): " Builds a context menu for the group of items " self.menu = QMenu() self.menu.addActions(self.groupMenu.actions()) # Note: if certain items need to be disabled then it should be done # here return def onSwitchIfBranch(self): " If primitive should switch the branches " selectedItems = self.selectedItems() for item in selectedItems: if item.kind == CellElement.IF: item.switchBranches() return def onCustomColors(self): " Custom background and foreground colors " print "Custom colors" def onReplaceText(self): " Replace the code with a title " print "Replace title" def onDelete(self): " Delete the item " print "Delete" def onGroup(self): " Groups items into a single one " print "Group" def onCopy(self): print "Copy" def onCut(self): print "Cut"
class MSQtCanvas(QWidget, MSDialogController): """ DONE:the current peak is not updated while the user press up and down key on the treeView TODO: think about a mjor redesign of those classes """ #linePlotted = pyqtSignal(object, str) #lineRemoved = pyqtSignal(object) def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data = data self.title = title self.flags = flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx = self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[ 1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k) #parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01) #antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems = [] #why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data) #initial plotting def getMax(self): localXmin = [] localXmax = [] localYmax = [] for el in self.data: if el is None: continue localXmin.append(min_f(el.x_data)) localXmax.append(max_f(el.x_data)) localYmax.append(max_l(el.y_data)) return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l( np.array(localYmax)) def _plotting(self, data): """ refactor this shit c = Line(chrom.x_data, chrom.y_data, QColor.fromRgbF(*(self.ref.sample.color+(.7,))), parent=self.pw.plotItem.vb, scene=self.pw.scene()) #test scatter plot self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) self.pw.addDataItem(self.scatter) self.scatter.sigClicked.connect(self.requestSpectra) """ if self.flags == 'peak': self.connect(self.pw.plotItem.vb, SIGNAL('showDiffOrSpectra(PyQt_PyObject)'), self.drawSpectra) self.ref = sorted([e for e in data if e is not None], key=lambda x: x.height)[-1] ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked( ) else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) #show labels self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data) #drawing color = QColor.fromRgbF(*self.ref.sample.color + (.5, )) c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color) self.drawnItems[self.ref.sample] = c # peak's pixmap on the ref peak pix = PeakArrowItem(self.ref, pen=color, brush=color, pos=(self.ref.rt, self.ref.height + (self.ref.height * 6) / 100.), angle=-90, parent=self.pw.plotItem.vb) pix.setZValue(1000) self.pw.addItem(pix) #both these connections are emitted #in peak Indicator by effictivamente qApp self.connect(qApp.instance(), SIGNAL("highlightRequested"), c.setHighlighted) self.connect(qApp.instance(), SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) # self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName()) #if qApp.instance().lowMemory: # chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \ # for el in data if el != ref and el is not None] #else: ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked( ) else self.ref.sample.ppm chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \ for el in data if el is not None and el != self.ref] self.drawEics(chromatograms) #initialisation zoom on the peak self.pw.setYRange(0., self.ref.height + (self.ref.height * 12) / 100.) self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20) elif self.flags == 'chroma': ref = [d for d in data if d is not None] if not ref: print "Error, empty data to plot" return self.ref = ref[0] self.textLabels += self.showTextLabel(self.ref.x_data, self.ref.y_data) self.drawEics(data) else: #spectrum if not data: #print "NOTHING TO PLOT" return self.ref = data[0] for el in data: c = SpectrumItem(el, centroid=True, scene=self.pw.scene()) self.pw.addItem(c) self.drawnItems[el.sample] = c self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), el.sample.shortName()) #just put time information if data: i = 0 while data[i] is None and i < len(data): i += 1 self.textLabels += self.showTextLabel(data[i].x_data, data[i].y_data) #setting the range #warning: autoRange pw function does not work well #on spectrum item maxY = max([el.y_data.max() for el in data]) minX, maxX = min([el.x_data.min() for el in data ]), max([el.x_data.max() for el in data]) self.pw.setXRange(minX, maxX, padding=0) self.pw.setYRange(0., maxY, padding=0) def drawEics(self, data): for chrom in data: color = QColor.fromRgbF(*(chrom.sample.color + (.5, ))) c = self.pw.plotItem.plot(x=chrom.x_data, y=chrom.y_data, pen=color) #c = Line(chrom.x_data, chrom.y_data, # color, # parent=self.pw.plotItem.vb, # scene=self.pw.scene()) self.drawnItems[chrom.sample] = c #self.pw.addItem(c) #self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), chrom.sample.shortName()) if self.flags != 'peaks': self.pw.autoRange() #=========================================================================== # UI stuffs #=========================================================================== def _setupUi(self): # self.stop = QToolButton() # self.stop.setIcon(QIcon('gui/icons/tools_wizard.png')) # self.stop.setToolTip('Enable or disable the appearance of the contextMenu') layout = QVBoxLayout(self) self.smoothButton = QToolButton() #self.smoothButton.setToolButtonStyle(2) self.smoothButton.setPopupMode(2) self.smoothButton.setToolTip("Smooth the visualized data") #self.smoothButton.setText("Smooth...") self.smoothButton.setIcon( QIcon(os.path.normcase('gui/icons/smooth.png'))) self.smoothMenu = QMenu() self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'), self.smooth) self.smoothButton.setMenu(self.smoothMenu) self.pw.plotItem.toolBar.addWidget(self.smoothButton) self.flipButton = QToolButton() #self.flipButton.setToolButtonStyle(2) self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png'))) self.flipButton.setToolTip("Flip the visualized data") #self.flipButton.setText("Flip...") self.flipButton.setPopupMode(2) self.flipMenu = QMenu() self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip) self.flipButton.setMenu(self.flipMenu) self.pw.plotItem.toolBar.addWidget(self.flipButton) self.annotButton = QToolButton() #self.annotButton.setToolButtonStyle(2) self.annotButton.setPopupMode(2) #self.annotButton.setText("&Annotate...") self.annotButton.setIcon( QIcon(os.path.normcase('gui/icons/attach.png'))) self.annotMenu = QMenu() self.annotMenu.addAction("&Add Annotation") self.annotMenu.addAction("&Remove last Annotation") self.annotMenu.addAction("&Remove All Annotation") self.annotButton.setMenu(self.annotMenu) self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"), self.annotate) self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"), self.removeLastAnnot) self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"), self.removeAllAnnot) self.pw.plotItem.toolBar.addWidget(self.annotButton) self.addPlotButton = QToolButton() #self.addPlotButton.setToolButtonStyle(2) self.addPlotButton.setText("Add...") self.addPlotButton.setIcon( QIcon(os.path.normcase('gui/icons/list_add.png'))) self.addPlotButton.setToolTip("Add a new plot to the current figure") #self.addPlotButton.setText('&Add Plot') self.pw.plotItem.toolBar.addWidget(self.addPlotButton) self.showSpectra = QToolButton() self.showSpectra.setPopupMode(2) #instant popup #self.showSpectra.setToolButtonStyle(2) self.showSpectra.setIcon( QIcon(os.path.normcase('gui/icons/file_export.png'))) #self.showSpectra.setText('&Show /hide...') self.showSpectra.setToolTip('Show/hide ...') self.showMenu = QMenu() self.showTextLabels = QAction("&Show Labels", self.showMenu) self.showTextLabels.setCheckable(True) self.showTextLabels.setChecked(True) self.showMenu.addAction(self.showTextLabels) self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'), self.setTextLabelsVisibility) showSpectrum = QAction("&Merged Spectrum", self.showMenu) showSpectrum.setCheckable(True) if self.flags == 'chroma' or self.flags == 'spectra': showSpectrum.setEnabled(False) self.showMenu.addAction(showSpectrum) self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'), self.drawSpectraRequested) showNonXCMSPeak = QAction("&Show Non XCMS Peak", self.showMenu) showNonXCMSPeak.setCheckable(True) if self.flags == 'spectra': showNonXCMSPeak.setEnabled(False) self.showMenu.addAction(showNonXCMSPeak) self.connect(self.showMenu.actions()[2], SIGNAL('toggled(bool)'), self.setPixmapVisibility) showDataPoints = QAction("&Show DataPoints", self.showMenu) showDataPoints.setCheckable(True) showDataPoints.setChecked(False) self.showMenu.addAction(showDataPoints) self.connect(self.showMenu.actions()[3], SIGNAL('toggled(bool)'), self.setDataPointsVisibility) self.showSpectra.setMenu(self.showMenu) self.pw.plotItem.toolBar.addWidget(self.showSpectra) self.saveToPng = QToolButton() self.saveToPng.setIcon( QIcon(os.path.normcase('gui/icons/thumbnail.png'))) #self.saveToPng.setToolButtonStyle(2) #self.saveToPng.setText("Save to Png...") self.pw.plotItem.toolBar.addWidget(self.saveToPng) self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage) #add bar plot even if we are plotting chroma #cause we can find non xcms peaks self.barPlot = BarPlot(scene=self.pw.sceneObj) #self.barPlot.rotate(-90.) if self.flags == 'peak': self.barPlot.setPeakGroup(self.data) #TODO modify to get this close to us #on the left part xpos = self.barPlot.scene().width() * 3.5 #-bwidth; ypos = self.barPlot.scene().height() * 1.1 self.barPlot.setPos(xpos, ypos) self.barPlot.setZValue(1000) layout.addWidget(self.pw) layout.addWidget(self.pw.plotItem.toolBar) def showTextLabel(self, x, y, secure=25): """ add labels of principle peaks of spectrum or chroma on the plot, return the labels, that we can show hide """ maxis = [] #will contain tuple(rt, intens) indexes = [] #from core.MetObjects import MSAbstractTypes from scipy.ndimage import gaussian_filter1d as gauss z = gauss(y, 1) #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8) i = 0 while i < len(z) - 1: while z[i + 1] >= z[i] and i < len(y) - 2: i += 1 maxis.append((x[i], y[i])) indexes.append(i) while z[i + 1] <= z[i] and i < len(z) - 2: i += 1 i += 1 labels = [] for t in sorted(maxis, key=lambda x: x[1])[-5:]: g = QGraphicsTextItem(str(t[0])) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) font = QApplication.font() font.setPointSizeF(6.5) g.setFont(font) g.setDefaultTextColor(Qt.black) g.setPos(t[0], t[1]) labels.append(g) self.pw.addItem(g) return labels #=============================================================================== #SLOTS #=============================================================================== def redrawAll(self, value): self.pw.clear() self._plotting(self.data) def disHighlightOne(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(False) except KeyError: pass def highlight(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(True) except KeyError: pass #print "sample not found" self.pw.plotItem.update() #works def disHighlight(self): for key in self.drawnItems.iterkeys(): self.drawnItems[key].setHighlighted(False) self.pw.plotItem.update() def setTextLabelsVisibility(self, bool_): for t in self.textLabels: t.setVisible(bool_) def setDataPointsVisibility(self, b): if self.dataPoints is None: if self.flags == 'peak': chrom = self.ref.sample.massExtraction(self.ref.mass(), self.ref.sample.ppm, asChromatogram=True) self.dataPoints = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) else: self.dataPoints = ScatterPlotItem(x=self.ref.x_data, y=self.ref.y_data) if self.flags != 'spectra': self.dataPoints.sigClicked.connect(self.requestSpectra) self.pw.addDataItem(self.dataPoints) self.dataPoints.setVisible(b) def setPixmapVisibility(self, bool_): """ draw other peaks than the xcms peak """ if not self.pixmaps and bool_: ppm = 1. if self.ref.sample.kind == 'MRM' else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \ if self.flags == 'peak' else self.ref chrom.findNonXCMSPeaks() for p in chrom.peaks.ipeaks(): if self.flags == 'peak': diff = (p.height * 10) / 100 if abs(p.height - self.ref.height) < diff: continue #we assume that they are the same peaks pix = PeakIndicator(p, icon='flags') #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted) self.connect(pix, SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) pix.setPos(p.rt, p.height + (p.height * 10) / 100.) pix.setZValue(1000) self.pixmaps.append(pix) self.pw.addItem(pix) if self.pixmaps: for t in self.pixmaps: t.setVisible(bool_) @pyqtSlot() def updateCurrentPeak(self): idx = self.acTree.selectedIndexes()[0] s = self.model.sample(idx.parent().data().toString(), fullNameEntry=False) if s is not None: self.currentPeak = s.peakAt(*map(float, idx.data().toString().split('/'))) def requestSpectra(self, scatter, l): """ idea plot all spectra between a time range and not only with only one spectra """ if not l: return ref = l[0] self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample) @pyqtSlot() def drawSpectraRequested(self, bool_): """ i think this is for plotting merged spectrum """ if bool_: self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak) else: self.hideRequested() def drawSpectra(self, l): self.emit( SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), l[0], l[1], self.ref.sample) @pyqtSlot() def hideRequested(self): self.emit(SIGNAL('hideRequested')) self.showMenu.actions()[1].setChecked(False) @pyqtSlot() def redraw(self): """ this is for updating the view port when hiding or not samples """ chromas = [] for spl in self.model: if spl.checked: if spl in self.drawnItems.keys(): self.drawnItems[spl].setVisible(True) else: chromas.append(spl.chroma[0]) else: self.drawnItems[spl].setVisible(False) self._plotting(chromas) self.pw.plotItem.update() #works def cleanScene(self): """ remove all items in the trash """ for element in self.trashItems: self.pw.sceneObj.removeItem(element) @pyqtSlot() def updateContextMenu(self, line): self.flipMenu.addAction(line) self.smoothMenu.addAction(line) #=============================================================================== # CONTEXT MENU SLOTS #=============================================================================== @pyqtSlot(str) def flip(self, action): spl = self.model.sample(self.fullXmlPath(action.text())) if spl is None: print "can not flip, can not recognize the selected sample" return try: self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1], self.drawnItems[spl].getData()[0]) except KeyError: pass if len(self.data) == 1: #we are flipping the text labels only #if only one dataset is flipped for item in self.textLabels: item.setPos(item.pos().x(), -item.pos().y()) @pyqtSlot(str) def smooth(self, action): """ TODO: would be good to reuse the widget in the menuControl """ from core.MetObjects import MSAbstractTypes class Dial(QDialog): choices = ['flat', 'hanning', 'hamming', 'bartlett', 'blackman'] def __init__(self, parent): QDialog.__init__(self, parent) f = QFormLayout(self) self.a = QSpinBox(self) self.a.setValue(30) self.b = QComboBox(self) self.b.addItems(self.choices) self.c = QDialogButtonBox(self) self.c.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) f.addRow("window:", self.a) f.addRow("method:", self.b) f.addRow("", self.c) self.connect(self.c, SIGNAL("accepted()"), self.sendData) self.connect(self.c, SIGNAL("rejected()"), self.reinitialize) def sendData(self): self.parent().window = self.a.value() self.parent().method = self.b.currentText() self.close() def reinitialize(self): self.parent().window = None self.parent().method = None self.close() Dial(self).exec_() if self.window and self.method: for spl in self.drawnItems.keys(): if action.text() == spl.shortName(): self.drawnItems[spl].updateData( MSAbstractTypes.averageSmoothing( self.drawnItems[spl].getData()[1], self.window, self.method), self.drawnItems[spl].getData()[0]) @pyqtSlot() def plotEIC(self): if self.flags == 'spectra': #show double combobox #select the good spectra then draw pass else: mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:") if not (mass and ok): return xmlfile = self.fullXmlPath(self.selection[0].data().toString()) if not xmlfile: xmlfile = self.fullXmlPath( self.selection[0].parent().data().toString()) if not xmlfile: print "item clicked not recognized..." return sample = self.model.sample(xmlfile) if sample.kind == 'HighRes': error = (sample.ppm / 1e6) * float(mass) x, y = massExtraction(sample, float(mass), error) from core.MetObjects import MSChromatogram chrom = MSChromatogram(x_data=x, y_data=y, sample=sample) else: chrom = sample.getChromWithTrans(math.ceil(float(mass))) self.view.addMdiSubWindow( MSQtCanvas([chrom], "EIC %s" % str(mass), labels={ 'bottom': 'RT(s)', 'left': 'INTENSITY' })) #=========================================================================== # annotate stuff #=========================================================================== @pyqtSlot() def annotate(self): text, bool_ = QInputDialog.getText(self.view, "Annotation dialog", "Annotation:") g = QGraphicsTextItem(str(text)) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) g.setFlag(QGraphicsItem.ItemIsMovable) g.setTextInteractionFlags(Qt.TextEditorInteraction) font = qApp.instance().font() font.setPointSizeF(10.) g.setFont(font) g.setDefaultTextColor(Qt.blue) g.setPos(500, 1e4) self.trashItems.append(g) self.pw.addItem(g) def removeAllAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") return for i in self.trashItems: self.pw.removeItem(i) def removeLastAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") self.pw.removeItem(self.trashItems[-1])
class QuestionDlg(QDialog): def __init__(self,parent=None): super(QuestionDlg,self).__init__(parent) # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;") self.setWindowFlags(Qt.CustomizeWindowHint) # self.setStyleSheet("border: 2px; border-radius 2px;") # self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet("background-color: rgba(132, 171, 208, 200);") tabWidget=QTabWidget(self) tabWidget.currentChanged.connect(self.changeTab) # tabWidget.setTabShape(QTabWidget.Triangular) tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\ border-style: outset;background-color: rgb(132, 171, 208);\ background: transparent;} \ QTabWidget::tab-bar{border-width:0px;}\ QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \ QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \ QTabBar::tab:selected{border-color:green;background-color:white;color:green;}") # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}") self.btngroup = QButtonGroup() self.popMenu = QMenu(self) entry1 = self.popMenu.addAction("正确") self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight()) entry2 = self.popMenu.addAction("错误") self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong()) entry3 = self.popMenu.addAction("替换") self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent()) w1=QWidget() w1.setAccessibleName("w1tab") self.w1title = QLabel() self.btn_start = MyButton("开始") self.choicenum_text = QComboBox() self.choicenum_text.setObjectName('w1combonums') # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');") titleLayout, btnlayout, bottomlayout = self.genOneTab(tabtitle = self.w1title, tabbtn=self.btn_start, tabnums=self.choicenum_text) tab1layout = QVBoxLayout() tab1layout.addLayout(titleLayout) tab1layout.addLayout(btnlayout) tab1layout.addLayout(bottomlayout) w1.setLayout(tab1layout) w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") w2=QWidget() w2.setAccessibleName("w2tab") self.w2title = QLabel() self.btn_start2 = QPushButton("开始") self.choicenum_text2 = QComboBox() self.choicenum_text2.setObjectName('w2combonums') titleLayout2, btnlayout2, bottomlayout2 = self.genOneTab(tabtitle = self.w2title, tabbtn=self.btn_start2, tabnums=self.choicenum_text2, strwhere = "where studentsn like '04%' ") tab2layout = QVBoxLayout() tab2layout.addLayout(titleLayout2) tab2layout.addLayout(btnlayout2) tab2layout.addLayout(bottomlayout2) w2.setLayout(tab2layout) w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") tabWidget.addTab(w1,"三(3)班") tabWidget.addTab(w2,"三(4)班") tabWidget.resize(740,700) # print(tabWidget.parentWidget()) btnclose = QPushButton(self) btnclose.setToolTip("关闭") btnclose.setText("╳") btnclose.setGeometry(715, 5, 20, 20) btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnclose.clicked.connect(self.close) btnMinimized = QPushButton(self) btnMinimized.setToolTip("最小化") btnMinimized.setText("▁") btnMinimized.setGeometry(690, 5, 20, 20) btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnMinimized.clicked.connect(lambda: self.showMinimized()) self.btnSysMenu = QPushButton(self) # self.btnSysMenu.setText("▼") self.btnSysMenu.setGeometry(665, 5, 20, 20) self.btnSysMenu.setToolTip("系统设置") self.btnSysMenu.clicked.connect(lambda: self.showMinimized()) menufont = QFont("宋体", 10) popMenu = QMenu(self) entry1 = popMenu.addAction("初始化") entry1.setFont(menufont) self.connect(entry1,SIGNAL('triggered()'), self.initStudent) entry2 = popMenu.addAction("清除提问人员") entry2.setFont(menufont) self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata) self.btnSysMenu.setMenu(popMenu) self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ") # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);") authorinfo = QLabel(tabWidget) # authorinfo.setToolTip("关闭") authorinfo.setText("汕头市大华一小:赵小娜") authorinfo.setGeometry(20, 665, 235, 26) authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:20px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;") self.setWindowTitle("课堂随机提问") self.setWindowIcon(QIcon("image/start.ico")) self.setGeometry(100, 20, 740, 700) screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) self.btn_start.setMyarg('start') # print(self.btn_start.getMyarg()) self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) self.btngroup.buttonClicked[int].connect(self.btns_click) # self.connect(self.btn_start, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click()) def myslot(self, text): # print(text) self.g_curbtn = text if self.g_curbtn not in self.dict_choices: self.btnSysMenu.setFocus() return # print(self.btngroup.button(int(self.g_curbtn)).parent()) # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget())) pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos()) width = self.btngroup.button(int(self.g_curbtn)).rect().height() # print("-----", pos, width) pos.setY(pos.y()+width-5) indx = 0 for istate in self.dict_choices[self.g_curbtn]: if istate == '1': self.popMenu.actions()[indx].setEnabled(True) elif istate == '0': self.popMenu.actions()[indx].setEnabled(False) indx += 1 self.popMenu.exec_(pos) self.btnSysMenu.setFocus() # def on_context_menu(self, point): # print(point) # self.popMenu.exec_(self.button.mapToGlobal(point)) def btns_click(self, btnid): # print(self.btngroup.button(btnid).rect()) # print(self.mapToGlobal(self.btngroup.button(btnid).pos())) cur = conn.cursor() today = datetime.date.today() self.g_curbtn = str(btnid).zfill(4) if self.g_curbtn not in self.dict_choices: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new) cur.execute("select count(*) from tmprecord where studentsn='" + str(self.g_curbtn) + "'") if cur.fetchall()[0][0] == 0: strsql = "insert into tmprecord values (?, ?, ?)" cur.execute(strsql, (None, self.g_curbtn, today)) conn.commit() self.dict_choices[self.g_curbtn] = "111" else: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon()) # cur.execute("select count(*) from tmprecord where studentsn='" + str(self.g_curbtn) + "'") # print(cur.fetchall()) cur.execute("delete from tmprecord where studentsn='"+ str(self.g_curbtn) + "'") conn.commit() self.dict_choices.pop(self.g_curbtn) self.btnSysMenu.setFocus() cur.close() def initStudent(self): cur = conn.cursor() cur.execute("update student set wrongquestions=0") conn.commit() cur.execute("update student set rightquestions=0") conn.commit() # cur.execute("select * from student") # print(cur.fetchall()) cur.close() def deleteTmpdata(self): cur = conn.cursor() cur.execute("delete from tmprecord where 1=1" ) conn.commit() cur.close() def changeTab(self, curtab): if curtab == 0: strwhere = " and studentsn like '03%' " elif curtab == 1: strwhere = " and studentsn like '04%' " self.g_curbtn = "" self.dict_choices = {} cur = conn.cursor() cur.execute("delete from tmprecord where 1=1") conn.commit() cur.execute("select studentsn from student where 1=1 " + strwhere) self.studentSnlst = cur.fetchall() for isn in self.studentSnlst: self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(isn[0])).setIcon(QIcon()) # print(self.studentSnlst) self.group_animation = groupAnimation(self.studentSnlst, self.btngroup) # print(self.group_animation) cur.close() def mousePressEvent(self, event): if event.button() == Qt.RightButton: QDialog.mousePressEvent(self,event) return # print(event.sender(), event.button()) self.offset = event.pos() # print(self.offset) def mouseMoveEvent(self, event): if hasattr(self, 'offset'): x=event.globalX() y=event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x-x_w, y-y_w) else: pass def genOneTab(self, tabtitle="", tabbtn="", tabnums="", strwhere = "where studentsn like '03%' "): # tabtitle.setFixedHeight(40) # tabtitle.setFixedWidth(160) tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("随堂提问演板") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) btnlayout = QGridLayout() cur = conn.cursor() strsql = "select studentsn, studentname from student " + strwhere cur.execute(strsql) tmpnum = 0 for item in cur.fetchall(): irow = tmpnum // 7 icol = tmpnum % 7 tmpnum += 1 btnlayout.setRowMinimumHeight(irow, 80) tmpbtn = MyButton(item[1]) tmpbtn.setMyarg(item[0]) # tmpbtn.setFixedHeight(20) tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)) # tmpbtn.setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;") # tmpbtn.setFlat(True) self.connect(tmpbtn, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) # self.connect(tmpbtn, SIGNAL('customContextMenuRequested(const QPoint&)'), self.on_context_menu) tmpbtn.setAutoDefault(False) self.btngroup.addButton(tmpbtn, int(item[0])) btnlayout.addWidget(tmpbtn, irow, icol) tabbtn.setIcon(QIcon("image/start.png")) tabbtn.setStyleSheet("border: 1px solid yellow;") tabbtn.setFixedHeight(40) tabbtn.setFixedWidth(100) tabbtn.setFont(QFont('宋体', 20)) # tabnums.setFixedHeight(45) # tabnums.setFixedWidth(60) tabnums.setFont(QFont('Courier New', 20)) tabnums.setFixedHeight(45) tabnums.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\ border-radius: 6px; \ min-width: 2em; ") tabnums.setEditable(True) tabnums.lineEdit().setReadOnly(True); tabnums.lineEdit().setAlignment(Qt.AlignCenter); model = tabnums.model() for row in list(range(1, 7)): item = QStandardItem(str(row)) item.setTextAlignment(Qt.AlignCenter) item.setForeground(QColor('red')) item.setBackground(QColor(0,200,50, 130)) model.appendRow(item) tabnums.setCurrentIndex(2) # tabnums.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}") # tabnums.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}") bottomlayout = QHBoxLayout() bottomlayout.setSizeConstraint(QLayout.SetFixedSize) bottomlayout.addStretch(10) bottomlayout.addWidget(tabbtn) bottomlayout.setSpacing(5) bottomlayout.addWidget(tabnums) cur.close() return(titleLayout, btnlayout, bottomlayout) def startChoice(self, usernum="", oldbtn=""): if oldbtn != "": flag = str(int(oldbtn[:2])) else: self.dict_choices = {} whichtabpage = self.sender().parentWidget().accessibleName() flag = (whichtabpage == "w1tab") and "3" or "4" if flag== "3": strwhere = " and studentsn like '03%' " tabCombonums = self.findChild(QComboBox, 'w1combonums') else: strwhere = " and studentsn like '04%' " tabCombonums = self.findChild(QComboBox, 'w2combonums') # print(usernum, oldbtn) allstudent = [] lstrecord = ['0000', '1111'] cur = conn.cursor() cur.execute("select studentsn from tmprecord where 1=1 " + strwhere) for item in cur.fetchall(): lstrecord.append(item[0]) # print(lstrecord, 'record', "select studentsn from student where studentsn like '03%' and studentsn not in " + str(tuple(lstrecord))) cur.execute("select studentsn from student where studentsn not in " + str(tuple(lstrecord)) + strwhere) for item in cur.fetchall(): allstudent.append(item[0]) if usernum == "": nums = int(tabCombonums.currentText()) else: nums = usernum if nums >= len(allstudent): cur.execute("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today conn.commit() allstudent = [] cur.execute("select studentsn from student where 1=1 " + strwhere) for item in cur.fetchall(): allstudent.append(item[0]) # print(tabCombonums.currentText()) cur.close() if oldbtn == "": random.seed() lstchoices = random.sample(allstudent, nums) for ibtn in lstchoices: self.dict_choices[ibtn] = "111" self.group_animation.start() QTimer.singleShot(1200, self.stopmovie) else: random.seed() otherbtn = random.sample(allstudent, 1)[0] # self.btngroup.button(int(otherbtn)).setFocus() self.dict_choices.pop(oldbtn) self.dict_choices[otherbtn] = '111' self.stopmovie() self.btnSysMenu.setFocus() def stopmovie(self): self.group_animation.stop() for isn in self.studentSnlst: self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(isn[0])).setIcon(QIcon()) cur = conn.cursor() today = datetime.date.today() for ibtn in self.dict_choices: self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new) cur.execute("select count(*) from tmprecord where studentsn='" + str(ibtn) + "'") if cur.fetchall()[0][0] == 0: strsql = "insert into tmprecord values (?, ?, ?)" cur.execute(strsql, (None, ibtn, today)) conn.commit() # cur.execute("select * from tmprecord") # print(cur.fetchall()) cur.close() def answerRight(self): # print(self.g_curbtn) value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) cur = conn.cursor() cur.execute("select rightquestions from student where studentsn='" + value + "'") studentRightQuestions = cur.fetchall()[0][0] + 1 cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'") conn.commit() ########### if self.dict_choices[value] == "101": cur.execute("select wrongquestions from student where studentsn='" + value + "'") studentWrongQuestions = cur.fetchall()[0][0] - 1 cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'") conn.commit() cur.close() self.dict_choices[value] = "011" def answerWrong(self): value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);") cur = conn.cursor() cur.execute("select wrongquestions from student where studentsn='" + value + "'") studentWrongQuestions = cur.fetchall()[0][0] + 1 cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'") conn.commit() if self.dict_choices[value] == "011": cur.execute("select rightquestions from student where studentsn='" + value + "'") studentRightQuestions = cur.fetchall()[0][0] - 1 cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'") conn.commit() cur.close() self.dict_choices[value] = "101" def resetStudent(self): value = self.g_curbtn if value not in self.dict_choices: return # self.btngroup.button(int(value)).parentWidget().setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;") # self.btngroup.button(int(value)).setStyleSheet("border: 1px solid rgb(255,255,255,0);background-color: rgba(255,255,255,20);font-size:16px;") # self.btngroup.button(int(value)).setAutoDefault(False) cur = conn.cursor() if self.dict_choices[value] == "011": cur.execute("select rightquestions from student where studentsn='" + value + "'") studentRightQuestions = cur.fetchall()[0][0] - 1 cur.execute("update student set rightquestions=" + str(studentRightQuestions) + " where studentsn='" + value + "'") conn.commit() if self.dict_choices[value] == "101": cur.execute("select wrongquestions from student where studentsn='" + value + "'") studentWrongQuestions = cur.fetchall()[0][0] - 1 cur.execute("update student set wrongquestions=" + str(studentWrongQuestions) + " where studentsn='" + value + "'") conn.commit() cur.close() self.startChoice(usernum=1, oldbtn=value) # print("---reset___") # curmenu.actions()[0].setEnabled(True) # curmenu.actions()[1].setEnabled(True) # self.choiceOneStudent(value) def createDb(self): cur = conn.cursor() sqlstr = 'create table student (id integer primary key, \ studentsn varchar(20), \ studentname varchar(20), \ rightquestions integer, \ wrongquestions integer)' # print(sqlstr) sqlstr2 = 'create table tmprecord (id integer primary key, \ studentsn varchar(20), \ datequestion date)' strdelete = "delete from student where 1=1" cur.execute(strdelete) conn.commit() strdelete = "delete from tmprecord where 1=1" cur.execute(strdelete) conn.commit() # print(sqlstr2) # cur.execute(sqlstr) # conn.commit() # cur.execute(sqlstr2) # conn.commit() # insert example data a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"] a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"] strsql = "insert into student values (?, ?, ?,?,?)" for i in list(range(0,len(a03lst))): cur.execute(strsql, (None, "03"+str(i+1).zfill(2), a03lst[i], 0, 0)) conn.commit() strsql = "insert into student values (?, ?, ?,?,?)" for i in list(range(0,len(a04lst))): cur.execute(strsql, (None, "04"+str(i+1).zfill(2), a04lst[i], 0, 0)) conn.commit() cur.close()
class MSView(QSplitter): modifiedContext = pyqtSignal(object) def __init__(self, widget, parent=None, **kw): QSplitter.__init__(self, Qt.Horizontal, parent) self.setFocusPolicy(Qt.StrongFocus) self.mainWidget = widget self.addWidget(self.mainWidget) self.showHide = None self.subsidiaryWidget = MSQtCanvas( [], "", flags='spectrum') #, subsidiaryWidget=True) self.subsidiaryWidget.pw.plotItem.toolBar.hide() self.subsidiaryWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.subsidiaryWidget, SIGNAL("customContextMenuRequested(const QPoint &)"), self.showContextMenu) self.menu = QMenu(self.subsidiaryWidget) self.menu.addAction("&Hide...") self.connect(self.menu.actions()[0], SIGNAL("triggered()"), self.subsidiaryWidget.hide) self.addWidget(self.subsidiaryWidget) self.subsidiaryWidget.hide() self.barplotdrawn = False self.connect(self.mainWidget, SIGNAL('drawSpectraRequested'), self.drawSpectrum) self.connect( self.mainWidget, SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.drawSpectra) self.connect(self.mainWidget, SIGNAL('drawSpectrumByTime'), self.drawSpectrumByTime) self.connect(self.mainWidget, SIGNAL('hideRequested'), self.subsidiaryWidget.hide) def showContextMenu(self, pos): if self.subsidiaryWidget.pw.plotItem.vb.hasMoved: return self.menu.exec_(QCursor.pos()) @pyqtSlot() def drawSpectrum(self, p): if p is None: return mergedSpectra = p.merge(p.spectra) self.subsidiaryWidget.pw.clear() self.subsidiaryWidget._plotting([mergedSpectra]) self.subsidiaryWidget.pw.setTitle("Merged Spectrum@%s-%s" % (str(p.rtmin), str(p.rtmax))) self.subsidiaryWidget.show() def drawSpectrumByTime(self, t, sample): if not sample or not t: print "unknown error..." return spectra = sample.spectraInRTRange(t.x(), t.x() - 2., t.x() + 2.) if not spectra: print "No spectrum found at this retention time" return closest = sorted(spectra, key=lambda x: abs(t.x() - x.rtmin))[0] self.subsidiaryWidget.pw.clear() self.subsidiaryWidget._plotting([closest]) self.subsidiaryWidget.pw.setTitle("Spectrum@%s" % (str(closest.rtmin))) self.subsidiaryWidget.show() def drawSpectra(self, inf, sup, sample): if not sample: return spectra = sample.spectraInRTRange((inf + sup) / 2., inf, sup) print[s.rtmin for s in spectra] spectrum = None if not spectra: print "No spectrum found at this retention time" return elif len(spectra) > 1: ref = spectra[0] others = spectra[1:] spectrum = ref.merge(others) else: spectrum = spectra[0] self.subsidiaryWidget.pw.clear() self.subsidiaryWidget._plotting([spectrum]) self.subsidiaryWidget.pw.setTitle("Spectrum@%s" % (str(spectrum.rtmin))) self.subsidiaryWidget.show()
class MainWindow(QWidget): def __init__(self): super(QWidget, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.systemTray = QSystemTrayIcon(self) self.systemTray.setIcon(QIcon(':/images/icon.png')) self.act_autostart = QAction('开机启动', self) self.act_autostart.setCheckable(True) is_autostart = self.is_autostart() self.act_autostart.setChecked(is_autostart) self.act_autostart.triggered.connect(self.on_autostart) act_setting = QAction('设置启动项', self) act_setting.triggered.connect(self.on_settings) act_exit = QAction('退出', self) act_exit.triggered.connect(self.on_exit) self.menu_run = QMenu('运行', self) menu = QMenu('菜单', self) menu.addMenu(self.menu_run) menu.addAction(act_setting) menu.addSeparator() menu.addAction(self.act_autostart) menu.addAction(act_exit) self.systemTray.setContextMenu(menu) self.systemTray.show() self.showMessage('启动工具正在运行') self.ui.btn_add.clicked.connect(self.on_add) self.ui.btn_delete.clicked.connect(self.on_delete) self.ui.btn_apply.clicked.connect(self.on_apply) self.ui.btn_env_add.clicked.connect(self.on_env_add) self.ui.btn_env_del.clicked.connect(self.on_env_del) self.ui.btn_open.clicked.connect(self.on_open) self.ui.btn_run.clicked.connect(self.on_run) self.ui.le_args.textEdited.connect(self.on_edited) self.ui.le_desc.textEdited.connect(self.on_edited) self.ui.le_exe.textEdited.connect(self.on_edited) self.ui.cb_process.currentIndexChanged.connect(self.on_index_changed) self.ui.le_exe.installEventFilter(self) self.init() def eventFilter(self, obj, event): if event.type() == QEvent.DragEnter: # we need to accept this event explicitly to be able to receive QDropEvents! event.accept() if event.type() == QEvent.Drop: md = event.mimeData() urls = md.urls() if (urls and urls[0].scheme() == 'file'): # for some reason, this doubles up the intro slash filepath = urls[0].path().mid(1) self.ui.le_exe.setText(filepath) self.modify = True self.ui.btn_apply.setEnabled(True) event.accept() return QObject.eventFilter(self, obj, event) def showMessage(self, msg): self.systemTray.showMessage('Launcher', msg, QSystemTrayIcon.Information, 10000) def config_dir(self): confd = QString2str( QApplication.applicationDirPath()) + os.sep + 'configs' dir = QDir(confd) if not dir.exists(): dir.mkpath(confd) return confd def on_settings(self): self.show() def on_exit(self): QtGui.qApp.quit() def on_edited(self): self.modify = True self.ui.btn_apply.setEnabled(True) def on_apply(self): if self.currentProcess is None: QMessageBox.warning(self, '警告', '未选择有效启动项,无法完成保存!') return args = self.ui.le_args.text() exe = self.ui.le_exe.text() desc = self.ui.le_desc.text() isInherit = self.ui.cb_inheri.checkState() == QtCore.Qt.Checked self.currentProcess.setArgs(QString2str(args)) self.currentProcess.setExe(QString2str(exe)) self.currentProcess.setDesc(QString2str(desc)) self.currentProcess.setIsInherit(isInherit) envs = {} for i in range(self.ui.tw_envs.rowCount()): key = self.ui.tw_envs.item(i, 0).text() value = self.ui.tw_envs.item(i, 1).text() envs[QString2str(key)] = QString2str(value) self.currentProcess.setEnvs(envs) self.processDict[self.currentProcess.getName()] = self.currentProcess configDir = self.config_dir() configFilePath = configDir + os.sep + self.currentProcess.getName( ) + '.json' with open(configFilePath, 'w+') as f: f.write(self.currentProcess.save()) self.modify = False self.ui.btn_apply.setEnabled(False) QMessageBox.information(self, '提示', '已保存!') def on_add(self): ret = QInputDialog.getText(self, '请输入启动项目名称', '名称') if not ret[1]: return name = ret[0] if name.isEmpty(): return if self.processDict.has_key(QString2str(name)): QMessageBox.warning(self, '警告', '该启动项已存在!') return curProcess = Process() curProcess.setName(QString2str(name)) configDir = self.config_dir() configFilePath = configDir + os.sep + QString2str(name) + '.json' with open(configFilePath, 'w+') as f: f.write(curProcess.save()) self.add_item(curProcess) self.ui.cb_process.setCurrentIndex(self.ui.cb_process.count() - 1) def on_delete(self): name = self.ui.cb_process.currentText() index = self.ui.cb_process.currentIndex() if not self.processDict.has_key(QString2str(name)): QMessageBox.warning(self, '警告', '请先选择要删除的配置项!') return process = self.processDict.pop(QString2str(name)) for action in self.menu_run.actions(): if action.text() == name: self.menu_run.removeAction(action) self.ui.cb_process.removeItem(index) configFilePath = self.config_dir() + os.sep + QString2str( name) + '.json' os.remove(configFilePath) def on_index_changed(self, index): if self.modify and QMessageBox.question( self, '提示', '启动项已修改,是否保存?', QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes: self.on_apply() name = self.ui.cb_process.itemText(index) self.reset() if self.processDict.has_key(QString2str(name)): process = self.processDict[QString2str(name)] self.currentProcess = process self.display(process) def on_env_add(self): self.ui.tw_envs.setRowCount(self.ui.tw_envs.rowCount() + 1) self.modify = True self.ui.btn_apply.setEnabled(True) def on_env_del(self): index = self.ui.tw_envs.currentRow() self.ui.tw_envs.removeRow(index) self.modify = True self.ui.btn_apply.setEnabled(True) def on_run(self): if self.modify and QMessageBox.question( self, '提示', '启动项已修改,是否保存?', QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes: self.on_apply() name = self.ui.cb_process.currentText() if self.processDict.has_key(QString2str(name)): process = self.processDict[QString2str(name)] if process.start(): self.showMessage(u'%s启动项已执行' % process.getName()) else: self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName()) else: QMessageBox.warning(self, '警告', '请先选择要运行的启动项!') def on_action_run(self): name = self.sender().text() if self.processDict.has_key(QString2str(name)): process = self.processDict[QString2str(name)] if process.start(): self.showMessage(u'%s启动项已执行' % process.getName()) else: self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName()) else: QMessageBox.warning(self, '警告', '请先选择要运行的启动项!') def on_open(self): filePath = QFileDialog.getOpenFileName(self, '选择程序') self.ui.le_exe.setText(filePath) self.modify = True self.ui.btn_apply.setEnabled(True) def closeEvent(self, event): event.ignore() self.hide() def add_item(self, process): self.processDict[process.getName()] = process self.ui.cb_process.addItem(process.getName()) act = self.menu_run.addAction(process.getName()) act.triggered.connect(self.on_action_run) def init(self): self.modify = False self.ui.btn_apply.setEnabled(False) self.currentProcess = None self.processDict = {} config_dir = self.config_dir() items = os.listdir(config_dir) for item in items: currentPath = self.config_dir() + os.sep + item if not os.path.isdir(currentPath) and os.path.exists(currentPath): with open(currentPath, 'r') as f: content = f.read() process = Process() if process.load(content): self.add_item(process) def reset(self): self.ui.le_args.setText('') self.ui.le_exe.setText('') self.ui.le_desc.setText('') self.ui.tw_envs.clear() self.ui.tw_envs.setRowCount(0) self.modify = False self.ui.btn_apply.setEnabled(False) def display(self, process): self.ui.le_args.setText(process.getArgs()) self.ui.le_exe.setText(process.getExe()) self.ui.le_desc.setText(process.getDesc()) envs = process.getEnvs() for key in envs.keys(): row = self.ui.tw_envs.rowCount() self.ui.tw_envs.setRowCount(row + 1) self.ui.tw_envs.setItem(row, 0, QTableWidgetItem(key)) self.ui.tw_envs.setItem(row, 1, QTableWidgetItem(envs[key])) def on_autostart(self): if self.act_autostart.isChecked(): self.set_autostart(True) self.showMessage('已设置开机启动') else: self.set_autostart(False) self.showMessage('已取消开机启动') def is_autostart(self): reg = QSettings( "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings.NativeFormat) return reg.contains("launcher") def set_autostart(self, auto): path = QApplication.applicationFilePath() path = QDir.toNativeSeparators(path) reg = QSettings( "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings.NativeFormat) if auto is True: reg.setValue("launcher", QVariant(QString('"%1"').arg(path))) else: reg.remove("launcher")