class TestApp(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.studFrame = QFrame() self._s = Stud() self._s.setupUi(self.studFrame) self.settFrame = QFrame() self._set = Settings() self._set.setupUi(self.settFrame) self.info = self.ui.infoLine self.q1 = self.ui.question self.a_dic = { 1: self.ui.answer1, 2: self.ui.answer2, 3: self.ui.answer3, 4: self.ui.answer4, 5: self.ui.answer5 } self.ch_dic = { 1: self.ui.checkBox1, 2: self.ui.checkBox2, 3: self.ui.checkBox3, 4: self.ui.checkBox4, 5: self.ui.checkBox5 } self.next = self.ui.next self.print = self.ui.print self.open = self.ui.open self.settings = self.ui.settings self.exit = self.ui.exit self.about = self.ui.about self.bar = self.ui.statusbar self.btnStud = self._s.buttonBox self.lineStud = self._s.student self.next.clicked.connect(self.fileOpen) self.print.clicked.connect(self.printer) self.open.triggered.connect(self.fileOpen) self.settings.triggered.connect(self.settFrameShow) self.about.triggered.connect(self.aboutMenu) self.exit.triggered.connect(sys.exit) self.q1.hide() self.info.hide() self.print.hide() for a in self.a_dic.values(): a.hide() for ch in self.ch_dic.values(): ch.hide() self.rep_key = QShortcut(QtGui.QKeySequence("Ctrl+R"), self) self.rep_key.activated.connect(self.openRep) self.ui.centralwidget.setStyleSheet('background: url(bkgnd.png)') self.font1 = QFont("Comic Sans Ms", 20, QFont.DemiBold, QFont.AnyStyle) self.font2 = QFont("Arial Rounded MT Bold", 25, QFont.Bold) def fileOpen(self): # Open test file and create question-answer dictionary f_dialog = QFileDialog() f_dialog.setFileMode(QFileDialog.AnyFile) f_dialog.setNameFilter("Text (*.txt)") if f_dialog.exec_(): self.file_name = f_dialog.selectedFiles()[0] self.test = {} try: with open(self.file_name, 'r', encoding='utf-8') as f: lines = f.readlines() except Exception: with open(self.file_name, 'r', encoding='cp1251') as f: lines = f.readlines() pass for line in lines: try: if not 'Name' in lines[0]: self.test_name = 'Не найдено название теста' elif 'Name' in line[:5]: self.test_name = line[6:] except Exception: pass n = 0 t = [] test_dic = dict.fromkeys( ('Qs', 'A1', 'A2', 'A3', 'A4', 'A5', 'An'), 0) for line in lines: for k in test_dic.keys(): if k in line[:3]: t.append(line) if 'An' in line[:3]: self.test.update({n: t}) n += 1 t = [] self.q1.show() self.q1.setText("\n\n" + self.test_name) self.q1.setStyleSheet("") self.q1.setFrameStyle(QFrame.NoFrame) self.next.clicked.disconnect() self.next.setText('Далее') self.next.clicked.connect(self.studSet) self.print.hide() self.ui.menubar.hide() self.ui.centralwidget.setStyleSheet('background: url(bkgnd.png)') else: self.close() def studSet(self): # Student name input frame self.studFrame.show() application.hide() self.next.clicked.disconnect() self.btnStud.accepted.connect(self.testInit) self.btnStud.rejected.connect(self.studFrame.hide) self.btnStud.rejected.connect(self.close) def testInit(self): self.settRead() # Define variables self.fin = False self.q_num_list = [] self.result = 0 self.percent = 0 self.q_count = 0 self.spent_time = False self.student = self.lineStud.text().title() try: # Check if questions in settings not exceed questions in self.test dictionary if self.q_try > len(self.test): self.q_try = len(self.test) # Vars for messagebar (random and color) if self.rand: self.ifrand = 'ВКЛ' else: self.ifrand = 'ОТКЛ' if self.color: self.ifcolor = 'ВКЛ' else: self.ifcolor = 'ОТКЛ' self.studFrame.hide() application.show() self.q1.setFont(self.font1) self.q1.setText("\n\n\n" + self.student + ", желаю удачи в прохождении теста:\n" + self.test_name) self.next.setText("Поехали!") self.next.clicked.connect(self.testMain) except Exception as e: pass def testMain(self): if not self.spent_time: self.start_time = time.time() self.timeSpent() self.info.hide() for a in self.a_dic.values(): a.hide() for ch in self.ch_dic.values(): ch.hide() ch.setChecked(False) if self.q_try: if not self.rand: self.q_num = self.q_count else: self.q_num = random.choice(list(self.test)) if self.q_num in self.q_num_list: while self.q_num in self.q_num_list: self.q_num = random.choice(list(self.test)) self.q_num_list.append(self.q_num) try: tek = self.test[self.q_num] question = tek[0][3:] frame = 1 for k, a in self.a_dic.items(): try: tek_a = tek[k] if 'An' in tek_a: pass else: a.setText(tek_a[3:]) frame += 1 except IndexError: pass key = [int(i) for i in tek[-1][3:].split()] key.sort() for i in range(1, frame): a = self.a_dic[i] a.show() a.setStyleSheet("") ch = self.ch_dic[i] ch.show() self.q1.setFont(self.font2) self.q1.setText(question) if len(key) > 1: self.info.setText('Выберите несколько вариантов ответа') elif len(key) <= 1: self.info.setText('Выберите один вариант ответа') self.info.show() self.q1.setFrameShape(QFrame.WinPanel) self.q1.setStyleSheet("background-color:rgb(91, 213, 89)") self.ui.centralwidget.setStyleSheet(" ") self.next.setText("Далее") self.next.clicked.disconnect() self.next.clicked.connect(lambda: self.answerCheck(key)) except KeyError: tek = ['*** No more question', '', '', '', ''] self.finish() else: self.finish() def answerCheck(self, key): self.q_count += 1 self.q_try -= 1 answer = [] for k, v in self.ch_dic.items(): if v.isChecked(): answer.append(k) if key == answer: self.result += 1 else: self.q1.setStyleSheet("background-color: rgb(255, 0, 0)") if self.color == 1: for i in key: a = self.a_dic[i] a.setStyleSheet("background-color:rgb(91, 213, 89)") if self.q_count == 0: p = 0 else: p = self.result * 100 / self.q_count self.percent = float("%.1f" % p) QTimer.singleShot(self.color_time * 1000, self.testMain) def finish(self): self.fin = True for a in self.a_dic.values(): a.hide() for ch in self.ch_dic.values(): ch.hide() self.day = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) if self.percent >= self.mark_5: self.mark = '5' elif self.percent >= self.mark_4: self.mark = '4' elif self.percent >= self.mark_3: self.mark = '3' elif self.percent >= self.mark_2: self.mark = '2' else: self.mark = '1' if int(self.mark) > 3: self.q1.setStyleSheet("background-color:rgb(91, 213, 89)") else: self.q1.setStyleSheet("background-color: rgb(255, 0, 0)") self.rep = ("Дата: " + self.day + "\nТестируемый: " + self.student + "\nТема: " + self.test_name + "\nПравильных ответов: " + str(self.result) + "\nВсего вопросов: " + str(self.q_count) + "\nЗатрачено времени: " + str(self.spent_time) + " мин." "\nРезультативность: " + str(self.percent) + "%" "\nОценка: " + self.mark + "\n\n") with open('report.txt', 'a', encoding='utf-8') as f_rep: f_rep.write(self.rep) self.q1.setText(self.rep) self.next.show() self.print.show() self.next.clicked.disconnect() self.next.setText("Закончить") self.next.clicked.connect(self.close) self.ui.menubar.show() def openRep(self): try: subprocess.Popen(['notepad.exe', r'report.txt']) except Exception as e: self.q1.show() self.q1.setText(str(e)) def settFrameShow(self): self.settRead() try: if self.color == 1: self._set.colBox.setChecked(True) self._set.colTimeLine.setText(str(self.color_time)) if self.rand == 1: self._set.ranBox.setChecked(True) self._set.tryLine.setText(str(self.q_try)) self._set.mark5Line.setText(str(self.mark_5)) self._set.mark4Line.setText(str(self.mark_4)) self._set.mark3Line.setText(str(self.mark_3)) self._set.mark2Line.setText(str(self.mark_2)) self.settFrame.show() self._set.buttonBox.accepted.connect(self.settWrite) self._set.buttonBox.rejected.connect(self.settFrame.close) except Exception as e: pass def settWrite(self): if self._set.colBox.isChecked(): self.color = 1 self.color_time = self._set.colTimeLine.text() else: self.color = 0 self.color_time = 0 if self._set.ranBox.isChecked(): self.rand = 1 else: self.rand = 0 self.q_try = self._set.tryLine.text() self.mark_5 = self._set.mark5Line.text() self.mark_4 = self._set.mark4Line.text() self.mark_3 = self._set.mark3Line.text() self.mark_2 = self._set.mark2Line.text() settings = [ self.color, self.color_time, self.rand, self.q_try, self.mark_5, self.mark_4, self.mark_3, self.mark_2 ] with open("settings.ini", "w", encoding='utf-8') as f: for i in settings: f.write("%s " % i) self.settFrame.close() def settRead(self): # Settings read from ini file try: with open('settings.ini', 'r', encoding='utf-8') as f: line = f.readline().split() line = [int(l) for l in line] self.color = line[0] self.color_time = line[1] self.rand = line[2] self.q_try = line[3] self.mark_5 = line[4] self.mark_4 = line[5] self.mark_3 = line[6] self.mark_2 = line[7] except Exception as e: self.settFrame.show() self._set.buttonBox.accepted.connect(self.settWrite) self._set.buttonBox.rejected.connect(self.settFrame.close) def timeSpent(self): if not self.fin: t = int(time.time()) - int(self.start_time) if t >= 60: tm = int(t / 60) ts = t - tm * 60 else: tm = 0 ts = t if ts < 10: self.spent_time = str(tm) + ":0" + str(ts) else: self.spent_time = str(tm) + ":" + str(ts) self.bar.showMessage("Время " + self.spent_time + " Тест: " + self.test_name + " Вопрос №" + str(self.q_count + 1) + " Результат: " + str(self.percent) + "% Студент " + self.student + " Вопросов " + str(self.q_try) + " Случайно " + self.ifrand + " Контроль " + self.ifcolor) QTimer.singleShot(500, self.timeSpent) else: self.bar.showMessage(" ") def printer(self): with open('temp.txt', 'w', encoding='utf-8') as f: f.write(self.rep) os.startfile("temp.txt", "print") time.sleep(3) os.remove("temp.txt") def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: try: self.finish() except AttributeError: pass self.close() def aboutMenu(self): self.q1.setFont(self.font1) self.q1.show() self.q1.setText( 'Программа для тестирования была написана для проведения проверки знаний у персонала ГП "Кыргызаэронавигация"\n' 'Настройка и использование программы не должны вызвать каких-либо затруднений. Для настройки нажмите "Меню"' '-> "Настройки"\nВ случае возникновения вопросов прошу обращаться.\n\nРазработчик: Мамутов А' )
class Window(QMainWindow): '''This class instantiates the main gui window''' def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("ManagerCraft") self.setCentralWidget(QWidget()) self.styleFrame = QFrame(self.centralWidget()) self.styleFrame.setFixedSize(1024, 500) self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_R.png); background-repeat: no-repeat;") self.setGeometry(100, 100, 1024, 540) self.setFixedSize(1024, 540) self._createMenu() self.ss = QLabel( "<b>Be sure you're under the same network as your server or connected via VPN!</b>" ) self.ss.setFixedSize(1024, 20) self._createStatusBar() font = QFont("Minecrafter", 22) self.host = QLineEdit() self.path = QLineEdit() self.user = QLineEdit() self.pas = QLineEdit() self.host.setFont(font) #self.path.setFont(font) self.user.setFont(font) self.pas.setFont(font) self.pas.setEchoMode(QLineEdit.Password) self.host.setFixedSize(250, 50) self.path.setFixedSize(350, 35) self.user.setFixedSize(250, 50) self.pas.setFixedSize(250, 50) self.dialog = QDialog(self.centralWidget(), Qt.WindowTitleHint | Qt.WindowSystemMenuHint) self.dialog.setModal(True) self.dui = UI_Dialog() self.dui.setupUi(self.dialog) self.frameR = QFrame(self.centralWidget()) self.frameR.setFixedSize(1024, 540) self.frameL = QFrame(self.centralWidget()) self.frameL.hide() self.frameL.setFixedSize(1024, 540) self.frameC = QFrame(self.centralWidget()) self.frameC.hide() self.frameC.setFixedSize(1024, 540) self.frameS = QFrame(self.centralWidget()) self.frameS.hide() self.frameS.setFixedSize(1024, 540) self.err = QLabel( "<h2><font color='red'>Error: Invalid Input! Try again!</font></h2>", parent=self.frameR) self.err.hide() self.cui = UI2() self.cui.setupUi(self.frameC) self._createFirstScreen() self.mainMenu = True self.tools = None self.pwd = None self.client = None def __return_to(self, prev, frame): prev.hide() frame.show() def __DC(self): try: self.client.close() except AttributeError: pass self.ss.setStyleSheet("background-color: white") self.ss.setText( "<b>Server Status: N/A | Be sure you're under the same network as your server or connected via VPN!</b>" ) self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_R.png); background-repeat: no-repeat;") self.err.hide() self.close_dialog() self.setWindowTitle("ManagerCraft") self.removeToolBar(self.tools) self.frameL.close() self.frameC.close() self.frameS.close() self.frameR.show() def __check_status(self): stdin, stdout, stderr = self.client.exec_command( "systemctl status minecraft") stat = [i for i in stdout if True][2] if "Active: active" in stat: self.ss.setStyleSheet("background-color: green") self.ss.setText("<b>Server Status: Online</b>") stdin, stdout, stderr = self.client.exec_command( 'systemctl status ngrok') grabIP = [ re.search(r"(?<=url=tcp://).+\d+$", i).group() for i in stdout if re.search(r"(?<=url=tcp://).+\d+$", i) ][0] self.cui.serverIP.setText(grabIP) else: self.cui.serverIP.setText("N/A") self.ss.setStyleSheet("background-color: red") self.ss.setText( "<b><font color='white'>Server Status: Offline</font></b>") def __startServer(self): stdin, stdout, stderr = self.client.exec_command( 'sudo systemctl start minecraft ngrok', get_pty=True) stdin.write(f'{self.pas.text()}\n') stdin.flush() self.status.showMessage("Server Is Starting", 20000) stdin, stdout, stderr = self.client.exec_command( 'systemctl status ngrok') grabIP = [ re.search(r"(?<=url=tcp://).+\d+$", i).group() for i in stdout if re.search(r"(?<=url=tcp://).+\d+$", i) ][0] self.cui.serverIP.setText(grabIP) QTimer.singleShot(20000, self.__check_status) def __stopServer(self): stdin, stdout, stderr = self.client.exec_command( 'sudo systemctl stop minecraft ngrok', get_pty=True) stdin.write(f'{self.pas.text()}\n') stdin.flush() self.status.showMessage("Server Is Stopping", 10000) self.cui.serverIP.setText("N/A") QTimer.singleShot(10000, self.__check_status) def __restartServer(self): stdin, stdout, stderr = self.client.exec_command( 'sudo systemctl restart minecraft', get_pty=True) stdin.write(f'{self.pas.text()}\n') stdin.flush() self.status.showMessage("Server Is Restarting", 10000) QTimer.singleShot(10000, self.__check_status) def _createMenu(self): self.menu = self.menuBar().addMenu("Menu") self.menu.addAction("Disconnect", self.__DC) self.menu.addAction("Exit", self.close) def _createToolBar(self): self.tools = QToolBar() self.tools.setMovable(False) self.addToolBar(Qt.LeftToolBarArea, self.tools) self.tools.addAction("CONFIGURATION", self.close) self.tools.addAction("STATUS", self.close) def _createStatusBar(self): self.status = QStatusBar() self.status.addWidget(self.ss) self.setStatusBar(self.status) def _createSecondScreen(self): vLayout = QVBoxLayout(self.centralWidget()) vLayout.setAlignment(Qt.AlignTop) vLayout.addWidget(QLabel()) hLayout = QHBoxLayout() hLayout.setSpacing(0) hLayout.setAlignment(Qt.AlignHCenter) formLayout = QFormLayout(self.centralWidget()) formLayout.setFormAlignment(Qt.AlignHCenter) formLayout.setLabelAlignment(Qt.AlignRight) btnGroup = QButtonGroup() btnGroup.setExclusive(True) title = QLabel() tPng = QPixmap("./graphics/ManageCraft.png") title.setPixmap(tPng) btn1 = QPushButton() btn1.setFixedSize(130, 40) btn1.setCheckable(True) btn1.setChecked(False) rcPng = QIcon("./graphics/RemoteBtn.png") btn1.setIcon(rcPng) btn1.setIconSize(QSize(170, 40)) btn2 = QPushButton() btn2.setFixedSize(130, 40) btn2.setCheckable(True) btn2.setChecked(True) lcPng = QIcon("./graphics/LocalBtnChecked.png") btn2.setIcon(lcPng) btn2.setIconSize(QSize(170, 40)) btn3 = QPushButton() btn3.setFixedSize(130, 40) bPng = QIcon("./graphics/BrowseBtn.png") btn3.setIcon(bPng) btn3.setIconSize(QSize(200, 40)) btn1.toggled.connect(self.remote) btnGroup.addButton(btn1) btn2.toggled.connect(self.local) btnGroup.addButton(btn2) btn3.clicked.connect(self.browseL) btn1.pressed.connect( partial(self.btnPressToggle, btn1, "RemoteBtnChecked.png")) btn1.released.connect( partial(self.btnPressToggle, btn1, "RemoteBtn.png")) btn3.pressed.connect( partial(self.btnPressToggle, btn3, "BrowseBtnChecked.png")) btn3.released.connect( partial(self.btnPressToggle, btn3, "BrowseBtn.png")) vLayout.addWidget(title, alignment=Qt.AlignCenter) hLayout.addWidget(btn1, alignment=Qt.AlignHCenter) hLayout.addWidget(btn2, alignment=Qt.AlignHCenter) vLayout.addLayout(hLayout) vLayout.addWidget(self.path, alignment=Qt.AlignHCenter) vLayout.addWidget(btn3, alignment=Qt.AlignCenter) self.frameL.setLayout(vLayout) self.mainMenu = False self.frameL.hide() def _createFirstScreen(self): vLayout = QVBoxLayout(self.centralWidget()) vLayout.setAlignment(Qt.AlignTop) vLayout.addWidget(QLabel()) hLayout = QHBoxLayout() hLayout.setSpacing(0) hLayout.setAlignment(Qt.AlignHCenter) formLayout = QFormLayout(self.centralWidget()) formLayout.setFormAlignment(Qt.AlignHCenter) formLayout.setLabelAlignment(Qt.AlignRight) btnGroup = QButtonGroup() btnGroup.setExclusive(True) title = QLabel() tPng = QPixmap("./graphics/ManageCraft.png") title.setPixmap(tPng) btn1 = QPushButton() btn1.setFixedSize(130, 40) btn1.setCheckable(True) btn1.setChecked(True) rcPng = QIcon("./graphics/RemoteBtnChecked.png") btn1.setIcon(rcPng) btn1.setIconSize(QSize(170, 40)) btn2 = QPushButton() btn2.setFixedSize(130, 40) btn2.setCheckable(True) btn2.setChecked(False) lcPng = QIcon("./graphics/LocalBtn.png") btn2.setIcon(lcPng) btn2.setIconSize(QSize(170, 40)) btn3 = QPushButton() btn3.setFixedSize(155, 45) cPng = QIcon("./graphics/ConnectBtn.png") btn3.setIcon(cPng) btn3.setIconSize(QSize(200, 40)) btn1.toggled.connect(self.remote) btnGroup.addButton(btn1) btn2.toggled.connect(self.local) btnGroup.addButton(btn2) btn3.clicked.connect(partial(self.browseR)) btn2.pressed.connect( partial(self.btnPressToggle, btn2, "LocalBtnChecked.png")) btn2.released.connect( partial(self.btnPressToggle, btn2, "LocalBtn.png")) btn3.pressed.connect( partial(self.btnPressToggle, btn3, "ConnectBtnChecked.png")) btn3.released.connect( partial(self.btnPressToggle, btn3, "ConnectBtn.png")) host = QLabel() hPng = QPixmap("./graphics/Host.png") host.setPixmap(hPng) user = QLabel() uPng = QPixmap("./graphics/Username.png") user.setPixmap(uPng) pas = QLabel() pPng = QPixmap("./graphics/Password.png") pas.setPixmap(pPng) formLayout.addRow(host, self.host) formLayout.addRow(user, self.user) formLayout.addRow(pas, self.pas) vLayout.addWidget(title, alignment=Qt.AlignCenter) hLayout.addWidget(btn1, alignment=Qt.AlignHCenter) hLayout.addWidget(btn2, alignment=Qt.AlignHCenter) vLayout.addLayout(hLayout) vLayout.addLayout(formLayout) vLayout.addWidget(btn3, alignment=Qt.AlignCenter) vLayout.addWidget(self.err, alignment=Qt.AlignHCenter) self.frameR.setLayout(vLayout) self.mainMenu = False self._createSecondScreen() def remote(self): if self.frameR.isVisible(): pass else: self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_R.png); background-repeat: no-repeat;") self.frameL.hide() self.frameR.show() def local(self): if self.frameL.isVisible(): pass else: self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_L.png); background-repeat: no-repeat;") self.frameR.hide() self.frameL.show() def connect(self): # Pack to config window self.path.setText(self.dui.path.text()) if self.path.text() != '': stdin, stdout, stderr = self.client.exec_command( f"cd {self.path.text()}") try: err = [i for i in stderr if True][0] self.err.setText( "<h2><font color='red'>Error: No such file or directory!</font></h2>" ) self.err.show() except IndexError: self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_2.png); background-repeat: no-repeat;") self.cui.startBtn.clicked.connect(self.__startServer) self.cui.stopBtn.clicked.connect(self.__stopServer) self.cui.restartBtn.clicked.connect(self.__restartServer) self.cui.startBtn.pressed.connect( partial(self.btnStyleToggle, self.cui.startBtn, "StartChecked.png")) self.cui.startBtn.released.connect( partial(self.btnStyleToggle, self.cui.startBtn, "Start.png")) self.cui.stopBtn.pressed.connect( partial(self.btnStyleToggle, self.cui.stopBtn, "StopChecked.png")) self.cui.stopBtn.released.connect( partial(self.btnStyleToggle, self.cui.stopBtn, "Stop.png")) self.cui.restartBtn.pressed.connect( partial(self.btnStyleToggle, self.cui.restartBtn, "RestartChecked.png")) self.cui.restartBtn.released.connect( partial(self.btnStyleToggle, self.cui.restartBtn, "Restart.png")) self.err.hide() self.setWindowTitle(f"{self.path.text()} - ManageCraft") self._createToolBar() self.frameR.hide() self.frameC.show() self.__check_status() self.close_dialog() def browseL(self): getPath = QFileDialog().getExistingDirectory() self.path.setText(getPath) if self.path.text() != '': self.styleFrame.setStyleSheet( "border-image: url(./graphics/WindowFrame.png);\ background-image: url(./graphics/Frame_2.png); background-repeat: no-repeat;") self.setWindowTitle(f"{self.path.text()} - ManageCraft") self._createToolBar() self.frameL.hide() self.frameC.show() def browseR(self): if self.host.text() == '' or self.user.text() == '' or self.pas.text( ) == '': self.err.setText( "<h2><font color='red'>Error: Invalid Input! Try again!</font></h2>" ) self.err.show() else: try: self.err.hide() client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(self.host.text(), port=22, username=self.user.text(), password=self.pas.text()) self.client = client self.dui.btnBox.accepted.connect(self.connect) self.dui.btnBox.rejected.connect(self.close_dialog) self.plant_tree(self.client) self.dialog.show() #Don't proceed until connected except (socket.gaierror, paramiko.ssh_exception.AuthenticationException): self.err.setText( "<h2><font color='red'>Error: Invalid Input! Try again!</font></h2>" ) self.err.show() #Don't proceed unless path given def next_layer(self, lst): #Loops through folders and returns dict of subfolders d = {} for i in lst: stdin, stdout, stderr = self.client.exec_command( f"cd {i} && ls -d */ && cd ..") dirs = [fold.strip('/\n') for fold in stdout if True] if len(dirs) > 0: d[i] = dirs else: d[i] = 0 return d def plant_tree(self, client): self.dui.treeW.setColumnCount(1) self.dui.treeW.setAlternatingRowColors(True) self.dui.treeW.itemExpanded.connect( partial(self.water_tree, self.dui.treeW)) self.dui.treeW.itemClicked.connect( partial(self.get_path, self.dui.treeW)) stdin, stdout, stderr = client.exec_command('ls -d */') top = [i.strip('/\n') for i in stdout if True] folders = self.next_layer(top) self.cache = [] stdin, stdout, stderr = client.exec_command('pwd') self.pwd = [i for i in stdout if True][0].strip('\n') self.grow_tree(folders) def grow_tree(self, folders): items = [] folderIcon = QIcon("./graphics/folder.jpeg") for folder in folders: item = QTreeWidgetItem([folder]) item.setIcon(0, folderIcon) if folders[folder] != 0: childs = [] for sub in folders[folder]: s = QTreeWidgetItem([sub]) s.setIcon(0, folderIcon) childs.append(s) item.addChildren(childs) items.append(item) self.dui.treeW.addTopLevelItems(items) def bloom_tree(self, branchItem, folders): folderIcon = QIcon("./graphics/folder.jpeg") it = QTreeWidgetItemIterator(branchItem, flags=QTreeWidgetItemIterator.NoChildren) while it.value(): item = it.value() for folder in folders: if folder == self.get_roots(item) and folder not in self.cache: self.cache.append(folder) childs = [] if folders[folder] != 0: for sub in folders[folder]: s = QTreeWidgetItem([sub]) s.setIcon(0, folderIcon) childs.append(s) item.addChildren(childs) it += 1 def water_tree(self, tree): it = QTreeWidgetItemIterator(tree, flags=QTreeWidgetItemIterator.HasChildren) while it.value(): item = it.value() tempath = self.get_roots(item) if item.isExpanded(): cs = item.childCount() childs = [ f"{tempath}/{item.child(idx).text(0)}" for idx in range(cs) if True ] folders = self.next_layer(childs) self.bloom_tree(item, folders) it += 1 def get_roots(self, item): # Trace back parents of selected item it = QTreeWidgetItemIterator(self.dui.treeW, flags=QTreeWidgetItemIterator.All) while it.value(): if it.value() == item: if item.parent() != None: return self.get_roots(item.parent()) + '/' + item.text(0) else: return item.text(0) it += 1 def get_path(self, tree): path = self.get_roots(tree.selectedItems()[0]) self.dui.path.setText(f"{self.pwd}/{path}") def close_dialog(self): self.dui.path.setText('') self.dui.treeW.clear() def btnPressToggle(self, btn, png): Png = QIcon(f"./graphics/{png}") btn.setIcon(Png) btn.setIconSize(QSize(200, 40)) def btnStyleToggle(self, btn, png): btn.setStyleSheet(f"border-image: url(./graphics/{png})")
class ViewsController(QMainWindow): """This class will handle all the views of the application. Responsible for showing the differnet views in a specific order depending on the input of the user. If the application is launched with a profile (configuration file), the main view of the application will be shown; otherwise, the title and the configuration views will be shown prior to the main view. """ home_singal = pyqtSignal() robot_select_signal = pyqtSignal() def __init__(self, parent, configuration, controller=None): """Constructor of the class. Arguments: parent {ui.gui.views_controller.ParentWindow} -- Parent of this. configuration {utils.configuration.Config} -- Configuration instance of the application Keyword Arguments: controller {utils.controller.Controller} -- Controller of the application (default: {None}) """ QMainWindow.__init__(self) self.parent = parent self.controller = controller self.configuration = configuration self.main_view = None self.thread_gui = ThreadGUI(self) self.thread_gui.daemon = True # self.home_singal.connect(self.show_title) # self.robot_select_signal.connect(self.show_robot_selection) def show_title(self): """Shows the title view""" title = TitleWindow(self.parent) title.switch_window.connect(self.show_robot_selection) self.parent.main_layout.addWidget(title) self.fadein_animation() def show_robot_selection(self): """Shows the robot selection view""" from views.robot_selection import RobotSelection delete_widgets_from(self.parent.main_layout) robot_selector = RobotSelection(self.parent) robot_selector.switch_window.connect(self.show_world_selection) self.parent.main_layout.addWidget(robot_selector, 0) self.fadein_animation() def show_world_selection(self): """Shows the world selection view""" from views.world_selection import WorldSelection delete_widgets_from(self.parent.main_layout) world_selector = WorldSelection(self.parent.robot_selection, self.configuration, self.parent) world_selector.switch_window.connect(self.show_layout_selection) self.parent.main_layout.addWidget(world_selector) self.fadein_animation() def show_layout_selection(self): """Show the layout configuration view""" delete_widgets_from(self.parent.main_layout) self.layout_selector = LayoutSelection(self.configuration, self.parent) self.layout_selector.switch_window.connect(self.show_main_view_proxy) self.parent.main_layout.addWidget(self.layout_selector) self.fadein_animation() def show_main_view_proxy(self): """Helper function to show the main view. Will close the parent window to create a new one""" # self.show_main_view(False) self.parent.close() def show_main_view(self, from_main): """Shows the main window depending on where the application comes from. If the from_main flag is true, the configuration comes from the previous GUI views. Otherwise, the configuration comes from a configuration file. Eitherway, the main view will be shown with the proper configuration. Arguments: from_main {bool} -- tells if the configuration comes from either configuration file or GUI. """ if not from_main: layout_configuration = self.layout_selector.get_config() delete_widgets_from(self.parent.main_layout) else: layout_configuration = None self.main_view = MainView(layout_configuration, self.configuration, self.controller, self.parent) self.parent.main_layout.addWidget(self.main_view) self.fadein_animation() self.start_thread() def start_thread(self): """Start the GUI refresing loop""" self.thread_gui.start() def fadein_animation(self): """Start a fadein animation for views transitions""" self.w = QFrame(self.parent) # self.parent.main_layout.addWidget(self.w, 0) self.w.setFixedSize(WIDTH, HEIGHT) self.w.setStyleSheet('background-color: rgba(51,51,51,1)') self.w.show() effect = QGraphicsOpacityEffect() self.w.setGraphicsEffect(effect) self.animation = QPropertyAnimation(effect, b"opacity") self.animation.setDuration(500) self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start(QPropertyAnimation.DeleteWhenStopped) self.animation.finished.connect(self.fade_animation) def fade_animation(self): """Safe kill the animation""" self.w.close() del self.w del self.animation def update_gui(self): """Update the GUI. Called from the refresing loop thread""" while not self.parent.closing: if self.main_view: self.main_view.update_gui() time.sleep(0.1)
class Tablewidget(QTableWidget): def __init__(self,parent): super().__init__() self.setParent(parent) self.frontandnextFlag = [] self.pat = re.compile(r"<font style='background-color:red;'>(.*?)</font>") self.searchbox = QFrame(self) self.searchbox.setGeometry(10,50,330,30) # self.searchbox.setFrameRect(QRect(10,10,10,10)) self.searchbox.setStyleSheet("border-radius:2px;background-color:rgb(200,200,200)") self.searchbox.setHidden(True) self.searchtextbox = QLineEdit(self.searchbox) self.searchtextbox.setGeometry(0,0,210,30) self.searchtextbox.setStyleSheet("border:none") #文本显示框 self.textwindow = QTextEdit(self) self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100) self.textwindow.setVisible(False) self.textwindow_text = None #搜索窗口 self.search = QPushButton("", self.searchbox) self.search.setIcon(QIcon("./pic/search.ico")) self.search.setGeometry(210, 0, 30, 30) self.search.setStyleSheet("border:none") self.search.clicked.connect(self.searchdata) self.front = QPushButton("",self.searchbox) self.front.setIcon(QIcon("./pic/front.ico")) self.front.setGeometry(240,0,30,30) self.front.setStyleSheet("border:none") self.front.clicked.connect(lambda: self.frontandnextpress(-1)) self.next = QPushButton("", self.searchbox) self.next.setIcon(QIcon("./pic/next.ico")) self.next.setGeometry(270,0,30,30) self.next.setStyleSheet("border:none") self.next.clicked.connect(lambda: self.frontandnextpress(1)) self.clo = QPushButton("", self.searchbox) self.clo.setIcon(QIcon("./pic/close.ico")) self.clo.setGeometry(300, 0, 30, 30) self.clo.setStyleSheet("border:none") self.clo.clicked.connect(self.searchboxclo) self.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) # 设置垂直方向滑块像素移动 self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) # 设置水平方向滑块像素移动 self.setEditTriggers(QAbstractItemView.NoEditTriggers | QAbstractItemView.DoubleClicked) # 设置表格不可编辑 self.setContextMenuPolicy(Qt.CustomContextMenu) # 设置启用右键策略 def showdata(self, data): self.setRowCount(len(data[0]) - 1) self.setColumnCount(len(data)) for i in range(0, len(data)): # 总列数,显示所有数据 self.setHorizontalHeaderItem(i, QTableWidgetItem(data[i][0])) for j in range(1, len(data[0])): # 总数据行数 ss = QTableWidgetItem(data[i][j]) self.setItem(j - 1, i, ss) ss.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter) # 设置所有单元格对齐方式 def keyPressEvent(self, QkeyEvent): if QkeyEvent.key() == Qt.Key_F: if QApplication.keyboardModifiers() == Qt.ControlModifier: self.searchbox.show() self.searchbox.setHidden(False) self.searchtextbox.setFocus() elif QkeyEvent.key() == Qt.Key_Escape: if self.searchbox.isHidden(): self.textwindow.setHidden(True) else: self.searchbox.setHidden(True) self.textwindow.setHidden(True) elif QkeyEvent.key() == Qt.Key_F2: self.textwindow.setGeometry(0,0, self.width() - 100, self.height() - 100) detail = JSONEncoder().encode(self.textwindow_text) detail = json.loads(detail) self.textwindow.setText(json.dumps(detail, indent=5, ensure_ascii=False)) self.textwindow.setHidden(False) def searchdata(self): self.frontandnextFlag = [] global pressFlag pressFlag = -1 findtext = "" # if self.searchtextbox.text() == "": # return # else: try: findtext = self.searchtextbox.text().split()[0] except IndexError: findtext = "$@##$$@!!" #如果为空,标记特殊寻找字符,找不到将Qlabel替换为字符串 for a in range(self.rowCount()): for b in range(self.columnCount()): if isinstance(type(self.item(a,b)),type(None)) and isinstance(type(self.cellWidget(a,b)),type(None)): pass else: if isinstance(type(self.cellWidget(a,b)),type(QLabel)): if "<font style" in self.cellWidget(a,b).text(): d = self.cancelCssFormat(self.cellWidget(a,b).text()) celltext = self.cellWidget(a,b).text().replace( "<font style='background-color:red;'>{}</font>".format(d), d) if findtext in celltext: self.cellWidget(a,b).setText(self.setStrkeyColor(celltext,findtext)) self.frontandnextFlag.append([a,b]) else: self.removeCellWidget(a,b) celltext = celltext.replace("<br>", "\n") self.setItem(a,b,QTableWidgetItem(celltext)) else: celltext = self.cellWidget(a,b).text() celltext = celltext.replace("<br>", "\n") self.removeCellWidget(a,b) self.setItem(a,b,QTableWidgetItem(celltext)) elif isinstance(type(self.item(a, b)), type(QTableWidgetItem)): if findtext in self.item(a,b).text(): celltext = self.item(a,b).text().replace("\n","<br>") celltext = self.setStrkeyColor(celltext,findtext) lab = QLabel(celltext,self) self.setCellWidget(a,b,lab) self.setItem(a,b,QTableWidgetItem("")) self.frontandnextFlag.append([a, b]) # print(a,b,type(self.cellWidget(a,b)),type(self.item(a,b)),"\n",lab.text()) else: pass else: pass def setStrkeyColor(self,strdata,key): needstr = strdata.replace(key,"<font style='background-color:red;'>{}</font>".format(key)) return needstr def cancelCssFormat(self,strdata): return self.pat.search(strdata).group(1) def stecellbackcolor(self,a,b,color=QColor(200,200,200)): self.item(a,b).setBackground(QColor(color)) def searchboxclo(self): self.searchtextbox.clear() self.searchbox.close() def frontandnextpress(self,k): global pressFlag pressFlag += k if pressFlag >= 0 and pressFlag < len(self.frontandnextFlag): self.setCurrentCell(self.frontandnextFlag[pressFlag][0],self.frontandnextFlag[pressFlag][1]) else: pressFlag = -1