210 lines
7.2 KiB
Python
210 lines
7.2 KiB
Python
from PyQt5.QtCore import QSettings, pyqtSignal, Qt
|
||
from PyQt5.QtGui import QIcon, QTextBlock, QTextCursor
|
||
from PyQt5.QtWidgets import QDialog, QLabel,QComboBox, QDialogButtonBox, QFileDialog, QHBoxLayout, QMessageBox, QProgressBar, QPushButton, QTextEdit, QVBoxLayout
|
||
import subprocess
|
||
import threading
|
||
import sys
|
||
from rscder.utils.icons import IconInstance
|
||
import os
|
||
import sys
|
||
import ai_method.subprcess_python as sp
|
||
from ai_method import AI_METHOD
|
||
from misc.main import AlgFrontend
|
||
import abc
|
||
|
||
class AIMethodDialog(QDialog):
|
||
|
||
stage_end = pyqtSignal(int)
|
||
stage_log = pyqtSignal(str)
|
||
|
||
ENV = 'base'
|
||
name = ''
|
||
stages = []
|
||
setting_widget = None
|
||
|
||
def __init__(self, parent = None) -> None:
|
||
super().__init__(parent)
|
||
|
||
# self.setting_widget:AlgFrontend = setting_widget
|
||
|
||
vlayout = QVBoxLayout()
|
||
|
||
hlayout = QHBoxLayout()
|
||
select_label = QLabel('模式选择:')
|
||
self.select_mode = QComboBox()
|
||
self.select_mode.addItem('----------', 'NoValue')
|
||
for stage in self.stages:
|
||
self.select_mode.addItem(stage[1], stage[0])
|
||
|
||
setting_btn = QPushButton(IconInstance().SELECT, '配置')
|
||
|
||
hlayout.addWidget(select_label)
|
||
hlayout.addWidget(self.select_mode, 2)
|
||
hlayout.addWidget(setting_btn)
|
||
self.setting_args = []
|
||
|
||
def show_setting():
|
||
if self.setting_widget is None:
|
||
return
|
||
dialog = QDialog(parent)
|
||
vlayout = QVBoxLayout()
|
||
dialog.setLayout(vlayout)
|
||
widget = self.setting_widget.get_widget(dialog)
|
||
vlayout.addWidget(widget)
|
||
|
||
dbtn_box = QDialogButtonBox(dialog)
|
||
dbtn_box.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||
dbtn_box.button(QDialogButtonBox.Ok).setText('确定')
|
||
dbtn_box.button(QDialogButtonBox.Cancel).setText('取消')
|
||
dbtn_box.button(QDialogButtonBox.Ok).clicked.connect(dialog.accept)
|
||
dbtn_box.button(QDialogButtonBox.Cancel).clicked.connect(dialog.reject)
|
||
vlayout.addWidget(dbtn_box, 1, Qt.AlignRight)
|
||
dialog.setMinimumHeight(500)
|
||
dialog.setMinimumWidth(900)
|
||
if dialog.exec_() == QDialog.Accepted:
|
||
self.setting_args = self.setting_widget.get_params(widget)
|
||
|
||
setting_btn.clicked.connect(show_setting)
|
||
|
||
btnbox = QDialogButtonBox(self)
|
||
btnbox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||
btnbox.button(QDialogButtonBox.Ok).setText('确定')
|
||
btnbox.button(QDialogButtonBox.Cancel).setText('取消')
|
||
|
||
processbar = QProgressBar(self)
|
||
processbar.setMaximum(1)
|
||
processbar.setMinimum(0)
|
||
processbar.setEnabled(False)
|
||
def run_stage():
|
||
self.log = f'开始{self.current_stage}...\n'
|
||
btnbox.button(QDialogButtonBox.Cancel).setEnabled(True)
|
||
processbar.setMaximum(0)
|
||
processbar.setValue(0)
|
||
processbar.setEnabled(True)
|
||
q = threading.Thread(target=self.run_stage, args=(self.current_stage,))
|
||
q.start()
|
||
pass
|
||
|
||
btnbox.button(QDialogButtonBox.Cancel).setEnabled(False)
|
||
btnbox.accepted.connect(run_stage)
|
||
btnbox.rejected.connect(self._stage_stop)
|
||
self.processbar = processbar
|
||
|
||
vlayout.addLayout(hlayout)
|
||
self.detail = QTextEdit(self)
|
||
vlayout.addWidget(self.detail)
|
||
vlayout.addWidget(processbar)
|
||
vlayout.addWidget(btnbox)
|
||
self.detail.setReadOnly(True)
|
||
# self.detail.copyAvailable(True)
|
||
self.detail.setText(f'等待开始...')
|
||
self.setLayout(vlayout)
|
||
|
||
self.setMinimumHeight(500)
|
||
self.setMinimumWidth(500)
|
||
self.setWindowIcon(IconInstance().AI_DETECT)
|
||
self.setWindowTitle(self.name)
|
||
|
||
self.stage_end.connect(self._stage_end)
|
||
self.log = f'等待开始...\n'
|
||
self.stage_log.connect(self._stage_log)
|
||
self.p = None
|
||
|
||
@property
|
||
def current_stage(self):
|
||
if self.select_mode.currentData() == 'NoValue':
|
||
return None
|
||
return self.select_mode.currentData()
|
||
|
||
@property
|
||
def _python_base(self):
|
||
return os.path.abspath(os.path.join(os.path.dirname(sys.executable), '..', '..'))
|
||
|
||
@property
|
||
def activate_env(self):
|
||
script = os.path.join(self._python_base, 'Scripts','activate')
|
||
if self.ENV == 'base':
|
||
return script
|
||
else:
|
||
return script + ' ' + self.ENV
|
||
|
||
@property
|
||
def python_path(self):
|
||
if self.ENV == 'base':
|
||
return self._python_base
|
||
return os.path.join(self._python_base, 'envs', self.ENV, 'python.exe')
|
||
|
||
@property
|
||
def workdir(self):
|
||
raise NotImplementedError()
|
||
|
||
@abc.abstractmethod
|
||
def stage_script(self, stage):
|
||
return None
|
||
|
||
def _stage_log(self, l):
|
||
self.log += l + '\n'
|
||
self.detail.setText(self.log)
|
||
cursor = self.detail.textCursor()
|
||
# QTextCursor
|
||
cursor.movePosition(QTextCursor.End)
|
||
self.detail.setTextCursor(cursor)
|
||
def closeEvent(self, e) -> None:
|
||
if self.p is None:
|
||
return super().closeEvent(e)
|
||
dialog = QMessageBox(QMessageBox.Warning, '警告', '关闭窗口将停止' + self.current_stage + '!', QMessageBox.Ok | QMessageBox.Cancel)
|
||
dialog.button(QMessageBox.Ok).clicked.connect(dialog.accepted)
|
||
dialog.button(QMessageBox.Cancel).clicked.connect(dialog.rejected)
|
||
dialog.show()
|
||
r = dialog.exec()
|
||
# print(r)
|
||
# print(QMessageBox.Rejected)
|
||
# print(QMessageBox.Accepted)
|
||
if r == QMessageBox.Cancel:
|
||
e.ignore()
|
||
return
|
||
return super().closeEvent(e)
|
||
|
||
def _stage_stop(self):
|
||
if self.p is not None:
|
||
try:
|
||
self.stage_log.emit(f'用户停止{self.stage}...')
|
||
self.p.kill()
|
||
except:
|
||
pass
|
||
|
||
def _stage_end(self, c):
|
||
self.processbar.setMaximum(1)
|
||
self.processbar.setValue(0)
|
||
self.processbar.setEnabled(False)
|
||
self.log += '完成!'
|
||
self.detail.setText(self.log)
|
||
|
||
def run_stage(self, stage):
|
||
if stage is None:
|
||
return
|
||
ss = self.stage_script(stage)
|
||
if ss is None:
|
||
self.stage_log.emit(f'开始{stage}时未发现脚本')
|
||
self.stage_end.emit(1)
|
||
return
|
||
|
||
if self.workdir is None:
|
||
self.stage_log.emit(f'未配置工作目录!')
|
||
self.stage_end.emit(2)
|
||
return
|
||
args = [ss, *self.setting_args]
|
||
self.p = sp.SubprocessWraper(self.python_path, self.workdir, args, self.activate_env)
|
||
|
||
for line in self.p.run():
|
||
self.stage_log.emit(line)
|
||
self.stage_end.emit(self.p.returncode)
|
||
|
||
|
||
from collections import OrderedDict
|
||
def option_to_gui(parent, options:OrderedDict):
|
||
for key in options:
|
||
pass
|
||
|
||
def gui_to_option(widget, options:OrderedDict):
|
||
pass |