C++编辑器-2
2026-02-15 14:23:31
发布于:浙江
该代码并不完整,点此进入代码框架页面
class RunWorker(QRunnable):
"""运行工作线程"""
def __init__(self, compiler_path, temp_cpp, output_file, include_paths, temp_dir, run_encoding, file_name_without_ext, use_saved_file, output_dir, parent):
super().__init__()
self.compiler_path = compiler_path
self.temp_cpp = temp_cpp
self.output_file = output_file
self.include_paths = include_paths
self.temp_dir = temp_dir
self.run_encoding = run_encoding
self.file_name_without_ext = file_name_without_ext
self.use_saved_file = use_saved_file
self.output_dir = output_dir
self.parent = parent # 保存对主窗口的引用
self.signals = WorkerSignals()
self.is_running = True
@pyqtSlot()
def run(self):
"""运行任务(编译并运行)"""
try:
self.signals.started.emit()
self.signals.output.emit(f"开始运行...\n临时目录: {self.temp_dir}\n", 'normal')
# 1. 运行自动检测:如果已编译且有输出文件,且代码未修改,则跳过编译
need_compile = True
skip_compile_message = ""
if self.use_saved_file and os.path.exists(self.output_file):
# 对于已保存的文件,检查代码是否有改动
current_code_hash = self.parent.get_current_code_hash()
last_compiled_hash = self.parent.last_compiled_hash.get(self.output_file)
if current_code_hash == last_compiled_hash:
# 代码未修改,检查输出文件是否存在且较新
if os.path.exists(self.output_file):
# 检查输出文件是否比源文件新(针对已保存文件)
# 从父窗口获取当前文件路径
current_file = self.parent.current_file
if current_file and os.path.exists(current_file):
source_mtime = os.path.getmtime(current_file)
else:
# 如果文件未保存,使用临时文件的时间
source_mtime = os.path.getmtime(self.temp_cpp) if os.path.exists(self.temp_cpp) else 0
output_mtime = os.path.getmtime(self.output_file)
if output_mtime > source_mtime:
need_compile = False
skip_compile_message = "检测到代码未修改且已存在编译输出,跳过编译...\n"
if need_compile:
# 需要编译
self.signals.output.emit("正在编译代码...\n", 'normal')
# 检查编译器类型
compiler_name = os.path.basename(self.compiler_path).lower()
# 构建编译命令
compile_cmd = []
if 'cl' in compiler_name and sys.platform == 'win32':
# MSVC编译器
compile_cmd = [self.compiler_path, self.temp_cpp, f'/Fe"{self.output_file}"', '/EHsc', '/nologo', '/utf-8']
# 添加include路径
for path in self.include_paths:
compile_cmd.append(f'/I"{path}"')
elif compiler_name in ['g++', 'gcc', 'clang++'] or 'g++' in compiler_name:
# g++、gcc、clang++等编译器
compile_cmd = [self.compiler_path, self.temp_cpp, '-o', self.output_file, '-std=c++20', '-finput-charset=UTF-8', '-fexec-charset=UTF-8']
# 添加include路径
for path in self.include_paths:
compile_cmd.append(f'-I{path}')
else:
# 默认使用g++风格
compile_cmd = [self.compiler_path, self.temp_cpp, '-o', self.output_file, '-std=c++20', '-finput-charset=UTF-8', '-fexec-charset=UTF-8']
# 添加include路径
for path in self.include_paths:
compile_cmd.append(f'-I{path}')
# 显示编译命令和INCLUDE路径
cmd_str = ' '.join(compile_cmd[:5]) + '...' if len(compile_cmd) > 5 else ' '.join(compile_cmd)
self.signals.output.emit(f"编译命令: {cmd_str}\n", 'command')
# 显示INCLUDE路径详情
if self.include_paths:
self.signals.output.emit(f"使用 {len(self.include_paths)} 个include路径:\n", 'normal')
for i, path in enumerate(self.include_paths[:3]): # 只显示前3个
self.signals.output.emit(f" [{i+1}] {path}\n", 'normal')
if len(self.include_paths) > 3:
self.signals.output.emit(f" ... 还有 {len(self.include_paths) - 3} 个路径\n", 'normal')
# 执行编译 - 隐藏控制台窗口
if sys.platform == 'win32':
# Windows:使用CREATE_NO_WINDOW标志隐藏控制台窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
compile_result = subprocess.run(
compile_cmd,
capture_output=True,
text=True,
encoding='utf-8',
errors='replace',
startupinfo=startupinfo
)
else:
# Linux/Mac:正常执行
compile_result = subprocess.run(
compile_cmd,
capture_output=True,
text=True,
encoding='utf-8',
errors='replace'
)
# 显示编译输出
if compile_result.stdout:
self.signals.output.emit(compile_result.stdout, 'normal')
if compile_result.stderr:
self.signals.output.emit(compile_result.stderr, 'error')
if compile_result.returncode != 0:
error_msg = "编译失败,无法运行!\n"
self.signals.output.emit(error_msg, 'error')
self.signals.compile_finished.emit(False, error_msg)
return
success_msg = "编译成功!\n"
self.signals.output.emit(success_msg, 'success')
# 记录编译哈希值
current_code_hash = self.parent.get_current_code_hash()
self.parent.last_compiled_hash[self.output_file] = current_code_hash
self.signals.compile_finished.emit(True, success_msg)
else:
# 不需要编译,直接使用现有输出文件
self.signals.output.emit(skip_compile_message, 'normal')
self.signals.output.emit("使用上次编译结果...\n", 'normal')
self.signals.compile_finished.emit(True, "使用上次编译结果")
# 运行程序
self.signals.output.emit(f"正在运行程序: {self.output_file}\n", 'normal')
# 获取配置的运行编码
run_encoding = self.run_encoding
# 直接运行生成的.exe程序,不捕获输入输出
if sys.platform == 'win32':
# Windows系统:使用正确的编码设置运行程序
if os.path.exists(self.output_file):
try:
# 根据配置的编码设置代码页
if run_encoding == 'utf-8':
code_page = '65001' # UTF-8代码页
else:
code_page = '936' # GBK代码页
# 创建批处理文件
if self.use_saved_file:
# 如果使用已保存文件,将.bat文件保存到相同目录
batch_file = os.path.join(self.output_dir, f"{self.file_name_without_ext}.bat")
else:
# 如果使用临时文件,创建临时批处理文件
batch_file = self.output_file + '.bat'
batch_content = f"""@echo off
chcp {code_page} > nul
title C++程序输出 - {self.file_name_without_ext}
"{self.output_file}"
echo.
echo 程序执行完毕,按任意键退出...
pause > nul
"""
with open(batch_file, 'w', encoding='utf-8') as f:
f.write(batch_content)
# 使用subprocess启动批处理文件
subprocess.Popen(['cmd.exe', '/c', batch_file],
creationflags=subprocess.CREATE_NEW_CONSOLE)
# 注册一个函数来清理批处理文件(如果是临时文件)
if not self.use_saved_file:
def cleanup_batch():
try:
if os.path.exists(batch_file):
os.remove(batch_file)
except:
pass
atexit.register(cleanup_batch)
info_msg = "程序已在新的命令行窗口中启动。\n"
self.signals.output.emit(info_msg, 'normal')
if self.use_saved_file:
self.signals.output.emit(f"批处理启动器已保存到: {batch_file}\n", 'normal')
self.signals.output.emit(f"下次双击 '{self.file_name_without_ext}.bat' 运行程序可避免中文乱码\n", 'normal')
self.signals.output.emit(f"注意:新窗口已设置为{run_encoding.upper()}编码,支持中文显示。\n", 'normal')
self.signals.run_started.emit(self.output_file)
except Exception as e:
error_msg = f"启动程序时出错: {str(e)}\n"
self.signals.output.emit(error_msg, 'error')
# 如果上面的方法失败,尝试直接运行
try:
subprocess.Popen([self.output_file],
creationflags=subprocess.CREATE_NEW_CONSOLE)
info_msg = "程序已启动(未设置编码)。\n"
self.signals.output.emit(info_msg, 'normal')
self.signals.run_started.emit(self.output_file)
except Exception as e2:
error_msg2 = f"备用启动方法也失败: {str(e2)}\n"
self.signals.output.emit(error_msg2, 'error')
else:
error_msg = f"错误: 可执行文件不存在: {self.output_file}\n"
self.signals.output.emit(error_msg, 'error')
else:
# Linux/Mac系统:直接运行程序
if os.path.exists(self.output_file):
# 确保文件有可执行权限
os.chmod(self.output_file, 0o755)
# 在终端中运行程序
try:
# 设置环境变量,确保UTF-8编码
env = os.environ.copy()
env['LC_ALL'] = 'en_US.UTF-8'
env['LANG'] = 'en_US.UTF-8'
if sys.platform == 'darwin': # macOS
# 使用osascript在Terminal中运行并设置环境变量
applescript = f'''
tell application "Terminal"
activate
do script "export LC_ALL=en_US.UTF-8 && export LANG=en_US.UTF-8 && {self.output_file} && echo '' && echo '程序执行完毕,按回车键退出...' && read"
end tell
'''
subprocess.Popen(['osascript', '-e', applescript])
else: # Linux
# 使用x-terminal-emulator运行并设置环境变量
subprocess.Popen(['x-terminal-emulator', '-e',
f'bash -c "export LC_ALL=en_US.UTF-8 && export LANG=en_US.UTF-8 && {self.output_file} && echo && echo 程序执行完毕,按回车键退出... && read"'])
info_msg = "程序已在新的终端窗口中启动。\n"
self.signals.output.emit(info_msg, 'normal')
if self.use_saved_file:
self.signals.output.emit(f"可执行文件已保存到: {self.output_file}\n", 'normal')
self.signals.run_started.emit(self.output_file)
except Exception as e:
error_msg = f"启动程序时出错: {str(e)}\n"
self.signals.output.emit(error_msg, 'error')
else:
error_msg = f"错误: 可执行文件不存在: {self.output_file}\n"
self.signals.output.emit(error_msg, 'error')
except Exception as e:
error_msg = f"运行错误: {str(e)}\n"
self.signals.output.emit(error_msg, 'error')
finally:
# 清理临时源文件
try:
if os.path.exists(self.temp_cpp):
os.unlink(self.temp_cpp)
except:
pass
self.signals.finished.emit()
def stop(self):
"""停止运行"""
self.is_running = False
这里空空如也





















有帮助,赞一个