class VMWidget(QWidget): def __init__(self,parent = None): super(VMWidget,self).__init__(parent) #self.setStyleSheet("QToolTip{background-color:white;color:black;font-size:12px;}") #self.setFont(QFont(u"微软雅黑",12)) self.vmInfoList = [] self.oldVmInfoList = [] self.vmOffInfoList = [] self.threadMap = {} self.processMap = {} self.parent = parent self.domainManager = DomainManager() self.progressMonitor = ProgressThread() self.vmstatusTimer = QTimer() #self.vmstatusTimer.start(7000) self.connect(self.vmstatusTimer, SIGNAL("timeout()"),self.postStatusToServer) self.startVmInfo = None if common.SCROLL_TYPE != "slider": self.scrollArea = QScrollArea(self) self.scrollArea.setStyleSheet("background-color:transparent;border:0px") self.vmButtonList = [] self.vmTableWidget = QTableWidget() self.setTableWidgetStyle() self.mainLayout = QVBoxLayout() self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.scrollArea) self.mainLayout.addSpacing(10) self.setLayout(self.mainLayout) self.downloadingList = [] if common.SCROLL_TYPE == "slider": #三个自定义button,用于显示相应的虚拟机 self.firstVM = CustomVMButton(self) self.secondVM = CustomVMButton(self) self.thirdVM = CustomVMButton(self) self.vmButtonList = [self.firstVM, self.secondVM, self.thirdVM] for i in range(len(self.vmButtonList)): self.vmButtonList[i].setIcon(QIcon("images/windows.png")) self.vmButtonList[i].setIconSize(QSize(100,100)) self.vmButtonList[i].setFlat(True) self.vmButtonList[i].setFont(QFont("Times", 15, QFont.Bold)) #设置滑动条的样式 self.slider = QSlider(Qt.Vertical,self) self.slider.setStyleSheet( "QSlider::groove:vertical { " "border: 1px solid #4A708B; " "background: #C0C0C0; " "width: 5px; " "border-radius: 1px; " "padding-left:-1px; " "padding-right:-1px; " "padding-top:-1px; " "padding-bottom:-1px; " "}" "QSlider::handle:vertical {" "height: 100px;" "background: white;" "margin: 0 -4px;" "}" ) self.btnLayout = QHBoxLayout(self) self.btnLayout.addStretch() self.btnLayout.addWidget(self.firstVM) self.btnLayout.addWidget(self.secondVM) self.btnLayout.addWidget(self.thirdVM) self.btnLayout.addStretch() self.btnLayout.addSpacing(10) self.btnLayout.addWidget(self.slider) self.btnLayout.setSpacing(10) self.btnLayout.setMargin(10) self.setLayout(self.btnLayout) def setTableWidgetStyle(self): #self.vmTableWidget.setColumnCount(3) #self.vmTableWidget.setRowCount(1) self.vmTableWidget.setFrameShape(QFrame.NoFrame) self.vmTableWidget.setEditTriggers(QTableWidget.NoEditTriggers)#不能编辑 self.vmTableWidget.setSelectionMode(QAbstractItemView.NoSelection) self.vmTableWidget.verticalHeader().setVisible(False)#设置垂直头不可见 self.vmTableWidget.horizontalHeader().setVisible(False)#设置垂直头不可见 self.vmTableWidget.setShowGrid(False) self.vmTableWidget.setFocusPolicy(Qt.NoFocus) self.vmTableWidget.setStyleSheet("QTableWidget{background-color: rgb(235, 235, 235,0);}") def getVmList(self): vmList = [] vmInfo = {} vmInfo["name"] = "15615123021654541" vmInfo["status"] = "offline" vmInfo["name"] = "offline" vmInfo["os_distro"] = "windows_7" vmInfo1 = {} vmInfo1["name"] = "1561545421654541" vmInfo1["status"] = "offline" vmInfo1["name"] = "offline" vmInfo2 = {} vmInfo2["name"] = "1561afew21654541" vmInfo2["status"] = "offline" vmInfo2["name"] = "windows_7" vmInfo3 = {} vmInfo3["name"] = "afewfdsafewfa" vmInfo3["status"] = "offline" vmInfo3["name"] = "windows_7" vmList.append(vmInfo) vmList.append(vmInfo1) vmList.append(vmInfo2) vmList.append(vmInfo3) vmList.append(vmInfo1) vmList.append(vmInfo2) vmList.append(vmInfo3) return vmList def postStatusToServer(self): '''serverState = VMInfoManager.instance().getCurCloudServerState() if serverState != "enable": return''' postInfo = {} state = self.domainManager.getStatus() if self.vmOffInfoList == [] or len(self.downloadingList) != 0: #self.processMap.clear() #self.threadMap.clear() return if len(state) == 0: postInfo["state"] = "shutdown" postInfo["vmname"] = self.vmOffInfoList[0]["vmname"] else: for item in state: postInfo["state"] = "running" if state[item].has_key("disk_io"): postInfo["io_throughput"] = state[item]["disk_io"] if state[item].has_key("max_disk_io"): postInfo["io_throughput_peak"] = state[item]["max_disk_io"] if state[item].has_key("net_io"): postInfo["net_throughput"] = state[item]["net_io"] if state[item].has_key("max_net_io"): postInfo["net_throughput_peak"] = state[item]["max_net_io"] if state[item].has_key("memory_size"): postInfo["memory"] = state[item]["memory_size"]*1024 if state[item].has_key("vmname"): postInfo["vmname"] = state[item]["vmname"] if state[item].has_key("name"): postInfo["coursename"] = state[item]["name"] if state[item].has_key("cpu"): postInfo["cpu_utilization"] = state[item]["cpu"] self.emit(SIGNAL("vmstateinfo"),postInfo) def showVmList(self): subWidget = QWidget() if self.vmstatusTimer.isActive(): pass else: #if globalvariable.CLASS_STATUS: self.vmstatusTimer.start(7000) #self.connect(self.vmstatusTimer, SIGNAL("timeout()"),self.postStatusToServer) if self.scrollArea.widget(): self.scrollArea.takeWidget() self.vmTableWidget = QTableWidget() self.setTableWidgetStyle() #if self.vmTableWidget self.vmTableWidget.clear() #self.vmInfoList = self.getVmList() num = len(self.vmInfoList) columnCount = 1 rowCount = 1 if num == 0: return if num <=3: #self.scrollArea.verticalScrollBar().hide() rowCount = 1 if num == 1: columnCount = 1 elif num == 2: columnCount = 2 elif num == 3: columnCount = 3 else: rowCount = num/3 rest = num%3 if (rowCount == 2 and rest == 0) or rowCount == 1 : pass if rest > 0: rowCount+=1 columnCount = 3 parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 tableWidth = (parentWidth - 20*2 -50*2*ratio)/3 + 5 if len(self.vmInfoList) > 3: tableWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) + 5 self.vmTableWidget.setColumnCount(columnCount) self.vmTableWidget.setRowCount(rowCount) self.vmTableWidget.setFixedWidth(parentWidth-100) self.vmTableWidget.setFixedHeight((tableWidth+10)*rowCount) self.vmTableWidget.verticalHeader().setDefaultSectionSize(tableWidth+10) self.vmTableWidget.horizontalHeader().setDefaultSectionSize((parentWidth-100)/columnCount) #self.setWidget("status") if columnCount <= 3 and rowCount == 1: for i in range(columnCount): self.setRowColumnWidget(0,i,self.vmInfoList[i]["name"]) else: for i in range(rowCount): for j in range(3): if i*3 + j <= num-1: self.setRowColumnWidget(i, j, self.vmInfoList[i*3+j]["name"]) mainLayout = QHBoxLayout() mainLayout.setMargin(0) mainLayout.addWidget(self.vmTableWidget) subWidget.setLayout(mainLayout) #if self.scrollArea.widget(): #self.scrollArea.takeWidget() self.scrollArea.setWidget(subWidget) self.scrollArea.setWidgetResizable(True) #self.scrollArea.horizontalScrollBar().hide() def setRowColumnWidget(self,row,column,vmid): status = "sfw" #self.vmTableWidget.clear() mainWidget = QWidget() #self.vmTableWidget.hideColumn() #vmRowButtonList = [] parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 if len(self.vmInfoList) > 3: vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) vmButton = CustomVMButton() vmButton.setFixedSize(QSize(vmWidth, vmWidth + 5)) vmButton.setIconSize(QSize(vmWidth - 60*ratio,vmWidth - 30*ratio)) vmButton.setText(self.vmInfoList[row*3 + column]["name"]) vmButton.setFlat(True) vmButton.setFont(QFont("Times", 15, QFont.Bold)) vmInfo = self.vmInfoList[row*3 + column] vmButton.setVMInfo(vmInfo) imageName = "other.png" if self.vmInfoList[row*3 + column].has_key("os_distro"): if common.imageMap.has_key(self.vmInfoList[row*3 + column]["os_distro"]): imageName = common.imageMap[self.vmInfoList[row*3 + column]["os_distro"]] else: LogRecord.instance().logger.info(u'common.imageMap中未找到键值%s' % self.vmInfoList[row*3 + column]["os_distro"]) vmButton.setIcon(QIcon("images/systemImage/%s" % imageName)) # if globalvariable.CLASS_STATUS and not globalvariable.TICHU_STATUS: # self.connect(vmButton, SIGNAL("clicked()"),self.slotOpenVMLesson) # self.connect(vmButton, SIGNAL("controlvm"),self.slotControlVM) # else: # self.connect(vmButton, SIGNAL("clicked()"),self.slotCreateVMLesson) #vmRowButtonList.append(vmButton) self.vmButtonList.append(vmButton) #firMybutton.setStatus("undownload") vmButton.setObjectName(vmid + ":" + QString.number(row) + ":" + QString.number(column)) self.connect(vmButton, SIGNAL("clicked()"),self.startDomain) progressBar = WidgetProgress() progressBar.setFixedSize(vmWidth, vmWidth + 5) #progressBar.progressBar.setValue(0) progressBar.setVmName(self.vmInfoList[row*3 + column]["name"]) progressBar.setObjectName(vmid + ":" + QString.number(row) + ":" + QString.number(column)) #progressBar.objectName() #self.firMybutton.setText(self.tr("确萨")) #progressBar = QProgressBar() myLayout = QHBoxLayout() myLayout.setMargin(0) myLayout.addStretch() myLayout.addWidget(vmButton) myLayout.addWidget(progressBar) myLayout.addStretch() if vmid in self.downloadingList: vmButton.hide() else: progressBar.hide() #firMybutton.hide() mainWidget.setLayout(myLayout) self.vmTableWidget.setCellWidget(row, column, mainWidget) #self.mainLayout.addWidget(mainWidget) def setVMInfoList(self, vmInfoList, vmOffInfoList): self.oldVmInfoList = LocalImgManager.instance().getCompleteList() self.vmInfoList = vmInfoList self.vmOffInfoList = vmOffInfoList self.domainManager.deleteImgList(vmOffInfoList) # needDeleteList = self.compareDelete(self.oldVmInfoList, vmOffInfoList) if self.vmOffInfoList == []: #self.progressMonitor.stop() #self.threadMap.clear() for item in self.processMap: self.processMap[item].stop() if self.processMap[item].isRunning(): self.processMap[item].exit() for item in self.threadMap: if self.threadMap[item].isRunning(): self.threadMap[item].exit() self.processMap.clear() self.threadMap.clear() #self.killRsyncThread() # if len(needDeleteList) == 0: # return # else: # self.domainManager.deleteImgList(needDeleteList) def stopAllDownload(self): for item in self.processMap: self.processMap[item].stop() if self.processMap[item].isRunning(): self.processMap[item].exit() self.killScpThread() for item in self.threadMap: #self.threadMap[item].stop() if self.threadMap[item].isRunning(): self.threadMap[item].exit() self.downloadingList = [] self.processMap.clear() self.threadMap.clear() def killScpThread(self): pidList = self.getScpsProcessId() #sshPidList = self.getSshProcessId() for item in pidList: self.killVmId(item) '''for mtem in sshPidList: self.killVmId(mtem)''' def killVmId(self,killid): cmd = "kill -9 " + killid os.system(str(cmd)) def getScpsProcessId(self):#得到运行虚拟机的进程号序列,可用于关闭某个虚拟机 idList = [] cmd = "ps aux | grep scp" output = "" statusOutput = [] statusOutput = commands.getstatusoutput(cmd) if statusOutput[0] == 0: output = statusOutput[1] else: output = "" result = output.split("\n") for i in range(len(result)): if QString(result[i]).contains("scp"): idList.append(QString(result[i]).simplified().split(" ")[1]) return idList def getSshProcessId(self):#得到运行虚拟机的进程号序列,可用于关闭某个虚拟机 idList = [] cmd = "ps aux | grep /usr/bin/ssh" output = "" statusOutput = [] statusOutput = commands.getstatusoutput(cmd) if statusOutput[0] == 0: output = statusOutput[1] else: output = "" result = output.split("\n") for i in range(len(result)): if QString(result[i]).contains("/usr/bin/ssh"): idList.append(QString(result[i]).simplified().split(" ")[1]) return idList def compareDelete(self,oldList,newList): nameList = [] deleteList = [] for item in newList: nameList.append(item["name"]) for name in oldList: if name not in nameList: deleteList.append(name) return deleteList def autoStartDownload(self): #return num = len(self.vmInfoList) if num == 0: return else: #self.progressMonitor.setVmInfoList(self.vmInfoList) #self.progressMonitor.start() #self.connect(self.progressMonitor, SIGNAL("downloadover"),self.slotDownloadOver) imgMap = LocalImgManager.instance().getCompliteListSize() for i in range(len(self.vmInfoList)): mark = 0 for item in imgMap: if item == self.vmInfoList[i]["name"] and imgMap[item] == self.vmInfoList[i]["img_file_size"]: mark = 1 if mark == 1: continue row = i/3 column = i%3 self.downloadingList.append(self.vmInfoList[i]["name"]) # self.downloadThread = DownloadThread() # self.progressThread = ProgressThread() threadid = self.vmInfoList[i]["name"] + ":" + QString.number(row) + ":" + QString.number(column) # self.downloadThread.setProcessId(threadid + ":" + QString.number(self.vmInfoList[i]["img_file_size"])) # self.progressThread.setProcessId(threadid + ":" + QString.number(self.vmInfoList[i]["img_file_size"])) # self.connect(self.progressThread, SIGNAL("currentprogress"),self.updateProgressBar) # self.connect(self.progressThread, SIGNAL("downloadover"),self.slotDownloadOver) # self.downloadThread.start() # self.progressThread.start() self.setRowColumnWidget(int(row), int(column), self.vmInfoList[i]["name"]) self.createThread(threadid,self.vmInfoList[i]) #time.sleep(1) #return self.startFirstThread() def startFirstThread(self): for item in self.threadMap: self.threadMap[item].start() self.processMap[item].start() self.connect(self.processMap[item], SIGNAL("currentprogress"),self.updateProgressBar) #self.connect(self.processMap[item], SIGNAL("downloadover"),self.slotDownloadOver) self.connect(self.threadMap[item], SIGNAL("downloadover"),self.slotDownloadOver) self.connect(self.threadMap[item], SIGNAL("downloaderror"),self.slotDownloadError) return def slotDownloadError(self,signalid): pass def createThread(self,threadid,vmInfo): if self.threadMap.has_key(threadid): if self.threadMap[threadid].isRunning(): self.threadMap[threadid].exit() self.threadMap.pop(threadid) if self.processMap.has_key(threadid): if self.processMap[threadid].isRunning(): self.processMap[threadid].exit() self.processMap.pop(threadid) downloadThread = DownloadThread() progressThread = ProgressThread() self.threadMap[threadid] = downloadThread self.processMap[threadid] = progressThread self.threadMap[threadid].setProcessId(threadid + ":" + str(vmInfo["img_file_size"])) self.processMap[threadid].setProcessId(threadid + ":" + str(vmInfo["img_file_size"])) #self.threadMap[threadid].start() #self.processMap[threadid].start() #self.connect(self.processMap[threadid], SIGNAL("currentprogress"),self.updateProgressBar) #self.connect(self.processMap[threadid], SIGNAL("downloadover"),self.slotDownloadOver) def checkAddDownload(self): #return num = len(self.vmInfoList) #existImgList = LocalImgManager.instance().getCompleteList() existImgList = LocalImgManager.instance().getCompliteListSize() if num == 0: return else: count = 0 for i in range(len(self.vmInfoList)): row = i/3 column = i%3 if existImgList.has_key(self.vmInfoList[i]["name"]) and existImgList.get(self.vmInfoList[i]["name"]) == self.vmInfoList[i]["img_file_size"]: pass elif self.vmInfoList[i]["name"] in self.downloadingList: pass elif existImgList.has_key(self.vmInfoList[i]["name"]) and self.domainManager.getDom() != None and self.startVmInfo != None and self.startVmInfo == self.domainManager.getDomainInfo(): pass else: if self.vmInfoList[i]["name"] not in self.downloadingList: self.downloadingList.append(self.vmInfoList[i]["name"]) threadid = self.vmInfoList[i]["name"] + ":" + QString.number(row) + ":" + QString.number(column) self.createThread(threadid, self.vmInfoList[i]) self.setRowColumnWidget(int(row), int(column), self.vmInfoList[i]["name"]) count+= 1 if len(self.threadMap) == count: self.startFirstThread() if count > 0: self.emit(SIGNAL("startadddownload")) def startDomain(self): pbp = CustomVMButton().sender() buttonName = pbp.objectName() vmInfo = pbp.vmInfo for item in self.vmOffInfoList: if item["name"] == vmInfo["name"]: self.startVmInfo = item #return vmid = buttonName.split(":")[0] row = buttonName.split(":")[1] column = buttonName.split(":")[2] self.domainManager.setDomainInfo(self.startVmInfo) LogRecord.instance().logger.info(u"开始开启虚拟机-----------------------------------------------00") self.domainManager.startDomainByName() LogRecord.instance().logger.info(u"结束开启虚拟机-----------------------------------------------11") def updateProgressBar(self,count,objectname): #if self.threadMap[objectname].isRunning(): # for i in range(len(self.downloadingList)): # if objectname == self.downloadingList[i]: # progress=self.vmTableWidget.findChild((WidgetProgress, ),objectname) # progress.progressBar.setValue(count) progress=self.vmTableWidget.findChild((WidgetProgress, ),objectname) if not progress: return progress.progressBar.setValue(count) def slotDownloadOver(self,count,name): serverState = VMInfoManager.instance().getCurCloudServerState() if serverState != "enable": return if self.processMap.has_key(name): self.processMap[name].stop() #self.processMap.pop(name) #self.threadMap.pop(name) vmid = name.split(":")[0] row = name.split(":")[1] column = name.split(":")[2] self.downloadingList = [] self.setRowColumnWidget(int(row), int(column), vmid) time.sleep(4) if self.processMap.has_key(name) and self.processMap[name].isRunning: self.processMap[name].exit() if self.threadMap.has_key(name) and self.threadMap[name].isRunning: self.threadMap[name].exit() self.processMap.pop(name) self.threadMap.pop(name) self.emit(SIGNAL("avmdownloadover")) # for item in self.threadMap: # self.threadMap[item].start() # self.processMap[item].start() # self.connect(self.processMap[item], SIGNAL("currentprogress"),self.updateProgressBar) # self.connect(self.processMap[item], SIGNAL("downloadover"),self.slotDownloadOver) # return def getDownloadingList(self): return self.downloadingList def updateVMList(self): language = StoreInfoParser.instance().getLanguage() m_pTranslator = QTranslator() exePath = "./" if language == "chinese": QmName = "zh_CN.qm" StoreInfoParser.instance().setLanguage("chinese") else: QmName = "en_US.qm" if(m_pTranslator.load(QmName, exePath)): QCoreApplication.instance().installTranslator(m_pTranslator) if self.vmstatusTimer.isActive(): self.vmstatusTimer.stop() else: pass subWidget = QWidget() vmNum = len(self.vmInfoList) rowNum = 0 subMainLayout = QVBoxLayout() subMainLayout.setMargin(0) #subMainLayout.addStretch() #subMainLayout.addSpacing(10) #subMainLayout.setSpacing(10) self.vmButtonList = [] if vmNum % 3 != 0: rowNum = vmNum / 3 + 1 else: rowNum = vmNum / 3 for i in range(rowNum): indexEnd = 3 if i == rowNum - 1: indexEnd = vmNum - (i*3) parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 if vmNum > 3: vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) vmRowButtonList = [] for j in range(indexEnd): vmButton = CustomVMButton(self) vmButton.setFixedSize(QSize(vmWidth, vmWidth + 5)) vmButton.setIconSize(QSize(vmWidth - 60*ratio,vmWidth - 30*ratio)) vmButton.setText(self.vmInfoList[i*3 + j]["name"]) vmButton.setToolTip(self.tr("course: ") + self.vmInfoList[i*3 + j]["name"]) vmButton.setStyleSheet(u"QToolTip{border-radius:5px;background-color:white;color:black;font-size:20px;font-family:微软雅黑;}") vmButton.setFlat(True) vmButton.setFont(QFont("Times", 15, QFont.Bold)) vmInfo = self.vmInfoList[i*3 + j] vmButton.setVMInfo(vmInfo) imageName = "other.png" if self.vmInfoList[i*3 + j].has_key("os_distro"): if common.imageMap.has_key(self.vmInfoList[i*3 + j]["os_distro"]): imageName = common.imageMap[self.vmInfoList[i*3 + j]["os_distro"]] else: LogRecord.instance().logger.info(u'common.imageMap中未找到键值%s' % self.vmInfoList[i*3 + j]["os_distro"]) vmButton.setIcon(QIcon("images/systemImage/%s" % imageName)) if globalvariable.CLASS_STATUS and not globalvariable.TICHU_STATUS: self.connect(vmButton, SIGNAL("clicked()"),self.slotOpenVMLesson) self.connect(vmButton, SIGNAL("controlvm"),self.slotControlVM) else: self.connect(vmButton, SIGNAL("clicked()"),self.slotCreateVMLesson) vmRowButtonList.append(vmButton) self.vmButtonList.append(vmButton) btnLayout = QHBoxLayout() if vmNum > 3: btnLayout.setSpacing(10) #btnLayout.setMargin(10) btnLayout.addSpacing(30) for vmbtn in vmRowButtonList: btnLayout.addWidget(vmbtn) btnLayout.addStretch() subMainLayout.addLayout(btnLayout) #subMainLayout.addStretch() subWidget.setLayout(subMainLayout) if self.scrollArea.widget(): self.scrollArea.takeWidget() self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(subWidget) def startVM(self): return def autoOpenVMLesson(self, vmName, allflag = False): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') if self.vmButtonList: vmInfo = self.vmButtonList[0].getVMInfo() VMOperation.instance().setCurrentVMInfo(vmInfo) #thread.start_new_thread(VMOperation.instance().openVM,()) if allflag == True: if VMOperation.instance().openVM(): LogRecord.instance().logger.info(u'start the lesson') else: if VMOperation.instance().openVM(): LogRecord.instance().logger.info(u'start the lesson') else: LogRecord.instance().logger.info(u'未监测到虚拟机%s的信息' % vmName) def autoOpenOffVMLesson(self): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') if len(self.vmInfoList) == 1: if self.vmInfoList[0]["name"] in self.downloadingList: return else: self.startVmInfo = self.vmInfoList[0] self.domainManager.setDomainInfo(self.startVmInfo) self.domainManager.startDomainByName() else: return def checkDownloadOver(self): if self.autoCourse in self.downloadingList: pass else: self.courseTimer.stop() #self.autoCourse = "" for item in self.vmOffInfoList: if self.autoCourse == item["name"]: vmInfo = item self.domainManager.setDomainInfo(vmInfo) self.domainManager.startDomainByName() return def autoOpenCourse(self,name,classid = None): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') self.autoCourse = name if name in self.downloadingList: self.courseTimer = QTimer() self.courseTimer.start(1000) self.connect(self.courseTimer, SIGNAL("timeout()"),self.checkDownloadOver) else: for item in self.vmOffInfoList: if name == item["name"]: vmInfo = item if classid != None: vmInfo["classid"] = classid self.domainManager.setDomainInfo(vmInfo) self.domainManager.startDomainByName() return def slotCreateVMLesson(self): vmBtn = self.sender() if vmBtn: LogRecord.instance().logger.info(u'开始创建虚拟机') if globalvariable.VM_IS_CREATE_STATUS: LogRecord.instance().logger.info(u'重复点击!') return else: globalvariable.VM_IS_CREATE_STATUS = True LogRecord.instance().logger.info(u'准备获取虚拟机信息!') paramInfo = vmBtn.getVMInfo() LogRecord.instance().logger.info(u'准备获取虚拟机信息完成!') try: vmName = VMOperation.instance().createVMLesson(paramInfo) except: LogRecord.instance().logger.info(u'创建虚拟机异常.........!') LogRecord.instance().logger.info(u'得到创建的虚拟机信息!') if vmName: LogRecord.instance().logger.info(u'创建虚拟机%s成功' % vmName) vmInfo = NetworkManager.instance().getVMInfo(vmName) if vmInfo == None: globalvariable.VM_IS_CREATE_STATUS = False return if len(vmInfo) == 0: globalvariable.VM_IS_CREATE_STATUS = False return vmInfo[0]["vmname"] = vmInfo[0]["name"] if vmInfo: VMOperation.instance().setCurrentVMInfo(vmInfo[0]) if VMOperation.instance().openVM(True): #保存开启虚拟机的名称 #globalvariable.VM_IS_CREATE_STATUS = False WindowMonitor.instance().insertVmId(vmName) else: globalvariable.VM_IS_CREATE_STATUS = False #删除没有成功运行的虚拟机 if VMOperation.instance().removeVMLesson(vmName): LogRecord.instance().logger.info(u"删除后台相应的虚拟机成功") else: LogRecord.instance().logger.info(u'未查询到相应的虚拟机:%s' % vmName) globalvariable.VM_IS_CREATE_STATUS = False else: LogRecord.instance().logger.info(u'创建虚拟机失败') globalvariable.VM_IS_CREATE_STATUS = False #刷新虚拟机界面 self.emit(SIGNAL("refreshVMS")) def slotControlVM(self, action): vmBtn = self.sender() if vmBtn: vmInfo = vmBtn.getVMInfo() VMOperation.instance().setCurrentVMInfo(vmInfo) VMOperation.instance().controlVM(action) vmInfos = globalvariable.VM_INFO self.setVMInfoList(vmInfos,[]) self.updateVMList() def slotOpenVMLesson(self): #vmInfo = [] vmBtn = self.sender() if vmBtn: btnVMInfo = vmBtn.getVMInfo() VMOperation.instance().setCurrentVMInfo(btnVMInfo) VMOperation.instance().openVM(True) # if globalvariable.CLASS_STATUS: # vmInfo = globalvariable.VM_INFO # else: # vmInfo = VMInfoManager.instance().getLessonListInfo() # #self.setVMInfoList(vmInfo,[]) #self.updateVMList() #slider def setSliderMaxValue(self, value): """设在滑动条的最大值""" maxValue = 1 if value % 3 == 0: maxValue = (value / 3) else: maxValue = (value / 3 + 1) maxValue = maxValue - 1 self.slider.setMinimum(1) self.slider.setMaximum(maxValue*3) self.slider.setValue(self.slider.maximum()) self.currentIndex = maxValue self.maxValue = maxValue self.updateVMList() def paintEvent(self,event): if common.SCROLL_TYPE == "slider": self.setNodeSize(QSize(self.geometry().width()*4/15,self.geometry().height()*4/9)) elif len(self.vmInfoList) <= 6: subWidget = self.scrollArea.widget() if subWidget != None: if len(self.vmInfoList) <= 3: subWidget.move((self.geometry().width() - subWidget.width())/2, (self.geometry().height() - subWidget.height())/2 - 20) else: subWidget.move((self.geometry().width() - subWidget.width())/2 - 15, (self.geometry().height() - subWidget.height())/2) QWidget.paintEvent(self, event) #slider def setNodeSize(self,size): self.btnLayout.setSpacing(size.width()/20) self.btnLayout.setMargin(size.width()*3/20) self.firstVM.setIconSize(size) self.secondVM.setIconSize(size) self.thirdVM.setIconSize(size) self.slider.resize(QSize(self.slider.frameGeometry().width(),self.height()-100)) def wheelEvent(self,event): """鼠标滚轮滚动事件,显示对应的虚拟机""" if common.SCROLL_TYPE == "slider": if event.delta() < 0 and self.currentIndex > 0: self.currentIndex -= 1 self.updateVMListSlider() elif event.delta() > 0 and self.currentIndex < self.maxValue: self.currentIndex += 1 self.updateVMListSlider() self.slider.wheelEvent(event) else: maxValue = self.scrollArea.verticalScrollBar().maximum() minValue = self.scrollArea.verticalScrollBar().minimum() currentValue = self.scrollArea.verticalScrollBar().value() if event.delta() < 0 and currentValue < maxValue: self.scrollArea.wheelEvent(event) elif event.delta() > 0 and currentValue > minValue: self.scrollArea.wheelEvent(event) #slider def updateVMListSlider(self): """更新虚拟机列表""" for i in range(len(self.vmButtonList)): self.vmButtonList[i].hide() vmsInfoList = VMInfoManager.instance().getVMSInfo() if vmsInfoList: self.slider.show() startIndex = (self.maxValue - self.currentIndex) * 3 if startIndex/3 == (self.maxValue): endIndex = len(vmsInfoList) else: endIndex = startIndex + 3 for i in range(startIndex, endIndex): self.vmButtonList[i - startIndex].setText(vmsInfoList[i]) self.vmButtonList[i - startIndex].show() else: self.slider.hide() """ echo <graphics type='sdl display='$DISPLAY' xauth='$XAUTHORITY'/>
class FitParam(object): def __init__(self, name, value, mini, maxi, logscale=False, steps=5000, format='%.3f', size_offset=0, unit=''): self.name = name self.value = value self.min = mini if logscale == False else max(1e-120, mini) self.max = maxi self.logscale = logscale self.steps = steps self.format = format self.unit = unit self.prefix_label = None self.lineedit = None self.unit_label = None self.slider = None self.button = None self._widgets = [] self._size_offset = size_offset self._refresh_callback = None self.dataset = FitParamDataSet(title=_("Curve fitting parameter")) def copy(self): """Return a copy of this fitparam""" return self.__class__(self.name, self.value, self.min, self.max, self.logscale, self.steps, self.format, self._size_offset, self.unit) def create_widgets(self, parent, refresh_callback): self._refresh_callback = refresh_callback self.prefix_label = QLabel() font = self.prefix_label.font() font.setPointSize(font.pointSize() + self._size_offset) self.prefix_label.setFont(font) self.button = QPushButton() self.button.setIcon(get_icon('settings.png')) self.button.setToolTip( _("Edit '%s' fit parameter properties") % self.name) QObject.connect(self.button, SIGNAL('clicked()'), lambda: self.edit_param(parent)) self.lineedit = QLineEdit() QObject.connect(self.lineedit, SIGNAL('editingFinished()'), self.line_editing_finished) self.unit_label = QLabel(self.unit) self.slider = QSlider() self.slider.setOrientation(Qt.Horizontal) self.slider.setRange(0, self.steps - 1) QObject.connect(self.slider, SIGNAL("valueChanged(int)"), self.slider_value_changed) self.update(refresh=False) self.add_widgets([ self.prefix_label, self.lineedit, self.unit_label, self.slider, self.button ]) def add_widgets(self, widgets): self._widgets += widgets def get_widgets(self): return self._widgets def set_scale(self, state): self.logscale = state > 0 self.update_slider_value() def set_text(self, fmt=None): style = "<span style=\'color: #444444\'><b>%s</b></span>" self.prefix_label.setText(style % self.name) if self.value is None: value_str = '' else: if fmt is None: fmt = self.format value_str = fmt % self.value self.lineedit.setText(value_str) self.lineedit.setDisabled(self.value == self.min and self.max == self.min) def line_editing_finished(self): try: self.value = float(self.lineedit.text()) except ValueError: self.set_text() self.update_slider_value() self._refresh_callback() def slider_value_changed(self, int_value): if self.logscale: #~ total_delta = np.log10(1+self.max-self.min) #~ self.value = self.min+10**(total_delta*int_value/(self.steps-1))-1 #~ total_delta = np.log10(self.max)-np.log10(self.min) ratio = int_value / (self.steps - 1) self.value = self.max**ratio * self.min**(1 - ratio) else: total_delta = self.max - self.min self.value = self.min + total_delta * int_value / (self.steps - 1) self.set_text() self._refresh_callback() def update_slider_value(self): from numpy import isnan, isinf if (self.value is None or self.min is None or self.max is None): self.slider.setEnabled(False) if self.slider.parent() and self.slider.parent().isVisible(): self.slider.show() elif self.value == self.min and self.max == self.min: self.slider.hide() else: self.slider.setEnabled(True) if self.slider.parent() and self.slider.parent().isVisible(): self.slider.show() if self.logscale: value_delta = max([np.log10(self.value / self.min), 0.]) total_delta = np.log10(self.max / self.min) if not isnan(self.steps * value_delta / total_delta): intval = int(self.steps * value_delta / total_delta) else: intval = int(self.min) else: value_delta = self.value - self.min total_delta = self.max - self.min intval = int(self.steps * value_delta / total_delta) self.slider.blockSignals(True) print intval print sys.stdout.flush() self.slider.setValue(intval) self.slider.blockSignals(False) def edit_param(self, parent): update_dataset(self.dataset, self) if self.dataset.edit(parent=parent): restore_dataset(self.dataset, self) if self.value > self.max: self.max = self.value if self.value < self.min: self.min = self.value self.update(True) def update(self, refresh=True): self.unit_label.setText(self.unit) self.slider.setRange(0, self.steps - 1) self.update_slider_value() self.set_text() if refresh: self._refresh_callback()
class PreviewWindow(QMainWindow): """ QMainWindow subclass used to show frames & tracking. """ def __init__(self, controller): QMainWindow.__init__(self) # set controller self.controller = controller # set title self.setWindowTitle("Preview") # get parameter window position & size param_window_x = self.controller.param_window.x() param_window_y = self.controller.param_window.y() param_window_width = self.controller.param_window.width() # set position & size to be next to the parameter window self.setGeometry(param_window_x + param_window_width, param_window_y, 10, 10) # create main widget self.main_widget = QWidget(self) self.main_widget.setMinimumSize(QSize(500, 500)) # create main layout self.main_layout = QGridLayout(self.main_widget) self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) # create label that shows frames self.image_widget = QWidget(self) self.image_layout = QVBoxLayout(self.image_widget) self.image_layout.setContentsMargins(0, 0, 0, 0) self.image_label = PreviewQLabel(self) self.image_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.image_label.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.image_label.hide() self.image_layout.addWidget(self.image_label) self.main_layout.addWidget(self.image_widget, 0, 0) # self.image_label.setStyleSheet("border: 1px solid rgba(122, 127, 130, 0.5)") self.bottom_widget = QWidget(self) self.bottom_layout = QVBoxLayout(self.bottom_widget) self.bottom_layout.setContentsMargins(8, 0, 8, 8) self.bottom_widget.setMaximumHeight(40) self.main_layout.addWidget(self.bottom_widget, 1, 0) # create label that shows crop instructions self.instructions_label = QLabel("") self.instructions_label.setStyleSheet("font-size: 11px;") self.instructions_label.setAlignment(Qt.AlignCenter) self.bottom_layout.addWidget(self.instructions_label) # create image slider self.image_slider = QSlider(Qt.Horizontal) self.image_slider.setFocusPolicy(Qt.StrongFocus) self.image_slider.setTickPosition(QSlider.NoTicks) self.image_slider.setTickInterval(1) self.image_slider.setSingleStep(1) self.image_slider.setValue(0) self.image_slider.valueChanged.connect(self.controller.show_frame) self.image_slider.hide() self.bottom_layout.addWidget(self.image_slider) self.zoom = 1 self.offset = [0, 0] self.center_y = 0 self.center_x = 0 # initialize variables self.image = None # image to show self.tracking_data = None # list of tracking data self.selecting_crop = False # whether user is selecting a crop self.changing_heading_angle = False # whether the user is changing the heading angle self.body_crop = None self.final_image = None # set main widget self.setCentralWidget(self.main_widget) # set window buttons if pyqt_version == 5: self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowFullscreenButtonHint) else: self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint) self.show() def wheelEvent(self, event): old_zoom = self.zoom self.zoom = max(1, self.zoom + event.pixelDelta().y() / 100) self.zoom = int(self.zoom * 100) / 100.0 self.update_image_label(self.final_image, zooming=True) def start_selecting_crop(self): # start selecting crop self.selecting_crop = True # add instruction text self.instructions_label.setText("Click & drag to select crop area.") def plot_image(self, image, params, crop_params, tracking_results, new_load=False, new_frame=False, show_slider=True, crop_around_body=False): if image is None: self.update_image_label(None) self.image_slider.hide() self.image_label.hide() else: if new_load: self.image_label.show() self.remove_tail_start() if show_slider: if not self.image_slider.isVisible(): self.image_slider.setValue(0) self.image_slider.setMaximum(self.controller.n_frames - 1) self.image_slider.show() else: self.image_slider.hide() max_inititial_size = 500 if image.shape[0] > max_inititial_size: min_height = max_inititial_size min_width = max_inititial_size * image.shape[ 1] / image.shape[0] elif image.shape[1] > max_inititial_size: min_width = max_inititial_size min_height = max_inititial_size * image.shape[ 0] / image.shape[1] else: min_height = image.shape[0] min_width = image.shape[1] self.main_widget.setMinimumSize( QSize(min_width, min_height + self.bottom_widget.height())) # convert to RGB if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) # update image self.image = image.copy() try: body_crop = params['body_crop'] except: body_crop = None try: tail_start_coords = params['tail_start_coords'] # add tail start point to image cv2.circle(image, (int( round(tail_start_coords[1] - crop_params['offset'][1])), int( round(tail_start_coords[0] - crop_params['offset'][0]))), 1, (180, 180, 50), -1) except (KeyError, TypeError) as error: tail_start_coords = None if tracking_results is not None: body_position = tracking_results['body_position'] heading_angle = tracking_results['heading_angle'] # add tracking to image image = tracking.add_tracking_to_frame(image, tracking_results, cropped=True) if body_crop is not None and body_position is not None: if not crop_around_body: # copy image overlay = image.copy() # draw tail crop overlay cv2.rectangle(overlay, (int(body_position[1] - body_crop[1]), int(body_position[0] - body_crop[0])), (int(body_position[1] + body_crop[1]), int(body_position[0] + body_crop[0])), (242, 242, 65), -1) # overlay with the original image cv2.addWeighted(overlay, 0.2, image, 0.8, 0, image) self.body_crop = None else: self.body_crop = body_crop if crop_around_body: _, image = tracking.crop_frame_around_body( image, body_position, params['body_crop']) self.final_image = image # update image label self.update_image_label( self.final_image, zoom=(not (crop_around_body and body_position is not None)), new_load=new_load) def draw_crop_selection(self, start_crop_coords, end_crop_coords): if self.selecting_crop and self.image is not None: # convert image to rgb if len(self.image.shape) < 3: image = np.repeat(self.image[:, :, np.newaxis], 3, axis=2) else: image = self.image.copy() # copy image overlay = image.copy() # draw crop selection overlay cv2.rectangle(overlay, (start_crop_coords[1], start_crop_coords[0]), (end_crop_coords[1], end_crop_coords[0]), (255, 51, 0), -1) # overlay with the original image cv2.addWeighted(overlay, 0.5, image, 0.5, 0, image) # update image label self.update_image_label(image) def change_offset(self, prev_coords, new_coords): self.offset[0] -= new_coords[0] - prev_coords[0] self.offset[1] -= new_coords[1] - prev_coords[1] self.update_image_label(self.final_image) def draw_tail_start(self, rel_tail_start_coords): if self.controller.params['type'] == "headfixed": # send new tail start coordinates to controller self.controller.update_tail_start_coords(rel_tail_start_coords) # clear instructions text self.instructions_label.setText("") if self.image is not None: image = self.image.copy() cv2.circle(image, (int(round(rel_tail_start_coords[1])), int(round(rel_tail_start_coords[0]))), 1, (180, 180, 50), -1) # update image label self.update_image_label(image) def remove_tail_start(self): self.update_image_label(self.image) def add_angle_overlay(self, angle): image = self.image.copy() image_height = self.image.shape[0] image_width = self.image.shape[1] center_y = image_height / 2 center_x = image_width / 2 cv2.arrowedLine( image, (int(center_x - 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)), int(center_y - 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))), (int(center_x + 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)), int(center_y + 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))), (50, 255, 50), 2) self.update_image_label(image) def remove_angle_overlay(self): self.update_image_label(self.image) def update_image_label(self, image, zoom=True, new_load=False, zooming=False): if image is not None and self.zoom != 1 and zoom: if zooming: self.offset[0] = min( max( 0, self.offset[0] + int( (self.image_label.image.shape[0]) / 2.0) - int(round((image.shape[0] / self.zoom) / 2.0))), image.shape[0] - int(round(image.shape[0] / self.zoom))) self.offset[1] = min( max( 0, self.offset[1] + int( (self.image_label.image.shape[1]) / 2.0) - int(round((image.shape[1] / self.zoom) / 2.0))), image.shape[1] - int(round(image.shape[1] / self.zoom))) else: self.offset[0] = min( max(0, self.offset[0]), image.shape[0] - int(round(image.shape[0] / self.zoom))) self.offset[1] = min( max(0, self.offset[1]), image.shape[1] - int(round(image.shape[1] / self.zoom))) if self.center_y is None: self.center_y = int(round(image.shape[0] / 2.0)) if self.center_x is None: self.center_x = int(round(image.shape[1] / 2.0)) image = image[ self.offset[0]:int(round(image.shape[0] / self.zoom)) + self.offset[0], self.offset[1]:int(round(image.shape[1] / self.zoom)) + self.offset[1], :].copy() if image is not None: if zoom: self.setWindowTitle("Preview - Zoom: {:.1f}x".format( self.zoom)) else: self.setWindowTitle("Preview - Zoom: 1x") else: self.setWindowTitle("Preview") self.image_label.update_pixmap(image, new_load=new_load) def crop_selection(self, start_crop_coord, end_crop_coord): if self.selecting_crop: # stop selecting the crop self.selecting_crop = False # clear instruction text self.instructions_label.setText("") # update crop parameters from the selection self.controller.update_crop_from_selection(start_crop_coord, end_crop_coord) def closeEvent(self, ce): if not self.controller.closing: ce.ignore() else: ce.accept()