class AsyncCaller(object): """Call a Python function after a delay.""" def __init__(self, delay=10): self._delay = delay self._timer = None def _create_timer(self, f): self._timer = QTimer() self._timer.timeout.connect(f) self._timer.setSingleShot(True) def set(self, f): """Call a function after a delay, unless another function is set in the meantime.""" self.stop() self._create_timer(f) self.start() def start(self): """Start the timer and call the function after a delay.""" if self._timer: self._timer.start(self._delay) def stop(self): """Stop the current timer if there is one and cancel the async call.""" if self._timer: self._timer.stop() self._timer.deleteLater()
class total_countdown(QThread): """ This class defines the progressbar update process """ update_trigger = pyqtSignal() end_trigger = pyqtSignal() def __init__(self, *args, **kwargs): super(self.__class__, self).__init__() print("### total_countdown initializeed") def start(self, Total_time): print("### countdown started") self.Total_time = Total_time self.timer = QTimer(self) self.timer.timeout.connect(self.emit_update_sputter) self.timer.start(1000) def emit_update_sputter(self): self.update_trigger.emit() def stop(self): self.timer.stop() self.timer.deleteLater()
class GuiResourceMonitor(ResourceMonitor, QWidget): """ Implementation class of ResourceMonitor by the GUI process. The GUI process uses QTimer to implement start() and stop() methods. """ def __init__(self): QWidget.__init__(self) ResourceMonitor.__init__(self, history_size=GUI_RESOURCE_HISTORY_SIZE) self.resource_monitor_timer = None def start(self): """ Start the resource monitor by scheduling a QTimer. """ self.resource_monitor_timer = QTimer() self.resource_monitor_timer.setSingleShot(False) self.resource_monitor_timer.timeout.connect(self.check_resources) self.resource_monitor_timer.start(GUI_RESOURCE_CHECK_INTERVAL) def stop(self): if self.resource_monitor_timer: try: self.resource_monitor_timer.stop() self.resource_monitor_timer.deleteLater() except RuntimeError: self._logger.error( "Failed to stop GUI resource monitor timer in Debug pane")
def remove_warn(self, timer: QtCore.QTimer, label: QtWidgets.QLabel): timer.deleteLater() label.setParent(None) label.destroy() self.parent.setGeometry(0, 20, 300, self.main_layout.count() * 200 - 200) if self.main_layout.count() == 0: self.parent.hide()
class MessageTip(QWidget): def __init__(self, msg: str): super().__init__() self.initUI(msg) def initUI(self, msg: str): self.setGeometry(300, 300, 350, 120) self.setStyleSheet("background-color: blue") self.setWindowFlags(Qt.FramelessWindowHint) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) label = QLabel() label.setText(msg) layout.addWidget(label) self.setLayout(layout) self.desktop = QDesktopWidget() self.move((self.desktop.availableGeometry().width() - self.width()), self.desktop.availableGeometry().height()) #初始化位置到右下角 self.showAnimation() def showAnimation(self): #显示弹出框动画 self.animation = QPropertyAnimation(self, b'pos') self.animation.setDuration(500) self.animation.setStartValue(QPoint(self.x(), self.y())) self.animation.setEndValue( QPoint( (self.desktop.availableGeometry().width() - self.width()), (self.desktop.availableGeometry().height() - self.height()))) self.animation.start() #设置弹出框1秒弹出,然后渐隐 self.remainTimer = QTimer() self.remainTimer.timeout.connect(self.closeAnimation) self.remainTimer.start(1000) #定时器3秒 def closeAnimation(self): #清除Timer和信号槽 self.remainTimer.stop() #self.disconnect(self.remainTimer,SLOT("closeAnimation()")) self.remainTimer.timeout.disconnect(self.closeAnimation) self.remainTimer.deleteLater() self.remainTimer = None #弹出框渐隐 self.animation = QPropertyAnimation(self, b"windowOpacity") self.animation.setDuration(1000) self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start() #动画完成后清理 #self.connect(self.animation,SIGNAL("finished()"),SLOT("clearAll()")) self.animation.finished.connect(self.clearAll) def clearAll(self): self.close()
class Reloj(QObject): ''' clase ocupada para manejar los temporizadores ''' def __init__(self): super().__init__() self.rapidez_reloj = RAPIDEZ_RELOJ # ponderador self.temporizadores = [] self.intervalo_clientes = LLEGADA_CLIENTES # no cambia durante el juego def reanudar_reloj(self): for temporizador in self.temporizadores: temporizador.start() def pausar_reloj(self): for temporizador in self.temporizadores: temporizador.stop() def temporizador_chef(self, tiempo, senal, chef): tmp_chef = ChefTimer(tiempo * self.rapidez_reloj, senal, chef) tmp_chef.start() self.temporizadores.append(tmp_chef) def temporizador_cliente(self): ''' temporizador asociado a un cliente en especifico ''' tmp_enojarse = QTimer() tmp_enojarse.setSingleShot(True) tmp_irse = QTimer() tmp_irse.setSingleShot(True) self.temporizadores.extend([tmp_enojarse, tmp_irse]) # guardamos el temporizador del ultimo cliente para saber cuando cerrar # el DCC: self.ultimo_cliente_timer = tmp_irse return tmp_enojarse, tmp_irse def temporizador_clientes(self, func): ''' temporizador asociado a la llegada periodica de clientes ''' self.tmp_clientes = QTimer() self.tmp_clientes.setInterval(self.rapidez_reloj * self.intervalo_clientes) self.tmp_clientes.timeout.connect(func) self.tmp_clientes.start() self.temporizadores.append(self.tmp_clientes) def temporizador_acabar_ronda(self, func): self.temporizadores.remove(self.tmp_clientes) self.tmp_clientes.deleteLater() # nos aseguramos # que en caso de pausar y reanudar la ronda, no se vuelva a activar self.tmp_acabar_ronda = QTimer() self.tmp_acabar_ronda.setInterval(self.rapidez_reloj * self.intervalo_clientes) self.tmp_acabar_ronda.setSingleShot(True) self.tmp_acabar_ronda.timeout.connect(func) self.tmp_acabar_ronda.start() self.temporizadores.append(self.tmp_acabar_ronda)
class Progress(QDialog): def __init__( self, title, status, parent=None # type: Any ): super().__init__(parent) self.setWindowTitle(title) buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel) buttonBox.rejected.connect(self.reject) self._status = status self.progressBar = QProgressBar() self.progressBar.setRange(0, 1000) self.progressBar.setValue(0) self.description = QLabel() self.description.setText("") layout = QVBoxLayout() layout.addWidget(self.description) layout.addWidget(self.progressBar) layout.addWidget(buttonBox) self.setLayout(layout) self.prev_st = "" self.prev_pr = 0 self.timer = QTimer(self) self.timer.timeout.connect(self._check_status) self.timer.start(100) self._starter = status["start"] def _check_status(self): if self._starter is not None: self._starter() self._starter = None cur_pr = int(self._status.get("part", 0.) * 1000) if self.prev_pr != cur_pr: self.progressBar.setValue(cur_pr) self.prev_pr = cur_pr cur_st = self._status.get("description", "") if self.prev_st != cur_st: self.description.setText(cur_st) self.prev_st = cur_st if self._status.get("complete"): self.reject() def reject(self): try: self.timer.stop() except RuntimeError: pass else: self.timer.deleteLater() self._status["stop"] = True return super().reject()
class Message(QDialog): def __init__(self): self.desktop = QDesktopWidget() self.move((self.desktop.availableGeometry().width() - self.width()), self.desktop.availableGeometry().height()) # 初始化位置到右下角 self.showAnimation() # 弹出动画 def showAnimation(self): # 显示弹出框动画 self.animation = QPropertyAnimation(self, "pos") self.animation.setDuration(1000) self.animation.setStartValue(QPoint(self.x(), self.y())) self.animation.setEndValue( QPoint((self.desktop.availableGeometry().width() - self.width()), (self.desktop.availableGeometry().height() - self.height() + self.SHADOW_WIDTH))) self.animation.start() # 设置弹出框1秒弹出,然后渐隐 self.remainTimer = QTimer() self.connect(self.remainTimer, signal("timeout()"), self, signal.__slots__("closeAnimation()")) self.remainTimer.start(10000) # 定时器10秒 # 关闭动画 @pyqtSlot() def closeAnimation(self): # 清除Timer和信号槽 self.remainTimer.stop() self.disconnect(self.remainTimer, signal("timeout()"), self, signal.__slots__("closeAnimation()")) self.remainTimer.deleteLater() self.remainTimer = None # 弹出框渐隐 self.animation = QPropertyAnimation(self, "windowOpacity") self.animation.setDuration(1000) self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start() # 动画完成后清理 self.connect(self.animation, signal("finished()"), self, signal.__slots__("clearAll()")) # 清理及退出 def clearAll(self): self.disconnect(self.animation, signal("finished()"), self, signal.__slots__("clearAll()")) sys.exit() # 退出
class ProgressBar(QProgressBar): def __init__(self, *args, **kwargs): super(ProgressBar, self).__init__(*args, **kwargs) self.setValue(0) if self.minimum() != self.maximum(): self.timer = QTimer(self, timeout=self.onTimeout) self.timer.start(randint(1, 3) * 1000) def onTimeout(self): if self.value() >= 100: self.timer.stop() self.timer.deleteLater() del self.timer return self.setValue(self.value() + 1)
def wait_for(ms): future = Future() timer = QTimer() timer.timeout.connect(lambda: (future.set_result(None), timer.deleteLater())) timer.setSingleShot(True) timer.start(ms) return future
class ProgressBar(QProgressBar): """ This class is a custom progress bar which shows a dynamic loading bar. Attributes ---------- timer : QTimer Loop iteration duration. Methods ---------- onTimeOut() Updates the loading bar value. """ def __init__(self, *args, **kwargs): super(ProgressBar, self).__init__(*args, **kwargs) self.setValue(0) if self.minimum() != self.maximum(): self.timer = QTimer(self, timeout=self.onTimeout) self.timer.start(randint(1, 3) * 1000) def onTimeout(self): """ This method changes the bar value. """ if self.value() >= 100: self.timer.stop() self.timer.deleteLater() del self.timer return self.setValue(self.value() + 1)
class mainWindow(QMainWindow): def __init__(self,obj): super().__init__() self.setObjectName('Window1') self.obj=obj self.set=0 self.initUI() def initUI(self): self.resize(850,500) self.setWindowTitle('Moodly 1.0 Beta - Configure') self.setWindowIcon(QIcon(':/Assets/moodly.gif')) self.setFixedSize(830,500) self.center() self.sysTray=QWidget() self.tray = SystemTrayIcon(QIcon(':/Assets/moodly.gif'),self.sysTray) self.tray.show() self.tray.trigger.connect(self.showApp) self.tray.qtrigger.connect(self.closeApp) self.tray.uptrigger.connect(self.updateNow) self.setWidget() self.show() def setWidget(self): if self.obj.configured==0: self.setCentralWidget(configureWidget(self)) elif self.obj.configured==1: self.setCentralWidget(setupWidget(self)) elif self.obj.configured==2: self.setStyleSheet('''#Window1{background-color: light gray;}''') self.setWindowTitle('Moodly 1.0 Beta') self.setMenuBar() self.tabWidget = tabWidget(self) self.setCentralWidget(self.tabWidget) self.tray.updateAction.setEnabled(True) self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.hide() self.statusLbl1 = QLabel() self.statusLbl2 = QLabel() self.statusLbl2.setAlignment(QtCore.Qt.AlignRight) self.statusBar.addWidget(self.statusLbl1) self.statusBar.addWidget(self.statusLbl2,QtCore.Qt.AlignRight) self.updateTimer() self.notifTimer() self.i_thread = {} self.nt=0 def showApp(self): if self.isMinimized(): self.showNormal() self.show() self.activateWindow() def closeApp(self): self.tray.hide() qApp.quit() def showStatus(self,msg,id_): if id_ == 0: self.statusLbl1.setText(msg) else: self.statusLbl2.setText(msg) self.statusBar.show() def hideStatus(self,id_): if id_==0: self.statusLbl1.setText('') else: self.statusLbl2.setText('') if self.statusLbl1.text() == '' and self.statusLbl2.text()=='': self.statusBar.hide() def updateTimer(self): self.current_timer = QTimer() delay = int(re.findall(r'\d+', self.obj.upIntval)[0]) delay = delay*60*60*1000 self.current_timer.timeout.connect(self.updater) self.current_timer.setSingleShot(True) if self.set==0: self.updater() else: self.current_timer.start(delay) def notifTimer(self): if self.obj.nIntval=="Turn Off": self.notifier = False else: delay = int(re.findall(r'\d+', self.obj.nIntval)[0])*60*60 self.timer1 = QTimer() self.timer1.timeout.connect(partial(self.quickNotify)) self.timer1.setSingleShot(True) self.timer1.start(10*60*1000) self.notifier= True def quickNotify(self): if self.obj.n !=0 and self.obj.updating==False: str_ = str(self.obj.n) self.tray.display_notify("Moodly","You have %s unread notifications"%str_,1) self.notifTimer() def quickStatus(self,i): if self.obj.updating==False: if i==0: self.showStatus('Next Update Scheduled at %s'%str(self.obj.scheduled)) self.timer2 = QTimer() self.timer2.timeout.connect(partial(self.quickStatus,1)) self.timer2.setSingleShot(True) self.timer2.start(6000) elif i==1: delay = int(re.findall(r'\d+', self.obj.upIntval)[0])*60*60 self.showStatus('Last Update Scheduled at %s'%str(self.obj.scheduled-datetime.timedelta(0,delay))+'Failed') self.timer2 = QTimer() self.timer2.timeout.connect(partial(self.quickStatus,2)) self.timer2.setSingleShot(True) self.timer2.start(6000) else: self.showStatus('Last Successful Update ') self.timer2 = QTimer() self.timer2.timeout.connect(self.hideStatus) self.timer2.setSingleShot(True) self.timer2.start(6000) self.statusTimer() def updater(self): self.obj.updating = True self.showStatus('Updating Moodly.....',0) self.thread=updateThread(self.obj) self.thread.finished.connect(self.downloader) self.thread.start() def downloader(self): if int(self.obj.dwnld)==1: self.showStatus('Downloading Files.....',0) self.dthread=downloadThread(self.obj) self.dthread.finished.connect(self.tabUpdater) self.dthread.start() else: self.tabUpdater() def closeEvent(self, event): self.hide() event.ignore() self.tray.display_notify('Moodly','Moodly running in notification tray.',1) def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def setMenuBar(self): exitAction = QAction(QIcon(':/Assets/close.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.triggered.connect(self.closeApp) self.alreadyOpen = 0 configAction = QAction(QIcon(':/Assets/setting.png'), '&Configure', self) configAction.triggered.connect(self.changeConfig) configAction.setShortcut('Ctrl+Shift+C') updateAction = QAction(QIcon(':/Assets/sync.png'), '&Update Now', self) updateAction.triggered.connect(self.updateNow) updateAction.setShortcut('Ctrl+U') menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(configAction) fileMenu.addAction(updateAction) fileMenu.addAction(exitAction) def updateNow(self): if self.obj.updating==False: self.current_timer.stop() self.current_timer.deleteLater() self.updater() else: reply = QMessageBox.information(self,'Moodly',"An update is already in progress. ", QMessageBox.Ok) if reply == QMessageBox.Ok: pass def changeConfig(self): if self.alreadyOpen is 0: self.tab = reConfigureWidget(self.tabWidget) self.tabWidget.addTab(self.tab,QIcon(':/Assets/setting.png'),'Configure') self.tabWidget.setTabToolTip(self.tabWidget.indexOf(self.tab),'Configure') self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.tab)) self.alreadyOpen=1 else: self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.tab)) def verify(self): self.obj.saveConfig(1) self.thread=WorkThread(self.obj) self.thread.finished.connect(self.notify) self.thread.start() self.set=1 self.setWidget() def notify(self): self.setWidget() self.tray.display_notify("Moodly",self.obj.status_msg[0],self.obj.status_msg[1]) def tabUpdater(self): self.set=1 self.tabWidget.tab1.updater() self.tabWidget.tab2.updater() for tab in self.tabWidget.tab: tab.updater() self.obj.updating = False self.c_timer = QTimer() self.c_timer.timeout.connect(partial(self.hideStatus,0)) self.c_timer.setSingleShot(True) self.showStatus('Update Completed',0) self.c_timer.start(5000) self.tray.display_notify("Moodly",self.obj.status_msg[0],self.obj.status_msg[1]) self.updateTimer() def itemsWriter(self,fileName,id1,id2): nt=self.getIndex() self.i_thread[nt] = itemsWriterThread(fileName,id1,id2,nt,self.obj) self.i_thread[nt].finished.connect(partial(self.del_i_thread,self.i_thread[nt].id3)) self.i_thread[nt].start() def del_i_thread(self,id3): self.i_thread[id3]=0 def getIndex(self): if self.nt==0: return self.nt else: for i in range(0,self.nt): if self.i_thread[i]==0: return i self.nt+=1 return self.nt def configWriter(self,text1,text2,combo1,combo2,text3,path_): self.sid3=self.showStatus('Configuring...',1) self.c_thread = configWriterThread(self.obj,text1,text2,combo1,combo2,text3,path_) self.c_thread.finished.connect(self.reConfigModify) self.c_thread.start() def reConfigModify(self): if self.alreadyOpen==1: self.tab.status_label.setText(self.obj.config_status) self.tray.display_notify("Moodly",self.obj.status_msg[0],self.obj.status_msg[1]) self.re_timer = QTimer() self.re_timer.timeout.connect(partial(self.hideStatus,1)) self.re_timer.setSingleShot(True) self.showStatus(self.obj.config_status,1) self.re_timer.start(5000) self.tabWidget.updating = False if self.obj.intValChanged ==0: self.current_timer.stop() self.current_timer.deleteLater() self.updateTimer() self.obj.intValChanged = -1 elif self.obj.intValChanged ==1: if self.notifier == True: self.timer1.stop() self.timer1.deleteLater() self.notifTimer() self.obj.intValChanged = -1 elif self.obj.intValChanged ==2: self.current_timer.stop() self.current_timer.deleteLater() self.updateTimer() if self.notifier == True: self.timer1.stop() self.timer1.deleteLater() self.notifTimer() self.obj.intValChanged = -1
class Timer(QWidget): def __init__(self): super(Timer, self).__init__() self.sec = 0 self.hourLCDNumber = QLCDNumber() self.hourLCDNumber.setDigitCount(2) self.hourLCDNumber.display(00) self.minLCDNumber = QLCDNumber() self.minLCDNumber.setDigitCount(2) self.minLCDNumber.display(00) self.secLCDNumber = QLCDNumber() self.secLCDNumber.setDigitCount(2) self.secLCDNumber.display(00) self.startSuspendButton = QPushButton('开始') self.restartButton = QPushButton('重置') self.startSuspendButton.clicked.connect(self.startSuspend) self.restartButton.clicked.connect(self.restart) hTimerLayout = QHBoxLayout() hTimerLayout.addWidget(self.hourLCDNumber) hTimerLayout.addWidget(self.minLCDNumber) hTimerLayout.addWidget(self.secLCDNumber) hButtonLayout = QHBoxLayout() hButtonLayout.addWidget(self.startSuspendButton) hButtonLayout.addWidget(self.restartButton) vLayout = QVBoxLayout() vLayout.addLayout(hTimerLayout) vLayout.addLayout(hButtonLayout) self.setLayout(vLayout) def operate(self): self.sec += 1 min, sec = divmod(self.sec, 60) hour, min = divmod(min, 60) self.hourLCDNumber.display(hour) self.minLCDNumber.display(min) self.secLCDNumber.display(sec) def startSuspend(self): bText = self.startSuspendButton.text() if bText == '开始' or bText == '继续': self.timer = QTimer(self) self.timer.timeout.connect(self.operate) self.timer.start(1000) self.startSuspendButton.setText('暂停') GPIO.setup() GPIO.loop() elif bText == '暂停': self.timer.deleteLater() self.startSuspendButton.setText('继续') GPIO.destroy() def restart(self): self.sec = -1 self.operate() if self.startSuspendButton.text() == '暂停': self.timer.deleteLater() GPIO.destroy() self.startSuspendButton.setText('开始')
class FullscreenToolbar(QWidget): def __init__(self, parent=None, flags=0): super().__init__(parent) uic.loadUi('ui/fullscreenToolbar.ui', self) self.setWindowFlags(Qt.Tool|Qt.Widget|Qt.FramelessWindowHint); self.setAttribute(Qt.WA_NoSystemBackground, True); self.setAttribute(Qt.WA_TranslucentBackground, True); app = QApplication.instance() settings = app.settings_manager if settings.value("player/volume"): self.volume_slider.setValue(int(settings.value("player/volume"))) parent.playback_started.connect(self.video_playback_started) parent.playback_paused.connect(self.video_playback_paused) parent.playback_stopped.connect(self.video_playback_stopped) parent.playback_error.connect(self.video_playback_error) parent.volume_changed.connect(self.video_volume_changed) self.play_btn.clicked.connect(self.play_btn_clicked) self.stop_btn.clicked.connect(self.stop_btn_clicked) self.fullscreen_btn.clicked.connect(self.switch_fullscreen_mode) self.volume_slider.sliderMoved.connect(self.volume_changed) self.timer = None self.epg = None self.epg_list = [] # Set custom icons self.play_btn.setIcon(TXIcon('icons/play-button.svg', Qt.white)) self.stop_btn.setIcon(TXIcon('icons/stop-button.svg', Qt.white)) self.fullscreen_btn.setIcon(TXIcon('icons/unfullscreen.svg', Qt.white)) self.show_progress.hide() def show(self): super().show() self.activateWindow() self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.timer.start(1000) def hide(self): super().hide() if self.timer: self.timer.stop() self.timer.deleteLater() self.timer = None def play_btn_clicked(self, checked=False): from videoplayer import VideoPlayerState player_state = self.parent().get_state() if player_state is VideoPlayerState.PLAYER_PLAYING: self.parent().pause() else: self.parent().unpause() def stop_btn_clicked(self, checked=False): self.parent().stop() def volume_changed(self, level): self.parent().volume_changed.disconnect(self.video_volume_changed) self.parent().set_volume(level) self.parent().volume_changed.connect(self.video_volume_changed) def switch_fullscreen_mode(self, checked=False): self.parent().exit_fullscreen() def epg_data_available(self, epg_list): self.epg_list = epg_list # Signals def video_playback_started(self, channel): self.play_btn.setIcon(TXIcon('icons/pause-button.svg', Qt.white)) self.osd_channel_name.setText(channel.name) self.epg = EPGRetriever(channel, datetime.datetime.now().strftime("%Y-%m-%d")) self.epg.epg_data_available.connect(self.epg_data_available) self.epg.retrieve_epg() def video_playback_paused(self, channel): self.play_btn.setIcon(TXIcon('icons/play-button.svg', Qt.white)) def video_playback_stopped(self, channel): self.play_btn.setIcon(TXIcon('icons/play-button.svg', Qt.white)) def video_playback_error(self, channel): self.play_btn.setIcon(TXIcon('icons/play-button.svg', Qt.white)) def video_volume_changed(self, value): self.volume_slider.setValue(int(value)) # Qt Events def paintEvent(self, event): super().paintEvent(event) now = datetime.datetime.now() self.clock_label.setText(now.strftime("%X")) if self.epg_list: hours = [toLocalTime(x[0]) for x in self.epg_list] now = datetime.datetime.strptime(datetime.datetime.now().strftime("%H:%M"), "%H:%M") current = [x for x in itertools.takewhile(lambda t: now >= datetime.datetime.strptime(t, "%H:%M"), hours)][-1] for idx, epg_line in enumerate(self.epg_list): if toLocalTime(epg_line[0]) == current: self.show_name_label.setText(epg_line[1]) if len(self.epg_list) > idx + 1: start_time = datetime.datetime.strptime(toLocalTime(epg_line[0]), "%H:%M") end_time = datetime.datetime.strptime(toLocalTime(self.epg_list[idx + 1][0]), "%H:%M") elapsed_time = datetime.datetime.strptime(datetime.datetime.now().strftime("%H:%M"), "%H:%M") show_duration = end_time - start_time elapsed_duration = elapsed_time - start_time self.show_progress.setMinimum(0) self.show_progress.setMaximum(show_duration.seconds) self.show_progress.setValue(elapsed_duration.seconds) self.show_progress.show() return self.show_name_label.setText("") def keyPressEvent(self, event): super().keyPressEvent(event) self.parent().keyPressEvent(event)
class PlotWindow(QWidget, Ui_MainWindow): def __init__(self): super(self.__class__, self).__init__() self.setupUi(self) """ setup initial parameters """ self.time_frame = 1 # default update time frame [s] for LOAD LOG data self.n_points = int(self.lineEdit_1.text()) # default N points to plot self.channel = 0 # channel number 0 or 1 self.reload_flag = True # flag that is used to reload data in LOAD LOG self.common_path = 'C:/Users/Preparation PC/Documents/Python scripts/Communication_LOG_SERVER_2020/' """ connect all signals """ for i in self.buttons_dict: """ direct construction of lambda with argument and state of the button (not used but has to be there) """ self.buttons_dict[i].clicked.connect( lambda state, b=i: self.load_file(b)) self.lineEdit_1.returnPressed.connect( lambda: self.change_n_points(self.lineEdit_1.text())) self.lineEdit_2.returnPressed.connect( lambda: self.change_channel(self.lineEdit_2.text())) self.load_button.clicked.connect(lambda: self.load_file()) """ create a timer for updating plot (only for Load LOG button) """ self.timer_update = QTimer(self) self.timer_update.timeout.connect(self.update_plot) def load_file(self, *server_name): """ Read values from saved log file into a local panda frame. In case *sever_name is given - starts the server client and does not load log file anymore, instead adds new values from the server to the displayed data. If there is no *server_name then it shows the open file dialog. """ self.stop() # stop all running timers/server_clients """ Get the file name: either from servers dict or from user dialog""" try: if server_name: self.server_name = server_name[0] self.port = LoS.server_list[self.server_name][1] self.servers_with_port = [ k for k, v in LoS.server_list.items() if v[1] == self.port ] # return servers with this port print(self.servers_with_port) # TODO: provide full path from log folder self.load_file_name = str(self.common_path) + str( self.servers_with_port[0] ) + '-log-dynamic.dat' # takes the first server log with this port print(self.load_file_name) self.channel = int(LoS.server_list[self.server_name][4]) else: self.load_file_name = QFileDialog.getOpenFileName( self, 'Open file', '', '*.dat')[0] except: print("error getting file name") """ Load data from the file self.load_file_name """ try: with open(self.load_file_name, 'rb') as f: self.loaded_data = pd.read_csv(f, sep=",") f.close() except: self.loaded_data = [] print("error loading file") pass """ Exctract necessary n_points from self.channel from panda frame """ if len(self.loaded_data) != 0: self.data_to_display = np.array( self.loaded_data.tail(self.n_points).iloc[1:, self.channel + 1]) else: self.data_to_display = np.array([]) """ Start the server client or run the timer to reload data from log file """ if server_name: print(f"starting smart {self.server_name} watch") self.start_network_client(self.server_name) else: print("starting standard log watch") self.start_reload_log_loop() def start_network_client(self, server_name: str): """ Starts the separate thread with server client NetworkGetPressure to obtain pressure/temp values from the corresponding server. Server_dictionary is used to obtain connection parameters. """ print("connecting to server ", server_name) self.reload_flag = False self.host = LoS.server_list[self.server_name][0] self.port = int(LoS.server_list[self.server_name][1]) self.channel = int(LoS.server_list[self.server_name][4]) self.networking = NetworkGetPressure(self.host, self.port) # thread self.networking.new_value_trigger.connect(self.update_data_to_display) self.networking.start() # start this thread to get pressure gc.collect() def update_data_to_display(self, pressure): """ Update data array when a new value comes in the networking thread""" try: self.pressure_preliminary = float( pressure.split(',')[self.channel]) """ If we are getting temperature from the Lakeshore""" if self.port == 63205: if (self.pressure_preliminary < 500): self.pressure = self.pressure_preliminary else: """ If we are getting pressure values""" if (self.pressure_preliminary > 0) and (self.pressure_preliminary < 0.05): self.pressure = self.pressure_preliminary print(self.pressure) else: pass except: self.pressure = 0.0 pass """ Append the value from server to the data which we display (with shift) """ if len(self.data_to_display) >= self.n_points: self.data_to_display = np.append(self.data_to_display, self.pressure)[1:] else: self.data_to_display = np.append(self.data_to_display, self.pressure) self.update_plot() # call the plot update function def update_plot(self): """ Updates the plot. Depending on the reload_flag it can re-load data from the LOG file (in case LOAD LOG button is used) or just updates the plot after the new value from the server was appended to the data array. """ if self.reload_flag: try: with open(self.load_file_name, 'rb') as f: self.loaded_data = pd.read_csv(f, sep=",") f.close() self.data_to_display = np.array( self.loaded_data.tail( self.n_points).iloc[1:, self.channel + 1]) print("reloaded") except: print("error loading data") pass """Check the data prior plot""" for i in range(len(self.data_to_display)): try: self.data_to_display[i] = float(self.data_to_display[i]) except: self.data_to_display[i] = 0.0 pass """ Update plot """ try: self.plot_T.clear() self.plot_T.plot(np.arange(0, len(self.data_to_display)) * self.time_frame, self.data_to_display, symbolSize=5, symbolBrush="r", symbol='o') except: print("error in plot") pass def change_n_points(self, new_n_points: int): """ Change number of points in the data array to plot """ if (int(new_n_points) > 0) and (int(new_n_points) < 360 * 24): self.n_points = int(new_n_points) print("changed number of points to ", self.n_points) else: print("invalid number of points") pass """ Reload once from the log file in case reading from server """ if not self.reload_flag: self.load_file(str(self.server_name)) def change_channel(self, new_channel: int): """ Works only for LOAD LOG case """ if (int(new_channel) == 0) or (int(new_channel) == 1): self.channel = int(new_channel) print("changed channel to ", self.channel) # self.label_3.setText(str(self.channels_list[self.channel+1])) else: print("invalid channel") pass def start_reload_log_loop(self): """ Works only for LOAD LOG case """ # self.label_3.setText(str(self.channels_list[self.channel+1])) self.plot_T.clear() self.reload_flag = True self.timer_update.start(self.time_frame * 1000) def stop(self): try: self.timer_update.stop() except Exception as e: logging.exception(e) print(e) try: self.data_to_display = np.array([]) except: pass try: self.networking.quit() self.networking.wait() except Exception as e: logging.exception(e) print(e) pass def __del__(self): self.stop() try: self.timer_update.deleteLater() except: pass def closeEvent(self, event): try: self.__del__() self.stop() except: print("error killing timer") event.accept()
class SecondWindow(QWidget): def __init__(self): super(SecondWindow, self).__init__() self.setWindowTitle("BME Reaction Time Tester Pro 2000") self.label = QLabel(self) self.label.resize(MW.dispWidth, MW.dispHeight) # self.display_monitor = 1 # the number of the monitor you want to display your widget # self.monitor = QDesktopWidget().screenGeometry(self.display_monitor) # self.move(self.monitor.left(), self.monitor.top()) self.showFullScreen() self.initUI() self.showThisMany = 10 self.state = 0 self.imShowed = 0 self.popped = 0 self.p = vlc.MediaPlayer("song.mp3") self.timeClick = 0 self.timeImage = 0 self.reaction = 0 self.reactions = [] self.imgLabel = QLabel(self) self.image = QPixmap('audi.jpg') self.imgLabel.setPixmap(self.image) self.imgLabel.move(MW.dispWidth / 2 - self.imgLabel.width() / 2, MW.dispHeight / 2 - self.imgLabel.height() / 2) self.instText = QLabel(self) self.timer = QTimer(self) self.stateMachine() def stateMachine(self): if self.state == 0: self.showInstLabel("Hello " + MW.lineInName.text() + " !") if MW.radiobutton.isChecked(): self.p.play() self.state = 1 self.timer.timeout.connect(self.stateMachine) self.timer.start(4000) elif self.state == 1: self.showInstLabel("Press ENTER when you see the car on the screen!") self.state = 2 self.timer.timeout.connect(self.stateMachine) self.timer.start(4000) elif self.state == 2: self.showInstLabel("Press ENTER to start!") self.state = 3 elif self.state == 4: rt = randint(1000, 10000) self.timer.timeout.connect(self.showImage) self.timer.start(rt) elif self.state == 5: self.mn = mean(self.reactions) MW.fid.write(str(self.mn)) MW.fid.write("\n") MW.fid.close() self.showInstLabel("Thank you!" + "\n" + "Your average time was " + str('%.3f' % self.mn) + " s.\n"+"Press ENTER to quit!") self.timer.stop() self.timer.deleteLater() def showInstLabel(self, text): self.font = QFont("Courier", MW.dispWidth/40, QFont.Bold) self.instText.setStyleSheet('color:white') self.instText.setFont(self.font) self.instText.setText(text) self.instText.adjustSize() self.instText.move(MW.dispWidth / 2 - self.instText.width()/2, MW.dispHeight/2) self.instText.repaint() self.instText.show() @pyqtSlot(QImage) def setImage(self, image): self.label.setPixmap(QPixmap.fromImage(image)) def initUI(self): self.th = Thread(self) self.th.changePixmap.connect(self.setImage) self.th.start() def pressed(self): if self.state <= 3: self.instText.hide() self.state = 4 elif self.state == 4: self.imShowed = self.imShowed + 1 self.timePress= time.time() self.reaction = self.timePress - self.timeImage self.imgLabel.hide() self.popped = 0 self.reactions.append(self.reaction) self.buff = str(self.reaction) + ";" MW.fid.write(self.buff) print(str(self.reaction)) if self.imShowed >= self.showThisMany: self.state = 5 self.stateMachine() elif self.state == 5: if MW.radiobutton.isChecked(): self.p.stop() self.th.isRunning = False self.th.terminate() self.close() def showImage(self): self.imgLabel.move(MW.dispWidth/2 -self.imgLabel.width()/2, MW.dispHeight / 2 - self.imgLabel.height() / 2) self.imgLabel.show() self.timeImage = time.time() if self.popped == 0: self.stateMachine() self.popped = 1 def keyPressEvent(self, keyEvent): super(SecondWindow, self).keyPressEvent(keyEvent) if keyEvent.key() == Qt.Key_Space: self.pressed() elif keyEvent.key() == Qt.Key_Return: self.pressed()
class PermitBar(QWidget): to_usercenter = pyqtSignal(int) def __init__(self, *args, **kwargs): super(PermitBar, self).__init__(*args, **kwargs) self.user_id = None layout = QHBoxLayout(margin=0, spacing=0) # 用户头像 self.avatar = CAvatar(self, shape=CAvatar.Circle, url='media/avatar.png', size=QSize(22, 22), objectName='userAvatar') self.avatar.clicked.connect(self.to_user_center) layout.addWidget(self.avatar, alignment=Qt.AlignRight) # 用户名 self.username_shown = QPushButton('用户名用户名', parent=self, objectName='usernameShown', clicked=self.to_user_center) layout.addWidget(self.username_shown, alignment=Qt.AlignRight) # 按钮 self.login_button = QPushButton('登录', parent=self, objectName='loginBtn') layout.addWidget(self.login_button, alignment=Qt.AlignRight) self.register_button = QPushButton('注册', parent=self, objectName='registerBtn') layout.addWidget(self.register_button, alignment=Qt.AlignRight) self.logout_button = QPushButton('注销', parent=self, objectName='logoutBtn') layout.addWidget(self.logout_button, alignment=Qt.AlignRight) self.setLayout(layout) # 样式、属性 self.username = '' self.timer_finished_count = 0 self.login_button.setCursor(Qt.PointingHandCursor) self.register_button.setCursor(Qt.PointingHandCursor) self.logout_button.setCursor(Qt.PointingHandCursor) self.initial_show() # 初始显示的控件 self.setObjectName('permitBar') self.setStyleSheet(""" #permitBar{ min-height:22px; max-height:22px; } #loginBtn,#registerBtn,#logoutBtn{ border:none; padding-left: 2px; padding-right: 4px; color: #FFFFFF; } #logoutBtn{ margin-right:5px; } #loginBtn:hover,#registerBtn:hover,#logoutBtn:hover { color: rgb(54,220,180); } #usernameShown{ margin-left: 3px; border:none; padding: 0 2px; } /* #userAvatar{ background-color: rgb(100,255,120); min-width:22px; border-radius: 12px; margin-right: 2px; } */ """) def initial_show(self): self.avatar.hide() self.username_shown.hide() self.logout_button.hide() # 设置用户id def set_user_id(self, uid): self.user_id = uid # 前往用户中心 def to_user_center(self): if not self.user_id: return self.to_usercenter.emit(self.user_id) # 显示用户名 def show_username(self, username): self.avatar.show() self.username_shown.setText(username + " ") # 加空格防止初始动态化的时候跳动 self.username = username self.username_shown.show() self.login_button.hide() self.register_button.hide() self.logout_button.show() if hasattr(self, 'timer'): self.timer.deleteLater() del self.timer self.timer = QTimer() self.timer.start(500) self.timer.timeout.connect(self._dynamic_username) # 设置头像 def setAvatar(self, avatar_url): self.avatar.setUrl(avatar_url) # 用户注销 def user_logout(self): self.username_shown.setText('') self.username = '' self.username_shown.hide() self.logout_button.hide() self.avatar.hide() self.login_button.show() self.register_button.show() if hasattr(self, 'timer'): # print('注销销毁定时器piece.base.PermitBar.user_logout()') self.timer.stop() self.timer.deleteLater() del self.timer # 设置用户名滚动显示 def _dynamic_username(self): if self.timer_finished_count == len(self.username): self.username_shown.setText(self.username + " ") self.timer_finished_count = 0 else: text = self.username[ self. timer_finished_count:] + " " + self.username[:self. timer_finished_count] self.username_shown.setText(text) self.timer_finished_count += 1
class ResonanceFrequencyFinder(QMainWindow): # AVAILABLE_WINDOW_SIZES = ["5 Sec", "8 Sec", "10 Sec", "15 Sec", "20 Sec"] DEFAULT_GRAPH_PADDING = 2 DEFAULT_FFT_WINDOW_SIZE = 5 DEFAULT_SAMPLE_PADDING = 2 DEFAULT_RECORDING_DURATION = 30 + DEFAULT_SAMPLE_PADDING DEFAULT_MIN_FREQUENCY = 17 DEFAULT_MAX_FREQUENCY = 35 DEFAULT_FREQUENCY_STEP = 2 # Used to create a band for which the average frequency amplitude is computed DEFAULT_FREQUENCY_PADDING = 0.2 DEFAULT_BANDPASS_MIN = 8 DEFAULT_BANDPASS_MAX = 40 DEFAULT_C3_CHANNEL_INDEX = 4 DEFAULT_CZ_CHANNEL_INDEX = 2 DEFAULT_C4_CHANNEL_INDEX = 0 def __init__(self, board: BoardShim): super().__init__() self.setGeometry(0, 0, 1800, 900) self.setWindowTitle("Resonance-Like Frequency") self.board = board self.recording_progress_dialog = None self.eeg_data_buffer = utils.EegData() self.reading_timer = QTimer() self.recording = False self.recording_reference = False self.reference_eeg_data = utils.EegData() self.index_generator = utils.FrequencyIndexGenerator(global_config.SAMPLING_RATE) self.eeg_sample_count = 0 self.root_widget = QWidget() self.root_layout = QGridLayout() self.root_widget.setLayout(self.root_layout) self.setCentralWidget(self.root_widget) title = QLabel("<h1>Resonance Frequency Finder</h1>") title.setAlignment(Qt.AlignCenter) self.root_layout.addWidget(title, 0, 0, 1, 3) # window_size_label = QLabel("window size: ") # window_size_label.setAlignment(Qt.AlignRight) # self.window_size_combo_box = QComboBox() # self.window_size_combo_box.addItems(self.AVAILABLE_WINDOW_SIZES) self.root_directory_label = QLabel() self.select_root_directory = QPushButton("Select/Change") self.select_root_directory.clicked.connect(self.pick_root_directory) self.record_btn = QPushButton("Record") self.record_btn.setEnabled(False) self.record_btn.clicked.connect(self.record_clicked) self.record_reference_btn = QPushButton("Record Reference") self.record_reference_btn.clicked.connect(self.record_reference_clicked) # self.root_layout.addWidget(utils.construct_horizontal_box([ # window_size_label, self.window_size_combo_box, self.record_btn # ]), 1, 0, 1, 3) self.load_results_btn = QPushButton("Load Existing Data") self.load_results_btn.clicked.connect(self.load_existing_data) self.root_layout.addWidget(utils.construct_horizontal_box([ self.record_btn, self.record_reference_btn, self.root_directory_label, self.select_root_directory, self.load_results_btn ]), 1, 0, 1, 3) self.current_freq_label = QLabel() self.root_layout.addWidget(utils.construct_horizontal_box([self.current_freq_label]), 2, 0, 1, 3) self.frequency_slider = QSlider() self.frequency_slider.setRange(self.DEFAULT_MIN_FREQUENCY, self.DEFAULT_MAX_FREQUENCY) self.frequency_slider.setSingleStep(self.DEFAULT_FREQUENCY_STEP) self.frequency_slider.setTickInterval(self.DEFAULT_FREQUENCY_STEP) self.frequency_slider.valueChanged.connect(self.update_freq_label) self.frequency_slider.setTickPosition(QSlider.TicksBelow) self.frequency_slider.setOrientation(Qt.Horizontal) min_freq_label = QLabel(f"<b>{self.DEFAULT_MIN_FREQUENCY} Hz</b>") max_freq_label = QLabel(f"<b>{self.DEFAULT_MAX_FREQUENCY} Hz</b>") self.root_layout.addWidget(utils.construct_horizontal_box([ min_freq_label, self.frequency_slider, max_freq_label ]), 3, 0, 1, 3) self.c3_amplitude_bar_set = QBarSet("Electrode C3") self.cz_amplitude_bar_set = QBarSet("Electrode Cz") self.c4_amplitude_bar_set = QBarSet("Electrode C4") self.frequencies = [] for freq in range(self.DEFAULT_MIN_FREQUENCY, self.DEFAULT_MAX_FREQUENCY + 1, self.DEFAULT_FREQUENCY_STEP): self.frequencies.append(f"{freq} Hz") self.c3_amplitude_bar_set.append(1) self.cz_amplitude_bar_set.append(1) self.c4_amplitude_bar_set.append(1) self.freq_axis = QBarCategoryAxis() self.freq_axis.append(self.frequencies) self.amplitude_axis = QValueAxis() self.amplitude_axis.setRange(0, 4) self.freq_chart = QChart() self.freq_chart.setAnimationOptions(QChart.SeriesAnimations) self.electrodes_data_series = QBarSeries() self.electrodes_data_series.append(self.c3_amplitude_bar_set) self.electrodes_data_series.append(self.cz_amplitude_bar_set) self.electrodes_data_series.append(self.c4_amplitude_bar_set) self.freq_chart.addSeries(self.electrodes_data_series) self.freq_chart.setTitle("<h1>Frequency Amplitude Increase</h1>") self.freq_chart.addAxis(self.freq_axis, Qt.AlignBottom) self.freq_chart.addAxis(self.amplitude_axis, Qt.AlignLeft) self.electrodes_data_series.attachAxis(self.amplitude_axis) self.electrodes_data_series.attachAxis(self.freq_axis) self.frequency_amplitude_graph = QChartView(self.freq_chart) self.frequency_amplitude_graph.setRenderHint(QPainter.Antialiasing) self.root_layout.addWidget(self.frequency_amplitude_graph, 4, 0, 15, 3) self.auto_adjust_axis() def update_freq_label(self): self.current_freq_label.setText("Selected Frequency: {} Hz".format(self.frequency_slider.value())) def pick_root_directory(self): path = QFileDialog.getExistingDirectory(self, "Root Directory...") self.root_directory_label.setText(path) def record_clicked(self, reference: bool = False): # selected_window_text = self.window_size_combo_box.currentText() # window_size_text = selected_window_text.replace(" Sec", "") # window_size = -1 # # if utils.is_integer(window_size_text): # window_size = int(window_size_text) # else: # print("Invalid window size...") # return # window_size_in_samples = window_size * SAMPLING_RATE recording_duration_in_samples = self.DEFAULT_RECORDING_DURATION * global_config.SAMPLING_RATE if not reference and (self.frequency_slider.value() - self.DEFAULT_MIN_FREQUENCY) % self.DEFAULT_FREQUENCY_STEP != 0: err = QErrorMessage(self) err.showMessage("Invalid Frequency Selected") err.exec() return self.recording_progress_dialog = \ QProgressDialog("Reading EEG data from board...", "Stop Recording", 0, int(recording_duration_in_samples), self) self.recording_progress_dialog.setWindowTitle("Reading Data, Please Wait...") self.recording_progress_dialog.setWindowModality(Qt.WindowModal) self.recording_progress_dialog.show() if reference: self.recording_reference = True else: self.recording = True self.eeg_data_buffer.clear() self.board.start_stream() self.reading_timer = QTimer() self.reading_timer.timeout.connect(self.read_data) self.reading_timer.start(100) def record_reference_clicked(self): print("Record reference clicked") if self.reference_eeg_data.get_channel_data(0).shape[0] > 0: self.reference_eeg_data.clear() self.record_clicked(reference=True) def read_data(self): if not self.recording and not self.recording_reference: return recording_duration_in_samples = self.recording_progress_dialog.maximum() if self.recording_reference: if self.reference_eeg_data.get_channel_data(0).shape[0] > recording_duration_in_samples or\ self.recording_progress_dialog.wasCanceled(): self.stop_recording(True) return if self.recording: if self.recording_progress_dialog.wasCanceled() or\ self.eeg_data_buffer.get_channel_data(0).shape[0] > recording_duration_in_samples: self.stop_recording(self.recording_reference) return if self.board.get_board_data_count() > 0: raw_data = self.board.get_board_data() raw_eeg_data = utils.extract_eeg_data(raw_data, global_config.BOARD_ID) self.eeg_sample_count += raw_eeg_data.shape[1] path = self.root_directory_label.text() if path != "": full_path = path + "/" + global_config.RESONANCE_DATA_FILE_NAME DataFilter.write_file(raw_eeg_data, full_path, "a") # c3 = raw_eeg_data[self.DEFAULT_C3_CHANNEL_INDEX, :] # cz = raw_eeg_data[self.DEFAULT_CZ_CHANNEL_INDEX, :] # c4 = raw_eeg_data[self.DEFAULT_C4_CHANNEL_INDEX, :] if self.recording_reference: self.reference_eeg_data.append_data(raw_eeg_data) print(f"reference size: {self.reference_eeg_data.sample_count()}") self.recording_progress_dialog.setValue(self.reference_eeg_data.get_channel_data(0).shape[0]) else: self.eeg_data_buffer.append_data(raw_eeg_data) print(f"data size: {self.eeg_data_buffer.sample_count()}") self.recording_progress_dialog.setValue(self.eeg_data_buffer.get_channel_data(0).shape[0]) def load_existing_data(self): path = QFileDialog.getExistingDirectory(self, "Root Directory...") if path == "": return filter_settings = utils.FilterSettings(global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX) frequencies, eeg_data, reference_data = utils.load_slice_and_filter_resonance_data(path, filter_settings) print(frequencies) size = len(frequencies) x = np.arange(size) x_ticks = [] plot_data = np.zeros((3, size)) for i in range(size): current_eeg_data = eeg_data[i] freq = frequencies[i] x_ticks.append(f"{freq} Hz") freq_band = utils.FrequencyBand( freq - self.DEFAULT_FREQUENCY_PADDING, freq + self.DEFAULT_FREQUENCY_PADDING) reference_c3_extractor = reference_data.feature_extractor( self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE ) reference_cz_extractor = reference_data.feature_extractor( self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE ) reference_c4_extractor = reference_data.feature_extractor( self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_c3_extractor = current_eeg_data.feature_extractor( self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_cz_extractor = current_eeg_data.feature_extractor( self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_c4_extractor = current_eeg_data.feature_extractor( self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE ) c3_diff, cz_diff, c4_diff = self.amplitude_diff(freq_band, reference_c3_extractor, reference_cz_extractor, reference_c4_extractor, data_c3_extractor, data_cz_extractor, data_c4_extractor) plot_data[0, i] = c3_diff plot_data[1, i] = cz_diff plot_data[2, i] = c4_diff plt.figure() plt.title("Amplitude Increase") plt.bar(x, plot_data[0], width=0.25, label="C3 amplitude increase") plt.bar(x + 0.25, plot_data[1], width=0.25, label="Cz amplitude increase") plt.bar(x + 0.50, plot_data[2], width=0.25, label="C4 amplitude increase") plt.xticks(x + 0.25, x_ticks) plt.ylabel("Average Band Amplitude") plt.legend(loc="best") plt.show() def amplitude_diff(self, freq_band, ref_c3_extractor, ref_cz_extractor, ref_c4_extractor, data_c3_extractor, data_cz_extractor, data_c4_extractor): ref_c3_amplitude = ref_c3_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) ref_cz_amplitude = ref_cz_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) ref_c4_amplitude = ref_c4_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) data_c3_amplitude = data_c3_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) data_cz_amplitude = data_cz_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) data_c4_amplitude = data_c4_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE) c3_diff = data_c3_amplitude - ref_c3_amplitude cz_diff = data_cz_amplitude - ref_cz_amplitude c4_diff = data_c4_amplitude - ref_c4_amplitude return c3_diff, cz_diff, c4_diff # return data_c3_amplitude, data_cz_amplitude, data_c4_amplitude def stop_recording(self, reference: bool = False): if self.reading_timer is not None: self.reading_timer.deleteLater() self.board.stop_stream() self.recording = False self.recording_reference = False self.recording_progress_dialog.setValue(self.recording_progress_dialog.maximum()) recording_duration_in_samples = self.recording_progress_dialog.maximum() selected_freq = self.frequency_slider.value() if reference: sample_count = min(self.reference_eeg_data.get_channel_data(0).shape[0], recording_duration_in_samples) sample_count -= global_config.SAMPLING_RATE * self.DEFAULT_SAMPLE_PADDING self.index_generator.add_slice(0, self.eeg_sample_count - sample_count, self.eeg_sample_count) else: sample_count = min(self.eeg_data_buffer.get_channel_data(0).shape[0], recording_duration_in_samples) sample_count -= global_config.SAMPLING_RATE * self.DEFAULT_SAMPLE_PADDING self.index_generator.add_slice(selected_freq, self.eeg_sample_count - sample_count, self.eeg_sample_count) if self.root_directory_label.text() != "": self.index_generator.write_to_file(self.root_directory_label.text()) QApplication.beep() start = self.DEFAULT_SAMPLE_PADDING * global_config.SAMPLING_RATE if reference: print(f"reference size: {self.reference_eeg_data.sample_count()}") self.record_btn.setEnabled(True) # self.record_reference_btn.setEnabled(False) self.reference_eeg_data.filter_all_channels( global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX, True ) self.reference_eeg_data = utils.EegData(self.reference_eeg_data.to_row_array()[:, start:]) print("Reference data saved...") else: print("Stopping the recording...") print("Filtering data...") self.eeg_data_buffer.filter_all_channels( global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX, subtract_average=True ) self.eeg_data_buffer = utils.EegData(self.eeg_data_buffer.to_row_array()[:, start:]) print(f"data size: {self.eeg_data_buffer.sample_count()}") reference_c3_extractor = self.reference_eeg_data.feature_extractor( self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE ) reference_cz_extractor = self.reference_eeg_data.feature_extractor( self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE ) reference_c4_extractor = self.reference_eeg_data.feature_extractor( self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_c3_extractor = self.eeg_data_buffer.feature_extractor( self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_cz_extractor = self.eeg_data_buffer.feature_extractor( self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE ) data_c4_extractor = self.eeg_data_buffer.feature_extractor( self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE ) for i in range(self.c3_amplitude_bar_set.count()): current_freq = int(self.frequencies[i].replace(" Hz", "")) if current_freq == selected_freq: freq_band = utils.FrequencyBand( current_freq - self.DEFAULT_FREQUENCY_PADDING, current_freq + self.DEFAULT_FREQUENCY_PADDING) c3_diff, cz_diff, c4_diff = self.amplitude_diff(freq_band, reference_c3_extractor,reference_cz_extractor, reference_c4_extractor, data_c3_extractor, data_cz_extractor, data_c4_extractor) print(f"C3 diff = {c3_diff}") print(f"Cz diff = {cz_diff}") print(f"C4 diff = {c4_diff}") self.c3_amplitude_bar_set.replace(i, c3_diff) self.cz_amplitude_bar_set.replace(i, cz_diff) self.c4_amplitude_bar_set.replace(i, c4_diff) utils.auto_adjust_axis(self.amplitude_axis, [self.c3_amplitude_bar_set, self.cz_amplitude_bar_set, self.c4_amplitude_bar_set], self.DEFAULT_GRAPH_PADDING) def auto_adjust_axis(self): # Adjust the range so that everything is visible and add some gaps c3_min = sys.maxsize cz_min = sys.maxsize c4_min = sys.maxsize c3_max = -sys.maxsize cz_max = -sys.maxsize c4_max = -sys.maxsize for i in range(self.c3_amplitude_bar_set.count()): c3_min = min(c3_min, self.c3_amplitude_bar_set.at(i)) cz_min = min(cz_min, self.cz_amplitude_bar_set.at(i)) c4_min = min(c4_min, self.c4_amplitude_bar_set.at(i)) c3_max = max(c3_max, self.c3_amplitude_bar_set.at(i)) cz_max = max(cz_max, self.cz_amplitude_bar_set.at(i)) c4_max = max(c4_max, self.c4_amplitude_bar_set.at(i)) print("c3 min = {}, cz min = {}, c4 min = {}".format(c3_min, cz_min, c4_min)) print("c3 max = {}, cz max = {}, c4 max = {}".format(c3_max, cz_max, c4_max)) axis_min = min(0, c3_min, cz_min, c4_min) - self.DEFAULT_GRAPH_PADDING axis_max = max(0, c3_max, cz_max, c4_max) + self.DEFAULT_GRAPH_PADDING print("axis min = {}, axis max = {}".format(axis_min, axis_max)) self.amplitude_axis.setMin(axis_min) self.amplitude_axis.setMax(axis_max)
class DebugWindow(QMainWindow): """ The debug window shows various statistics about Tribler such as performed requests, IPv8 statistics and community information. """ resize_event = pyqtSignal() def __init__(self, settings, tribler_version): self._logger = logging.getLogger(self.__class__.__name__) QMainWindow.__init__(self) self.request_mgr = None self.cpu_plot = None self.memory_plot = None self.initialized_cpu_plot = False self.initialized_memory_plot = False self.cpu_plot_timer = None self.memory_plot_timer = None self.tribler_version = tribler_version self.profiler_enabled = False self.toggling_profiler = False uic.loadUi(get_ui_file_path('debugwindow.ui'), self) self.setWindowTitle("Tribler debug pane") self.window().dump_memory_core_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(True)) self.window().dump_memory_gui_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(False)) self.window().toggle_profiler_button.clicked.connect(self.on_toggle_profiler_button_clicked) self.window().debug_tab_widget.setCurrentIndex(0) self.window().ipv8_tab_widget.setCurrentIndex(0) self.window().tunnel_tab_widget.setCurrentIndex(0) self.window().system_tab_widget.setCurrentIndex(0) self.window().debug_tab_widget.currentChanged.connect(self.tab_changed) self.window().ipv8_tab_widget.currentChanged.connect(self.ipv8_tab_changed) self.window().tunnel_tab_widget.currentChanged.connect(self.tunnel_tab_changed) self.window().events_tree_widget.itemClicked.connect(self.on_event_clicked) self.window().system_tab_widget.currentChanged.connect(self.system_tab_changed) self.load_general_tab() self.window().open_files_tree_widget.header().setSectionResizeMode(0, QHeaderView.Stretch) # Enable/disable tabs, based on settings self.window().debug_tab_widget.setTabEnabled(2, settings and settings['trustchain']['enabled']) self.window().debug_tab_widget.setTabEnabled(3, settings and settings['ipv8']['enabled']) self.window().system_tab_widget.setTabEnabled(3, settings and settings['resource_monitor']['enabled']) self.window().system_tab_widget.setTabEnabled(4, settings and settings['resource_monitor']['enabled']) # Refresh logs self.window().log_refresh_button.clicked.connect(lambda: self.load_logs_tab()) self.window().log_tab_widget.currentChanged.connect(lambda index: self.load_logs_tab()) # IPv8 statistics enabled? self.ipv8_statistics_enabled = settings['ipv8']['statistics'] # Libtorrent tab self.init_libtorrent_tab() # Position to center frame_geometry = self.frameGeometry() screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos()) center_point = QDesktopWidget().screenGeometry(screen).center() frame_geometry.moveCenter(center_point) self.move(frame_geometry.topLeft()) # Refresh timer self.refresh_timer = None def hideEvent(self, hide_event): self.stop_timer() def run_with_timer(self, call_fn, timeout=DEBUG_PANE_REFRESH_TIMEOUT): call_fn() self.stop_timer() self.refresh_timer = QTimer() self.refresh_timer.setSingleShot(True) self.refresh_timer.timeout.connect(lambda _call_fn=call_fn, _timeout=timeout: self.run_with_timer(_call_fn, timeout=_timeout)) self.refresh_timer.start(timeout) def stop_timer(self): if self.refresh_timer: try: self.refresh_timer.stop() self.refresh_timer.deleteLater() except RuntimeError: self._logger.error("Failed to stop refresh timer in Debug pane") def init_libtorrent_tab(self): self.window().libtorrent_tab_widget.setCurrentIndex(0) self.window().libtorrent_tab_widget.currentChanged.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_zero_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_one_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_two_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_three_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_export_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=True)) self.window().lt_zero_hop_btn.setChecked(True) def tab_changed(self, index): if index == 0: self.load_general_tab() elif index == 1: self.load_requests_tab() elif index == 2: self.run_with_timer(self.load_trustchain_tab) elif index == 3: self.ipv8_tab_changed(self.window().ipv8_tab_widget.currentIndex()) elif index == 4: self.tunnel_tab_changed(self.window().tunnel_tab_widget.currentIndex()) elif index == 5: self.run_with_timer(self.load_dht_tab) elif index == 6: self.run_with_timer(self.load_events_tab) elif index == 7: self.system_tab_changed(self.window().system_tab_widget.currentIndex()) elif index == 8: self.load_libtorrent_data() elif index == 9: self.load_logs_tab() def ipv8_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_ipv8_general_tab) elif index == 1: self.run_with_timer(self.load_ipv8_communities_tab) elif index == 2: self.run_with_timer(self.load_ipv8_community_details_tab) def tunnel_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_tunnel_circuits_tab) elif index == 1: self.run_with_timer(self.load_tunnel_relays_tab) elif index == 2: self.run_with_timer(self.load_tunnel_exits_tab) def system_tab_changed(self, index): if index == 0: self.load_open_files_tab() elif index == 1: self.load_open_sockets_tab() elif index == 2: self.load_threads_tab() elif index == 3: self.load_cpu_tab() elif index == 4: self.load_memory_tab() elif index == 5: self.load_profiler_tab() def create_and_add_widget_item(self, key, value, widget): item = QTreeWidgetItem(widget) item.setText(0, key) item.setText(1, "%s" % value) widget.addTopLevelItem(item) def load_general_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("statistics/tribler", self.on_tribler_statistics) def on_tribler_statistics(self, data): if not data: return data = data["tribler_statistics"] self.window().general_tree_widget.clear() self.create_and_add_widget_item("Tribler version", self.tribler_version, self.window().general_tree_widget) self.create_and_add_widget_item("Number of channels", data["num_channels"], self.window().general_tree_widget) self.create_and_add_widget_item("Database size", format_size(data["db_size"]), self.window().general_tree_widget) self.create_and_add_widget_item("Number of known torrents", data["num_torrents"], self.window().general_tree_widget) self.create_and_add_widget_item("", "", self.window().general_tree_widget) disk_usage = psutil.disk_usage('/') self.create_and_add_widget_item("Total disk space", format_size(disk_usage.total), self.window().general_tree_widget) self.create_and_add_widget_item("Used disk space", format_size(disk_usage.used), self.window().general_tree_widget) self.create_and_add_widget_item("Free disk space", format_size(disk_usage.free), self.window().general_tree_widget) def load_requests_tab(self): self.window().requests_tree_widget.clear() for endpoint, method, data, timestamp, status_code in sorted(tribler_performed_requests, key=lambda x: x[3]): item = QTreeWidgetItem(self.window().requests_tree_widget) item.setText(0, "%s %s %s" % (method, endpoint, data)) item.setText(1, ("%d" % status_code) if status_code else "unknown") item.setText(2, "%s" % strftime("%H:%M:%S", localtime(timestamp))) self.window().requests_tree_widget.addTopLevelItem(item) def load_trustchain_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("trustchain/statistics", self.on_trustchain_statistics) def on_trustchain_statistics(self, data): if not data: return self.window().trustchain_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item(key, value, self.window().trustchain_tree_widget) def load_ipv8_general_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("statistics/ipv8", self.on_ipv8_general_stats) def on_ipv8_general_stats(self, data): if not data: return self.window().ipv8_general_tree_widget.clear() for key, value in data["ipv8_statistics"].items(): if key in ('total_up', 'total_down'): value = "%.2f MB" % (value / (1024.0 * 1024.0)) elif key == 'session_uptime': value = "%s" % str(datetime.timedelta(seconds=int(value))) self.create_and_add_widget_item(key, value, self.window().ipv8_general_tree_widget) def load_ipv8_communities_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/overlays", self.on_ipv8_community_stats) def _colored_peer_count(self, peer_count, overlay_count, master_peer): is_discovery = (master_peer == "3081a7301006072a8648ce3d020106052b81040027038192000403b3ab059ced9b20646ab5e01" "762b3595c5e8855227ae1e424cff38a1e4edee73734ff2e2e829eb4f39bab20d7578284fcba72" "51acd74e7daf96f21d01ea17077faf4d27a655837d072baeb671287a88554e1191d8904b0dc57" "2d09ff95f10ff092c8a5e2a01cd500624376aec875a6e3028aab784cfaf0bac6527245db8d939" "00d904ac2a922a02716ccef5a22f7968") limits = [20, overlay_count * 30 + 1] if is_discovery else [20, 31] color = 0xF4D03F if peer_count < limits[0] else (0x56F129 if peer_count < limits[1] else 0xF12929) return QBrush(QColor(color)) def on_ipv8_community_stats(self, data): if not data: return self.window().communities_tree_widget.clear() for overlay in data["overlays"]: item = QTreeWidgetItem(self.window().communities_tree_widget) item.setText(0, overlay["overlay_name"]) item.setText(1, overlay["master_peer"][-12:]) item.setText(2, overlay["my_peer"][-12:]) peer_count = len(overlay["peers"]) item.setText(3, "%s" % peer_count) item.setForeground(3, self._colored_peer_count(peer_count, len(data["overlays"]), overlay["master_peer"])) if "statistics" in overlay and overlay["statistics"]: statistics = overlay["statistics"] item.setText(4, "%.3f" % (statistics["bytes_up"]/(1024.0 * 1024.0))) item.setText(5, "%.3f" % (statistics["bytes_down"]/(1024.0 * 1024.0))) item.setText(6, "%s" % statistics["num_up"]) item.setText(7, "%s" % statistics["num_down"]) item.setText(8, "%.3f" % statistics["diff_time"]) else: item.setText(4, "N/A") item.setText(5, "N/A") item.setText(6, "N/A") item.setText(7, "N/A") item.setText(8, "N/A") self.window().communities_tree_widget.addTopLevelItem(item) map(self.window().communities_tree_widget.resizeColumnToContents, xrange(10)) def load_ipv8_community_details_tab(self): if self.ipv8_statistics_enabled: self.window().ipv8_statistics_error_label.setHidden(True) self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/overlays/statistics", self.on_ipv8_community_detail_stats) else: self.window().ipv8_statistics_error_label.setHidden(False) self.window().ipv8_communities_details_widget.setHidden(True) def on_ipv8_community_detail_stats(self, data): if not data: return self.window().ipv8_communities_details_widget.setHidden(False) self.window().ipv8_communities_details_widget.clear() for overlay in data["statistics"]: self.window().ipv8_communities_details_widget.setColumnWidth(0, 250) for key, stats in overlay.items(): header_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget) header_item.setFirstColumnSpanned(True) header_item.setBackground(0, QtGui.QColor('#CCCCCC')) header_item.setText(0, key) self.window().ipv8_communities_details_widget.addTopLevelItem(header_item) for request_id, stat in stats.items(): stat_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget) stat_item.setText(0, request_id) stat_item.setText(1, "%.3f" % (stat["bytes_up"] / (1024.0 * 1024.0))) stat_item.setText(2, "%.3f" % (stat["bytes_down"] / (1024.0 * 1024.0))) stat_item.setText(3, "%s" % stat["num_up"]) stat_item.setText(4, "%s" % stat["num_down"]) self.window().ipv8_communities_details_widget.addTopLevelItem(stat_item) def add_items_to_tree(self, tree, items, keys): tree.clear() for item in items: widget_item = QTreeWidgetItem(tree) for index, key in enumerate(keys): value = format_size(item[key]) if key in ["bytes_up", "bytes_down"] else str(item[key]) widget_item.setText(index, value) tree.addTopLevelItem(widget_item) def load_tunnel_circuits_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/tunnel/circuits", self.on_tunnel_circuits) def on_tunnel_circuits(self, data): if data: self.add_items_to_tree(self.window().circuits_tree_widget, data.get("circuits"), ["circuit_id", "goal_hops", "actual_hops", "unverified_hop", "type", "state", "bytes_up", "bytes_down"]) def load_tunnel_relays_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/tunnel/relays", self.on_tunnel_relays) def on_tunnel_relays(self, data): if data: self.add_items_to_tree(self.window().relays_tree_widget, data["relays"], ["circuit_from", "circuit_to", "is_rendezvous", "bytes_up", "bytes_down"]) def load_tunnel_exits_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/tunnel/exits", self.on_tunnel_exits) def on_tunnel_exits(self, data): if data: self.add_items_to_tree(self.window().exits_tree_widget, data["exits"], ["circuit_from", "enabled", "bytes_up", "bytes_down"]) def load_dht_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("ipv8/dht/statistics", self.on_dht_statistics) def on_dht_statistics(self, data): if not data: return self.window().dht_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item(key, value, self.window().dht_tree_widget) def on_event_clicked(self, item): event_dict = item.data(0, Qt.UserRole) self.window().event_text_box.setPlainText(json.dumps(event_dict)) def load_events_tab(self): self.window().events_tree_widget.clear() for event_dict, timestamp in tribler_received_events: item = QTreeWidgetItem(self.window().events_tree_widget) item.setData(0, Qt.UserRole, event_dict) item.setText(0, "%s" % event_dict['type']) item.setText(1, "%s" % strftime("%H:%M:%S", localtime(timestamp))) self.window().events_tree_widget.addTopLevelItem(item) def load_open_files_tab(self): # Fill the open files (GUI) tree widget my_process = psutil.Process() self.window().open_files_tree_widget.clear() gui_item = QTreeWidgetItem(self.window().open_files_tree_widget) try: open_files = my_process.open_files() gui_item.setText(0, "GUI (%d)" % len(open_files)) self.window().open_files_tree_widget.addTopLevelItem(gui_item) for open_file in open_files: item = QTreeWidgetItem() item.setText(0, open_file.path) item.setText(1, "%d" % open_file.fd) gui_item.addChild(item) except psutil.AccessDenied as exc: gui_item.setText(0, "Unable to get open files for GUI (%s)" % exc) self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/open_files", self.on_core_open_files) def on_core_open_files(self, data): if not data: return core_item = QTreeWidgetItem(self.window().open_files_tree_widget) core_item.setText(0, "Core (%d)" % len(data["open_files"])) self.window().open_files_tree_widget.addTopLevelItem(core_item) for open_file in data["open_files"]: item = QTreeWidgetItem() item.setText(0, open_file["path"]) item.setText(1, "%d" % open_file["fd"]) core_item.addChild(item) def load_open_sockets_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/open_sockets", self.on_core_open_sockets) def on_core_open_sockets(self, data): if not data: return self.window().open_sockets_tree_widget.clear() self.window().open_sockets_label.setText("Sockets opened by core (%d):" % len(data["open_sockets"])) for open_socket in data["open_sockets"]: if open_socket["family"] == socket.AF_INET: family = "AF_INET" elif open_socket["family"] == socket.AF_INET6: family = "AF_INET6" elif open_socket["family"] == socket.AF_UNIX: family = "AF_UNIX" else: family = "-" item = QTreeWidgetItem(self.window().open_sockets_tree_widget) item.setText(0, open_socket["laddr"]) item.setText(1, open_socket["raddr"]) item.setText(2, family) item.setText(3, "SOCK_STREAM" if open_socket["type"] == socket.SOCK_STREAM else "SOCK_DGRAM") item.setText(4, open_socket["status"]) self.window().open_sockets_tree_widget.addTopLevelItem(item) def load_threads_tab(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/threads", self.on_core_threads) def on_core_threads(self, data): if not data: return self.window().threads_tree_widget.clear() for thread_info in data["threads"]: thread_item = QTreeWidgetItem(self.window().threads_tree_widget) thread_item.setText(0, "%d" % thread_info["thread_id"]) thread_item.setText(1, thread_info["thread_name"]) self.window().threads_tree_widget.addTopLevelItem(thread_item) for frame in thread_info["frames"]: frame_item = QTreeWidgetItem() frame_item.setText(2, frame) thread_item.addChild(frame_item) def load_cpu_tab(self): if not self.initialized_cpu_plot: vlayout = self.window().cpu_plot_widget.layout() self.cpu_plot = CPUPlotMplCanvas(self.window().cpu_plot_widget, dpi=100) vlayout.addWidget(self.cpu_plot) self.initialized_cpu_plot = True self.refresh_cpu_plot() # Start timer self.cpu_plot_timer = QTimer() self.cpu_plot_timer.timeout.connect(self.load_cpu_tab) self.cpu_plot_timer.start(5000) def refresh_cpu_plot(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/cpu/history", self.on_core_cpu_history) def on_core_cpu_history(self, data): if not data: return plot_data = [[], []] for cpu_info in data["cpu_history"]: if cpu_info["cpu"] == 0.0: continue # Ignore the initial measurement, is always zero plot_data[0].append(datetime.datetime.fromtimestamp(cpu_info["time"])) plot_data[1].append(cpu_info["cpu"]) if len(plot_data[0]) == 0: plot_data = [[datetime.datetime.now()], [0]] self.cpu_plot.plot_data = plot_data self.cpu_plot.compute_initial_figure() def load_memory_tab(self): if not self.initialized_memory_plot: vlayout = self.window().memory_plot_widget.layout() self.memory_plot = MemoryPlotMplCanvas(self.window().memory_plot_widget, dpi=100) vlayout.addWidget(self.memory_plot) self.initialized_memory_plot = True self.refresh_memory_plot() # Start timer self.memory_plot_timer = QTimer() self.memory_plot_timer.timeout.connect(self.load_memory_tab) self.memory_plot_timer.start(5000) def load_profiler_tab(self): self.window().toggle_profiler_button.setEnabled(False) self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/profiler", self.on_profiler_info) def on_profiler_info(self, data): if not data: return self.profiler_enabled = (data["state"] == "STARTED") self.window().toggle_profiler_button.setEnabled(True) self.window().toggle_profiler_button.setText("%s profiler" % ("Stop" if self.profiler_enabled else "Start")) def on_toggle_profiler_button_clicked(self): if self.toggling_profiler: return self.toggling_profiler = True self.window().toggle_profiler_button.setEnabled(False) self.request_mgr = TriblerRequestManager() method = "DELETE" if self.profiler_enabled else "PUT" self.request_mgr.perform_request("debug/profiler", self.on_profiler_state_changed, method=method) def on_profiler_state_changed(self, data): if not data: return self.toggling_profiler = False self.window().toggle_profiler_button.setEnabled(True) self.load_profiler_tab() if 'profiler_file' in data: QMessageBox.about(self, "Profiler statistics saved", "The profiler data has been saved to %s." % data['profiler_file']) def refresh_memory_plot(self): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("debug/memory/history", self.on_core_memory_history) def on_core_memory_history(self, data): if not data: return plot_data = [[], []] for mem_info in data["memory_history"]: plot_data[0].append(datetime.datetime.fromtimestamp(mem_info["time"])) plot_data[1].append(mem_info["mem"] / 1024 / 1024) if len(plot_data[0]) == 0: plot_data = [[datetime.datetime.now()], [0]] self.memory_plot.plot_data = plot_data self.memory_plot.compute_initial_figure() def on_memory_dump_button_clicked(self, dump_core): self.export_dir = QFileDialog.getExistingDirectory(self, "Please select the destination directory", "", QFileDialog.ShowDirsOnly) if len(self.export_dir) > 0: filename = "tribler_mem_dump_%s_%s.json" % \ ('core' if dump_core else 'gui', datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")) if dump_core: self.request_mgr = TriblerRequestManager() self.request_mgr.download_file("debug/memory/dump", lambda data: self.on_memory_dump_data_available(filename, data)) elif scanner: scanner.dump_all_objects(os.path.join(self.export_dir, filename)) else: ConfirmationDialog.show_error(self.window(), "Error when performing a memory dump", "meliae memory dumper is not compatible with Python 3") def on_memory_dump_data_available(self, filename, data): if not data: return dest_path = os.path.join(self.export_dir, filename) try: memory_dump_file = open(dest_path, "wb") memory_dump_file.write(data) memory_dump_file.close() except IOError as exc: ConfirmationDialog.show_error(self.window(), "Error when exporting file", "An error occurred when exporting the torrent file: %s" % str(exc)) def closeEvent(self, close_event): self.request_mgr.cancel_request() if self.cpu_plot_timer: self.cpu_plot_timer.stop() if self.memory_plot_timer: self.memory_plot_timer.stop() def load_logs_tab(self): # Max lines from GUI max_log_lines = self.window().max_lines_value.text() tab_index = self.window().log_tab_widget.currentIndex() tab_name = "core" if tab_index == 0 else "gui" self.request_mgr = TriblerRequestManager() request_query = "process=%s&max_lines=%s" % (tab_name, max_log_lines) self.request_mgr.perform_request("debug/log?%s" % request_query, self.display_logs) def display_logs(self, data): if not data: return tab_index = self.window().log_tab_widget.currentIndex() log_display_widget = self.window().core_log_display_area if tab_index == 0 \ else self.window().gui_log_display_area log_display_widget.moveCursor(QTextCursor.End) key_content = u'content' key_max_lines = u'max_lines' if not key_content in data or not data[key_content]: log_display_widget.setPlainText('No logs found') else: log_display_widget.setPlainText(data[key_content]) if not key_max_lines in data or not data[key_max_lines]: self.window().max_lines_value.setText('') else: self.window().max_lines_value.setText(str(data[key_max_lines])) sb = log_display_widget.verticalScrollBar() sb.setValue(sb.maximum()) def show(self): super(DebugWindow, self).show() # this will remove minimized status # and restore window with keeping maximized/normal state self.window().setWindowState(self.window().windowState() & ~Qt.WindowMinimized | Qt.WindowActive) self.window().activateWindow() def load_libtorrent_data(self, export=False): tab = self.window().libtorrent_tab_widget.currentIndex() hop = 0 if self.window().lt_zero_hop_btn.isChecked() \ else 1 if self.window().lt_one_hop_btn.isChecked() \ else 2 if self.window().lt_two_hop_btn.isChecked() \ else 3 if tab == 0: self.load_libtorrent_settings_tab(hop, export=export) elif tab == 1: self.load_libtorrent_sessions_tab(hop, export=export) def load_libtorrent_settings_tab(self, hop, export=False): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("libtorrent/settings?hop=%d" % hop, lambda data: self.on_libtorrent_settings_received(data, export=export)) self.window().libtorrent_settings_tree_widget.clear() def on_libtorrent_settings_received(self, data, export=False): if not data: return for key, value in data["settings"].items(): item = QTreeWidgetItem(self.window().libtorrent_settings_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_settings_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_settings.json", data) def load_libtorrent_sessions_tab(self, hop, export=False): self.request_mgr = TriblerRequestManager() self.request_mgr.perform_request("libtorrent/session?hop=%d" % hop, lambda data: self.on_libtorrent_session_received(data, export=export)) self.window().libtorrent_session_tree_widget.clear() def on_libtorrent_session_received(self, data, export=False): if not data: return for key, value in data["session"].items(): item = QTreeWidgetItem(self.window().libtorrent_session_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_session_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_session.json", data) def save_to_file(self, filename, data): base_dir = QFileDialog.getExistingDirectory(self, "Select an export directory", "", QFileDialog.ShowDirsOnly) if len(base_dir) > 0: dest_path = os.path.join(base_dir, filename) try: torrent_file = open(dest_path, "wb") torrent_file.write(json.dumps(data)) torrent_file.close() except IOError as exc: ConfirmationDialog.show_error(self.window(), "Error exporting file", str(exc))
class OpencvWidget(QLabel): def __init__(self, *args, **kwargs): super(OpencvWidget, self).__init__(*args, **kwargs) self.httpRequestAborted = False self.fps = 24 self.resize(800, 600) if not os.path.exists( "D:/access55/shape_predictor_68_face_landmarks.dat"): self.setText("正在下载数据文件。。。") self.outFile = QFile( "D:/access55/shape_predictor_68_face_landmarks.dat.bz2") if not self.outFile.open(QIODevice.WriteOnly): QMessageBox.critical(self, '错误', '无法写入文件') return self.qnam = QNetworkAccessManager(self) self._reply = self.qnam.get(QNetworkRequest(QUrl(URL))) self._reply.finished.connect(self.httpFinished) self._reply.readyRead.connect(self.httpReadyRead) self._reply.downloadProgress.connect(self.updateDataReadProgress) else: self.startCapture() def httpFinished(self): self.outFile.close() if self.httpRequestAborted or self._reply.error(): self.outFile.remove() self._reply.deleteLater() del self._reply # 下载完成解压文件并加载摄像头 self.setText("正在解压数据。。。") try: bz = BZ2Decompressor() data = bz.decompress( open('D:/access55/shape_predictor_68_face_landmarks.dat.bz2', 'rb').read()) open('D:/access55/shape_predictor_68_face_landmarks.dat', 'wb').write(data) except Exception as e: self.setText('解压失败:' + str(e)) return self.setText('正在开启摄像头。。。') self.startCapture() def httpReadyRead(self): self.outFile.write(self._reply.readAll()) self.outFile.flush() def updateDataReadProgress(self, bytesRead, totalBytes): self.setText('已下载:{} %'.format(round(bytesRead / 64040097 * 100, 2))) def startCapture(self): self.setText("请稍候,正在初始化数据和摄像头。。。") try: # 检测相关 self.detector = dlib.get_frontal_face_detector() self.predictor = dlib.shape_predictor( "D:/access55/shape_predictor_68_face_landmarks.dat") cascade_fn = "D:/access55/lbpcascades/lbpcascade_frontalface.xml" self.cascade = cv2.CascadeClassifier(cascade_fn) if not self.cascade: return QMessageBox.critical(self, "错误", cascade_fn + " 无法找到") self.cap = cv2.VideoCapture(0) if not self.cap or not self.cap.isOpened(): return QMessageBox.critical(self, "错误", "打开摄像头失败") # 开启定时器定时捕获 self.timer = QTimer(self, timeout=self.onCapture) self.timer.start(1000 / self.fps) except Exception as e: QMessageBox.critical(self, "错误", str(e)) def closeEvent(self, event): if hasattr(self, "_reply") and self._reply: self.httpRequestAborted = True self._reply.abort() try: os.unlink( "D:/access55/shape_predictor_68_face_landmarks.dat.bz2") except: pass try: os.unlink("D:/access55/shape_predictor_68_face_landmarks.dat") except: pass if hasattr(self, "timer"): self.timer.stop() self.timer.deleteLater() self.cap.release() del self.predictor, self.detector, self.cascade, self.cap super(OpencvWidget, self).closeEvent(event) self.deleteLater() def onCapture(self): _, frame = self.cap.read() minisize = (int(frame.shape[1] / DOWNSCALE), int(frame.shape[0] / DOWNSCALE)) tmpframe = cv2.resize(frame, minisize) tmpframe = cv2.cvtColor(tmpframe, cv2.COLOR_BGR2GRAY) # 做灰度处理 tmpframe = cv2.equalizeHist(tmpframe) # minNeighbors表示每一个目标至少要被检测到5次 faces = self.cascade.detectMultiScale(tmpframe, minNeighbors=5) del tmpframe if len(faces) < 1: # 没有检测到脸 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888) del frame return self.setPixmap(QPixmap.fromImage(img)) # 特征点检测描绘 for x, y, w, h in faces: x, y, w, h = x * DOWNSCALE, y * DOWNSCALE, w * DOWNSCALE, h * DOWNSCALE # 画脸矩形 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0)) # 截取的人脸部分 tmpframe = frame[y:y + h, x:x + w] # 进行特征点描绘 rects = self.detector(tmpframe, 1) if len(rects) > 0: landmarks = numpy.matrix( [[p.x, p.y] for p in self.predictor(tmpframe, rects[0]).parts()]) for _, point in enumerate(landmarks): pos = (point[0, 0] + x, point[0, 1] + y) # 在原来画面上画点 cv2.circle(frame, pos, 3, color=(0, 255, 0)) # 转成Qt能显示的 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888) del frame self.setPixmap(QPixmap.fromImage(img))
class MainWindow(QtWidgets.QMainWindow, gui_main.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # Animation self.animation = QPropertyAnimation(self, b'windowOpacity') self.animation.setDuration(800) self.doShow() # ProgressBar self.progressBar.setValue(0) self.progressBar.setTextVisible(False) # Buttons self.to_page_action.clicked.connect(self.action) self.to_page_setting.clicked.connect(self.setting) self.to_page_home.clicked.connect(self.home) self.to_page_graph.clicked.connect(self.Graph) self.setTable.clicked.connect(self.set_to_table) self.setGraph.clicked.connect(self.set_to_graph) self.export_to_xls_.clicked.connect(self.resetBar) # SET self.from_data.setDateTime(one_day) self.to_date.setDateTime(now) self.MCCMNC.setText("*") self.ANI.setText("*") self.Client.addItem(None) self.Vendor.addItem(None) # Combo_box for i in client: self.Client.addItem(i[1]) for s in vendor: self.Vendor.addItem(s[1]) self.threadpool = QThreadPool() def set_to_table(self): worker = Worker(self.UserData) worker.signals.result.connect(self.run_to_table) #worker.signals.finished.connect(self.thread_complete) #worker.signals.progress.connect(self.progress_fn) self.threadpool.start(worker) def set_to_graph(self): worker = Worker(self.UserData) self.doAction() worker.signals.result.connect(self.WebGraph) worker.signals.finished.connect(self.resetBar) self.threadpool.start(worker) def flow(self): print('Start') worker = Worker(self.UserData) self.threadpool.start(worker) def doAction(self): self.progressBar.setValue(0) self.progressBar.setMaximum(0) self.progressBar.setMinimum(0) if self.progressBar.minimum() != self.progressBar.maximum(): self.timer = QTimer(self, timeout=self.onTimeout) self.timer.start(randint(1, 3) * 1000) def resetBar(self): self.step = 0 self.progressBar.setValue(0) self.timer.stop() def onTimeout(self): if self.progressBar.value() >= 100: self.timer.stop() self.timer.deleteLater() del self.timer return self.progressBar.setValue(self.progressBar.value() + 1) def UserData(self): fr = self.from_data.dateTime() star = fr.toPyDateTime() to = self.to_date.dateTime() en = to.toPyDateTime() mnc = self.MCCMNC.text() ani = self.ANI.text() cli = self.Client.currentText() vnd = self.Vendor.currentText() conn = cx_Oracle.connect(setting.connet) cursor = conn.cursor() cursor.execute(setting.url, src=cli, dst=vnd, st=star, en=en, mnc=mnc, ani=ani) result = cursor.fetchall() attempts = [] for row in result: attempts.append(row) cursor.close() conn.close() print('OK') # print(attempts) return attempts def WebGraph(self, s): self.stackedWidget.setCurrentWidget(self.page_chart) attempts = s labels = ['Date', 'attempts', 'ok'] df = pd.DataFrame.from_records(attempts, columns=labels) fig = go.Figure() fig.add_trace(go.Scatter(x=df['Date'], y=df['attempts'], name='Attempts')) fig.add_trace(go.Scatter(x=df['Date'], y=df['ok'], name='Delivrd OK')) fig.update_layout(legend_orientation="h", template="plotly_dark", legend=dict(x=.5, xanchor="center"), hovermode="x", margin=dict(l=0, r=0, t=0, b=0)) fig.update_traces(hoverinfo="all", hovertemplate=" %{x}<br>%{y}") raw_html = '<html><head><meta charset="utf-8" />' raw_html += '<script src="https://cdn.plot.ly/plotly-latest.min.js"></script></head>' raw_html += '<body>' raw_html += plotly.offline.plot(fig, include_plotlyjs=False, output_type='div', config=dict(displayModeBar=False)) raw_html += '</body></html>' self.webGraph.setHtml(raw_html) def run_to_table(self, s): attempts = s self.TABLE.setRowCount(len(attempts)) self.TABLE.setColumnCount(len(attempts[0])) for row_num, row in enumerate(attempts): for cell_num, cell_attem in enumerate(row): self.TABLE.setItem(row_num, cell_num, QTableWidgetItem(str(cell_attem))) def Graph(self): self.stackedWidget.setCurrentWidget(self.page_chart) def setting(self): self.stackedWidget.setCurrentWidget(self.page_setting) def action(self): self.stackedWidget.setCurrentWidget(self.page_action) def home(self): self.stackedWidget.setCurrentWidget(self.page_home) def doShow(self): try: self.animation.finished.disconnect(self.close) except: pass self.animation.stop() self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() self.show()
class ExampleApp(QWidget, Ui_MainWindow): global com_port_name, get_pos, motor_stop, move_abs, roll_right, roll_left global position_LEED, position_EXCH, position_PASS def __init__(self): super(self.__class__, self).__init__() self.setupUi(self) """ Start monitoring the current position and connect all signals""" self.update_thread = update_position() self.pushButton.clicked.connect(lambda: self.move_motor(self.lineEdit.text())) self.pushButton_1.clicked.connect(self.joystick_operation) self.pushButton_2.clicked.connect(self.stop_motor) self.pushButton_3.clicked.connect(lambda: self.shift_motor(1,self.lineEdit_3.text())) # L shift self.pushButton_4.clicked.connect(lambda: self.shift_motor(-1,self.lineEdit_3.text())) # R shift self.pushButton_5.clicked.connect(lambda: self.move_motor(self.lineEdit_4.text())) # LEED self.pushButton_6.clicked.connect(lambda: self.move_motor(self.lineEdit_5.text())) # EXCH self.pushButton_7.clicked.connect(lambda: self.move_motor(self.lineEdit_6.text())) # PASS self.start() """ Show the LEED, EXCH and PASS positions """ self.lineEdit_4.setText(str(position_LEED)) self.lineEdit_5.setText(str(position_EXCH)) self.lineEdit_6.setText(str(position_PASS)) def start (self): self.update_thread.new_value_trigger.connect(self.update_position_label) self.timer_x = QTimer(self) self.timer_x.timeout.connect(self.update_thread.update_position) self.timer_x.start(1000) def stop_motor(self): self.command = motor_stop # construct command send_motor.send_command(com_port_name, self.command) # senf command def update_position_label (self, value): self.position_mm = value self.lineEdit_2.setText("{:1.1f}".format(self.position_mm)) def roll_motor (self, value): if (float (value) >= 0): print ('rolling right ', value) self.command = roll_right+roll_speed.to_bytes(4, byteorder='big',signed=True) send_motor.send_command(com_port_name, self.command) else: print ('rolling left ', value) self.command = roll_left+roll_speed.to_bytes(4, byteorder='big',signed=True) send_motor.send_command(com_port_name, self.command) def move_motor (self, value): if (float (value) <= 265) & (float (value) >= 0): self.lineEdit.setText(value) self.value = convert (float(value), True) print ('moving to ', self.value) self.command = move_abs + (self.value).to_bytes(4, byteorder='big',signed=True) send_motor.send_command(com_port_name, self.command) def shift_motor(self, flag, value): self.shift=float(value) if (self.shift <= 50) & (self.shift >= 0): if flag == -1: self.shift = (-1)*self.shift self.new_value = float(self.lineEdit_2.text())+self.shift self.lineEdit.setText(str(self.new_value)) print (self.new_value) self.shift_steps = convert (self.new_value, True) print (self.shift_steps) self.command = move_abs + (self.shift_steps).to_bytes(4, byteorder='big',signed=True) send_motor.send_command(com_port_name, self.command) def joystick_operation(self): if self.pushButton_1.isChecked(): self.pushButton_1.setText("Disable Joystick") self.joystick_monitor = joystick_control_class() self.joystick_monitor.joystick_trigger.connect (self.joystick_processing) self.joystick_monitor.start() else: print ("not checked") self.pushButton_1.setText("Enable Joystick") self.joystick_monitor.stop() def joystick_processing(self, parameter): self.joystick_command = parameter if self.joystick_command == 'stop': self.stop_motor() elif self.joystick_command == 'shift_left': self.shift_motor(1,self.lineEdit_3.text()) elif self.joystick_command == 'shift_right': self.shift_motor(-1,self.lineEdit_3.text()) elif self.joystick_command == 'LEED': self.move_motor(self.lineEdit_4.text()) elif self.joystick_command == 'EXCH': self.move_motor(self.lineEdit_5.text()) elif self.joystick_command == 'PASS': self.move_motor(self.lineEdit_6.text()) elif self.joystick_command == 'move_right': self.roll_motor(1) elif self.joystick_command == 'move_left': self.roll_motor(-1) def __del__ (self): self.stop_motor() self.update_thread.quit() self.timer_x.stop() self.timer_x.deleteLater()
class GraphModule: """ Класс, занимающийся работой с GraphWidget. """ def __init__(self, window: QMainWindow, nodes=None, edges=None, **kwargs): """Конструктор класса :param window: Окно-родитель для GraphWidget :type window: QMainWindow :param nodes: Список вида { id: Id Вершины, args: Список аргументов для конструктора Node } :param edges: Список вида { id: Id Ребра, args: Список аргументов для конструктора Edge } :param kwargs: Аргументы для GraphWidget """ self.window = window self.widget = GraphWidget(self.window, **kwargs) self.fa2 = ForceAtlas2( outboundAttractionDistribution=False, scalingRatio=100.0, verbose=False, gravity=10.0 ) self._nodes = {} # Хранилище вершин self._edges = {} # Хранилище связей self._texts = {} # Хранилище текстов self.get_relation_text = lambda item: str(item) self.matrix = None self.positions = None self.gravity_timer = None # Таймер для работы с гравитацией self.widget.item_right_clicked.connect(self._on_item_clicked) def add_text(self, id, pos_x, pos_y, parent_item=None, **kwargs): """Добавить текст :param id: Уникальный id текста :param pos_x: x-координата :param pos_y: y-координата :param parent_node: вершина-родитель :param **kwargs: Аргументы конструктора TextItem """ text = TextItem(id=id, parent=parent_item, **kwargs) if parent_item: pos_x -= parent_item.x() pos_y -= parent_item.y() text.setPos(pos_x, pos_y) text.linkActivated.connect(self._on_text_link_clicked) self._texts[id] = text def add_node(self, id, pos_x, pos_y, **kwargs): """Добавить вершину :param id: Уникальный идентификатор вершины :param pos_x: x-координата вершины :param pos_y: y-координата вершины :param **kwargs: Аргументы конструктора Node """ # assert id not in self._nodes if id in self._nodes: log.warning(f"{id} уже добавлена") node = Node(self.widget, id=id, **kwargs) node.setPos(pos_x, pos_y) self.widget.scene().addItem(node) self._nodes[id] = node def add_edge(self, id1, id2, ud=False, **kwargs): """Добавить ребро :param id1: source id :param id2: target id :param ud: не добавлять связь, если уже есть связь в другую сторону :param **kwargs: Аргументы конструктора Edge """ assert (id1, id2) not in self._edges if ud and (id2, id1) in self._edges: return edge = Edge(self._nodes[id1], self._nodes[id2], self.widget, **kwargs) self._edges[(id1, id2)] = edge self.widget.scene().addItem(edge) def _on_text_link_clicked(self, link): if link[:11] == 'internal://': if re.search(r'close\?id=[0-9\-]+', link): id = link[re.search(r'id=[0-9\-]+', link).start()+3:] try: self.widget.scene().removeItem(self._texts[id]) except KeyError: id = int(id) self.widget.scene().removeItem(self._texts[id]) del self._texts[id] def _on_item_clicked(self, item: QGraphicsItem): if isinstance(item, Node) and item.info \ and item.id not in self._texts: self.add_text(item.id, item.x() + 15, item.y() + 15, item, html_text=item.info) elif isinstance(item, Edge) and item.info \ and item.id not in self._texts: x = (item.dest.x() - item.source.x()) / 2 + item.source.x() y = (item.dest.y() - item.source.y()) / 2 + item.source.y() self.add_text(item.id, x, y, parent_item=item.source, html_text=self.get_relation_text(item.info)) def clear(self): self._nodes.clear() self._edges.clear() self._texts.clear() self.matrix = None self.widget.scene().clear() @property def nodes(self): """Вернуть список вершин. Возможно (TODO), здесь будет реализовано скрытие вершин """ return list(self._nodes.values()) @property def edges(self): """Вернуть список ребер""" return list(self._edges.values()) def calculate_matrix(self, weight=None): head = list(self._nodes.keys()) self.head = head self.matrix = np.zeros(len(head)**2).reshape((len(head), len(head))) self.positions = [[0, 0] for _ in range(len(head))] for key, edge in self._edges.items(): id1, id2 = key id1, id2 = head.index(id1), head.index(id2) self.matrix[id1][id2] = edge.weight if weight is None else weight self.matrix[id2][id1] = edge.weight if weight is None else weight for id_, node in self._nodes.items(): self.positions[head.index(id_)] = [node.x(), node.y()] self.positions = np.array(self.positions) def save_graph(self): fig = Plotter.save_to_graph(self) Plotter.display(fig) def relayout_graph(self, name: str): """Расположить вершины графа по какому-то алгоритму. Алгоритмы: * circular - по кругу * kamada_kawai - Kamada-Kawai Algorithm * planar - без пересечений ребер * random - рандом * shell - пока то же, что circular * spring - Fruchterman-Reingold Algorithm :param name: :type name: str """ def kamada_kawai(G): return nx.kamada_kawai_layout(G, weight=1) # def spectral(G): # return nx.spectral_layout(G, scale=20) func_dict = { 'circular': nx.circular_layout, 'kamada_kawai': kamada_kawai, 'planar': nx.planar_layout, 'random': nx.random_layout, 'shell': nx.shell_layout, # TODO 'spring': nx.spring_layout, # 'spectral': spectral } scale_dict = { 'circular': 0.5, 'random': 0.3 } self.calculate_matrix() matrix = np.array(self.matrix) G = nx.from_numpy_matrix(matrix) # Получить networkx-граф из матрицы try: pos = func_dict[name](G) except nx.exception.NetworkXException: self.box = QMessageBox.critical(self.widget, 'Ошибка', 'Граф не планарен') return # Расчехлить позиции pos = np.array([pos[i] for i in range(len(pos))]) # Масштабировать scale = SupremeSettings()['graphmodule_graph_scale'] try: pos = nx.rescale_layout(pos, scale=scale * scale_dict[name]) except KeyError: pos = nx.rescale_layout(pos, scale=scale) # Применить позиции for index, position in enumerate(pos): x, y = position node = self._nodes[self.head[index]] if node != self.widget.scene().mouseGrabberItem(): node.setX(x) node.setY(y) self._adjust_scene() def _adjust_scene(self): """ Подровнять сцену под вершины """ if len(self.nodes) == 0: self.widget.scene().setSceneRect(-200, -200, 400, 400) min_x, min_y, max_x, max_y = sys.maxsize, sys.maxsize, \ -sys.maxsize, -sys.maxsize for node in self.nodes + list(self._texts.values()): min_x = min(node.x(), min_x) min_y = min(node.y(), min_y) max_x = max(node.x(), max_x) max_y = max(node.y(), max_y) margin = 30 x, y = min_x, min_y w, h = max(max_x - min_x, 100), max(max_y - min_y, 100) self.widget.scene().setSceneRect(x-margin, y-margin, w+margin*2, h+margin*2) def start_gravity(self): """ Запустить расчёт взаимодействия вершин """ if self.gravity_timer \ or not SupremeSettings()['graphmodule_gravity_enabled']: return self.gravity_timer = QTimer(self.widget) self.gravity_timer.start( SupremeSettings()['graphmodule_timer_interval']) self.gravity_timer.timeout.connect(self._process_gravity) def stop_gravity(self): if self.gravity_timer: self.gravity_timer.stop() self.gravity_timer.deleteLater() self.gravity_timer = None def do_gravity_ticks(self, ticks): """Выполнить нужное количество тиков расчёта гравитации. Можно использовать для первоначальной стабилизации сцены. :param ticks: Количество тиков """ self.stop_gravity() for _ in range(ticks): self._process_gravity() self.start_gravity() def _process_gravity(self, ticks=1): """ Один тик обработки взаимодействия вершин """ self.calculate_matrix() if len(self.matrix) > 0: positions = self.fa2.forceatlas2( self.matrix, pos=self.positions, iterations=ticks) for index, position in enumerate(positions): x, y = position node = self._nodes[self.head[index]] if node != self.widget.scene().mouseGrabberItem(): node.setX(x) node.setY(y) self.positions = np.array(positions) self._adjust_scene()
class OnlineClassifierGui(QMainWindow): """ A GUI for testing and training classifiers online. This class can be used alone, but is really meant to be the stage after training which is done by the Classifier Trainer class. """ INTERNAL_BUFFER_EXTRA_DURATION = 2 INTERNAL_BUFFER_EXTRA_SIZE = INTERNAL_BUFFER_EXTRA_DURATION * global_config.SAMPLING_RATE CLASS_IMAGE_HEIGHT = 400 MENTAL_TASK_DELAY = 5000 EV3_MAC_ADDRESS = "00:16:53:4f:bd:54" ROBOT_CONTROL = False DEFAULT_ROBOT_SPEED = 10 classifier: cls.SimpleClassifier def __init__(self, classifier: cls.SimpleClassifier, filter_settings: utils.FilterSettings, feature_extraction_info: utils.FeatureExtractionInfo, feature_types: [], trial_classes: [utils.TrialClass], parent=None, config: OnlineClassifierConfigurations = OnlineClassifierConfigurations()): super().__init__(parent) self.setWindowTitle("Online Classifier") self.setWindowModality(PyQt5.QtCore.Qt.ApplicationModal) # self.vibration_serial = serial.Serial(port=utils.vibration_port(), baudrate=115200, timeout=5000) # if not self.vibration_serial.isOpen(): # print("Opening port") # self.vibration_serial.open() # else: # print("Port is already open") self.classifier = classifier self.filter_settings = filter_settings self.feature_extraction_info = feature_extraction_info self.feature_types = feature_types self.trial_classes = trial_classes self.config = config self.slice_generator = utils.SliceIndexGenerator(global_config.SAMPLING_RATE, trial_classes) self.sample_count = 0 self.trial_count = 0 self.correct_count = 0 self.INTERNAL_BUFFER_EXTRA_SIZE = self.INTERNAL_BUFFER_EXTRA_DURATION * self.feature_extraction_info.sampling_rate self.data_buffer = np.array([]) self.root_layout = QGridLayout() self.root_layout.setAlignment(PyQt5.QtCore.Qt.AlignTop) self.root_widget = QWidget() self.root_widget.setLayout(self.root_layout) self.setCentralWidget(self.root_widget) title = QLabel("<h1>Online Classifier</h1>") title.setAlignment(PyQt5.QtCore.Qt.AlignCenter) self.root_layout.addWidget(title, 0, 0, 1, 3) self.feature_window_edit = QLineEdit() self.feature_window_edit.setText(str(self.config.feature_window_size)) self.repetition_interval_edit = QLineEdit() self.repetition_interval_edit.setText(str(self.config.repetition_interval)) self.detection_threshold_edit = QLineEdit() self.detection_threshold_edit.setText(str(self.config.detection_threshold)) self.online_training_checkbox = QCheckBox("Online Training") self.online_training = False self.robot_connect_btn = QPushButton("Connect to EV3") self.robot_connect_btn.clicked.connect(self.connect_clicked) self.manual_control_checkbox = QCheckBox("Manual Control") self.ev3 = ev3.EV3(self.EV3_MAC_ADDRESS) self.motor_control = ev3.MotorControl(1, 8, self.ev3) self.previous_direction = None self.previous_test_set_accuracy = 0.0 self.previous_cross_validation_accuracy = 0.0 self.root_layout.addWidget(utils.construct_horizontal_box([ QLabel("Feature Window Size (sec): "), self.feature_window_edit, QLabel("Repetition Interval (sec): "), self.repetition_interval_edit, QLabel("Detection Threshold: "), self.detection_threshold_edit, self.online_training_checkbox, self.robot_connect_btn, self.manual_control_checkbox ]), 1, 0, 1, 3) self.root_directory_label = QLabel() self.pick_root_directory_btn = QPushButton("Select/Change") self.pick_root_directory_btn.clicked.connect(self.pick_root_directory) self.root_layout.addWidget(utils.construct_horizontal_box([ QLabel("Root directory:"), self.root_directory_label, self.pick_root_directory_btn ]), 2, 0, 1, 3) self.start_btn = QPushButton("Start Streaming") self.start_btn.clicked.connect(self.start_clicked) self.stop_btn = QPushButton("Stop Streaming") self.stop_btn.clicked.connect(self.stop_clicked) self.root_layout.addWidget(utils.construct_horizontal_box([ self.stop_btn, self.start_btn ]), 3, 0, 1, 3) self.class_label = QLabel("Start stream to see result") self.class_label.setAlignment(PyQt5.QtCore.Qt.AlignCenter) self.root_layout.addWidget(self.class_label, 4, 0, 1, 3) self.root_layout.addWidget(utils.construct_horizontal_box([ QLabel("<h2>Mental Tasks:</h2>") ]), 5, 0, 1, 3) self.training_tasks_widget = QWidget() self.training_tasks_layout = QHBoxLayout() self.training_tasks_widget.setLayout(self.training_tasks_layout) self.class_tiles_list = [] for trial_class in trial_classes: self.class_tiles_list.append(TrainingTaskTile(trial_class, self.CLASS_IMAGE_HEIGHT / 2)) self.training_tasks_layout.addWidget(self.class_tiles_list[-1]) self.root_layout.addWidget(self.training_tasks_widget, 6, 0, 1, 3) self.class_pixmap = QPixmap() self.log_textarea = QPlainTextEdit() self.root_layout.addWidget(self.log_textarea, 7, 0, 1, 3) self.board = self.initialize_board() self.board.prepare_session() self.reading_timer = None self.samples_push_count = 0 self.online_training_samples_push_count = 0 self.online_training_timer = None self.current_mental_task = None self.show() @staticmethod def initialize_board() -> BoardShim: params = BrainFlowInputParams() params.serial_port = utils.cyton_port() board = BoardShim(global_config.BOARD_ID, params) return board def initialize_data_buffer(self): self.data_buffer = np.zeros(( self.feature_extraction_info.range_size(), int(self.INTERNAL_BUFFER_EXTRA_SIZE + self.config.feature_window_size * self.feature_extraction_info.sampling_rate) ), dtype=float) def connect_clicked(self): self.ev3.connect() def pick_root_directory(self): path = QFileDialog.getExistingDirectory(self, "Select Root Directory...") self.root_directory_label.setText(path) def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: print("key pressed") if self.manual_control_checkbox.isChecked(): if event.key() == Qt.Key_A: self.motor_control.turn_left_from_middle(90, self.DEFAULT_ROBOT_SPEED) elif event.key() == Qt.Key_D: self.motor_control.turn_right_from_middle(90, self.DEFAULT_ROBOT_SPEED) elif event.key() == Qt.Key_W: self.motor_control.forward(self.DEFAULT_ROBOT_SPEED) elif event.key() == Qt.Key_S: self.motor_control.backward(self.DEFAULT_ROBOT_SPEED) def close(self) -> bool: if self.vibration_serial.isOpen(): self.vibration_serial.close() return super().close() def start_clicked(self): if utils.is_float(self.feature_window_edit.text()): self.config.feature_window_size = float(self.feature_window_edit.text()) if utils.is_float(self.repetition_interval_edit.text()): self.config.repetition_interval = float(self.repetition_interval_edit.text()) if utils.is_float(self.detection_threshold_edit.text()): self.config.detection_threshold = float(self.detection_threshold_edit.text()) self.online_training = self.online_training_checkbox.isChecked() self.log(f"Starting data stream, online training? {self.online_training}") if self.online_training: self.online_training_timer = QTimer() self.online_training_timer.singleShot(self.MENTAL_TASK_DELAY, self.next_mental_task) self.initialize_data_buffer() self.samples_push_count = 0 self.online_training_samples_push_count = 0 if self.reading_timer is None: print("Starting data stream...") self.board.start_stream() self.reading_timer = QTimer() self.reading_timer.timeout.connect(self.read_data) # TODO: Replace with a config variable self.reading_timer.start(100) def stop_clicked(self): if self.reading_timer is not None: self.log("Stopping stream...") print("Stopping...") self.board.stop_stream() self.reading_timer.deleteLater() self.reading_timer = None self.slice_generator.write_to_file(self.root_directory_label.text()) if self.online_training: if self.online_training_timer is not None: self.online_training_timer.deleteLater() self.online_training_timer = None self.clear_highlight_tile() self.log(f"Accuracy during online training: {self.correct_count / self.trial_count * 100}%") print(f"Accuracy during online training: {self.correct_count / self.trial_count * 100}%") def read_data(self): if self.board.get_board_data_count() > 0: raw_data = self.board.get_board_data() raw_eeg_data = utils.extract_eeg_data(raw_data, global_config.BOARD_ID) if self.root_directory_label.text() != "": full_path = self.root_directory_label.text() + "/" + global_config.EEG_DATA_FILE_NAME DataFilter.write_file(raw_eeg_data, full_path, "a") self.slice_generator.write_to_file(self.root_directory_label.text()) # Make room for new samples, discard the oldest self.data_buffer = np.roll(self.data_buffer, shift=-raw_eeg_data.shape[1], axis=1) # Insert new samples first_index = self.feature_extraction_info.first_electrode() - 1 last_index = self.feature_extraction_info.last_electrode() # Not including self.data_buffer[:, self.data_buffer.shape[1] - raw_eeg_data.shape[1]:] = raw_eeg_data[first_index:last_index, :] self.samples_push_count += raw_eeg_data.shape[1] self.sample_count += raw_eeg_data.shape[1] if self.online_training and self.online_training_timer is None: self.online_training_samples_push_count += raw_eeg_data.shape[1] if self.samples_push_count >= self.config.repetition_interval * self.feature_extraction_info.sampling_rate: self.classify_data() self.samples_push_count = 0 if self.online_training_samples_push_count >= self.config.feature_window_size * self.feature_extraction_info.sampling_rate: self.classify_data(online_training=True) self.online_training_samples_push_count = 0 self.online_training_timer = QTimer() self.online_training_timer.singleShot(self.MENTAL_TASK_DELAY, self.next_mental_task) self.clear_highlight_tile() def clear_highlight_tile(self): for tile in self.class_tiles_list: if tile.highlighted: tile.disable_highlight() break def classify_data(self, online_training: bool = False): filtered_data = self.filter_settings.apply(self.data_buffer[:, self.INTERNAL_BUFFER_EXTRA_SIZE:]) feature_vector = \ utils.extract_features([utils.EegData(filtered_data)], self.feature_extraction_info, self.feature_types)[0] feature_data = feature_vector.data print("Feature Vector extracted successfully...") label = self.classifier.classify(feature_data) while type(label) == np.ndarray: label = label[0] print(f"label = {label}") direction = None if online_training: correct_label = self.current_mental_task.label self.trial_count += 1 if label != correct_label: self.log("Wrong classification!") else: self.log("Correct Classification") self.correct_count += 1 # self.classifier.get_data_set().append_to(feature_data, np.array([correct_label]), data.DataSubSetType.TRAINING) # TODO: Might block execution for too long # self.classifier.train() # self.log("Training accuracy: " + self.classifier.training_set_accuracy()) path = "" for trial_class in self.trial_classes: if trial_class.label == label: path = trial_class.get_image_path() direction = trial_class.direction break self.class_pixmap = QPixmap(path).scaledToHeight(self.CLASS_IMAGE_HEIGHT, Qt.FastTransformation) self.class_label.setPixmap(self.class_pixmap) if self.ROBOT_CONTROL: if direction == utils.Direction.LEFT: self.motor_control.turn_left_from_middle(90, self.DEFAULT_ROBOT_SPEED) print("left") elif direction == utils.Direction.RIGHT: self.motor_control.turn_right_from_middle(90, self.DEFAULT_ROBOT_SPEED) print("right") elif direction == utils.Direction.FORWARD: self.motor_control.forward(self.DEFAULT_ROBOT_SPEED) print("forward") elif direction == utils.Direction.BACKWARD: self.motor_control.backward(self.DEFAULT_ROBOT_SPEED) print("backward") def next_mental_task(self): self.current_mental_task = self.random_class() print(f"Next mental task is {self.current_mental_task.name}") self.slice_generator.add_slice(self.current_mental_task.label, self.sample_count, self.sample_count + int(self.config.feature_window_size * self.feature_extraction_info.sampling_rate)) for tile in self.class_tiles_list: if tile.trial_class == self.current_mental_task: tile.highlight() else: tile.disable_highlight() if self.online_training_timer is not None: self.online_training_timer.deleteLater() self.online_training_timer = None def random_class(self) -> utils.TrialClass: index = random.randint(0, len(self.trial_classes) - 1) return self.trial_classes[index] def log(self, text: str): self.log_textarea.insertPlainText(f"{text}\n") def closeEvent(self, a0: QtGui.QCloseEvent) -> None: self.board.release_session()
class OpencvWidget(QLabel): def __init__(self, *args, **kwargs): super(OpencvWidget, self).__init__(*args, **kwargs) self.fps = 24 self.resize(800, 600) self.setText("请稍候,正在初始化数据和摄像头。。。") def start(self): try: # 检测相关 self.detector = dlib.get_frontal_face_detector() self.predictor = dlib.shape_predictor( "data/shape_predictor_68_face_landmarks.dat") cascade_fn = "data/lbpcascades/lbpcascade_frontalface.xml" self.cascade = cv2.CascadeClassifier(cascade_fn) if not self.cascade: return QMessageBox.critical(self, "错误", cascade_fn + " 无法找到") self.cap = cv2.VideoCapture(0) if not self.cap or not self.cap.isOpened(): return QMessageBox.critical(self, "错误", "打开摄像头失败") # 开启定时器定时捕获 self.timer = QTimer(self, timeout=self.onCapture) self.timer.start(1000 / self.fps) except Exception as e: QMessageBox.critical(self, "错误", str(e)) def closeEvent(self, event): if hasattr(self, "timer"): self.timer.stop() self.timer.deleteLater() self.cap.release() del self.predictor, self.detector, self.cascade, self.cap super(OpencvWidget, self).closeEvent(event) self.deleteLater() def onCapture(self): _, frame = self.cap.read() minisize = ( int(frame.shape[1] / DOWNSCALE), int(frame.shape[0] / DOWNSCALE)) tmpframe = cv2.resize(frame, minisize) tmpframe = cv2.cvtColor(tmpframe, cv2.COLOR_BGR2GRAY) # 做灰度处理 tmpframe = cv2.equalizeHist(tmpframe) # minNeighbors表示每一个目标至少要被检测到5次 faces = self.cascade.detectMultiScale(tmpframe, minNeighbors=5) del tmpframe if len(faces) < 1: # 没有检测到脸 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = QImage( frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888) del frame return self.setPixmap(QPixmap.fromImage(img)) # 特征点检测描绘 for x, y, w, h in faces: x, y, w, h = x * DOWNSCALE, y * DOWNSCALE, w * DOWNSCALE, h * DOWNSCALE # 画脸矩形 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0)) # 截取的人脸部分 tmpframe = frame[y:y + h, x:x + w] # 进行特征点描绘 rects = self.detector(tmpframe, 1) if len(rects) > 0: landmarks = numpy.matrix( [[p.x, p.y] for p in self.predictor(tmpframe, rects[0]).parts()]) for _, point in enumerate(landmarks): pos = (point[0, 0] + x, point[0, 1] + y) # 在原来画面上画点 cv2.circle(frame, pos, 3, color=(0, 255, 0)) # 转成Qt能显示的 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = QImage( frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888) del frame self.setPixmap(QPixmap.fromImage(img))
class Mosaic(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(Mosaic, self).__init__(parent=parent) self.setupUi(self) self.squares = [[None for _ in range(4)] for _ in range(4)] # self.pushButton.isEnabled() for i in range(4): for j in range(4): button_num = 4 * i + j + 1 button_name = 'pushButton' + ('_' + str(button_num) if button_num > 1 else '') qt_button = getattr(self, button_name) qt_button.__class__ = Square qt_button.set_cords(i, j) qt_button.clicked.connect(self.square_click) self.squares[i][j] = qt_button self.pushButton_17.clicked.connect(self.new_game) self.space_cords = [3, 3] self.squares[3][3].setVisible(False) self.start_time = None self.end_time = None self.timer = None self.time_cnt = 0 self.pushButton_19.clicked.connect(self.scoreboard) self.pushButton_18.clicked.connect(self.reset_game) qApp.installEventFilter(self) def move(self, square): val = square.text() if square.cords[1] == self.space_cords[1] or square.cords[ 0] == self.space_cords[0]: cord = 0 if square.cords[1] == self.space_cords[1] else 1 direc = 1 if self.space_cords[cord] > square.cords[cord] else -1 for i in range(square.cords[cord], self.space_cords[cord], direc): if cord == 0: temp_val = self.squares[i + direc][square.cords[1]].text() self.squares[i + direc][square.cords[1]].setText(val) else: temp_val = self.squares[square.cords[0]][i + direc].text() self.squares[square.cords[0]][i + direc].setText(val) val = temp_val self.squares[self.space_cords[0]][self.space_cords[1]].setEnabled( True) self.squares[self.space_cords[0]][self.space_cords[1]].setVisible( True) square.setEnabled(False) square.setText('space') square.setVisible(False) self.space_cords[0] = square.cords[0] self.space_cords[1] = square.cords[1] def square_click(self): self.move(self.sender()) self.check_end() def new_game(self): if self.timer: self.timer.stop() self.timer.deleteLater() self.shuffle() self.timer = QTimer(self) self.timer.timeout.connect(self.tick) self.timer.start(1000) self.start_time = time.time() self.time_cnt = 0 self.label.setText("Time passed (sec): " + str(self.time_cnt)) def shuffle(self): for t in range(16 * 10): if t % 2: possible_cords = [ i for i in range(4) if i != self.space_cords[0] ] rnd_cord = possible_cords[randint(0, 2)] self.move(self.squares[rnd_cord][self.space_cords[1]]) else: possible_cords = [ j for j in range(4) if j != self.space_cords[1] ] rnd_cord = possible_cords[randint(0, 2)] self.move(self.squares[self.space_cords[1]][rnd_cord]) def check_end(self): if self.start_time is not None and self.check_mosaic(): self.end_game() def end_game(self): if self.start_time is not None: time_data = time.time() - self.start_time self.start_time = None self.label.setText("Your time (sec): " + str(round(time_data, 2))) if self.timer: self.timer.stop() self.timer.deleteLater() self.timer = None self.time_cnt = 0 save_dialog = SaveDialog(self, score=round(time_data, 2)) if save_dialog.exec(): with open('scoreboard.txt', 'a+', encoding='utf-8') as csv_file: writer = csv.writer(csv_file, delimiter='$') writer.writerow([ save_dialog.lineEdit.text(), save_dialog.label_5.text(), save_dialog.label_4.text() ]) self.label.setText('Press "New Game" to start new game') def reset_game(self): self.start_time = None if self.timer: self.timer.stop() self.timer.deleteLater() self.timer = None self.label.setText('Press "New Game" to start new game') for i in range(4): for j in range(4): button_num = 4 * i + j + 1 if button_num < 16: self.squares[i][j].setText(str(button_num)) if not self.squares[i][j].isEnabled(): self.squares[i][j].setVisible(True) self.squares[i][j].setEnabled(True) self.squares[3][3].setVisible(False) self.squares[3][3].setEnabled(False) self.squares[3][3].setText('space') self.space_cords = [3, 3] def check_mosaic(self): for i in range(4): for j in range(4): button_num = 4 * i + j + 1 if button_num < 16 and self.squares[i][j].text() != str( button_num): return False return True def eventFilter(self, source, event): if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Up and self.space_cords[0] + 1 < 4: self.move(self.squares[self.space_cords[0] + 1][self.space_cords[1]]) elif event.key() == Qt.Key_Down and self.space_cords[0] - 1 >= 0: self.move(self.squares[self.space_cords[0] - 1][self.space_cords[1]]) elif event.key() == Qt.Key_Right and self.space_cords[1] - 1 >= 0: self.move( self.squares[self.space_cords[0]][self.space_cords[1] - 1]) elif event.key() == Qt.Key_Left and self.space_cords[1] + 1 < 4: self.move( self.squares[self.space_cords[0]][self.space_cords[1] + 1]) else: return super(Mosaic, self).eventFilter(source, event) self.check_end() return True return super(Mosaic, self).eventFilter(source, event) def tick(self): self.time_cnt += 1 self.label.setText("Time passed (sec): " + str(self.time_cnt)) def scoreboard(self): scoreBoard = ScoreboardDialog(self) scoreBoard.exec()
class PoputDialog(QWidget): def __init__(self, mainWindow=None): super(PoputDialog, self).__init__(None, Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint) self.SHADOW_WIDTH = 0 self.__mw = mainWindow self.initUI() def initUI(self): self.setGeometry(300, 300, 300, 220) self.setWindowTitle('ToolTips') self.setStyleSheet('background:gold;') # self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint) self.btn = QPushButton(self) self.btn.setText('调用父窗口方法') self.btn.clicked.connect(self.__test) self.desktop=QDesktopWidget().availableGeometry() self.move( (self.desktop.width()), self.desktop.height()-self.height()) #初始化位置到右下角 self.showAnimation() self.show() def enterEvent(self, e): print(0) #清除Timer和信号槽 self.remainTimer.stop() self.remainTimer.deleteLater() self.remainTimer=None def leaveEvent(self, e): print(1) self.__delay() def __test(self): self.__mw.do() #弹出动画 def showAnimation(self): #显示弹出框动画 self.animation=QPropertyAnimation(self, b'pos') self.animation.setDuration(1000) self.animation.setStartValue(QPoint(self.x(),self.y())) self.animation.setEndValue( QPoint( (self.desktop.width()-self.width()-self.SHADOW_WIDTH), (self.desktop.height()-self.height()))) self.animation.start() self.animation.finished.connect(self.__delay) def __delay(self): self.remainTimer = QTimer(self) #初始化一个定时器 self.remainTimer.timeout.connect(self.closeAnimation) #计时结束调用operate()方法 self.remainTimer.start(3000) #设置计时间隔并启动 def closeAnimation(self): #清除Timer和信号槽 self.remainTimer.stop() # self.disconnect(self.remainTimer,pyqtSignal("timeout()"),self,pyqtSlot("closeAnimation()")) self.remainTimer.deleteLater() self.remainTimer=None #弹出框渐隐 self.animation =QPropertyAnimation(self,b'windowOpacity') self.animation.setDuration(1000) self.animation.setStartValue(1) self.animation.setEndValue(0) #动画完成后清理 self.animation.finished.connect(self.clearAll) self.animation.start() #清理及退出 def clearAll(self): # self.disconnect(self.animation,pyqtSignal("finished()"),self,pyqtSlot("clearAll()")) sys.exit() #退出
class DebugWindow(QMainWindow): """ The debug window shows various statistics about Tribler such as performed requests, IPv8 statistics and community information. """ resize_event = pyqtSignal() def __init__(self, settings, tribler_version): self._logger = logging.getLogger(self.__class__.__name__) QMainWindow.__init__(self) self.cpu_plot = None self.memory_plot = None self.initialized_cpu_plot = False self.initialized_memory_plot = False self.cpu_plot_timer = None self.memory_plot_timer = None self.tribler_version = tribler_version self.profiler_enabled = False self.toggling_profiler = False uic.loadUi(get_ui_file_path('debugwindow.ui'), self) self.setWindowTitle("Tribler debug pane") self.window().dump_memory_core_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(True)) self.window().dump_memory_gui_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(False)) self.window().toggle_profiler_button.clicked.connect(self.on_toggle_profiler_button_clicked) self.window().debug_tab_widget.setCurrentIndex(0) self.window().ipv8_tab_widget.setCurrentIndex(0) self.window().tunnel_tab_widget.setCurrentIndex(0) self.window().dht_tab_widget.setCurrentIndex(0) self.window().system_tab_widget.setCurrentIndex(0) self.window().debug_tab_widget.currentChanged.connect(self.tab_changed) self.window().ipv8_tab_widget.currentChanged.connect(self.ipv8_tab_changed) self.window().tunnel_tab_widget.currentChanged.connect(self.tunnel_tab_changed) self.window().dht_tab_widget.currentChanged.connect(self.dht_tab_changed) self.window().events_tree_widget.itemClicked.connect(self.on_event_clicked) self.window().system_tab_widget.currentChanged.connect(self.system_tab_changed) self.load_general_tab() self.window().open_files_tree_widget.header().setSectionResizeMode(0, QHeaderView.Stretch) # Enable/disable tabs, based on settings self.window().debug_tab_widget.setTabEnabled(2, settings and settings['trustchain']['enabled']) self.window().debug_tab_widget.setTabEnabled(3, settings and settings['ipv8']['enabled']) self.window().system_tab_widget.setTabEnabled(3, settings and settings['resource_monitor']['enabled']) self.window().system_tab_widget.setTabEnabled(4, settings and settings['resource_monitor']['enabled']) # Refresh logs self.window().log_refresh_button.clicked.connect(lambda: self.load_logs_tab()) self.window().log_tab_widget.currentChanged.connect(lambda index: self.load_logs_tab()) # IPv8 statistics enabled? self.ipv8_statistics_enabled = settings['ipv8']['statistics'] # Libtorrent tab self.init_libtorrent_tab() # Position to center frame_geometry = self.frameGeometry() screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos()) center_point = QDesktopWidget().screenGeometry(screen).center() frame_geometry.moveCenter(center_point) self.move(frame_geometry.topLeft()) # Refresh timer self.refresh_timer = None self.rest_request = None self.ipv8_health_widget = None def hideEvent(self, hide_event): self.stop_timer() self.hide_ipv8_health_widget() def showEvent(self, show_event): if self.ipv8_health_widget and self.ipv8_health_widget.isVisible(): self.ipv8_health_widget.resume() TriblerNetworkRequest("ipv8/asyncio/drift", self.on_ipv8_health_enabled, data={"enable": True}, method='PUT') def run_with_timer(self, call_fn, timeout=DEBUG_PANE_REFRESH_TIMEOUT): call_fn() self.stop_timer() self.refresh_timer = QTimer() self.refresh_timer.setSingleShot(True) self.refresh_timer.timeout.connect( lambda _call_fn=call_fn, _timeout=timeout: self.run_with_timer(_call_fn, timeout=_timeout) ) self.refresh_timer.start(timeout) def stop_timer(self): if self.refresh_timer: try: self.refresh_timer.stop() self.refresh_timer.deleteLater() except RuntimeError: self._logger.error("Failed to stop refresh timer in Debug pane") def init_libtorrent_tab(self): self.window().libtorrent_tab_widget.setCurrentIndex(0) self.window().libtorrent_tab_widget.currentChanged.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_zero_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_one_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_two_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_three_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False)) self.window().lt_export_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=True)) self.window().lt_zero_hop_btn.setChecked(True) def tab_changed(self, index): if index == 0: self.load_general_tab() elif index == 1: self.load_requests_tab() elif index == 2: self.run_with_timer(self.load_trustchain_tab) elif index == 3: self.ipv8_tab_changed(self.window().ipv8_tab_widget.currentIndex()) elif index == 4: self.tunnel_tab_changed(self.window().tunnel_tab_widget.currentIndex()) elif index == 5: self.dht_tab_changed(self.window().dht_tab_widget.currentIndex()) elif index == 6: self.run_with_timer(self.load_events_tab) elif index == 7: self.system_tab_changed(self.window().system_tab_widget.currentIndex()) elif index == 8: self.load_libtorrent_data() elif index == 9: self.load_logs_tab() def ipv8_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_ipv8_general_tab) elif index == 1: self.run_with_timer(self.load_ipv8_communities_tab) elif index == 2: self.run_with_timer(self.load_ipv8_community_details_tab) elif index == 3: self.run_with_timer(self.load_ipv8_health_monitor) def tunnel_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_tunnel_circuits_tab) elif index == 1: self.run_with_timer(self.load_tunnel_relays_tab) elif index == 2: self.run_with_timer(self.load_tunnel_exits_tab) elif index == 3: self.run_with_timer(self.load_tunnel_swarms_tab) elif index == 4: self.run_with_timer(self.load_tunnel_peers_tab) def dht_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_dht_statistics_tab) elif index == 1: self.run_with_timer(self.load_dht_buckets_tab) def system_tab_changed(self, index): if index == 0: self.load_open_files_tab() elif index == 1: self.load_open_sockets_tab() elif index == 2: self.load_threads_tab() elif index == 3: self.load_cpu_tab() elif index == 4: self.load_memory_tab() elif index == 5: self.load_profiler_tab() def create_and_add_widget_item(self, key, value, widget): item = QTreeWidgetItem(widget) item.setText(0, key) item.setText(1, "%s" % value) widget.addTopLevelItem(item) def load_general_tab(self): TriblerNetworkRequest("statistics/tribler", self.on_tribler_statistics) def on_tribler_statistics(self, data): if not data: return data = data["tribler_statistics"] self.window().general_tree_widget.clear() self.create_and_add_widget_item("Tribler version", self.tribler_version, self.window().general_tree_widget) self.create_and_add_widget_item( "Python version", sys.version.replace('\n', ''), self.window().general_tree_widget # to fit in one line ) self.create_and_add_widget_item("Libtorrent version", libtorrent.version, self.window().general_tree_widget) self.create_and_add_widget_item("", "", self.window().general_tree_widget) self.create_and_add_widget_item("Number of channels", data["num_channels"], self.window().general_tree_widget) self.create_and_add_widget_item( "Database size", format_size(data["db_size"]), self.window().general_tree_widget ) self.create_and_add_widget_item( "Number of known torrents", data["num_torrents"], self.window().general_tree_widget ) self.create_and_add_widget_item("", "", self.window().general_tree_widget) disk_usage = psutil.disk_usage('/') self.create_and_add_widget_item( "Total disk space", format_size(disk_usage.total), self.window().general_tree_widget ) self.create_and_add_widget_item( "Used disk space", format_size(disk_usage.used), self.window().general_tree_widget ) self.create_and_add_widget_item( "Free disk space", format_size(disk_usage.free), self.window().general_tree_widget ) def load_requests_tab(self): self.window().requests_tree_widget.clear() for request, status_code in sorted(tribler_performed_requests, key=lambda rq: rq[0].time): endpoint = request.url method = request.method data = request.raw_data timestamp = request.time item = QTreeWidgetItem(self.window().requests_tree_widget) item.setText(0, "%s %s %s" % (method, repr(endpoint), repr(data))) item.setText(1, ("%d" % status_code) if status_code else "unknown") item.setText(2, "%s" % strftime("%H:%M:%S", localtime(timestamp))) self.window().requests_tree_widget.addTopLevelItem(item) def load_trustchain_tab(self): TriblerNetworkRequest("trustchain/statistics", self.on_trustchain_statistics) def on_trustchain_statistics(self, data): if not data: return self.window().trustchain_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item(key, value, self.window().trustchain_tree_widget) def load_ipv8_general_tab(self): TriblerNetworkRequest("statistics/ipv8", self.on_ipv8_general_stats) def on_ipv8_general_stats(self, data): if not data: return self.window().ipv8_general_tree_widget.clear() for key, value in data["ipv8_statistics"].items(): if key in ('total_up', 'total_down'): value = "%.2f MB" % (value / (1024.0 * 1024.0)) elif key == 'session_uptime': value = "%s" % str(datetime.timedelta(seconds=int(value))) self.create_and_add_widget_item(key, value, self.window().ipv8_general_tree_widget) def load_ipv8_communities_tab(self): TriblerNetworkRequest("ipv8/overlays", self.on_ipv8_community_stats) def _colored_peer_count(self, peer_count, overlay_count, overlay_name): if overlay_name == 'DiscoveryCommunity': limits = [20, overlay_count * 30 + 1] elif overlay_name == 'DHTDiscoveryCommunity': limits = [20, 61] elif overlay_name == 'RemoteQueryCommunity': limits = [20, 51] else: limits = [20, 31] color = 0xF4D03F if peer_count < limits[0] else (0x56F129 if peer_count < limits[1] else 0xF12929) return QBrush(QColor(color)) def on_ipv8_community_stats(self, data): if not data: return self.window().communities_tree_widget.clear() for overlay in data["overlays"]: item = QTreeWidgetItem(self.window().communities_tree_widget) item.setText(0, overlay["overlay_name"]) item.setText(1, overlay["master_peer"][-12:]) item.setText(2, overlay["my_peer"][-12:]) peer_count = len(overlay["peers"]) item.setText(3, "%s" % peer_count) item.setForeground(3, self._colored_peer_count(peer_count, len(data["overlays"]), overlay["overlay_name"])) if "statistics" in overlay and overlay["statistics"]: statistics = overlay["statistics"] item.setText(4, "%.3f" % (statistics["bytes_up"] / (1024.0 * 1024.0))) item.setText(5, "%.3f" % (statistics["bytes_down"] / (1024.0 * 1024.0))) item.setText(6, "%s" % statistics["num_up"]) item.setText(7, "%s" % statistics["num_down"]) item.setText(8, "%.3f" % statistics["diff_time"]) else: item.setText(4, "N/A") item.setText(5, "N/A") item.setText(6, "N/A") item.setText(7, "N/A") item.setText(8, "N/A") self.window().communities_tree_widget.addTopLevelItem(item) map(self.window().communities_tree_widget.resizeColumnToContents, range(10)) def load_ipv8_community_details_tab(self): if self.ipv8_statistics_enabled: self.window().ipv8_statistics_error_label.setHidden(True) TriblerNetworkRequest("ipv8/overlays/statistics", self.on_ipv8_community_detail_stats) else: self.window().ipv8_statistics_error_label.setHidden(False) self.window().ipv8_communities_details_widget.setHidden(True) def on_ipv8_community_detail_stats(self, data): if not data: return self.window().ipv8_communities_details_widget.setHidden(False) self.window().ipv8_communities_details_widget.clear() for overlay in data["statistics"]: self.window().ipv8_communities_details_widget.setColumnWidth(0, 250) for key, stats in overlay.items(): header_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget) header_item.setFirstColumnSpanned(True) header_item.setBackground(0, QtGui.QColor('#CCCCCC')) header_item.setText(0, key) self.window().ipv8_communities_details_widget.addTopLevelItem(header_item) for request_id, stat in stats.items(): stat_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget) stat_item.setText(0, request_id) stat_item.setText(1, "%.3f" % (stat["bytes_up"] / (1024.0 * 1024.0))) stat_item.setText(2, "%.3f" % (stat["bytes_down"] / (1024.0 * 1024.0))) stat_item.setText(3, "%s" % stat["num_up"]) stat_item.setText(4, "%s" % stat["num_down"]) self.window().ipv8_communities_details_widget.addTopLevelItem(stat_item) def load_ipv8_health_monitor(self): """ Lazy load and enable the IPv8 core health monitor. """ if self.ipv8_health_widget is None: # Add the core monitor widget to the tab widget. from PyQt5.QtWidgets import QVBoxLayout widget = MonitorWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(widget) self.window().ipv8_health_monitor_widget.setLayout(layout) self.window().ipv8_health_monitor_widget.show() self.ipv8_health_widget = widget else: # We already loaded the widget, just resume it. self.ipv8_health_widget.resume() # Whether the widget is newly loaded or not, start the measurements. TriblerNetworkRequest("ipv8/asyncio/drift", self.on_ipv8_health_enabled, data={"enable": True}, method='PUT') def hide_ipv8_health_widget(self): """ We need to hide the IPv8 health widget, involving two things: 1. Stop the smooth graphical updates in the widget. 2. Remove the observer from the IPv8 core. """ if self.ipv8_health_widget is not None and not self.ipv8_health_widget.is_paused: self.ipv8_health_widget.pause() TriblerNetworkRequest("ipv8/asyncio/drift", lambda _: None, data={"enable": False}, method='PUT') def on_ipv8_health(self, data): """ Measurements came in, send them to the widget for "plotting". """ if not data or 'measurements' not in data or self.ipv8_health_widget is None: return self.ipv8_health_widget.set_history(data['measurements']) def on_ipv8_health_enabled(self, data): """ The request to enable IPv8 completed. Start requesting measurements. """ if not data: return self.run_with_timer(lambda: TriblerNetworkRequest("ipv8/asyncio/drift", self.on_ipv8_health), 100) def add_items_to_tree(self, tree, items, keys): tree.clear() for item in items: widget_item = QTreeWidgetItem(tree) for index, key in enumerate(keys): if key in ["bytes_up", "bytes_down"]: value = format_size(item[key]) elif key in ["creation_time", "last_lookup"]: value = str(datetime.timedelta(seconds=int(time() - item[key]))) if item[key] > 0 else '-' else: value = str(item[key]) widget_item.setText(index, value) tree.addTopLevelItem(widget_item) def load_tunnel_circuits_tab(self): self.window().circuits_tree_widget.setColumnWidth(3, 200) TriblerNetworkRequest("ipv8/tunnel/circuits", self.on_tunnel_circuits) def on_tunnel_circuits(self, circuits): if not circuits: return for c in circuits["circuits"]: c["hops"] = f"{c['goal_hops']} / {c['goal_hops']}" c["exit_flags"] = c["exit_flags"] if c["state"] == "READY" else "" self.add_items_to_tree( self.window().circuits_tree_widget, circuits.get("circuits"), ["circuit_id", "hops", "type", "state", "bytes_up", "bytes_down", "creation_time", "exit_flags"], ) def load_tunnel_relays_tab(self): TriblerNetworkRequest("ipv8/tunnel/relays", self.on_tunnel_relays) def on_tunnel_relays(self, data): if data: self.add_items_to_tree( self.window().relays_tree_widget, data["relays"], ["circuit_from", "circuit_to", "is_rendezvous", "bytes_up", "bytes_down", "creation_time"], ) def load_tunnel_exits_tab(self): TriblerNetworkRequest("ipv8/tunnel/exits", self.on_tunnel_exits) def on_tunnel_exits(self, data): if data: self.add_items_to_tree( self.window().exits_tree_widget, data["exits"], ["circuit_from", "enabled", "bytes_up", "bytes_down", "creation_time"], ) def load_tunnel_swarms_tab(self): TriblerNetworkRequest("ipv8/tunnel/swarms", self.on_tunnel_swarms) def on_tunnel_swarms(self, data): if data: self.add_items_to_tree( self.window().swarms_tree_widget, data.get("swarms"), [ "info_hash", "num_seeders", "num_connections", "num_connections_incomplete", "seeding", "last_lookup", "bytes_up", "bytes_down", ], ) def load_tunnel_peers_tab(self): self.window().peers_tree_widget.setColumnWidth(2, 300) TriblerNetworkRequest("ipv8/tunnel/peers", self.on_tunnel_peers) def on_tunnel_peers(self, data): if data: self.add_items_to_tree( self.window().peers_tree_widget, data.get("peers"), ["ip", "port", "mid", "is_key_compatible", "flags"] ) def load_dht_statistics_tab(self): TriblerNetworkRequest("ipv8/dht/statistics", self.on_dht_statistics) def on_dht_statistics(self, data): if not data: return self.window().dhtstats_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item(key, value, self.window().dhtstats_tree_widget) def load_dht_buckets_tab(self): TriblerNetworkRequest("ipv8/dht/buckets", self.on_dht_buckets) def on_dht_buckets(self, data): if data: for bucket in data["buckets"]: bucket["num_peers"] = len(bucket["peers"]) ts = bucket["last_changed"] bucket["last_changed"] = str(datetime.timedelta(seconds=int(time() - ts))) if ts > 0 else '-' self.add_items_to_tree( self.window().buckets_tree_widget, data.get("buckets"), [ "prefix", "last_changed", "num_peers" ], ) def on_event_clicked(self, item): event_dict = item.data(0, Qt.UserRole) self.window().event_text_box.setPlainText(json.dumps(event_dict)) def load_events_tab(self): self.window().events_tree_widget.clear() for event_dict, timestamp in tribler_received_events: item = QTreeWidgetItem(self.window().events_tree_widget) item.setData(0, Qt.UserRole, event_dict) item.setText(0, "%s" % event_dict['type']) item.setText(1, "%s" % strftime("%H:%M:%S", localtime(timestamp))) self.window().events_tree_widget.addTopLevelItem(item) def load_open_files_tab(self): # Fill the open files (GUI) tree widget my_process = psutil.Process() self.window().open_files_tree_widget.clear() gui_item = QTreeWidgetItem(self.window().open_files_tree_widget) try: open_files = my_process.open_files() gui_item.setText(0, "GUI (%d)" % len(open_files)) self.window().open_files_tree_widget.addTopLevelItem(gui_item) for open_file in open_files: item = QTreeWidgetItem() item.setText(0, open_file.path) item.setText(1, "%d" % open_file.fd) gui_item.addChild(item) except psutil.AccessDenied as exc: gui_item.setText(0, "Unable to get open files for GUI (%s)" % exc) TriblerNetworkRequest("debug/open_files", self.on_core_open_files) def on_core_open_files(self, data): if not data: return core_item = QTreeWidgetItem(self.window().open_files_tree_widget) core_item.setText(0, "Core (%d)" % len(data["open_files"])) self.window().open_files_tree_widget.addTopLevelItem(core_item) for open_file in data["open_files"]: item = QTreeWidgetItem() item.setText(0, open_file["path"]) item.setText(1, "%d" % open_file["fd"]) core_item.addChild(item) def load_open_sockets_tab(self): TriblerNetworkRequest("debug/open_sockets", self.on_core_open_sockets) def on_core_open_sockets(self, data): if not data: return self.window().open_sockets_tree_widget.clear() self.window().open_sockets_label.setText("Sockets opened by core (%d):" % len(data["open_sockets"])) for open_socket in data["open_sockets"]: if open_socket["family"] == socket.AF_INET: family = "AF_INET" elif open_socket["family"] == socket.AF_INET6: family = "AF_INET6" elif open_socket["family"] == socket.AF_UNIX: family = "AF_UNIX" else: family = "-" item = QTreeWidgetItem(self.window().open_sockets_tree_widget) item.setText(0, open_socket["laddr"]) item.setText(1, open_socket["raddr"]) item.setText(2, family) item.setText(3, "SOCK_STREAM" if open_socket["type"] == socket.SOCK_STREAM else "SOCK_DGRAM") item.setText(4, open_socket["status"]) self.window().open_sockets_tree_widget.addTopLevelItem(item) def load_threads_tab(self): TriblerNetworkRequest("debug/threads", self.on_core_threads) def on_core_threads(self, data): if not data: return self.window().threads_tree_widget.clear() for thread_info in data["threads"]: thread_item = QTreeWidgetItem(self.window().threads_tree_widget) thread_item.setText(0, "%d" % thread_info["thread_id"]) thread_item.setText(1, thread_info["thread_name"]) self.window().threads_tree_widget.addTopLevelItem(thread_item) for frame in thread_info["frames"]: frame_item = QTreeWidgetItem() frame_item.setText(2, frame) thread_item.addChild(frame_item) def load_cpu_tab(self): if not self.initialized_cpu_plot: vlayout = self.window().cpu_plot_widget.layout() self.cpu_plot = CPUPlot(self.window().cpu_plot_widget) vlayout.addWidget(self.cpu_plot) self.initialized_cpu_plot = True self.refresh_cpu_plot() # Start timer self.cpu_plot_timer = QTimer() self.cpu_plot_timer.timeout.connect(self.load_cpu_tab) self.cpu_plot_timer.start(5000) def refresh_cpu_plot(self): TriblerNetworkRequest("debug/cpu/history", self.on_core_cpu_history) def on_core_cpu_history(self, data): if not data: return self.cpu_plot.reset_plot() for cpu_info in data["cpu_history"]: self.cpu_plot.add_data(cpu_info["time"], [round(cpu_info["cpu"], 2)]) self.cpu_plot.render_plot() def load_memory_tab(self): if not self.initialized_memory_plot: vlayout = self.window().memory_plot_widget.layout() self.memory_plot = MemoryPlot(self.window().memory_plot_widget) vlayout.addWidget(self.memory_plot) self.initialized_memory_plot = True self.refresh_memory_plot() # Start timer self.memory_plot_timer = QTimer() self.memory_plot_timer.timeout.connect(self.load_memory_tab) self.memory_plot_timer.start(5000) def load_profiler_tab(self): self.window().toggle_profiler_button.setEnabled(False) TriblerNetworkRequest("debug/profiler", self.on_profiler_info) def on_profiler_info(self, data): if not data: return self.profiler_enabled = data["state"] == "STARTED" self.window().toggle_profiler_button.setEnabled(True) self.window().toggle_profiler_button.setText("%s profiler" % ("Stop" if self.profiler_enabled else "Start")) def on_toggle_profiler_button_clicked(self): if self.toggling_profiler: return self.toggling_profiler = True self.window().toggle_profiler_button.setEnabled(False) method = "DELETE" if self.profiler_enabled else "PUT" TriblerNetworkRequest("debug/profiler", self.on_profiler_state_changed, method=method) def on_profiler_state_changed(self, data): if not data: return self.toggling_profiler = False self.window().toggle_profiler_button.setEnabled(True) self.load_profiler_tab() if 'profiler_file' in data: QMessageBox.about( self, "Profiler statistics saved", "The profiler data has been saved to %s." % data['profiler_file'] ) def refresh_memory_plot(self): TriblerNetworkRequest("debug/memory/history", self.on_core_memory_history) def on_core_memory_history(self, data): if not data or data.get("memory_history") is None: return self.memory_plot.reset_plot() for mem_info in data["memory_history"]: self.memory_plot.add_data(mem_info["time"], [round(mem_info["mem"], 2)]) self.memory_plot.render_plot() def on_memory_dump_button_clicked(self, dump_core): self.export_dir = QFileDialog.getExistingDirectory( self, "Please select the destination directory", "", QFileDialog.ShowDirsOnly ) if len(self.export_dir) > 0: filename = "tribler_mem_dump_%s_%s.json" % ( 'core' if dump_core else 'gui', datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), ) if dump_core: self.rest_request = TriblerNetworkRequest( "debug/memory/dump", lambda data, _: self.on_memory_dump_data_available(filename, data) ) elif scanner: scanner.dump_all_objects(os.path.join(self.export_dir, filename)) else: ConfirmationDialog.show_error( self.window(), "Error when performing a memory dump", "meliae memory dumper is not compatible with Python 3", ) def on_memory_dump_data_available(self, filename, data): if not data: return dest_path = os.path.join(self.export_dir, filename) try: with open(dest_path, "wb") as memory_dump_file: memory_dump_file.write(data) except IOError as exc: ConfirmationDialog.show_error( self.window(), "Error when exporting file", "An error occurred when exporting the torrent file: %s" % str(exc), ) def closeEvent(self, close_event): if self.rest_request: self.rest_request.cancel_request() if self.cpu_plot_timer: self.cpu_plot_timer.stop() if self.memory_plot_timer: self.memory_plot_timer.stop() def load_logs_tab(self): # Max lines from GUI max_log_lines = self.window().max_lines_value.text() tab_index = self.window().log_tab_widget.currentIndex() tab_name = "core" if tab_index == 0 else "gui" request_query = "process=%s&max_lines=%s" % (tab_name, max_log_lines) TriblerNetworkRequest("debug/log?%s" % request_query, self.display_logs) def display_logs(self, data): if not data: return tab_index = self.window().log_tab_widget.currentIndex() log_display_widget = ( self.window().core_log_display_area if tab_index == 0 else self.window().gui_log_display_area ) log_display_widget.moveCursor(QTextCursor.End) key_content = u'content' key_max_lines = u'max_lines' if not key_content in data or not data[key_content]: log_display_widget.setPlainText('No logs found') else: log_display_widget.setPlainText(data[key_content]) if not key_max_lines in data or not data[key_max_lines]: self.window().max_lines_value.setText('') else: self.window().max_lines_value.setText(str(data[key_max_lines])) sb = log_display_widget.verticalScrollBar() sb.setValue(sb.maximum()) def show(self): super(DebugWindow, self).show() # this will remove minimized status # and restore window with keeping maximized/normal state self.window().setWindowState(self.window().windowState() & ~Qt.WindowMinimized | Qt.WindowActive) self.window().activateWindow() def load_libtorrent_data(self, export=False): tab = self.window().libtorrent_tab_widget.currentIndex() hop = ( 0 if self.window().lt_zero_hop_btn.isChecked() else 1 if self.window().lt_one_hop_btn.isChecked() else 2 if self.window().lt_two_hop_btn.isChecked() else 3 ) if tab == 0: self.load_libtorrent_settings_tab(hop, export=export) elif tab == 1: self.load_libtorrent_sessions_tab(hop, export=export) def load_libtorrent_settings_tab(self, hop, export=False): TriblerNetworkRequest( "libtorrent/settings?hop=%d" % hop, lambda data: self.on_libtorrent_settings_received(data, export=export) ) self.window().libtorrent_settings_tree_widget.clear() def on_libtorrent_settings_received(self, data, export=False): if not data: return for key, value in data["settings"].items(): item = QTreeWidgetItem(self.window().libtorrent_settings_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_settings_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_settings.json", data) def load_libtorrent_sessions_tab(self, hop, export=False): TriblerNetworkRequest( "libtorrent/session?hop=%d" % hop, lambda data: self.on_libtorrent_session_received(data, export=export) ) self.window().libtorrent_session_tree_widget.clear() def on_libtorrent_session_received(self, data, export=False): if not data: return for key, value in data["session"].items(): item = QTreeWidgetItem(self.window().libtorrent_session_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_session_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_session.json", data) def save_to_file(self, filename, data): base_dir = QFileDialog.getExistingDirectory(self, "Select an export directory", "", QFileDialog.ShowDirsOnly) if len(base_dir) > 0: dest_path = os.path.join(base_dir, filename) try: with open(dest_path, "w") as torrent_file: torrent_file.write(json.dumps(data)) except IOError as exc: ConfirmationDialog.show_error(self.window(), "Error exporting file", str(exc))
class ExampleApp(QWidget, Ui_MainWindow): global com_port_name, get_pos, motor_stop, move_abs global position_LEED, position_EXCH, position_PASS def __init__(self): super(self.__class__, self).__init__() self.setupUi(self) """ Start monitoring the current position and connect all signals""" self.update_thread = update_position() self.pushButton.clicked.connect( lambda: self.move_motor(self.lineEdit.text())) self.pushButton_2.clicked.connect(self.stop_motor) self.pushButton_3.clicked.connect( lambda: self.shift_motor(1, self.lineEdit_3.text())) # L shift self.pushButton_4.clicked.connect( lambda: self.shift_motor(-1, self.lineEdit_3.text())) # R shift self.pushButton_5.clicked.connect( lambda: self.move_motor(self.lineEdit_4.text())) # LEED self.pushButton_6.clicked.connect( lambda: self.move_motor(self.lineEdit_5.text())) # EXCH self.pushButton_7.clicked.connect( lambda: self.move_motor(self.lineEdit_6.text())) # PASS self.start() """ Show the LEED, EXCH and PASS positions """ self.lineEdit_4.setText(str(position_LEED)) self.lineEdit_5.setText(str(position_EXCH)) self.lineEdit_6.setText(str(position_PASS)) def start(self): self.update_thread.new_value_trigger.connect( self.update_position_label) self.timer_x = QTimer(self) self.timer_x.timeout.connect(self.update_thread.update_position) self.timer_x.start(1000) def stop_motor(self): self.command = motor_stop # construct command send_motor.send_command(com_port_name, self.command) # senf command def update_position_label(self, value): self.position_mm = value self.lineEdit_2.setText("{:1.1f}".format(self.position_mm)) def move_motor(self, value): if (float(value) <= 265) & (float(value) >= 0): self.lineEdit.setText(value) self.value = convert(float(value), True) print('moving to ', self.value) self.command = move_abs + (self.value).to_bytes( 4, byteorder='big', signed=True) send_motor.send_command(com_port_name, self.command) def shift_motor(self, flag, value): self.shift = float(value) if (self.shift <= 50) & (self.shift >= 0): if flag == -1: self.shift = (-1) * self.shift self.new_value = float(self.lineEdit_2.text()) + self.shift self.lineEdit.setText(str(self.new_value)) print(self.new_value) self.shift_steps = convert(self.new_value, True) print(self.shift_steps) self.command = move_abs + (self.shift_steps).to_bytes( 4, byteorder='big', signed=True) send_motor.send_command(com_port_name, self.command) def __del__(self): self.stop_motor() self.update_thread.quit() self.timer_x.stop() self.timer_x.deleteLater()
class Form(QtWidgets.QDialog): def __init__(self, parent=None): QtWidgets.QDialog.__init__(self, parent) self.ui = uic.loadUi("./res/vocatest.ui", self) self.ui.show() #초기화면 시작 버튼 생성 & 초기화 self.bnStart = QPushButton(self) self.bnStart.setDefault(False) self.bnStart.setGeometry(80, 40, 400, 320) self.bnStart.setIcon(QIcon(QPixmap("./res/start.jpg"))) self.bnStart.setIconSize(QSize(390, 310)) # self.bnStart.setStyleSheet("background-image: url('start.jpg'); border: none;") self.bnStart.clicked.connect(self.bnStart_clicked) #정답 선택 라벨 마우스 이벤트 설정 #self.ui.label_select4.mousePressEvent = self.slot_label_select_clicked self.ui.label_select1.installEventFilter(self) self.ui.label_select2.installEventFilter(self) self.ui.label_select3.installEventFilter(self) self.ui.label_select4.installEventFilter(self) #폰트 #font = QFont() #font.setFamily(_fromUtf8("")) #font.setBold(True) quesFont = QFont("Times", 21, QFont.Bold) self.ui.label_question.setFont(quesFont) self.ui.label_question.setStyleSheet( "QLabel { background-color : #ffd732; color : black; }") scoreFont = QFont("Times", 14, QFont.Bold) self.ui.label_score.setFont(scoreFont) self.ui.label_score.setStyleSheet("QLabel { color : blue; }") #"background-color : white;}"); #"border:1px solid rgb(100, 100, 255);}"); answFont = QFont("굴림", 11, QFont.Normal) self.ui.label_select1.setFont(answFont) self.ui.label_select2.setFont(answFont) self.ui.label_select3.setFont(answFont) self.ui.label_select4.setFont(answFont) #변수 초기화 self.timer = None self.testNum = 0 self.selAnswer = '' #유저가 선택한 답(정답 A,B형인 경우 '1' ~ '4', C형일 경우 'string') self.cntAnswer = 0 #정답개수 #csv 파일 load self.vocas = csv.DictReader(open("../data/test.csv")) self.vocas = list(self.vocas) self.nTestTotal = len(self.vocas) self.retImg = QLabel(self) self.retImg.setGeometry(30, 270, 190, 120) self.label_counter = QLabel(self) self.label_counter.setGeometry(510, 70, 50, 50) self.label_counter.setFont(quesFont) self.label_counter.setStyleSheet("QLabel { color : red; }") self.label_counter.setText("%d" % TIMEOUT) # "background-color : white;}"); # "border:1px solid rgb(100, 100, 255);}"); self.showControls(False) self.bnStart.show() self.updateScore() self.setWindowTitle('뇌새김 단어 맞추기') def init_vocaTest(self): self.timer = None self.testNum = 0 self.selAnswer = '' # 유저가 선택한 답(정답 A,B형인 경우 '1' ~ '4', C형일 경우 'string') self.cntAnswer = 0 # 정답개수 self.updateScore() def start_timer(self, slot, count=1, interval=1000): counter = 0 def handler(): nonlocal counter counter += 1 slot(counter) ''' if counter >= count: self.timer.stop() self.timer.deleteLater() ''' self.timer = QTimer() self.timer.timeout.connect(handler) self.timer.start(interval) def stop_timer(self): if self.timer != None: self.timer.stop() self.timer.deleteLater() self.timer = None def timer_func(self, count): print('Timer:', count) if count >= TIMEOUT: self.checkTest('') #print("Timeout - 다음 문제로 넘어 갑니다.") self.testNum += 1 self.goNextTest(self.testNum) self.label_counter.setText("%d" % TIMEOUT) else: self.label_counter.setText("%d" % (TIMEOUT - count)) def bnStart_clicked(self): self.bnStart.hide() self.showControls(True) self.init_vocaTest() self.setVocaTest(self.testNum) def showControls(self, bShow): if bShow: self.ui.label_descript.show() self.ui.label_question.show() self.ui.label_select1.show() self.ui.label_select2.show() self.ui.label_select3.show() self.ui.label_select4.show() self.ui.label_score.show() self.label_counter.show() else: self.ui.label_descript.hide() self.ui.label_question.hide() self.ui.label_select1.hide() self.ui.label_select2.hide() self.ui.label_select3.hide() self.ui.label_select4.hide() self.ui.label_score.hide() self.label_counter.hide() #시험문제 준비 def setVocaTest(self, currNum): self.stop_timer() test = self.vocas[currNum] type = test["TYPE"] if type == 'A': descript = "{0}. 다음 영단어의 뜻을 고르시오.".format(currNum + 1) elif type == 'B': descript = "{0}. 다음 뜻과 일치하는 영단어를 고르시오.".format(currNum + 1) elif type == 'C': descript = "{0}. 다음에 해당하는 영단어 철자를 입력하시오".format(currNum + 1) self.ui.label_descript.setText(descript) self.ui.label_question.setText(test["QUESTION"]) #폰트 크게 if type != 'C': strSel = '① ' + test["SELECT1"] self.ui.label_select1.setText(strSel) strSel = '② ' + test["SELECT2"] self.ui.label_select2.setText(strSel) strSel = '③ ' + test["SELECT3"] self.ui.label_select3.setText(strSel) strSel = '④ ' + test["SELECT4"] self.ui.label_select4.setText(strSel) #타이머 self.start_timer(self.timer_func, TIMEOUT) def checkTest(self, selAnswer): #정답인 경우 test = self.vocas[self.testNum] answer = test["ANSWER"] if selAnswer == answer: QSound.play("./res/good.wav") imgpath = "./res/good.png" self.cntAnswer += 1 else: QSound.play("./res/wrong.wav") imgpath = "./res/nogood.png" temp = QPixmap(imgpath) pixmap = temp.scaled(self.retImg.width(), self.retImg.height()) self.retImg.setPixmap(pixmap) self.retImg.show() self.retImg.repaint() #hide하기 전에 repaint를 해줘야 제대로 보이네... update는 안먹힘 time.sleep(0.5) #결과이미지 보여주고 2초간 대기 self.retImg.hide() self.updateScore() def updateScore(self): self.strScore = "%d / %d" % (self.cntAnswer, self.nTestTotal) self.ui.label_score.setText(self.strScore) def eventFilter(self, source, event): if event.type() == QEvent.MouseButtonPress: if source == self.ui.label_select1: selAnswer = '1' elif source == self.ui.label_select2: selAnswer = '2' elif source == self.ui.label_select3: selAnswer = '3' else: selAnswer = '4' print("The sender is:", source.text()) self.checkTest(selAnswer) # 다음문제로... self.testNum += 1 self.goNextTest(self.testNum) return super(Form, self).eventFilter(source, event) def goNextTest(self, testNum): if testNum < self.nTestTotal: self.setVocaTest(testNum) elif testNum >= self.nTestTotal: # 테스트종료 self.stop_timer() choice = QMessageBox.question( self, '시험 끝 ', "맞은 개수 : %d\n틀린 개수 : %d\n종합 점수 : %d점\n\n재시도 하시겠습니까?" % (self.cntAnswer, self.nTestTotal - self.cntAnswer, self.cntAnswer / self.nTestTotal * 100), QMessageBox.Yes | QMessageBox.No) if choice == QMessageBox.Yes: self.bnStart_clicked() else: sys.exit() '''
class App(QDialog): def __init__(self): ''' Initializes and loads the GUI PyQt file ''' super(App, self).__init__() self.vid = None self.name = None self.capture = None self.len = None self.l = 0 loadUi('gui.xml', self) self.startButton.clicked.connect(self.on_start_clicked) self.lButton.clicked.connect(self.open_file) self.playButton.clicked.connect(self.play_video) def play_video(self): ''' A function to play a given video ''' self.capture = cv2.VideoCapture(self.videoOut) frame_rate = self.capture.get(cv2.CAP_PROP_FPS) self.len = int(self.capture.get(cv2.CAP_PROP_FRAME_COUNT)) self.timer = QTimer(self) self.timer.timeout.connect(self.dispayImage) self.timer.start(frame_rate) def dispayImage(self): ''' Each video frame is read and loaded ''' self.l += 1 if self.l >= self.len: self.timer.stop() self.timer.deleteLater() self.l = 0 ret, img = self.capture.read() qformat = QImage.Format_RGB888 outImage = QImage(img, img.shape[1], img.shape[0], qformat) outImage = outImage.rgbSwapped() self.video.setPixmap(QPixmap.fromImage(outImage)) def open_file(self): ''' Opens Files ''' filename, _ = QFileDialog.getOpenFileName(self, 'Open Video File', '../', 'All Files(*)') if filename: self.vid = filename base = os.path.basename(filename) self.name = os.path.splitext(base)[0] self.nameLabel.setText(base) def on_start_clicked(self): ''' Reads the input from the GUI and uses the parameters to start the program ''' self.finished.clear() QApplication.instance().processEvents() alpha = float(self.alpha.text()) cutoff = float(self.cutoff.text()) low = float(self.low.text()) high = float(self.high.text()) chromAttenuation = float(self.chromAtt.text()) linearAttenuation = self.linearAtt.isChecked() mode = self.comboBox.currentIndex() if mode == 0: butterworth_filter.start(self.vid, alpha, cutoff, low, high, linearAttenuation, chromAttenuation, self.name) else: if mode == 1: ideal_filter.start(self.vid, alpha, low, high, chromAttenuation, self.name) self.finished.setText('Done!') self.videoOut = self.name + "Out.avi"
class Widget(QMainWindow): logger.info("---------- STARTED ----------") stop_signal = pyqtSignal( ) # sinaliza que o usuário clicou em "Stop Data Colleting" logout_signal = pyqtSignal() date = datetime.datetime.strptime(RELEASE_DATE, '%Y-%m-%d') version = VERSION # Check if all files/folders are present. if not os.path.exists("Data"): os.mkdir("Data") if not os.path.exists("Data\\Training Data"): os.mkdir("Data\\Training Data") try: with open("config.json", "r") as f: logger.info('Loading config file') output = json.loads(f.read()) used_key = output["Used key"] username = output['User'] ignore_login = output['Ignore Login Popup'] first_time_running = output['First Time Running'] token = output['Token'] except Exception as e: logger.error(e) output = { "Used key": "C", "User": "", "Ignore Login Popup": False, "First Time Running": True, "Token": "" } used_key = output["Used key"] username = output['User'] ignore_login = output['Ignore Login Popup'] first_time_running = output['First Time Running'] token = output['Token'] with open("config.json", 'w') as f: json.dump(output, f, indent=2) logger.info("Fixed config file") logger.info('Config file loaded') def __init__(self): super().__init__() self.initUI() # Starting threads for startup verification self.loading_dialog = Loading() if DEV: wait_time = 100 else: wait_time = random.randint(3550, 4500) # Defining control variables: self.auth_done = False self.update_check_done = False self.call_update_box = False self.call_accnt_box = False self.update_available = False self.wait_counter = 0 self.online = False self.bot_btn_clicks = 0 # Startup processes: self.startup_authorize_user() self.startup_update_check() self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.loading) self.loading_timer.start(wait_time) # Icons: self.setWindowIcon(QtGui.QIcon('media\\logo\\logo.ico')) self.dog_getting_up = QtGui.QMovie( 'media\\animations\\Dog Getting Up4.gif') self.dog_running = QtGui.QMovie('media\\animations\\Dog Running4.gif') self.dog_idle = QtGui.QMovie('media\\animations\\Dog Idle2.gif') self.dog_sitting_down = QtGui.QMovie( "media\\animations\\Dog Sitting Down4.gif") self.icons_label.setMovie(self.dog_idle) self.icons_label_2.setMovie(self.dog_idle) self.dog_idle.start() # Setting default labels and texts: self.v_label.setText("v{}".format(self.version)) self.v_label_2.setText("v{}".format(self.version)) # Defining button/checkbox actions self.data_start.clicked.connect(self.data_start_action) self.data_stop.clicked.connect(self.data_stop_action) self.send_btn.clicked.connect(self.send_data) self.bot_btn.clicked.connect(self.bot_controller) def initUI(self): logger.info("Initializing UI") loadUi('designs\\MainWindow.ui', self) # Main Window self.setFixedSize(333, 493) # Toolbar self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint) # Bug Report Tab self.send_message_btn.clicked.connect(self.send_message) # Menu self.logout_btn = self.menu.addAction('Logout') self.logout_btn.triggered.connect(self.logout) self.logout_btn.setVisible(False) self.login_btn = self.menu.addAction('Login') self.login_btn.triggered.connect(self.runtime_login) self.login_btn.setVisible(False) visit_ranking = self.menu.addAction('Ranking') visit_ranking.triggered.connect(lambda: webbrowser.open(RANKING_URL)) website = self.menu.addAction('GitHub') website.triggered.connect( lambda: webbrowser.open("https://github.com/Setti7/SVFB-GUI")) self.config = self.menu.addAction('Fast Config') self.config.triggered.connect(self.fast_config) logger.info("UI Initialized") # Loading screen controller def loading(self): if self.auth_done and self.update_check_done: logger.info("Loading main aplication finished") self.loading_timer.stop() self.loading_timer.deleteLater() self.call_accnt_box = True self.call_update_box = True self.loading_dialog.close() self.show() def fast_config(self): config_dialog = ChangeKey(self.used_key) if config_dialog.exec_(): self.used_key = config_dialog.new_key # Send message def send_message(self): msg = self.message_text.toPlainText() if self.update_available: bug_box = QMessageBox() bug_box.setIcon(QMessageBox.Warning) bug_box.setText( "<strong>You can't send bug reports while using an outdated version!</strong>" ) bug_box.setInformativeText( """Please click <i>Ok</i> to download the newer one. Maybe your bug is already fixed.""" ) bug_box.setWindowTitle("Please update before sending bug reports") bug_box.setWindowIcon(QtGui.QIcon('media\\logo\\logo.ico')) bug_box.setEscapeButton(QMessageBox.Close) bug_box.addButton(QMessageBox.Close) ok = bug_box.addButton(QMessageBox.Ok) ok.clicked.connect(lambda: webbrowser.open( "https://github.com/Setti7/SVFB-GUI/releases")) bug_box.exec_() elif len(msg) > 1000: self.message_status_label.clear() self.message_status_label.setStyleSheet("color: #dc3545;") self.timer_msg0 = QTimer() self.timer_msg0.timeout.connect( lambda: self.message_status_label.setText( "Your message is to big!\nThe maximum is 1000 chars.")) self.timer_msg0.timeout.connect(self.timer_msg0.stop) self.timer_msg0.timeout.connect(self.timer_msg0.deleteLater) self.timer_msg0.start(200) else: self.message_text.clear() try: data = { 'message': msg, 'user': self.username, 'version': self.version, } headers = {'Authorization': f'Token {self.token}'} response = requests.post(BUG_REPORT_URL, data=data, headers=headers) result = json.loads(response.text) if result['success']: self.message_status_label.setText( "Message successfully sent!") self.message_status_label.setStyleSheet("color: #28a745;") else: logger.error( f"Error while sending message: {result['error']}") self.message_status_label.setText( "There was an error while sending!") self.message_status_label.setStyleSheet("color: #dc3545;") self.timer_msg = QTimer() self.timer_msg.timeout.connect(self.message_status_label.clear) self.timer_msg.timeout.connect(self.timer_msg.stop) self.timer_msg.timeout.connect(self.timer_msg.deleteLater) self.timer_msg.start(5000) except Exception as e: print(e) logger.error(e) # Startup Processes and connection functions: def startup_update_check(self): logger.info("Searching for updates") self.check_thread = QThread() self.checker = CheckForUpdates() self.checker.moveToThread(self.check_thread) self.checker.update_text.connect(self.update_check_over) self.check_thread.started.connect(self.checker.do_work) self.check_thread.start() def update_check_over(self, update_info): self.checker.deleteLater() self.check_thread.quit() self.check_thread.deleteLater() self.check_thread.wait() self.update_timer = QTimer() self.update_timer.timeout.connect( lambda: self.update_message_box(update_info)) self.update_timer.start(200) self.update_check_done = True def startup_authorize_user(self): logger.info("Trying to login user") # Thread: self.login_thread = QThread() self.login_worker = LoginWorker(self.username, self.token) self.login_worker.moveToThread(self.login_thread) self.login_worker.result.connect(self.login_control) self.login_worker.result.connect(self.login_worker.deleteLater) self.login_worker.result.connect(self.login_thread.quit) self.login_thread.finished.connect(self.login_thread.deleteLater) self.login_thread.finished.connect(self.login_thread.wait) self.login_thread.started.connect(self.login_worker.do_work) self.login_thread.start() # If the user clicks the retry connection button too much: def wait_motherfucker(self, *args): self.wait_counter += 1 if self.wait_counter >= 5: self.wait_counter = 0 wait = QMessageBox() wait.setIcon(QMessageBox.Warning) wait.setText( "<strong>I AM TRYING TO CONNECT ALREADY. STOP MASHING THAT DAMN BUTTON" ) wait.setInformativeText( """I'm doing my best ok? Just have a little patience please.""" ) wait.setWindowTitle("FOR GOD'S SAKE, WAIT!") wait.setWindowIcon(QtGui.QIcon('media\\logo\\logo.ico')) close = wait.addButton(QMessageBox.Close) close.setText("Ok... I will stop") wait.setEscapeButton(QMessageBox.Close) wait.exec_() def retry_connection(self, *args): # *args are necessary so it can be called from the mousePressEvent # Label self.username_label.setText("Connecting") self.username_label.mousePressEvent = lambda x: self.wait_motherfucker( ) self.username_label_2.setText("Connecting") self.username_label_2.mousePressEvent = lambda x: self.wait_motherfucker( ) # Thread: self.login_thread = QThread() self.login_worker = LoginWorker(self.username, self.token) self.login_worker.moveToThread(self.login_thread) # Finished proccess self.login_worker.result.connect(self.login_worker.deleteLater) self.login_worker.result.connect(self.login_thread.quit) self.login_thread.finished.connect(self.login_thread.deleteLater) # Response from thread self.login_worker.result.connect(self.login_control) # Thread starting self.login_thread.started.connect(self.login_worker.do_work) self.login_thread.start() # Verifying new versions: self.check_thread = QThread() self.checker = CheckForUpdates() self.checker.moveToThread(self.check_thread) self.checker.update_text.connect(self.update_check_over) self.check_thread.started.connect(self.checker.do_work) self.check_thread.start() # As gui has already loaded, we jump through the code made to stop the message box from appearing while loading self.call_update_box = True def update_score(self, **kwargs): # if 'offline' in kwargs.keys(): # self.score_label.setText("") # # self.score_label.setText("Score: Offline") # # if 'waiting' in kwargs.keys(): # self.score_label.setText("") # # self.score_label.setText("Score: Waiting Connection") # # if 'not_logged' in kwargs.keys(): # self.score_label.setText("") # # self.score_label.setText("Score: Not Logged") if 'online_score' in kwargs.keys(): self.score_label.setVisible(True) self.line.setVisible(True) self.score_label.setText("Online Score: {}".format( kwargs['online_score'])) else: self.score_label.setVisible(False) self.line.setVisible(False) def dog_go_idle(self): self.icons_label.setMovie(self.dog_idle) self.dog_idle.start() self.dog_timer2.stop() def dog_run(self): self.icons_label.setMovie(self.dog_running) self.dog_running.start() self.dog_timer.stop() # Notification of new version: def call_not_critical_update_message_box(self, *args, **kwargs): current_version = kwargs['current_version'] new_version = kwargs['new_version'] changes = kwargs['changes'] updateBox = QMessageBox() updateBox.setIcon(QMessageBox.Information) updateBox.setText( """This new version has no critical changes, so you can choose to download it or not. Check the changelog below!""" ) updateBox.setWindowTitle("New Update Available") updateBox.setWindowIcon(QtGui.QIcon('media\\logo\\logo.ico')) text = """Version available: {1}\n\n{2}""".format( current_version, new_version, changes) updateBox.setDetailedText(text) updateBox.setEscapeButton(QMessageBox.Close) updateBox.addButton(QMessageBox.Close) ok = updateBox.addButton(QMessageBox.Ok) ok.setText('Update') ok.clicked.connect(lambda: webbrowser.open(HOME_PAGE_URL)) updateBox.exec_() def update_message_box(self, update_info): if self.call_update_box: self.update_timer.stop() self.update_timer.deleteLater() update = update_info['Update'] logger.info("Update available: %s" % update) else: update = False if update: self.update_available = True current_version = update_info['Current Version'] new_version = update_info['New Version'] changes = update_info['Changes'] critical = update_info['Critical'] logger.info("Update critical: %s" % critical) if not critical: self.v_label.setText( "v{} (<a href='#'>update to v{}</a>)".format( self.version, new_version)) self.v_label.mousePressEvent = lambda args: self.call_not_critical_update_message_box( current_version=current_version, new_version=new_version, changes=changes, ) self.v_label_2.setText( "v{} (<a href='#'>update to v{}</a>)".format( self.version, new_version)) self.v_label_2.mousePressEvent = lambda args: self.call_not_critical_update_message_box( current_version=current_version, new_version=new_version, changes=changes, ) if critical: updateBox = QMessageBox() updateBox.setIcon(QMessageBox.Warning) updateBox.setText( "<strong>Your version is super outdated and is not useful anymore!</strong>" ) updateBox.setInformativeText( """Please click <i>Ok</i> to download the newer one. You can also see the changelog details below! <small>(The critical change is highlighted)</small>""" ) updateBox.setWindowTitle("Unsupported Version") updateBox.setWindowIcon(QtGui.QIcon('media\\logo\\logo.ico')) text = """Version available: {1}\n\n{2}""".format( current_version, new_version, changes) updateBox.setDetailedText(text) updateBox.setEscapeButton(QMessageBox.Close) updateBox.addButton(QMessageBox.Close) self.v_label.setText("v{} (v{} REQUIRED)".format( self.version, new_version)) self.v_label_2.setText("v{} (v{} REQUIRED)".format( self.version, new_version)) ok = updateBox.addButton(QMessageBox.Ok) ok.clicked.connect(lambda: webbrowser.open(HOME_PAGE_URL)) updateBox.exec_() self.close() # Data processes: def data_start_action(self): # Flag to indicate data collection is running self.data_running = True self.data_start.setEnabled(False) self.data_stop.setEnabled(True) self.send_btn.setEnabled(False) self.logout_btn.setEnabled(False) self.login_btn.setEnabled(False) # Indicating user about the key being used: self.send_status_label.setText( f'Using "{self.used_key}" key. Change it in "Fast Config".') self.send_status_label.setStyleSheet("color: #007bff;") QTimer.singleShot(3000, self.send_status_label.clear) # Icon self.icons_label.setMovie(self.dog_getting_up) self.dog_getting_up.start() self.dog_timer = QTimer() self.dog_timer.timeout.connect(self.dog_run) self.dog_timer.start(370) try: # this is necessary to make the dog don't go idle if the user clicks start>stop too fast. self.dog_timer2.deleteLater() except: pass # fight me # Thread: __init__ logger.info("Creating data thread") self.thread = QThread() logger.info(f"Using: {self.used_key}") if self.used_key.upper() == "LEFT-CLICK": self.worker = SaveData(0x01) else: self.worker = SaveData(self.used_key) self.stop_signal.connect( self.worker.stop) # connect stop signal to worker stop method self.worker.moveToThread(self.thread) self.worker.finished.connect( self.thread.quit ) # connect the workers finished signal to stop thread self.worker.finished.connect( self.worker.deleteLater ) # connect the workers finished signal to clean up worker self.thread.finished.connect( self.thread.deleteLater ) # connect threads finished signal to clean up thread self.thread.started.connect(self.worker.main) self.thread.finished.connect(self.worker.stop) self.worker.send_data.connect(self.send_data) self.thread.start() def data_stop_action(self): # Flag to indicate data collection is not running self.data_running = False if hasattr(self, 'bot_running'): if not self.bot_running: self.logout_btn.setEnabled(True) self.login_btn.setEnabled(True) else: self.logout_btn.setEnabled(True) self.login_btn.setEnabled(True) self.data_start.setEnabled(True) self.data_stop.setEnabled(False) if self.online: self.send_btn.setEnabled(True) logger.info("Data stopped") self.stop_signal.emit() # emit the finished signal on stop # Icon self.dog_timer.deleteLater() self.icons_label.setMovie(self.dog_sitting_down) self.dog_sitting_down.start() self.dog_timer2 = QTimer() self.dog_timer2.timeout.connect(self.dog_go_idle) self.dog_timer2.start(370) def send_data(self): """ Creates thread to send data and don't stop the execution of the program while it is uploading. Every time the button is clicked, it is created a new thread, that is deleted after the upload. """ self.send_btn.setEnabled(False) if self.online: try: logger.info("Starting send data thread") self.send_data_thread = QThread() # Thread criado self.send_data_worker = SendData(version=self.version, token=self.token, username=self.username) self.send_data_worker.moveToThread(self.send_data_thread) self.send_data_worker.status_code.connect( self.auto_send_response_code_controller) self.send_data_worker.status_code.connect( self.score_worker.single_check_online_score) self.send_data_worker.status_code.connect( self.send_data_worker.deleteLater ) # Finished then deletes thread and worker self.send_data_worker.status_code.connect( self.send_data_thread.quit) self.send_data_thread.finished.connect( self.send_data_thread.deleteLater) self.send_data_thread.started.connect( self.send_data_worker.send_data) self.send_data_thread.start() logger.info('Send data thread started') except Exception as e: logger.error("Could not start thread to send data: %s" % e) QMessageBox.information( self, "Oops!", "Could not start thread to send data: %s" % e) else: # Raises the little offline message self.auto_send_response_code_controller(-2) def auto_send_response_code_controller(self, code): if code == 200: self.send_status_label.setText("Success! Thank you for helping!") self.send_status_label.setStyleSheet("color: #28a745;") self.send_btn.setText("Send Data") elif code == -1: self.send_status_label.setText('Everything was already sent!') self.send_status_label.setStyleSheet("color: #dc3545;") self.send_btn.setText("Send Data") elif code == -2: self.send_status_label.setText( 'Could not connect to server. Session is saved.') self.send_status_label.setStyleSheet("color: #ffaf00;") self.update_score(waiting=True) self.send_btn.setText("Send Data (upload pending)") else: self.send_status_label.setText("Verify your connection") self.send_status_label.setStyleSheet("color: #dc3545;") self.update_score(offline=True) QTimer.singleShot(5000, self.send_status_label.clear) if hasattr(self, 'data_running'): if not self.data_running: self.send_btn.setEnabled(True) else: self.send_btn.setEnabled(True) # Bot Functions def bot_controller(self): self.bot_btn_clicks += 1 if self.bot_btn_clicks == 1: # Configuring control variables self.bot_running = True # Changing labels self.bot_btn.setText("Stop") # Disabling buttons that could cause problems self.logout_btn.setEnabled(False) self.login_btn.setEnabled(False) self.change_dataset_btn.setEnabled(False) else: # Configuring control variables self.bot_btn_clicks = 0 self.bot_running = False # Changing labels self.bot_btn.setText("Start") # Enabling buttons self.change_dataset_btn.setEnabled(True) if hasattr(self, 'data_running'): if not self.data_running: self.logout_btn.setEnabled(True) self.login_btn.setEnabled(True) else: self.logout_btn.setEnabled(True) self.login_btn.setEnabled(True) # Account functions: def login_control(self, results): self.auth_done = True if "Logged" in results.keys(): if results['Logged']: logger.info("User successfully logged in") self.user_has_logged({ "Username": results['Username'], "Token": results['Token'], "Session": results['Session'] }) else: # If user has failed to login, keep calling the function until loading stops, so it does not pop up # with the loading screen still on. self.accnt_timer = QTimer() self.accnt_timer.timeout.connect(self.login_error) self.accnt_timer.start(200) if "Offline" in results.keys(): self.online = False self.update_score(offline=True) logger.warning("Offline") self.login_btn.setVisible(False) self.logout_btn.setVisible(False) self.username_label.mousePressEvent = self.retry_connection self.username_label.setText( '<a href="#"><span style=" text-decoration: underline; color:#0000ff;">Retry Connection</span></a>' ) self.username_label_2.mousePressEvent = self.retry_connection self.username_label_2.setText( '<a href="#"><span style=" text-decoration: underline; color:#0000ff;">Retry Connection</span></a>' ) self.wait_counter = 0 if self.first_time_running: welcome_dialog = WelcomeDialog() if welcome_dialog.exec_(): self.first_time_running = False def login_error(self): # when the loading has finished, call the accnt manager pop up if the login failed if self.call_accnt_box: logger.info("Opening account manager") self.accnt_timer.stop() self.accnt_timer.deleteLater() self.login_btn.setVisible(True) self.logout_btn.setVisible(False) if not self.ignore_login: self.accnt_manager = AccountManager() self.accnt_manager.user_logged.connect(self.user_has_logged) self.accnt_manager.rejected.connect(self.login_rejected) self.accnt_manager.exec_() else: self.username_label.setText("Not logged") self.username_label_2.setText("Not logged") self.username_label.mousePressEvent = None self.username_label_2.mousePressEvent = None self.update_score(not_logged=True) if self.first_time_running: welcome_dialog = WelcomeDialog() if welcome_dialog.exec_(): self.first_time_running = False def login_rejected(self): self.username_label.setText("Not logged") self.username_label_2.setText("Not logged") self.username_label.mousePressEvent = None self.username_label_2.mousePressEvent = None self.logout_btn.setVisible(False) self.login_btn.setVisible(True) self.update_score(not_logged=True) with open("config.json", 'r') as f: output = json.loads(f.read()) output["Ignore Login Popup"] = True with open("config.json", "w") as f: json.dump(output, f, indent=2) def user_has_logged(self, user_info): # When the user has logged in, create a score thread with its user/password to get the online score. # Check the online score as soon as possible. logger.info("User logged") self.username = user_info['Username'] self.token = user_info['Token'] # Checking if there is data to be sent if os.listdir('Data\\Training Data'): self.send_btn.setText("Send data (upload pending)") else: self.send_btn.setText("Send data") self.online = True self.username_label.setText(self.username) self.username_label_2.setText(self.username) self.send_message_btn.setEnabled(True) self.send_message_btn.setText("Send cool message") self.login_btn.setVisible(False) self.logout_btn.setVisible(True) # Fixes bug where offline user collecting data could retry connecting to the server, re-enabling the buttons. if hasattr(self, 'data_running'): if not self.data_running: self.send_btn.setEnabled(True) self.data_start.setEnabled(True) else: self.send_btn.setEnabled(True) self.data_start.setEnabled(True) # Score Thread initialization try: self.score_thread = QThread() # Thread criado self.score_worker = QuickCheck(token=self.token, username=self.username) # self.score_worker.moveToThread(self.score_thread) # If logout signal is emmitted, delete the worker and quit then delete the thread too self.logout_signal.connect(self.score_worker.deleteLater) self.logout_signal.connect(self.score_thread.quit) self.score_thread.finished.connect(self.score_thread.deleteLater) self.score_worker.online_score.connect( lambda ol_score: self.update_score(online_score=ol_score)) self.score_thread.start() logger.info("Score thread started") self.score_worker.single_check_online_score() except Exception as e: logger.error("Could not start score thread: %s" % e) QMessageBox.information(self, "Oops!", "Could not start score thread: %s" % e) # When user tries to login with the login button at the menu def runtime_login(self): self.ignore_login = False self.login_control({'Logged': False}) def logout(self): # When user logs out, emit a signal that kills the score_thread and score_worker, because the session will change # if the user logs in with another account. self.logout_signal.emit() logger.info("User logged out") self.username = None self.token = None self.username_label.setText("Not logged") self.username_label_2.setText("Not logged") self.send_btn.setText("Can't send data while offline") self.send_btn.setEnabled(False) self.send_message_btn.setEnabled(False) with open('config.json', 'r') as f: output = json.loads(f.read()) output['User'] = self.username output['Token'] = self.token with open('config.json', 'w') as f: json.dump(output, f, indent=2) self.update_score(not_logged=True) self.login_control({"Logged": False}) def closeEvent(self, event): stop_time = datetime.datetime.now() runtime = (stop_time - start_time).total_seconds() logger.info('---------- CLOSED. Runtime: %ss ----------' % runtime) event.accept() #.ignore
class DebugWindow(QMainWindow): """ The debug window shows various statistics about Tribler such as performed requests, IPv8 statistics and community information. """ resize_event = pyqtSignal() def __init__(self, settings, gui_settings, tribler_version): self._logger = logging.getLogger(self.__class__.__name__) QMainWindow.__init__(self) self.core_cpu_plot = None self.gui_cpu_plot = None self.initialized_cpu_plot = False self.cpu_plot_timer = None self.core_memory_plot = None self.gui_memory_plot = None self.initialized_memory_plot = False self.memory_plot_timer = None self.tribler_version = tribler_version self.profiler_enabled = False self.toggling_profiler = False uic.loadUi(get_ui_file_path('debugwindow.ui'), self) self.setWindowTitle("Tribler debug pane") connect(self.window().toggle_profiler_button.clicked, self.on_toggle_profiler_button_clicked) self.window().debug_tab_widget.setCurrentIndex(0) self.window().ipv8_tab_widget.setCurrentIndex(0) self.window().tunnel_tab_widget.setCurrentIndex(0) self.window().dht_tab_widget.setCurrentIndex(0) self.window().system_tab_widget.setCurrentIndex(0) connect(self.window().debug_tab_widget.currentChanged, self.tab_changed) connect(self.window().ipv8_tab_widget.currentChanged, self.ipv8_tab_changed) connect(self.window().communities_tree_widget.itemClicked, self.on_community_clicked) connect(self.window().tunnel_tab_widget.currentChanged, self.tunnel_tab_changed) connect(self.window().dht_tab_widget.currentChanged, self.dht_tab_changed) connect(self.window().events_tree_widget.itemClicked, self.on_event_clicked) connect(self.window().system_tab_widget.currentChanged, self.system_tab_changed) self.load_general_tab() self.window().open_files_tree_widget.header().setSectionResizeMode( 0, QHeaderView.Stretch) self.window().community_peers_tree_widget.hide() # Enable/disable tabs, based on settings self.window().debug_tab_widget.setTabEnabled(2, settings is not None) self.window().debug_tab_widget.setTabEnabled( 3, settings and settings['ipv8']['enabled']) self.window().system_tab_widget.setTabEnabled( 3, settings and settings['resource_monitor']['enabled']) self.window().system_tab_widget.setTabEnabled( 4, settings and settings['resource_monitor']['enabled']) # Refresh logs connect(self.window().log_refresh_button.clicked, lambda _: self.load_logs_tab()) connect(self.window().log_tab_widget.currentChanged, lambda index: self.load_logs_tab()) # IPv8 statistics enabled? self.ipv8_statistics_enabled = settings['ipv8']['statistics'] # Libtorrent tab self.init_libtorrent_tab() # Channels tab connect(self.window().channels_tab_widget.currentChanged, self.channels_tab_changed) self.window().channels_tab_widget.setCurrentIndex(0) # Position to center frame_geometry = self.frameGeometry() screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos()) center_point = QDesktopWidget().screenGeometry(screen).center() frame_geometry.moveCenter(center_point) self.move(frame_geometry.topLeft()) # Refresh timer self.refresh_timer = None self.rest_request = None self.ipv8_health_widget = None # GUI resource monitor self.resource_monitor = GuiResourceMonitor() self.resource_monitor.start() # QT settings self.gui_settings = gui_settings def hideEvent(self, hide_event): self.stop_timer() self.hide_ipv8_health_widget() def showEvent(self, show_event): if self.ipv8_health_widget and self.ipv8_health_widget.isVisible(): self.ipv8_health_widget.resume() TriblerNetworkRequest("ipv8/asyncio/drift", self.on_ipv8_health_enabled, data={"enable": True}, method='PUT') def run_with_timer(self, call_fn, timeout=DEBUG_PANE_REFRESH_TIMEOUT): call_fn() self.stop_timer() self.refresh_timer = QTimer() self.refresh_timer.setSingleShot(True) connect( self.refresh_timer.timeout, lambda _call_fn=call_fn, _timeout=timeout: self.run_with_timer( _call_fn, timeout=_timeout), ) self.refresh_timer.start(timeout) def stop_timer(self): if self.refresh_timer: try: self.refresh_timer.stop() self.refresh_timer.deleteLater() except RuntimeError: self._logger.error( "Failed to stop refresh timer in Debug pane") def init_libtorrent_tab(self): self.window().libtorrent_tab_widget.setCurrentIndex(0) connect(self.window().libtorrent_tab_widget.currentChanged, lambda _: self.load_libtorrent_data(export=False)) connect(self.window().lt_zero_hop_btn.clicked, lambda _: self.load_libtorrent_data(export=False)) connect(self.window().lt_one_hop_btn.clicked, lambda _: self.load_libtorrent_data(export=False)) connect(self.window().lt_two_hop_btn.clicked, lambda _: self.load_libtorrent_data(export=False)) connect(self.window().lt_three_hop_btn.clicked, lambda _: self.load_libtorrent_data(export=False)) connect(self.window().lt_export_btn.clicked, lambda _: self.load_libtorrent_data(export=True)) self.window().lt_zero_hop_btn.setChecked(True) def tab_changed(self, index): if index == 0: self.load_general_tab() elif index == 1: self.load_requests_tab() elif index == 2: self.run_with_timer(self.load_bandwidth_accounting_tab) elif index == 3: self.ipv8_tab_changed(self.window().ipv8_tab_widget.currentIndex()) elif index == 4: self.tunnel_tab_changed( self.window().tunnel_tab_widget.currentIndex()) elif index == 5: self.dht_tab_changed(self.window().dht_tab_widget.currentIndex()) elif index == 6: self.run_with_timer(self.load_events_tab) elif index == 7: self.system_tab_changed( self.window().system_tab_widget.currentIndex()) elif index == 8: self.load_libtorrent_data() elif index == 9: self.load_logs_tab() elif index == 10: self.channels_tab_changed( self.window().channels_tab_widget.currentIndex()) def ipv8_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_ipv8_general_tab) elif index == 1: self.run_with_timer(self.load_ipv8_communities_tab) elif index == 2: self.run_with_timer(self.load_ipv8_community_details_tab) elif index == 3: self.run_with_timer(self.load_ipv8_health_monitor) def tunnel_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_tunnel_circuits_tab) elif index == 1: self.run_with_timer(self.load_tunnel_relays_tab) elif index == 2: self.run_with_timer(self.load_tunnel_exits_tab) elif index == 3: self.run_with_timer(self.load_tunnel_swarms_tab) elif index == 4: self.run_with_timer(self.load_tunnel_peers_tab) def dht_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_dht_statistics_tab) elif index == 1: self.run_with_timer(self.load_dht_buckets_tab) def system_tab_changed(self, index): if index == 0: self.load_open_files_tab() elif index == 1: self.load_open_sockets_tab() elif index == 2: self.load_threads_tab() elif index == 3: self.load_cpu_tab() elif index == 4: self.load_memory_tab() elif index == 5: self.load_profiler_tab() def create_and_add_widget_item(self, key, value, widget): item = QTreeWidgetItem(widget) item.setText(0, key) item.setText(1, f"{value}") widget.addTopLevelItem(item) def load_general_tab(self): TriblerNetworkRequest("statistics/tribler", self.on_tribler_statistics) def on_tribler_statistics(self, data): if not data: return data = data["tribler_statistics"] self.window().general_tree_widget.clear() self.create_and_add_widget_item("Tribler version", self.tribler_version, self.window().general_tree_widget) self.create_and_add_widget_item( "Python version", sys.version.replace('\n', ''), self.window().general_tree_widget # to fit in one line ) self.create_and_add_widget_item("Libtorrent version", libtorrent.version, self.window().general_tree_widget) self.create_and_add_widget_item("BEP33 support", has_bep33_support(), self.window().general_tree_widget) self.create_and_add_widget_item("", "", self.window().general_tree_widget) self.create_and_add_widget_item("Number of channels", data["num_channels"], self.window().general_tree_widget) self.create_and_add_widget_item("Database size", format_size(data["db_size"]), self.window().general_tree_widget) self.create_and_add_widget_item("Number of known torrents", data["num_torrents"], self.window().general_tree_widget) self.create_and_add_widget_item("", "", self.window().general_tree_widget) disk_usage = psutil.disk_usage('/') self.create_and_add_widget_item("Total disk space", format_size(disk_usage.total), self.window().general_tree_widget) self.create_and_add_widget_item("Used disk space", format_size(disk_usage.used), self.window().general_tree_widget) self.create_and_add_widget_item("Free disk space", format_size(disk_usage.free), self.window().general_tree_widget) # Show GUI settings self.show_gui_settings() def show_gui_settings(self): # Empty line at the beginning self.create_and_add_widget_item("", "", self.window().general_tree_widget) # Heading: GUI Settings self.create_and_add_widget_item("GUI Settings:", "", self.window().general_tree_widget) # Location of the settings file self.create_and_add_widget_item("Qt file", self.gui_settings.fileName(), self.window().general_tree_widget) selected_settings = { "api_key": lambda val: val, "api_port": lambda val: val, "pos": lambda val: f"(x : {val.x()} px, y : {val.y()} px)", "size": lambda val: f"(width : {val.width()} px, height : {val.height()} px)", "ask_download_settings": lambda val: val, "autocommit_enabled": lambda val: val, "debug": lambda val: val, "family_filter": lambda val: val, "first_discover": lambda val: val, "use_monochrome_icon": lambda val: val, "recent_download_locations": lambda val: [unhexlify(url).decode('utf-8') for url in val.split(",")], } # List only selected gui settings for key in self.gui_settings.allKeys(): if key in selected_settings: value = selected_settings[key](self.gui_settings.value( key, 'N/A')) self.create_and_add_widget_item( key, value, self.window().general_tree_widget) def load_requests_tab(self): self.window().requests_tree_widget.clear() for request, status_code in sorted(tribler_performed_requests, key=lambda rq: rq[0].time): endpoint = request.url method = request.method data = request.raw_data timestamp = request.time item = QTreeWidgetItem(self.window().requests_tree_widget) item.setText(0, f"{method} {repr(endpoint)} {repr(data)}") item.setText(1, ("%d" % status_code) if status_code else "unknown") item.setText(2, f"{strftime('%H:%M:%S', localtime(timestamp))}") self.window().requests_tree_widget.addTopLevelItem(item) def load_bandwidth_accounting_tab(self) -> None: """ Initiate a request to the Tribler core to fetch statistics on bandwidth accounting. """ TriblerNetworkRequest("bandwidth/statistics", self.on_bandwidth_statistics) def on_bandwidth_statistics(self, data: Dict) -> None: """ We received bandwidth statistics from the core. :param data: The bandwidth statistics, in JSON format. """ if not data: return self.window().bandwidth_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item( key, value, self.window().bandwidth_tree_widget) def load_ipv8_general_tab(self): TriblerNetworkRequest("statistics/ipv8", self.on_ipv8_general_stats) def on_ipv8_general_stats(self, data): if not data: return self.window().ipv8_general_tree_widget.clear() for key, value in data["ipv8_statistics"].items(): if key in ('total_up', 'total_down'): value = f"{value / (1024.0 * 1024.0):.2f} MB" elif key == 'session_uptime': value = f"{str(datetime.timedelta(seconds=int(value)))}" self.create_and_add_widget_item( key, value, self.window().ipv8_general_tree_widget) def load_ipv8_communities_tab(self): TriblerNetworkRequest("ipv8/overlays", self.on_ipv8_community_stats) def _colored_peer_count(self, peer_count, max_peers): limits = [20, max_peers + 1] color = 0xF4D03F if peer_count < limits[0] else ( 0x56F129 if peer_count < limits[1] else 0xF12929) return QBrush(QColor(color)) def on_ipv8_community_stats(self, data): if not data: return for overlay in data["overlays"]: item = None item_exists = False # Check if this item is already rendered for ind in range( self.window().communities_tree_widget.topLevelItemCount()): existing_item = self.window( ).communities_tree_widget.topLevelItem(ind) if existing_item.data(0, Qt.UserRole)["id"] == overlay["id"]: item = existing_item item_exists = True break if not item: # Create a new one item = QTreeWidgetItem(self.window().communities_tree_widget) item.setData(0, Qt.UserRole, overlay) item.setText(0, overlay["overlay_name"]) item.setText(1, overlay["id"][:10]) item.setText(2, overlay["my_peer"][-12:]) peer_count = len(overlay["peers"]) item.setText(3, f"{peer_count}") item.setForeground( 3, self._colored_peer_count(peer_count, overlay["max_peers"])) if "statistics" in overlay and overlay["statistics"]: statistics = overlay["statistics"] item.setText( 4, f"{statistics['bytes_up'] / (1024.0 * 1024.0):.3f}") item.setText( 5, f"{statistics['bytes_down'] / (1024.0 * 1024.0):.3f}") item.setText(6, f"{statistics['num_up']}") item.setText(7, f"{statistics['num_down']}") item.setText(8, f"{statistics['diff_time']:.3f}") else: item.setText(4, "N/A") item.setText(5, "N/A") item.setText(6, "N/A") item.setText(7, "N/A") item.setText(8, "N/A") if not item_exists: self.window().communities_tree_widget.addTopLevelItem(item) map(self.window().communities_tree_widget.resizeColumnToContents, range(10)) # Reload the window with peers selected_items = self.window().communities_tree_widget.selectedItems() if len(selected_items) > 0: self.update_community_peers(selected_items[0]) def on_community_clicked(self, item, _): self.window().community_peers_tree_widget.show() self.update_community_peers(item) def update_community_peers(self, item): self.window().community_peers_tree_widget.clear() peers_info = item.data(0, Qt.UserRole)["peers"] for peer_info in peers_info: item = QTreeWidgetItem(self.window().community_peers_tree_widget) item.setText(0, peer_info["ip"]) item.setText(1, f"{peer_info['port']}") item.setText(2, peer_info["public_key"]) self.window().community_peers_tree_widget.addTopLevelItem(item) def load_ipv8_community_details_tab(self): if self.ipv8_statistics_enabled: self.window().ipv8_statistics_error_label.setHidden(True) TriblerNetworkRequest("ipv8/overlays/statistics", self.on_ipv8_community_detail_stats) else: self.window().ipv8_statistics_error_label.setHidden(False) self.window().ipv8_communities_details_widget.setHidden(True) def on_ipv8_community_detail_stats(self, data): if not data: return self.window().ipv8_communities_details_widget.setHidden(False) self.window().ipv8_communities_details_widget.clear() for overlay in data["statistics"]: self.window().ipv8_communities_details_widget.setColumnWidth( 0, 250) for key, stats in overlay.items(): header_item = QTreeWidgetItem( self.window().ipv8_communities_details_widget) header_item.setFirstColumnSpanned(True) header_item.setBackground(0, QtGui.QColor('#CCCCCC')) header_item.setText(0, key) self.window().ipv8_communities_details_widget.addTopLevelItem( header_item) for request_id, stat in stats.items(): stat_item = QTreeWidgetItem( self.window().ipv8_communities_details_widget) stat_item.setText(0, request_id) stat_item.setText( 1, f"{stat['bytes_up'] / (1024.0 * 1024.0):.3f}") stat_item.setText( 2, f"{stat['bytes_down'] / (1024.0 * 1024.0):.3f}") stat_item.setText(3, f"{stat['num_up']}") stat_item.setText(4, f"{stat['num_down']}") self.window( ).ipv8_communities_details_widget.addTopLevelItem( stat_item) def load_ipv8_health_monitor(self): """ Lazy load and enable the IPv8 core health monitor. """ if self.ipv8_health_widget is None: # Add the core monitor widget to the tab widget. from PyQt5.QtWidgets import QVBoxLayout widget = MonitorWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(widget) self.window().ipv8_health_monitor_widget.setLayout(layout) self.window().ipv8_health_monitor_widget.show() self.ipv8_health_widget = widget else: # We already loaded the widget, just resume it. self.ipv8_health_widget.resume() # Whether the widget is newly loaded or not, start the measurements. TriblerNetworkRequest("ipv8/asyncio/drift", self.on_ipv8_health_enabled, data={"enable": True}, method='PUT') def hide_ipv8_health_widget(self): """ We need to hide the IPv8 health widget, involving two things: 1. Stop the smooth graphical updates in the widget. 2. Remove the observer from the IPv8 core. """ if self.ipv8_health_widget is not None and not self.ipv8_health_widget.is_paused: self.ipv8_health_widget.pause() TriblerNetworkRequest("ipv8/asyncio/drift", lambda _: None, data={"enable": False}, method='PUT') def on_ipv8_health(self, data): """ Measurements came in, send them to the widget for "plotting". """ if not data or 'measurements' not in data or self.ipv8_health_widget is None: return self.ipv8_health_widget.set_history(data['measurements']) def on_ipv8_health_enabled(self, data): """ The request to enable IPv8 completed. Start requesting measurements. """ if not data: return self.run_with_timer( lambda: TriblerNetworkRequest("ipv8/asyncio/drift", self. on_ipv8_health), 100) def add_items_to_tree(self, tree, items, keys): tree.clear() for item in items: widget_item = QTreeWidgetItem(tree) for index, key in enumerate(keys): if key in ["bytes_up", "bytes_down"]: value = format_size(item[key]) elif key in ["creation_time", "last_lookup"]: value = str( datetime.timedelta( seconds=int(time() - item[key]))) if item[key] > 0 else '-' else: value = str(item[key]) widget_item.setText(index, value) tree.addTopLevelItem(widget_item) def load_tunnel_circuits_tab(self): self.window().circuits_tree_widget.setColumnWidth(3, 200) TriblerNetworkRequest("ipv8/tunnel/circuits", self.on_tunnel_circuits) def on_tunnel_circuits(self, circuits): if not circuits: return for c in circuits["circuits"]: c["hops"] = f"{c['goal_hops']} / {c['goal_hops']}" c["exit_flags"] = c["exit_flags"] if c["state"] == "READY" else "" self.add_items_to_tree( self.window().circuits_tree_widget, circuits.get("circuits"), [ "circuit_id", "hops", "type", "state", "bytes_up", "bytes_down", "creation_time", "exit_flags" ], ) def load_tunnel_relays_tab(self): TriblerNetworkRequest("ipv8/tunnel/relays", self.on_tunnel_relays) def on_tunnel_relays(self, data): if data: self.add_items_to_tree( self.window().relays_tree_widget, data["relays"], [ "circuit_from", "circuit_to", "is_rendezvous", "bytes_up", "bytes_down", "creation_time" ], ) def load_tunnel_exits_tab(self): TriblerNetworkRequest("ipv8/tunnel/exits", self.on_tunnel_exits) def on_tunnel_exits(self, data): if data: self.add_items_to_tree( self.window().exits_tree_widget, data["exits"], [ "circuit_from", "enabled", "bytes_up", "bytes_down", "creation_time" ], ) def load_tunnel_swarms_tab(self): TriblerNetworkRequest("ipv8/tunnel/swarms", self.on_tunnel_swarms) def on_tunnel_swarms(self, data): if data: self.add_items_to_tree( self.window().swarms_tree_widget, data.get("swarms"), [ "info_hash", "num_seeders", "num_connections", "num_connections_incomplete", "seeding", "last_lookup", "bytes_up", "bytes_down", ], ) def load_tunnel_peers_tab(self): self.window().peers_tree_widget.setColumnWidth(2, 300) TriblerNetworkRequest("ipv8/tunnel/peers", self.on_tunnel_peers) def on_tunnel_peers(self, data): if data: self.add_items_to_tree( self.window().peers_tree_widget, data.get("peers"), ["ip", "port", "mid", "is_key_compatible", "flags"]) def load_dht_statistics_tab(self): TriblerNetworkRequest("ipv8/dht/statistics", self.on_dht_statistics) def on_dht_statistics(self, data): if not data: return self.window().dhtstats_tree_widget.clear() for key, value in data["statistics"].items(): self.create_and_add_widget_item(key, value, self.window().dhtstats_tree_widget) def load_dht_buckets_tab(self): TriblerNetworkRequest("ipv8/dht/buckets", self.on_dht_buckets) def on_dht_buckets(self, data): if data: for bucket in data["buckets"]: bucket["num_peers"] = len(bucket["peers"]) ts = bucket["last_changed"] bucket["last_changed"] = str( datetime.timedelta(seconds=int(time() - ts))) if ts > 0 else '-' self.add_items_to_tree( self.window().buckets_tree_widget, data.get("buckets"), ["prefix", "last_changed", "num_peers"], ) def on_event_clicked(self, item, _): event_dict = item.data(0, Qt.UserRole) self.window().event_text_box.setPlainText(json.dumps(event_dict)) def load_events_tab(self): self.window().events_tree_widget.clear() for event_dict, timestamp in tribler_received_events: item = QTreeWidgetItem(self.window().events_tree_widget) item.setData(0, Qt.UserRole, event_dict) item.setText(0, f"{event_dict['type']}") item.setText(1, f"{strftime('%H:%M:%S', localtime(timestamp))}") self.window().events_tree_widget.addTopLevelItem(item) def load_open_files_tab(self): # Fill the open files (GUI) tree widget my_process = psutil.Process() self.window().open_files_tree_widget.clear() gui_item = QTreeWidgetItem(self.window().open_files_tree_widget) try: open_files = my_process.open_files() gui_item.setText(0, "GUI (%d)" % len(open_files)) self.window().open_files_tree_widget.addTopLevelItem(gui_item) for open_file in open_files: item = QTreeWidgetItem() item.setText(0, open_file.path) item.setText(1, "%d" % open_file.fd) gui_item.addChild(item) except psutil.AccessDenied as exc: gui_item.setText(0, f"Unable to get open files for GUI ({exc})") TriblerNetworkRequest("debug/open_files", self.on_core_open_files) def on_core_open_files(self, data): if not data: return core_item = QTreeWidgetItem(self.window().open_files_tree_widget) core_item.setText(0, "Core (%d)" % len(data["open_files"])) self.window().open_files_tree_widget.addTopLevelItem(core_item) for open_file in data["open_files"]: item = QTreeWidgetItem() item.setText(0, open_file["path"]) item.setText(1, "%d" % open_file["fd"]) core_item.addChild(item) def load_open_sockets_tab(self): TriblerNetworkRequest("debug/open_sockets", self.on_core_open_sockets) def on_core_open_sockets(self, data): if not data: return self.window().open_sockets_tree_widget.clear() self.window().open_sockets_label.setText( "Sockets opened by core (%d):" % len(data["open_sockets"])) for open_socket in data["open_sockets"]: if open_socket["family"] == socket.AF_INET: family = "AF_INET" elif open_socket["family"] == socket.AF_INET6: family = "AF_INET6" elif open_socket["family"] == socket.AF_UNIX: family = "AF_UNIX" else: family = "-" item = QTreeWidgetItem(self.window().open_sockets_tree_widget) item.setText(0, open_socket["laddr"]) item.setText(1, open_socket["raddr"]) item.setText(2, family) item.setText( 3, "SOCK_STREAM" if open_socket["type"] == socket.SOCK_STREAM else "SOCK_DGRAM") item.setText(4, open_socket["status"]) self.window().open_sockets_tree_widget.addTopLevelItem(item) def load_threads_tab(self): TriblerNetworkRequest("debug/threads", self.on_core_threads) def on_core_threads(self, data): if not data: return self.window().threads_tree_widget.clear() for thread_info in data["threads"]: thread_item = QTreeWidgetItem(self.window().threads_tree_widget) thread_item.setText(0, "%d" % thread_info["thread_id"]) thread_item.setText(1, thread_info["thread_name"]) self.window().threads_tree_widget.addTopLevelItem(thread_item) for frame in thread_info["frames"]: frame_item = QTreeWidgetItem() frame_item.setText(2, frame) thread_item.addChild(frame_item) def load_cpu_tab(self): if not self.initialized_cpu_plot: self.core_cpu_plot = CPUPlot(self.window().tab_system_cpu, process='Core') self.gui_cpu_plot = CPUPlot(self.window().tab_system_cpu, process='GUI') vlayout = self.window().system_cpu_layout.layout() vlayout.addWidget(self.core_cpu_plot) vlayout.addWidget(self.gui_cpu_plot) self.initialized_cpu_plot = True self.refresh_cpu_plot() # Start timer self.cpu_plot_timer = QTimer() connect(self.cpu_plot_timer.timeout, self.load_cpu_tab) self.cpu_plot_timer.start(5000) def refresh_cpu_plot(self): # To update the core CPU graph, call Debug REST API to get the history # and update the CPU graph after receiving the response. TriblerNetworkRequest("debug/cpu/history", self.on_core_cpu_history) # GUI CPU graph can be simply updated using the data from GuiResourceMonitor object. self._update_cpu_graph(self.gui_cpu_plot, self.resource_monitor.get_cpu_history_dict()) def on_core_cpu_history(self, data): if not data or "cpu_history" not in data: return self._update_cpu_graph(self.core_cpu_plot, data['cpu_history']) def _update_cpu_graph(self, cpu_graph, history_data): cpu_graph.reset_plot() for cpu_info in history_data: process_cpu = [round(cpu_info["cpu"], 2)] cpu_graph.add_data(cpu_info["time"], process_cpu) cpu_graph.render_plot() def load_memory_tab(self): if not self.initialized_memory_plot: self.core_memory_plot = MemoryPlot(self.window().tab_system_memory, process='Core') self.gui_memory_plot = MemoryPlot(self.window().tab_system_memory, process='GUI') vlayout = self.window().system_memory_layout.layout() vlayout.addWidget(self.core_memory_plot) vlayout.addWidget(self.gui_memory_plot) self.initialized_memory_plot = True self.refresh_memory_plot() # Start timer self.memory_plot_timer = QTimer() connect(self.memory_plot_timer.timeout, self.load_memory_tab) self.memory_plot_timer.start(5000) def load_profiler_tab(self): self.window().toggle_profiler_button.setEnabled(False) TriblerNetworkRequest("debug/profiler", self.on_profiler_info) def on_profiler_info(self, data): if not data: return self.window().toggle_profiler_button.setEnabled(True) self.profiler_enabled = data["state"] == "STARTED" self.window().toggle_profiler_button.setText( f"{'Stop' if self.profiler_enabled else 'Start'} profiler") def on_toggle_profiler_button_clicked(self, checked=False): if self.toggling_profiler: return self.toggling_profiler = True self.window().toggle_profiler_button.setEnabled(False) method = "DELETE" if self.profiler_enabled else "PUT" TriblerNetworkRequest("debug/profiler", self.on_profiler_state_changed, method=method) def on_profiler_state_changed(self, data): if not data: return self.toggling_profiler = False self.window().toggle_profiler_button.setEnabled(True) self.load_profiler_tab() if 'profiler_file' in data: QMessageBox.about( self, "Profiler statistics saved", f"The profiler data has been saved to {data['profiler_file']}." ) def refresh_memory_plot(self): # To update the core memory graph, call Debug REST API to get the history # and update the memory graph after receiving the response. TriblerNetworkRequest("debug/memory/history", self.on_core_memory_history) # GUI memory graph can be simply updated using the data from GuiResourceMonitor object. self._update_memory_graph( self.gui_memory_plot, self.resource_monitor.get_memory_history_dict()) def on_core_memory_history(self, data): if not data or data.get("memory_history") is None: return self._update_memory_graph(self.core_memory_plot, data["memory_history"]) def _update_memory_graph(self, memory_graph, history_data): memory_graph.reset_plot() for mem_info in history_data: process_memory = round(mem_info["mem"] / MB, 2) memory_graph.add_data(mem_info["time"], [process_memory]) memory_graph.render_plot() def closeEvent(self, close_event): if self.rest_request: self.rest_request.cancel_request() if self.cpu_plot_timer: self.cpu_plot_timer.stop() if self.memory_plot_timer: self.memory_plot_timer.stop() def load_logs_tab(self): # Max lines from GUI max_log_lines = self.window().max_lines_value.text() tab_index = self.window().log_tab_widget.currentIndex() tab_name = "core" if tab_index == 0 else "gui" request_query = f"process={tab_name}&max_lines={max_log_lines}" TriblerNetworkRequest(f"debug/log?{request_query}", self.display_logs) def display_logs(self, data): if not data: return tab_index = self.window().log_tab_widget.currentIndex() log_display_widget = (self.window().core_log_display_area if tab_index == 0 else self.window().gui_log_display_area) log_display_widget.moveCursor(QTextCursor.End) key_content = 'content' key_max_lines = 'max_lines' if not key_content in data or not data[key_content]: log_display_widget.setPlainText('No logs found') else: log_display_widget.setPlainText(data[key_content]) if not key_max_lines in data or not data[key_max_lines]: self.window().max_lines_value.setText('') else: self.window().max_lines_value.setText(str(data[key_max_lines])) sb = log_display_widget.verticalScrollBar() sb.setValue(sb.maximum()) def show(self): super().show() # this will remove minimized status # and restore window with keeping maximized/normal state self.window().setWindowState(self.window().windowState() & ~Qt.WindowMinimized | Qt.WindowActive) self.window().activateWindow() def load_libtorrent_data(self, export=False): tab = self.window().libtorrent_tab_widget.currentIndex() hop = (0 if self.window().lt_zero_hop_btn.isChecked() else 1 if self.window().lt_one_hop_btn.isChecked() else 2 if self.window().lt_two_hop_btn.isChecked() else 3) if tab == 0: self.load_libtorrent_settings_tab(hop, export=export) elif tab == 1: self.load_libtorrent_sessions_tab(hop, export=export) def load_libtorrent_settings_tab(self, hop, export=False): TriblerNetworkRequest( "libtorrent/settings?hop=%d" % hop, lambda data: self.on_libtorrent_settings_received(data, export=export)) self.window().libtorrent_settings_tree_widget.clear() def on_libtorrent_settings_received(self, data, export=False): if not data: return for key, value in data["settings"].items(): item = QTreeWidgetItem( self.window().libtorrent_settings_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_settings_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_settings.json", data) def load_libtorrent_sessions_tab(self, hop, export=False): TriblerNetworkRequest( "libtorrent/session?hop=%d" % hop, lambda data: self.on_libtorrent_session_received(data, export=export)) self.window().libtorrent_session_tree_widget.clear() def on_libtorrent_session_received(self, data, export=False): if not data: return for key, value in data["session"].items(): item = QTreeWidgetItem( self.window().libtorrent_session_tree_widget) item.setText(0, key) item.setText(1, str(value)) self.window().libtorrent_session_tree_widget.addTopLevelItem(item) if export: self.save_to_file("libtorrent_session.json", data) def save_to_file(self, filename, data): base_dir = QFileDialog.getExistingDirectory( self, "Select an export directory", "", QFileDialog.ShowDirsOnly) if len(base_dir) > 0: dest_path = os.path.join(base_dir, filename) try: with open(dest_path, "w") as torrent_file: torrent_file.write(json.dumps(data)) except OSError as exc: ConfirmationDialog.show_error(self.window(), "Error exporting file", str(exc)) def on_channels_peers(self, data): widget = self.window().channels_peers_tree_widget widget.clear() if not data: return for c in data["channels_list"]: channel_item = QTreeWidgetItem() channel_item.setText(0, str(c["channel_name"])) channel_item.setText(1, str(c["channel_pk"])) channel_item.setText(2, str(c["channel_id"])) channel_item.setData(3, Qt.DisplayRole, len(c["peers"])) # Peers count for p in c["peers"]: peer_item = QTreeWidgetItem() peer_item.setText(1, str(p[0])) # Peer mid peer_item.setData(4, Qt.DisplayRole, p[1]) # Peer age channel_item.addChild(peer_item) widget.addTopLevelItem(channel_item) def load_channels_peers_tab(self): TriblerNetworkRequest("remote_query/channels_peers", self.on_channels_peers) def channels_tab_changed(self, index): if index == 0: self.run_with_timer(self.load_channels_peers_tab) elif index == 1: pass