""" 微信多开对话框 """ import os import subprocess import tempfile from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSpinBox, QFileDialog, QTextEdit, QWidget ) from PyQt6.QtCore import Qt from PyQt6.QtGui import QIcon import ui.theme as theme from db import database _DB_KEY_PATH = "wechat_multi_path" _DB_KEY_COUNT = "wechat_multi_count" _DEFAULT_PATHS = [ r"D:\Softwares\Tencent\Weixin\Weixin.exe", r"C:\Program Files\Tencent\WeChat\WeChat.exe", r"C:\Program Files (x86)\Tencent\WeChat\WeChat.exe", ] _USAGE = """使用说明: 1. 填写微信 Weixin.exe 的完整路径。 点击右侧「浏览」按钮可以直接选择文件。 2. 设置多开数量(建议不超过 5 个, 数量过多可能导致电脑卡顿)。 3. 点击「开始多开」,程序会依次启动 对应数量的微信进程。 4. 每个微信实例需要单独登录账号。 注意:微信官方不支持多开,使用本功能 请自行承担相关风险。 """ def _detect_wechat() -> str: """尝试自动检测微信路径。""" saved = database.get_setting(_DB_KEY_PATH, "") if saved and os.path.isfile(saved): return saved for p in _DEFAULT_PATHS: if os.path.isfile(p): return p return "" class WechatMultiDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("微信多开") self.setMinimumWidth(460) self.setWindowFlags( Qt.WindowType.Dialog | Qt.WindowType.FramelessWindowHint ) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self._drag_pos = None self._build() self._apply_theme() def _build(self): saved_path = _detect_wechat() saved_count = int(database.get_setting(_DB_KEY_COUNT, "2")) root = QVBoxLayout(self) root.setContentsMargins(0, 0, 0, 0) self._card = QWidget() self._card.setObjectName("wechat_card") card_layout = QVBoxLayout(self._card) card_layout.setContentsMargins(20, 16, 20, 16) card_layout.setSpacing(12) # 标题栏 title_row = QHBoxLayout() lbl_title = QLabel("微信多开") lbl_title.setStyleSheet("font-size:14px; font-weight:bold;") close_btn = QPushButton("✕") close_btn.setFixedSize(24, 24) close_btn.setStyleSheet("border:none; background:transparent; font-size:13px;") close_btn.clicked.connect(self.reject) title_row.addWidget(lbl_title) title_row.addStretch() title_row.addWidget(close_btn) card_layout.addLayout(title_row) # 路径 card_layout.addWidget(QLabel("微信程序路径(Weixin.exe):")) path_row = QHBoxLayout() self._path_edit = QLineEdit(saved_path) self._path_edit.setPlaceholderText("请输入或浏览 Weixin.exe 路径") browse_btn = QPushButton("浏览") browse_btn.setFixedWidth(56) browse_btn.clicked.connect(self._browse) path_row.addWidget(self._path_edit) path_row.addWidget(browse_btn) card_layout.addLayout(path_row) # 数量 count_row = QHBoxLayout() count_row.addWidget(QLabel("多开数量:")) self._spin = QSpinBox() self._spin.setRange(2, 9) self._spin.setValue(saved_count) self._spin.setFixedWidth(70) count_row.addWidget(self._spin) count_row.addStretch() card_layout.addLayout(count_row) # 使用说明 usage = QTextEdit() usage.setReadOnly(True) usage.setPlainText(_USAGE) usage.setFixedHeight(150) usage.setStyleSheet("font-size:11px; border-radius:6px;") card_layout.addWidget(usage) # 按钮行 btn_row = QHBoxLayout() btn_row.addStretch() self._start_btn = QPushButton("开始多开") self._start_btn.setFixedHeight(32) self._start_btn.setMinimumWidth(90) self._start_btn.clicked.connect(self._start) cancel_btn = QPushButton("取消") cancel_btn.setFixedHeight(32) cancel_btn.setMinimumWidth(70) cancel_btn.clicked.connect(self.reject) btn_row.addWidget(self._start_btn) btn_row.addWidget(cancel_btn) card_layout.addLayout(btn_row) root.addWidget(self._card) def _apply_theme(self): t = theme.current() is_dark = theme.name() == "dark" self._card.setStyleSheet(f""" QWidget#wechat_card {{ background: {t['panel_bg']}; border-radius: 10px; border: 1px solid {t['panel_border']}; }} QLabel {{ color: {t['search_color']}; background: transparent; }} QLineEdit {{ background: {t['search_bg']}; border: 1px solid {t['search_border']}; border-radius: 5px; color: {t['search_color']}; padding: 4px 8px; }} QSpinBox {{ background: {t['search_bg']}; border: 1px solid {t['search_border']}; border-radius: 5px; color: {t['search_color']}; padding: 2px 4px; }} QTextEdit {{ background: {t['search_bg']}; color: {t['search_color']}; border: 1px solid {t['search_border']}; }} QPushButton {{ border: 1px solid {t['search_border']}; border-radius: 5px; color: {t['btn_color']}; background: {t['search_bg']}; font-size: 12px; padding: 0 10px; }} QPushButton:hover {{ background: {t['header_hover']}; }} """) def _browse(self): path, _ = QFileDialog.getOpenFileName( self, "选择 Weixin.exe", "", "可执行文件 (*.exe)" ) if path: self._path_edit.setText(path) def _start(self): exe = self._path_edit.text().strip() count = self._spin.value() if not exe: self._path_edit.setPlaceholderText("⚠ 请先填写路径") return if not os.path.isfile(exe): self._path_edit.setStyleSheet( self._path_edit.styleSheet() + "border-color: red;" ) return # 保存设置 database.set_setting(_DB_KEY_PATH, exe) database.set_setting(_DB_KEY_COUNT, str(count)) # 写临时 bat,连续 start 多次 lines = ["@echo off"] for _ in range(count): lines.append(f'start "" "{exe}"') bat_content = "\r\n".join(lines) + "\r\n" tmp = tempfile.NamedTemporaryFile( delete=False, suffix=".bat", mode="w", encoding="gbk" ) tmp.write(bat_content) tmp.close() subprocess.Popen( ["cmd", "/c", tmp.name], creationflags=subprocess.CREATE_NO_WINDOW ) self.accept() # 无边框拖动 def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft() def mouseMoveEvent(self, event): if self._drag_pos and event.buttons() & Qt.MouseButton.LeftButton: self.move(event.globalPosition().toPoint() - self._drag_pos) def mouseReleaseEvent(self, event): self._drag_pos = None