C++编辑器-7.1
2026-02-15 14:39:29
发布于:浙江
该代码并不完整,点此进入代码框架页面
class CppIdle(QMainWindow):
"""C++ IDLE主窗口"""
def __init__(self):
super().__init__()
self.current_file = None
self.compiler_path = None
self.include_paths = [] # 存储include路径
self.editor = None
self.output = None
self.config_manager = ConfigManager()
# 新增:存储上次编译的代码哈希值,用于检测代码是否修改
self.last_compiled_hash = {} # key: 输出文件路径, value: 代码哈希值
# 线程池
self.thread_pool = QThreadPool()
print(f"线程池最大线程数: {self.thread_pool.maxThreadCount()}")
# 当前工作线程
self.current_worker = None
# 加载配置
self.config_manager.load_config()
# 获取字体设置
font_family = self.config_manager.get('font_family', 'Courier New')
font_size = self.config_manager.get('font_size', 10)
# 获取自动补全设置
enable_auto_completion = self.config_manager.get('enable_auto_completion', True)
# 创建临时目录
self.temp_dir = self.create_temp_dir()
self.init_ui(font_family, font_size, enable_auto_completion)
self.check_compiler()
# 加载include路径
self.include_paths = self.config_manager.get('include_paths', [])
if not self.include_paths:
# 如果没有保存的路径,自动查找
self.include_paths = self.find_include_paths()
# 恢复窗口状态
self.restore_window_state()
def get_current_code_hash(self):
"""获取当前代码的哈希值,用于检测代码是否修改"""
if self.editor:
code = self.editor.toPlainText()
# 使用MD5计算哈希值
return hashlib.md5(code.encode('utf-8')).hexdigest()
return ""
def restore_window_state(self):
"""恢复窗口状态"""
geometry = self.config_manager.get('window_geometry')
state = self.config_manager.get('window_state')
if geometry:
self.restoreGeometry(geometry)
if state:
self.restoreState(state)
def create_temp_dir(self):
"""创建临时目录"""
# 获取系统临时目录
system_temp_dir = tempfile.gettempdir()
# 创建C++ IDLE的临时目录
cpp_idle_temp_dir = os.path.join(system_temp_dir, "C++_IDLE_temp")
# 确保目录存在
try:
os.makedirs(cpp_idle_temp_dir, exist_ok=True)
print(f"临时目录已创建: {cpp_idle_temp_dir}")
return cpp_idle_temp_dir
except Exception as e:
print(f"创建临时目录失败: {e}")
# 如果创建失败,使用系统临时目录
return system_temp_dir
def cleanup_temp_files(self):
"""清理临时文件"""
try:
if os.path.exists(self.temp_dir):
# 只删除C++_IDLE_temp目录中的文件,不删除目录本身
for filename in os.listdir(self.temp_dir):
file_path = os.path.join(self.temp_dir, filename)
try:
if os.path.isfile(file_path):
os.unlink(file_path)
print(f"已删除临时文件: {file_path}")
except Exception as e:
print(f"删除文件失败 {file_path}: {e}")
print(f"临时目录已清理: {self.temp_dir}")
except Exception as e:
print(f"清理临时文件失败: {e}")
def open_temp_dir(self):
"""打开临时目录"""
try:
if sys.platform == 'win32':
os.startfile(self.temp_dir)
elif sys.platform == 'darwin': # macOS
subprocess.Popen(['open', self.temp_dir])
else: # Linux
subprocess.Popen(['xdg-open', self.temp_dir])
self.statusBar().showMessage(f"已打开临时目录: {self.temp_dir}")
except Exception as e:
QMessageBox.warning(self, "错误", f"无法打开临时目录: {str(e)}")
def save_window_state(self):
"""保存窗口状态"""
self.config_manager.set('window_geometry', self.saveGeometry())
self.config_manager.set('window_state', self.saveState())
self.config_manager.save_config()
def init_ui(self, font_family, font_size, enable_auto_completion):
"""初始化UI"""
self.setWindowTitle("C++ IDLE 3.14.5")
self.setGeometry(100, 100, 800, 600)
# 创建中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)
# 创建编辑器
self.editor = CppEditor(font_family, font_size, enable_auto_completion)
main_layout.addWidget(self.editor)
# 创建输出区域(用于编译信息) - 添加语法高亮支持
self.output = QPlainTextEdit()
self.output.setReadOnly(True)
self.output.setMaximumHeight(120)
font = QFont()
font.setFamily(font_family)
font.setPointSize(font_size - 1 if font_size > 9 else font_size)
self.output.setFont(font)
# 为输出区域创建高亮器
self.output_highlighter = OutputHighlighter(self.output.document())
main_layout.addWidget(self.output)
# 设置默认C++代码
default_code = """#include <iostream>
using namespace std;
int main() {
return 0;
}"""
self.editor.setPlainText(default_code)
# 创建菜单栏
self.create_menus()
# 创建工具栏
self.create_toolbar()
# 创建状态栏
self.statusBar().showMessage("就绪")
# 设置窗口图标
self.setWindowIcon(self.create_cpp_idle_icon())
def create_menus(self):
"""创建菜单栏"""
menubar = self.menuBar()
# 文件菜单
file_menu = menubar.addMenu("文件(&F)")
new_action = QAction("新建(&N)", self)
new_action.setShortcut("Ctrl+N")
new_action.triggered.connect(self.new_file)
file_menu.addAction(new_action)
open_action = QAction("打开(&O)...", self)
open_action.setShortcut("Ctrl+O")
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)
save_action = QAction("保存(&S)", self)
save_action.setShortcut("Ctrl+S")
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)
save_as_action = QAction("另存为(&A)...", self)
save_as_action.triggered.connect(self.save_file_as)
file_menu.addAction(save_as_action)
file_menu.addSeparator()
exit_action = QAction("退出(&X)", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
# 编辑菜单
edit_menu = menubar.addMenu("编辑(&E)")
# 检查编辑器是否已创建
if self.editor:
undo_action = QAction("撤销(&U)", self)
undo_action.setShortcut("Ctrl+Z")
undo_action.triggered.connect(self.editor.undo)
edit_menu.addAction(undo_action)
redo_action = QAction("重做(&R)", self)
redo_action.setShortcut("Ctrl+Shift+Z")
redo_action.triggered.connect(self.editor.redo)
edit_menu.addAction(redo_action)
edit_menu.addSeparator()
cut_action = QAction("剪切(&T)", self)
cut_action.setShortcut("Ctrl+X")
cut_action.triggered.connect(self.editor.cut)
edit_menu.addAction(cut_action)
copy_action = QAction("复制(&C)", self)
copy_action.setShortcut("Ctrl+C")
copy_action.triggered.connect(self.editor.copy)
edit_menu.addAction(copy_action)
paste_action = QAction("粘贴(&P)", self)
paste_action.setShortcut("Ctrl+V")
paste_action.triggered.connect(self.editor.paste)
edit_menu.addAction(paste_action)
edit_menu.addSeparator()
# 添加自动缩进相关菜单项
indent_action = QAction("增加缩进(&I)", self)
indent_action.setShortcut("Tab")
indent_action.triggered.connect(self.indent_text)
edit_menu.addAction(indent_action)
unindent_action = QAction("减少缩进(&U)", self)
unindent_action.setShortcut("Shift+Tab")
unindent_action.triggered.connect(self.unindent_text)
edit_menu.addAction(unindent_action)
else:
# 如果编辑器未创建,添加禁用的菜单项
edit_menu.addAction("编辑器未初始化").setEnabled(False)
# 设置菜单
settings_menu = menubar.addMenu("设置(&S)")
# 字体设置
font_action = QAction("字体设置(&F)...", self)
font_action.triggered.connect(self.configure_font)
settings_menu.addAction(font_action)
include_paths_action = QAction("Include路径(&I)...", self)
include_paths_action.triggered.connect(self.configure_include_paths)
settings_menu.addAction(include_paths_action)
# 自动补全设置
auto_completion_action = QAction("启用自动补全(&A)", self)
auto_completion_action.setCheckable(True)
auto_completion_action.setChecked(self.editor.enable_auto_completion)
auto_completion_action.triggered.connect(self.toggle_auto_completion)
settings_menu.addAction(auto_completion_action)
settings_menu.addSeparator()
# 编码设置子菜单
encoding_menu = settings_menu.addMenu("运行编码(&E)")
utf8_action = QAction("UTF-8", self)
utf8_action.setCheckable(True)
utf8_action.triggered.connect(lambda: self.set_run_encoding('utf-8'))
encoding_menu.addAction(utf8_action)
gbk_action = QAction("GBK", self)
gbk_action.setCheckable(True)
gbk_action.triggered.connect(lambda: self.set_run_encoding('gbk'))
encoding_menu.addAction(gbk_action)
# 设置当前编码
current_encoding = self.config_manager.get('run_encoding', 'utf-8')
if current_encoding == 'utf-8':
utf8_action.setChecked(True)
else:
gbk_action.setChecked(True)
# 工具菜单
tools_menu = menubar.addMenu("工具(&T)")
# 清理临时文件
cleanup_action = QAction("清理临时文件(&C)", self)
cleanup_action.triggered.connect(self.cleanup_temp_files)
tools_menu.addAction(cleanup_action)
# 打开临时目录
open_temp_dir_action = QAction("打开临时目录(&O)", self)
open_temp_dir_action.triggered.connect(self.open_temp_dir)
tools_menu.addAction(open_temp_dir_action)
# 运行菜单
run_menu = menubar.addMenu("运行(&R)")
run_action = QAction("运行模块(&F5)", self)
run_action.setShortcut("F5")
run_action.triggered.connect(self.run_code)
run_menu.addAction(run_action)
compile_action = QAction("编译(&C)", self)
compile_action.setShortcut("F6")
compile_action.triggered.connect(self.compile_code)
run_menu.addAction(compile_action)
# 停止按钮(新增)
stop_action = QAction("停止执行(&S)", self)
stop_action.setShortcut("Ctrl+.")
stop_action.triggered.connect(self.stop_execution)
run_menu.addAction(stop_action)
# 帮助菜单
help_menu = menubar.addMenu("帮助(&H)")
about_action = QAction("关于(&A)", self)
about_action.triggered.connect(self.about)
help_menu.addAction(about_action)
def create_toolbar(self):
"""创建工具栏"""
toolbar = self.addToolBar("工具")
# 新建按钮
new_action = QAction(QIcon.fromTheme("document-new"), "新建", self)
new_action.triggered.connect(self.new_file)
toolbar.addAction(new_action)
# 打开按钮
open_action = QAction(QIcon.fromTheme("document-open"), "打开", self)
open_action.triggered.connect(self.open_file)
toolbar.addAction(open_action)
# 保存按钮
save_action = QAction(QIcon.fromTheme("document-save"), "保存", self)
save_action.triggered.connect(self.save_file)
toolbar.addAction(save_action)
toolbar.addSeparator()
# 运行按钮
run_action = QAction(QIcon.fromTheme("media-playback-start"), "运行", self)
run_action.triggered.connect(self.run_code)
toolbar.addAction(run_action)
# 编译按钮
compile_action = QAction(QIcon.fromTheme("system-run"), "编译", self)
compile_action.triggered.connect(self.compile_code)
toolbar.addAction(compile_action)
# 停止按钮
stop_action = QAction(QIcon.fromTheme("media-playback-stop"), "停止", self)
stop_action.triggered.connect(self.stop_execution)
toolbar.addAction(stop_action)
def create_cpp_idle_icon(self):
"""创建C++ IDLE图标"""
# 创建一个简单的C++ IDLE图标(模仿Python IDLE的样式)
pixmap = QPixmap(64, 64)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
# 绘制白纸背景
painter.setBrush(QColor(255, 255, 255))
painter.setPen(QColor(200, 200, 200))
painter.drawRoundedRect(4, 4, 56, 56, 8, 8)
# 绘制C++文字
painter.setPen(QColor(0, 0, 255))
font = QFont()
font.setPointSize(20)
font.setBold(True)
painter.setFont(font)
painter.drawText(0, 0, 64, 64, Qt.AlignCenter, "C++")
painter.end()
return QIcon(pixmap)
def toggle_auto_completion(self):
"""切换自动补全状态"""
enabled = not self.editor.enable_auto_completion
self.editor.set_auto_completion(enabled)
# 更新配置
self.config_manager.set('enable_auto_completion', enabled)
self.config_manager.save_config()
# 更新菜单项状态
for action in self.menuBar().findChildren(QAction):
if action.text() == "启用自动补全(&A)":
action.setChecked(enabled)
status = "启用" if enabled else "禁用"
self.statusBar().showMessage(f"自动补全已{status}")
def indent_text(self):
"""增加缩进"""
cursor = self.editor.textCursor()
# 如果有选中文本,则缩进选中的行
if cursor.hasSelection():
# 获取选中的起始和结束位置
start = cursor.selectionStart()
end = cursor.selectionEnd()
# 获取起始和结束块
document = self.editor.document()
start_block = document.findBlock(start)
end_block = document.findBlock(end)
# 如果结束位置在块开头,则不包含该块
if end == end_block.position():
end_block = end_block.previous()
# 批量编辑
cursor.beginEditBlock()
# 为每个选中的行添加缩进
block = start_block
while block.isValid() and block.blockNumber() <= end_block.blockNumber():
cursor.setPosition(block.position())
cursor.insertText(' ')
block = block.next()
cursor.endEditBlock()
# 恢复选中状态
cursor.setPosition(start_block.position())
cursor.setPosition(end_block.position() + end_block.length(), QTextCursor.KeepAnchor)
# 如果结束块不是最后一个块,调整结束位置
if end_block.next().isValid():
cursor.setPosition(end_block.position() + end_block.length(), QTextCursor.KeepAnchor)
self.editor.setTextCursor(cursor)
else:
# 否则插入4个空格
cursor.insertText(' ')
def unindent_text(self):
"""减少缩进"""
cursor = self.editor.textCursor()
# 如果有选中文本,则减少选中行的缩进
if cursor.hasSelection():
# 获取选中的起始和结束位置
start = cursor.selectionStart()
end = cursor.selectionEnd()
# 获取起始和结束块
document = self.editor.document()
start_block = document.findBlock(start)
end_block = document.findBlock(end)
# 如果结束位置在块开头,则不包含该块
if end == end_block.position():
end_block = end_block.previous()
# 批量编辑
cursor.beginEditBlock()
# 为每个选中的行减少缩进
block = start_block
while block.isValid() and block.blockNumber() <= end_block.blockNumber():
block_text = block.text()
# 检查行首是否有4个空格或1个Tab
if block_text.startswith(' '):
# 删除4个空格
cursor.setPosition(block.position())
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 4)
cursor.removeSelectedText()
elif block_text.startswith('\t'):
# 删除1个Tab
cursor.setPosition(block.position())
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 1)
cursor.removeSelectedText()
block = block.next()
cursor.endEditBlock()
# 恢复选中状态
cursor.setPosition(start_block.position())
cursor.setPosition(end_block.position() + end_block.length(), QTextCursor.KeepAnchor)
# 如果结束块不是最后一个块,调整结束位置
if end_block.next().isValid():
cursor.setPosition(end_block.position() + end_block.length(), QTextCursor.KeepAnchor)
self.editor.setTextCursor(cursor)
def set_run_encoding(self, encoding):
"""设置运行编码"""
self.config_manager.set('run_encoding', encoding)
self.config_manager.save_config()
self.statusBar().showMessage(f"运行编码已设置为: {encoding}")
# 更新菜单项的选中状态
for action in self.menuBar().findChildren(QAction):
if action.text() == "UTF-8":
action.setChecked(encoding == 'utf-8')
elif action.text() == "GBK":
action.setChecked(encoding == 'gbk')
def configure_font(self):
"""配置字体"""
current_font = self.editor.font()
dialog = FontDialog(current_font.family(), current_font.pointSize(), self)
if dialog.exec_() == QDialog.Accepted:
font_family, font_size = dialog.get_font_settings()
# 更新编辑器字体
self.editor.set_editor_font(font_family, font_size)
# 更新输出区域字体
font = QFont()
font.setFamily(font_family)
font.setPointSize(font_size - 1 if font_size > 9 else font_size)
self.output.setFont(font)
# 保存配置
self.config_manager.set('font_family', font_family)
self.config_manager.set('font_size', font_size)
self.config_manager.save_config()
self.statusBar().showMessage(f"字体已更改为: {font_family}, 大小: {font_size}")
def find_include_paths(self):
"""查找系统中的include路径"""
include_paths = []
# 1. 首先查找编译器自带的include路径
if self.compiler_path:
try:
# 尝试获取编译器的默认include路径
if 'g++' in self.compiler_path or 'gcc' in self.compiler_path:
# 使用gcc/g++的-print-search-dirs选项
result = subprocess.run(
[self.compiler_path, '-print-search-dirs'],
capture_output=True, text=True, encoding='utf-8'
)
if result.returncode == 0:
for line in result.stdout.split('\n'):
if 'libraries:' in line:
paths = line.split('=')[1].strip().split(':')
for path in paths:
if 'include' in path.lower() and os.path.exists(path):
include_paths.append(path)
# 尝试使用编译器的-v选项来查看包含路径
try:
if 'cl' in self.compiler_path.lower():
# MSVC编译器 - 使用/Bv参数获取版本信息,但我们需要包含路径
# 先尝试通过环境变量获取
include_env = os.environ.get('INCLUDE')
if include_env:
for path in include_env.split(';'):
if path.strip() and os.path.exists(path.strip()):
include_paths.append(path.strip())
else:
# GCC/Clang编译器
result = subprocess.run(
[self.compiler_path, '-v', '-E', '-'],
input='',
capture_output=True, text=True, encoding='utf-8'
)
# 解析输出,查找include路径
for line in result.stderr.split('\n') + result.stdout.split('\n'):
line = line.strip()
if 'include' in line.lower() and not line.startswith('#') and not line.startswith('End'):
# 提取路径
if sys.platform == 'win32':
# Windows路径
if ':' in line and ('\\include' in line or '\\Include' in line):
path = line.split()[-1].strip()
if os.path.exists(path):
include_paths.append(path)
else:
# Unix/Linux路径
if '/include' in line and not line.startswith('-'):
path = line.split()[-1].strip()
if os.path.exists(path):
include_paths.append(path)
except:
pass
except:
pass
# 2. 查找常见的标准库路径
common_paths = []
if sys.platform == 'win32':
# Windows路径
# MinGW路径
mingw_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "mingw-w64", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "mingw-w64", "include"),
os.path.join(os.environ.get("ProgramFiles", ""), "mingw64", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "mingw64", "include"),
os.path.join(os.environ.get("ProgramFiles", ""), "MinGW", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "MinGW", "include"),
]
# Visual Studio路径 - C++标准库路径
vs_versions = ["2022", "2019", "2017", "2015"]
vs_editions = ["Community", "Professional", "Enterprise", "BuildTools"]
for version in vs_versions:
for edition in vs_editions:
# Visual Studio的MSVC编译器包含路径
vs_msvc_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", version, edition, "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", version, edition, "VC", "Tools", "MSVC", "*", "include"),
]
# Visual Studio的ATL/MFC包含路径
vs_atl_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", version, edition, "VC", "Tools", "MSVC", "*", "atlmfc", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", version, edition, "VC", "Tools", "MSVC", "*", "atlmfc", "include"),
]
for pattern in vs_msvc_paths + vs_atl_paths:
for path in glob.glob(pattern):
if os.path.exists(path):
common_paths.append(path)
# Windows SDK路径
try:
# 通过注册表查找Windows SDK路径
sdk_roots = []
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows Kits\Installed Roots")
kits_root10, _ = winreg.QueryValueEx(key, "KitsRoot10")
sdk_roots.append(("10", kits_root10))
winreg.CloseKey(key)
except:
pass
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows Kits\Installed Roots")
kits_root81, _ = winreg.QueryValueEx(key, "KitsRoot81")
sdk_roots.append(("8.1", kits_root81))
winreg.CloseKey(key)
except:
pass
for version, kits_root in sdk_roots:
sdk_include = os.path.join(kits_root, "Include")
if os.path.exists(sdk_include):
# 查找所有的SDK版本
for item in os.listdir(sdk_include):
version_path = os.path.join(sdk_include, item)
if os.path.isdir(version_path):
# 检查是否是版本号目录
if any(char.isdigit() for char in item):
um_path = os.path.join(version_path, "um")
shared_path = os.path.join(version_path, "shared")
ucrt_path = os.path.join(version_path, "ucrt")
winrt_path = os.path.join(version_path, "winrt")
if os.path.exists(um_path):
common_paths.append(um_path)
if os.path.exists(shared_path):
common_paths.append(shared_path)
if os.path.exists(ucrt_path):
common_paths.append(ucrt_path)
if os.path.exists(winrt_path):
common_paths.append(winrt_path)
except:
pass
# 查找Visual C++ Build Tools路径
vc_tools_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2022", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2022", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2019", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2019", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2017", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2017", "BuildTools", "VC", "Tools", "MSVC", "*", "include"),
]
for pattern in vc_tools_paths:
for path in glob.glob(pattern):
if os.path.exists(path):
common_paths.append(path)
else:
# Linux/Mac路径
common_paths = [
"/usr/include",
"/usr/local/include",
"/usr/include/c++/*",
"/usr/local/include/c++/*",
"/opt/local/include",
"/opt/homebrew/include", # macOS Homebrew
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", # macOS Xcode
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include", # macOS Xcode SDK
]
# 添加找到的常见路径
for path in common_paths:
if '*' in path:
# 处理通配符
for expanded_path in glob.glob(path):
if os.path.exists(expanded_path):
include_paths.append(expanded_path)
elif os.path.exists(path):
include_paths.append(path)
# 3. 检查路径中是否包含C++标准库文件
valid_include_paths = []
for path in include_paths:
normalized_path = os.path.normpath(path)
# 检查这个路径是否包含C++标准库文件
cpp_headers = ["iostream", "vector", "string", "algorithm", "memory"]
found_header = False
for header in cpp_headers:
# 检查头文件是否存在(可能有.h扩展名,也可能没有)
header_path = os.path.join(normalized_path, header)
if os.path.exists(header_path) or os.path.exists(header_path + ".h"):
found_header = True
break
# 如果找不到标准库头文件,检查是否是包含子目录的路径
if not found_header:
# 检查路径中是否有子目录包含C++头文件
try:
for root, dirs, files in os.walk(normalized_path, topdown=True):
for file in files:
if file in cpp_headers or any(file.startswith(h) for h in cpp_headers):
found_header = True
break
if found_header:
break
except:
pass
# 如果是有效的include路径,添加到列表中
if normalized_path not in valid_include_paths and os.path.exists(normalized_path):
if found_header:
valid_include_paths.append(normalized_path)
else:
# 即使没有找到标准库头文件,也可能是有效的include路径
# 检查路径名中是否包含"include"
if "include" in normalized_path.lower():
valid_include_paths.append(normalized_path)
# 显示找到的路径数量
self.statusBar().showMessage(f"找到 {len(valid_include_paths)} 个include路径")
return valid_include_paths
def check_compiler(self):
"""检查C++编译器"""
# 检查环境变量中的编译器
possible_compilers = ["g++", "gcc", "clang++", "cl"]
for compiler in possible_compilers:
try:
if compiler == "cl": # MSVC编译器使用不同的参数
# 在Windows上,cl通常通过Visual Studio命令提示符使用
result = subprocess.run([compiler],
capture_output=True, text=True, shell=True)
# cl通常会在没有参数时显示使用说明
if "Microsoft" in result.stderr or "Microsoft" in result.stdout or "C/C++" in result.stderr:
self.compiler_path = compiler
self.statusBar().showMessage(f"找到编译器: {compiler} (MSVC)")
return
else:
# g++、gcc、clang++等编译器使用--version参数
result = subprocess.run([compiler, "--version"],
capture_output=True, text=True, shell=True)
if result.returncode == 0 or "gcc" in result.stdout or "clang" in result.stdout:
self.compiler_path = compiler
self.statusBar().showMessage(f"找到编译器: {compiler}")
return
except FileNotFoundError:
continue
except Exception:
continue
# 检查MinGW-w64
mingw_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "mingw-w64", "bin", "g++.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "mingw-w64", "bin", "g++.exe"),
os.path.join(os.environ.get("ProgramFiles", ""), "mingw64", "bin", "g++.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "mingw64", "bin", "g++.exe"),
os.path.join(os.environ.get("ProgramFiles", ""), "MinGW", "bin", "g++.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "MinGW", "bin", "g++.exe"),
]
# 检查Visual Studio的安装路径
vs_paths = [
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2022", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2022", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2019", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2019", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "2017", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "2017", "Community", "VC", "Tools", "MSVC", "*", "bin", "Hostx64", "x64", "cl.exe"),
]
# 检查MinGW路径
for path in mingw_paths:
if os.path.exists(path):
self.compiler_path = path
self.statusBar().showMessage(f"找到编译器: {path}")
return
# 检查Visual Studio路径
for vs_pattern in vs_paths:
for path in glob.glob(vs_pattern):
if os.path.exists(path):
self.compiler_path = path
self.statusBar().showMessage(f"找到编译器: {path}")
return
# 如果没有找到编译器
reply = QMessageBox.warning(
self, "编译器未找到",
"未找到C++编译器(如g++、clang++或MinGW-w64)。\n"
"请安装编译器并将其添加到系统PATH环境变量中。\n\n"
"是否继续运行?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if reply == QMessageBox.No:
self.close()
else:
self.statusBar().showMessage("警告: 未找到编译器,无法编译运行代码")
def configure_include_paths(self):
"""配置include路径"""
dialog = IncludePathsDialog(self)
dialog.paths_edit.setPlainText("\n".join(self.include_paths))
if dialog.exec_() == QDialog.Accepted:
new_paths = dialog.paths_edit.toPlainText().strip().split('\n')
self.include_paths = [path.strip() for path in new_paths if path.strip()]
# 保存配置
self.config_manager.set('include_paths', self.include_paths)
self.config_manager.save_config()
self.statusBar().showMessage(f"已更新include路径 ({len(self.include_paths)} 个)")
def new_file(self):
"""新建文件"""
if self.maybe_save():
if self.editor:
self.editor.clear()
self.current_file = None
self.setWindowTitle("C++ IDLE")
self.statusBar().showMessage("新建文件")
def open_file(self):
"""打开文件"""
if self.maybe_save():
file_name, _ = QFileDialog.getOpenFileName(
self, "打开文件", "", "C++ 文件 (*.cpp *.cxx *.cc *.c);;所有文件 (*.*)"
)
if file_name:
self.load_file(file_name)
def load_file(self, file_name):
"""加载文件 - 改进:支持更多编码"""
# 尝试的编码顺序
encodings_to_try = [
'utf-8',
'gbk',
'gb2312',
'gb18030',
'big5', # 繁体中文
'utf-16',
'utf-16-le', # UTF-16 Little Endian
'utf-16-be', # UTF-16 Big Endian
'iso-8859-1', # Latin-1
'windows-1252', # Windows Latin-1
'cp1250', # Windows Central European
'cp1251', # Windows Cyrillic
'cp1253', # Windows Greek
'shift_jis', # Japanese
'euc-jp', # Japanese
'euc-kr', # Korean
]
# 首先尝试自动检测编码(使用chardet)
detected_encoding = None
try:
# 读取文件前一部分来检测编码
with open(file_name, 'rb') as f:
raw_data = f.read(4096) # 读取前4KB
if raw_data:
result = chardet.detect(raw_data)
if result['confidence'] > 0.7: # 置信度高于70%
detected_encoding = result['encoding']
# 将一些常见别名转换为标准名称
encoding_map = {
'ascii': 'utf-8',
'ISO-8859-1': 'iso-8859-1',
'Windows-1252': 'windows-1252',
}
detected_encoding = encoding_map.get(detected_encoding, detected_encoding)
except Exception as e:
print(f"编码检测失败: {e}")
# 如果检测到编码,优先尝试
if detected_encoding and detected_encoding not in encodings_to_try:
encodings_to_try.insert(0, detected_encoding)
# 添加系统默认编码和区域编码
try:
system_encoding = locale.getpreferredencoding()
if system_encoding and system_encoding not in encodings_to_try:
encodings_to_try.append(system_encoding)
except:
pass
# 尝试所有编码
last_error = None
for encoding in encodings_to_try:
try:
with open(file_name, 'r', encoding=encoding, errors='strict') as f:
content = f.read()
if self.editor:
self.editor.setPlainText(content)
self.current_file = file_name
self.setWindowTitle(f"C++ IDLE 3.14.5 - {os.path.basename(file_name)}")
# 记录使用的编码
if encoding == detected_encoding:
self.statusBar().showMessage(f"已打开(自动检测到{encoding}编码): {file_name}")
else:
self.statusBar().showMessage(f"已打开({encoding}编码): {file_name}")
# 更新配置中的编码设置(如果是常见编码)
if encoding in ['utf-8', 'gbk', 'gb2312', 'gb18030']:
self.config_manager.set('last_file_encoding', encoding)
self.config_manager.save_config()
return
except UnicodeDecodeError as e:
last_error = e
continue
except Exception as e:
last_error = e
continue
# 如果所有编码都失败,使用宽松模式
try:
with open(file_name, 'r', encoding='utf-8', errors='replace') as f:
content = f.read()
if self.editor:
self.editor.setPlainText(content)
self.current_file = file_name
self.setWindowTitle(f"C++ IDLE 3.14.5 - {os.path.basename(file_name)}")
self.statusBar().showMessage(f"已打开(UTF-8宽松模式,部分字符可能显示不正确): {file_name}")
# 显示警告
QMessageBox.warning(
self,
"编码警告",
f"无法确定文件编码,已使用UTF-8宽松模式打开。\n"
f"文件中可能包含无法识别的字符,已用�代替。\n\n"
f"文件: {os.path.basename(file_name)}"
)
except Exception as e:
QMessageBox.critical(
self,
"打开文件失败",
f"无法打开文件: {file_name}\n\n"
f"错误: {str(e)}\n\n"
f"已尝试的编码: {', '.join(encodings_to_try[:5])}..."
)
def save_file(self):
"""保存文件"""
if self.current_file:
try:
# 确保使用UTF-8编码保存文件
with open(self.current_file, 'w', encoding='utf-8') as f:
if self.editor:
f.write(self.editor.toPlainText())
self.statusBar().showMessage(f"已保存(UTF-8编码): {self.current_file}")
return True
except Exception as e:
QMessageBox.warning(self, "错误", f"无法保存文件: {str(e)}")
return False
else:
return self.save_file_as()
def save_file_as(self):
"""另存为"""
file_name, _ = QFileDialog.getSaveFileName(
self, "另存为", "", "C++ 文件 (*.cpp *.cxx *.cc *.c);;所有文件 (*.*)"
)
if file_name:
self.current_file = file_name
self.setWindowTitle(f"C++ IDLE 3.14.5 - {os.path.basename(file_name)}")
return self.save_file()
return False
def maybe_save(self):
"""检查是否需要保存"""
if not self.editor or not self.editor.document().isModified():
return True
reply = QMessageBox.question(
self, "保存文件",
"文件已被修改,是否保存更改?",
QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
QMessageBox.Save
)
if reply == QMessageBox.Save:
return self.save_file()
elif reply == QMessageBox.Discard:
return True
else:
return False
代码过长,下文:C++编辑器-7.2
这里空空如也





















有帮助,赞一个