在回家后继续卷的时候,机缘巧合发现的。
想起以前项目中,花费那么多时间都没解决的问题,答案居然就在帮助文档中躺着,分享一下,虽然不是所需要的效果,但好歹迈出了第一步。

做了二次开发的小伙伴可能清楚,通过BCWindowCreate创建的window窗口会占用当前进程,在点击界面上其他命令的时候,窗口就会被摧毁。例如上述图片,编辑器也会变为灰色。这的确很苦恼,这就得要求在开发命令的时候,涉及到的操作全都得写在界面上,这很麻烦,很麻烦,很麻烦。。。。。怎么就不能像HyperWork一样,所创建的窗口互不干涉。
现在解决办法来了,这是23.1.0帮助文档里写的,监控ABAQUS计算进程的案例,低版本的能否运行,大家自行判断。重点来了,修改create_options_frame函数内的功能就可以实现创建控件,但是当控件所绑定的函数需要修改模型的操作,例如创建点,程序就会闪退。目前还不知道怎么解决。

from __future__ import annotationsimport osimport reimport shleximport subprocessfrom ansa import base, session, guitk, constants, analysis_tools_RE_FLOAT = r"[-+]?(?:(?:\d*\.?\d+)|(?:\d+\.?\d*))(?:[eE][-+]?\d+)?"def _show_msg_win_critical(msg):msg_win = guitk.BCMessageWindowCreate(guitk.constants.BCMessageBoxCritical, msg, False)guitk.BCMessageWindowSetRejectButtonVisible(msg_win, False)guitk.BCMessageWindowExecute(msg_win)def _show_msg_win_information(msg):msg_win = guitk.BCMessageWindowCreate(guitk.constants.BCMessageBoxInformation, msg, False)guitk.BCMessageWindowSetRejectButtonVisible(msg_win, False)guitk.BCMessageWindowExecute(msg_win)def _show_msg_win_question(msg):msg_win = guitk.BCMessageWindowCreate(guitk.constants.BCMessageBoxQuestion, msg, False)return guitk.BCMessageWindowExecute(msg_win) == guitk.constants.BCRetKeydef _get_path_from_line_edit_path(ledit_path):file_path = guitk.BCLineEditPathLineEditText(ledit_path)if not file_path:return ""return os.path.abspath(file_path)class AbqTextViewer(analysis_tools.RunSolverTextViewer):def __init__(self, run_abq: RunAbq, name, is_console=False):super().__init__(name=name, is_console=is_console, supports_errors=True,supports_warnings=True, supports_notes=True)self._run_abq = run_abqdef get_file_path(self):dir_name = self._run_abq.get_output_dir_name()job_name = self._run_abq.get_job_name()file_path = os.path.join(dir_name, job_name) + "." + self.name.lower()return file_pathdef has_error_in_line(self, text):return text.startswith(" ***ERROR") or text.startswith("***ERROR")def has_warning_in_line(self, text):return text.startswith(" ***WARNING") or text.startswith("***WARNING")def has_note_in_line(self, text):return text.startswith(" ***NOTE") or text.startswith("***NOTE")class AbqTotalIterationsPlotViewer(analysis_tools.RunSolverPlotViewer):def __init__(self, run_abq: RunAbq):super().__init__(name="Total Iterations")self._run_abq = run_abqself._numbers_pattern = r"^\s*" + 5*(r"\d+\s+") + r"(\d+)\s+" + "("+_RE_FLOAT+")" +\r"\s+" + _RE_FLOAT + r"\s+" + _RE_FLOAT + r"\s*"def get_file_path(self):return os.path.join(self._run_abq.get_output_dir_name(),self._run_abq.get_job_name()) + ".sta"def set_plot_options(self):self.set_axis_title(pos="yleft", title="Total Iterations")self.set_axis_title(pos="xbottom", title="Total Time")self.set_curve_name(name="Total Iterations")self.set_curve_color(r=0, g=0, b=255)def file_updated(self, new_text, file_index):points = []for line in new_text.splitlines():match = re.search(self._numbers_pattern, line)if match:total_iters = float(match.group(1))total_time = float(match.group(2))points.append((total_time, total_iters))if len(points) > 0:self.append_points_to_curve(points)class RunAbq(analysis_tools.RunSolver):def __init__(self):super().__init__(window_caption="Run Abaqus", query_status_interval=1.0,initial_actions="Start")self._out_ledit_path = Noneself._exec_ledit_path = Noneself._scratch_dir = Noneself._data_check_cbox = Noneself._cpus_ledit = Noneself._mem_size_ledit = Noneself._mem_unit_combo = Noneself._log_file = Noneself._process = Noneself._suspend_process = Noneself._resume_process = Nonedef _get_output_file_path(self):return _get_path_from_line_edit_path(self._out_ledit_path)def get_output_dir_name(self):return os.path.dirname(self._get_output_file_path())def get_job_name(self):return os.path.splitext(os.path.basename(self._get_output_file_path()))[0]def _get_lock_file(self):dir_name = self.get_output_dir_name()job_name = self.get_job_name()file_path = os.path.join(dir_name, job_name) + ".lck"return file_pathdef _get_exec_file_path(self):return _get_path_from_line_edit_path(self._exec_ledit_path)def _get_log_file_path(self):return os.path.join(self.get_output_dir_name(), self.get_job_name()) + ".log"def _get_mem_size(self):mem_size = guitk.BCLineEditGetText(self._mem_size_ledit).strip()if not mem_size:return ""mem_unit = guitk.BCComboBoxCurrentText(self._mem_unit_combo)return mem_size + mem_unitdef _get_solver_args(self):args = []args.append(f"job={self.get_job_name()}")args.append("interactive")if guitk.BCCheckBoxIsChecked(self._data_check_cbox):args.append("datacheck")cpus_num = guitk.BCLineEditGetInt(self._cpus_ledit)if cpus_num != guitk.constants.blank:args.append(f"cpus={cpus_num}")mem_size = self._get_mem_size()if mem_size:args.append(f"memory={mem_size}")scratch_dir_name = _get_path_from_line_edit_path(self._scratch_dir)if scratch_dir_name:args.append(f"scratch={scratch_dir_name}")additional_args = guitk.BCLineEditGetText(self._additional_args_ledit).strip()if additional_args:for arg in shlex.split(additional_args):args.append(arg)return argsdef _check_user_input(self):if not os.path.exists(self._get_exec_file_path()):_show_msg_win_critical("Executable does not exist")return Falseif not self._get_output_file_path():_show_msg_win_critical("Output file is empty")return Falsereturn Truedef _init(self):if not self._check_user_input():return Falseif os.path.exists(self._get_lock_file()):ret = _show_msg_win_question("Lock file detected. Delete and continue?")if not ret:return Falseos.remove(self._get_lock_file())if base.OutputAbaqus(self._get_output_file_path()) == 0:_show_msg_win_critical("Output failed")return Falseself._log_file = open(self._get_log_file_path(), "w")return Truedef handle_action(self, action):if action == "Start":if not self._init():returnself.initialize()self.set_busy()args = [self._get_exec_file_path()] + self._get_solver_args()self._process = subprocess.Popen(args, cwd=self.get_output_dir_name(),stdout=self._log_file, stderr=subprocess.STDOUT)elif action == "Terminate":args = [self._get_exec_file_path(), "terminate", f"job={self.get_job_name()}"]subprocess.Popen(args, cwd=self.get_output_dir_name(),stdout=self._log_file, stderr=subprocess.STDOUT)elif action == "Suspend":args = [self._get_exec_file_path(), "suspend", f"job={self.get_job_name()}"]self._suspend_process = subprocess.Popen(args, cwd=self.get_output_dir_name(),stdout=self._log_file, stderr=subprocess.STDOUT)elif action == "Resume":self.set_busy()args = [self._get_exec_file_path(), "resume", f"job={self.get_job_name()}"]self._resume_process = subprocess.Popen(args, cwd=self.get_output_dir_name(),stdout=self._log_file, stderr=subprocess.STDOUT)else:raise Exception("Invalid action:", action)def query_status(self):if self._process is not None:ret = self._process.poll()if ret is not None:self._process = Noneif ret == 0:return "Completed"else:return "Failed"if self._suspend_process is not None:ret = self._suspend_process.poll()if ret is not None:self._suspend_process = Noneif ret == 0:return "Suspended"else:return "Running"if self._resume_process is not None:ret = self._resume_process.poll()if ret is not None:self._resume_process = Noneif ret == 0:return "Resumed"else:return "Suspended"return "Running"def status_changed(self, new_status):if new_status == "Running":self.show_only_actions(actions=("Terminate", "Suspend"))elif new_status == "Resumed":self.show_only_actions(actions=("Terminate", "Suspend"))elif new_status == "Suspended":self.set_idle()self.show_only_actions(actions="Resume")elif new_status == "Completed":self.set_idle()self.show_only_actions(actions="Start")self._log_file.close()_show_msg_win_information("Job was completed")elif new_status == "Failed":self.set_idle()self.show_only_actions(actions="Start")self._log_file.close()_show_msg_win_critical("Job failed")else:raise Exception("Invalid new_status:", new_status)def create_analysis_top_frame(self, parent):g_layout = guitk.BCGridLayoutCreate(parent)guitk.BCGridLayoutSetColStretch(g_layout, 0, 0)guitk.BCGridLayoutSetColStretch(g_layout, 1, 1)label = guitk.BCLabelCreate(g_layout, "Output file")guitk.BCGridLayoutAddWidget(g_layout, label, 0, 0, guitk.constants.BCAlignAuto)self._out_ledit_path = guitk.BCLineEditPathCreate(g_layout, guitk.constants.BCHistoryFiles,"", guitk.constants.BCHistorySaveAs, "RunAbq_OutputPath")guitk.BCLineEditPathAddFilter(self._out_ledit_path, "ABAQUS", "inp")guitk.BCGridLayoutAddWidget(g_layout, self._out_ledit_path, 0, 1, guitk.constants.BCAlignAuto)def create_options_frame(self, parent):g_layout = guitk.BCGridLayoutCreate(parent)guitk.BCGridLayoutSetColStretch(g_layout, 0, 0)guitk.BCGridLayoutSetColStretch(g_layout, 1, 1)label = guitk.BCLabelCreate(g_layout, "Executable")guitk.BCGridLayoutAddWidget(g_layout, label, 0, 0, guitk.constants.BCAlignAuto)self._exec_ledit_path = guitk.BCLineEditPathCreate(g_layout, guitk.constants.BCHistoryFiles,"", guitk.constants.BCHistorySelect, "RunAbq_Executable")guitk.BCGridLayoutAddWidget(g_layout, self._exec_ledit_path, 0, 1, guitk.constants.BCAlignAuto)label = guitk.BCLabelCreate(g_layout, "Scratch directory")guitk.BCGridLayoutAddWidget(g_layout, label, 1, 0, guitk.constants.BCAlignAuto)self._scratch_dir = guitk.BCLineEditPathCreate(g_layout, guitk.constants.BCHistoryFiles,"", guitk.constants.BCHistorySelect, "RunAbq_ScratchDirectory")guitk.BCGridLayoutAddWidget(g_layout, self._scratch_dir, 1, 1, guitk.constants.BCAlignAuto)self._data_check_cbox = guitk.BCCheckBoxCreate(g_layout, "Data check")guitk.BCGridLayoutAddMultiCellWidget(g_layout, self._data_check_cbox, 2, 2, 0, 1,guitk.constants.BCAlignAuto)label = guitk.BCLabelCreate(g_layout, "Number of CPUs")guitk.BCGridLayoutAddWidget(g_layout, label, 3, 0, guitk.constants.BCAlignAuto)self._cpus_ledit = guitk.BCLineEditCreateInt(g_layout)guitk.BCGridLayoutAddWidget(g_layout, self._cpus_ledit, 3, 1, guitk.constants.BCAlignAuto)label = guitk.BCLabelCreate(g_layout, "Memory size")guitk.BCGridLayoutAddWidget(g_layout, label, 4, 0, guitk.constants.BCAlignAuto)frame = guitk.BCFrameCreate(g_layout)h_layout = guitk.BCBoxLayoutCreate(frame, guitk.constants.BCHorizontal)guitk.BCBoxLayoutSetMargin(h_layout, 0)guitk.BCBoxLayoutSetSpacing(h_layout, 0)self._mem_size_ledit = guitk.BCLineEditCreateInt(h_layout)guitk.BCBoxLayoutSetStretchFactor(h_layout, self._mem_size_ledit, 1)self._mem_unit_combo = guitk.BCComboBoxCreate(h_layout, ("MB", "GB", "%"))guitk.BCBoxLayoutSetStretchFactor(h_layout, self._mem_unit_combo, 0)guitk.BCGridLayoutAddWidget(g_layout, frame, 4, 1, guitk.constants.BCAlignAuto)label = guitk.BCLabelCreate(g_layout, "Additional arguments")guitk.BCGridLayoutAddWidget(g_layout, label, 5, 0, guitk.constants.BCAlignAuto)self._additional_args_ledit = guitk.BCLineEditCreate(g_layout, "")guitk.BCGridLayoutAddWidget(g_layout, self._additional_args_ledit, 5, 1,guitk.constants.BCAlignAuto)guitk.BCSpacerCreate(parent)def create_run_abq_win():run_abq = RunAbq()run_abq.add_viewer(AbqTextViewer(run_abq, name="LOG", is_console=True))run_abq.add_viewer(AbqTextViewer(run_abq, name="DAT"))run_abq.add_viewer(AbqTextViewer(run_abq, name="MSG"))run_abq.add_viewer(AbqTextViewer(run_abq, name="STA"))run_abq.add_viewer_group(group="Plots")run_abq.add_viewer(AbqTotalIterationsPlotViewer(run_abq), group="Plots")run_abq.add_action(action="Start", icon="run_small.svg")run_abq.add_action(action="Resume", icon="run_small.svg")run_abq.add_action_group(group="Stop", icon="rect_red_small.svg")run_abq.add_action(action="Terminate", icon="rect_red_small.svg", group="Stop")run_abq.add_action(action="Suspend", icon="media_pause.svg", group="Stop")run_abq.create_window()create_run_abq_win ()