from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QLabel, QHBoxLayout, QListWidget, QStackedWidget, QPushButton, QLineEdit, QMessageBox, QFormLayout, QComboBox, QListWidgetItem, QFrame, QScrollArea, QAbstractItemView, ) from PyQt6.QtCore import Qt, QEvent, QObject, QThread, QTimer, pyqtSignal from PyQt6.QtGui import QMouseEvent import codecs from utils.wifi_manager import WifiManager from utils.floating_keyboard import FloatingKeyboard class DragScrollArea(QScrollArea): """支持鼠标/触屏点击拖拽滑动的滚动区域""" def __init__(self, parent=None): super().__init__(parent) self._press_pos = None self._start_value = 0 self._dragging = False def viewportEvent(self, event): etype = event.type() if etype == QEvent.Type.MouseButtonPress: if event.button() == Qt.MouseButton.LeftButton: self._press_pos = event.position().toPoint() self._start_value = self.verticalScrollBar().value() self._dragging = False elif etype == QEvent.Type.MouseMove: if self._press_pos and event.buttons() & Qt.MouseButton.LeftButton: pos = event.position().toPoint() delta = pos - self._press_pos # 移动超过15px阈值才触发拖拽,避免误触 if self._dragging or delta.manhattanLength() > 15: self._dragging = True new_val = self._start_value - delta.y() # 限制在有效范围内 self.verticalScrollBar().setValue( max(0, min(new_val, self.verticalScrollBar().maximum())) ) return True # 拖拽中拦截事件,不传递给子控件 elif etype == QEvent.Type.MouseButtonRelease: if event.button() == Qt.MouseButton.LeftButton and self._press_pos is not None: was_dragging = self._dragging self._press_pos = None self._dragging = False if was_dragging: return True # 拖拽结束,拦截释放事件,避免触发子控件点击 return super().viewportEvent(event) class DraggableListWidget(QListWidget): """支持鼠标/触屏点击拖拽滑动的列表控件""" def __init__(self, parent=None): super().__init__(parent) self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self._press_pos = None self._start_value = 0 self._dragging = False def viewportEvent(self, event): etype = event.type() if etype == QEvent.Type.MouseButtonPress: if event.button() == Qt.MouseButton.LeftButton: self._press_pos = event.position().toPoint() self._start_value = self.verticalScrollBar().value() self._dragging = False elif etype == QEvent.Type.MouseMove: if self._press_pos and event.buttons() & Qt.MouseButton.LeftButton: pos = event.position().toPoint() delta = pos - self._press_pos # 移动超过15px阈值才触发拖拽,避免误触 if self._dragging or delta.manhattanLength() > 15: self._dragging = True new_val = self._start_value - int(delta.y()) # 限制在有效范围内 self.verticalScrollBar().setValue( max(0, min(new_val, self.verticalScrollBar().maximum())) ) return True # 拖拽中拦截事件,不传递给子控件 elif etype == QEvent.Type.MouseButtonRelease: if event.button() == Qt.MouseButton.LeftButton and self._press_pos is not None: was_dragging = self._dragging self._press_pos = None self._dragging = False if was_dragging: return True # 拖拽结束,拦截释放事件,避免触发子控件点击 return super().viewportEvent(event) class WifiScanWorker(QObject): """在后台线程中执行WiFi扫描,避免阻塞UI""" scan_finished = pyqtSignal(list) scan_error = pyqtSignal(str) def __init__(self, wifi_manager): super().__init__() self.wifi_manager = wifi_manager def run(self): try: networks = self.wifi_manager.scan_networks() self.scan_finished.emit(networks) except Exception as e: self.scan_error.emit(str(e)) class SettingPage(QWidget): def __init__(self, api_client, parent=None): super().__init__(parent) self.api_client = api_client self.wifi_manager = WifiManager() self._saved_networks_cache = [] # 缓存上次的已保存网络列表 # 让页面自身能接收焦点,用于点击扫描按钮后转移焦点防止跳动 self.setFocusPolicy(Qt.FocusPolicy.ClickFocus) # 创建悬浮键盘 self._keyboard = FloatingKeyboard() self._keyboard_attached = False self.init_ui() self._start_status_timer() def _attach_keyboard(self, widget): """将悬浮键盘绑定到指定输入框并显示""" self._keyboard.attach(widget) self._keyboard.show_below(widget) self._keyboard_attached = True def _dismiss_keyboard(self): """关闭悬浮键盘""" self._keyboard.hide() self._keyboard.detach() self._keyboard_attached = False def _on_input_focus_in(self, widget): """输入框获得焦点时的处理""" self._attach_keyboard(widget) def eventFilter(self, obj, event): if event.type() == QEvent.Type.FocusIn: if obj in (self.ssid_input, self.identity_input, self.password_input): self._attach_keyboard(obj) # 如果不是输入框获得焦点且键盘正显示,则关闭键盘 elif self._keyboard_attached and not isinstance(obj, (QLineEdit, QComboBox, QPushButton)): self._dismiss_keyboard() elif event.type() == QEvent.Type.FocusOut: # 延迟检查:如果焦点真的离开了所有输入框,就关闭键盘 if obj in (self.ssid_input, self.identity_input, self.password_input): QTimer.singleShot(100, self._check_dismiss_keyboard) return super().eventFilter(obj, event) def _check_dismiss_keyboard(self): """检查当前焦点是否还在任何输入控件上,不在则关闭键盘""" w = self.focusWidget() if w not in (self.ssid_input, self.identity_input, self.password_input, self.auth_combo): self._dismiss_keyboard() @staticmethod def _styled_message(icon, parent, title, text, buttons=QMessageBox.StandardButton.Ok): """显示与整体风格一致的暗色主题消息框""" msg = QMessageBox(parent) msg.setIcon(icon) msg.setWindowTitle(title) msg.setText(text) msg.setStandardButtons(buttons) msg.setStyleSheet(""" QMessageBox { background-color: #3f3f3f; color: #f2f2f2; border: 2px solid #646464; border-radius: 12px; padding: 20px; } QMessageBox QLabel { color: #f2f2f2; font-size: 20px; padding: 10px; } QMessageBox QPushButton { min-width: 130px; min-height: 50px; font-size: 20px; font-weight: 600; color: #f8f8f8; background-color: #555555; border: 2px solid #888888; border-radius: 10px; padding: 8px 24px; } QMessageBox QPushButton:hover { background-color: #636363; border-color: #aaaaaa; } QMessageBox QPushButton:pressed { background-color: #3d3d3d; border-color: #5a9fcf; } """) return msg.exec() def init_ui(self): layout = QHBoxLayout(self) layout.setContentsMargins(14, 14, 14, 14) layout.setSpacing(14) left_panel = QFrame() left_panel.setStyleSheet("background-color: #3f3f3f; border-radius: 10px;") left_layout = QVBoxLayout(left_panel) left_layout.setContentsMargins(10, 10, 10, 10) title = QLabel("系统设置") title.setAlignment(Qt.AlignmentFlag.AlignCenter) title.setStyleSheet("color: #efefef; font-size: 24px; font-weight: 600;") left_layout.addWidget(title) # 左侧设置项列表(启用平滑/按像素滚动,增大触摸目标) self.item_list = QListWidget() self.item_list.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self.item_list.setSpacing(6) self.item_list.setUniformItemSizes(False) self.item_list.setStyleSheet( """ QListWidget { background-color: #4a4a4a; color: #f2f2f2; border: 1px solid #646464; border-radius: 8px; font-size: 22px; outline: none; } QListWidget::item { height: 56px; padding-left: 10px; border-radius: 6px; } QListWidget::item:selected { background-color: #2f6f91; color: white; } """ ) self.item_list.addItem("WiFi设置") self.item_list.addItem("其它设置(待定)") self.item_list.currentRowChanged.connect(self.display_setting) left_layout.addWidget(self.item_list) layout.addWidget(left_panel, 1) # 右侧设置参数区域(放入可滚动区域,便于触屏上下滑动) self.settings_stack = QStackedWidget() self.settings_stack.setStyleSheet("background-color: #444444; border-radius: 10px;") self.init_wifi_settings() self.init_todo_settings() right_scroll = DragScrollArea() right_scroll.setWidgetResizable(True) right_scroll.setFrameShape(QFrame.Shape.NoFrame) # 将堆叠面板放入 scroll area right_scroll.setWidget(self.settings_stack) right_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) right_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) layout.addWidget(right_scroll, 3) self.item_list.setCurrentRow(0) def init_wifi_settings(self): wifi_widget = QWidget() wifi_widget.setStyleSheet( """ /* ------ 通用标签 ------ */ QLabel { color: #e8e8e8; } /* ------ 大按钮:清晰边框、足够高度 ------ */ QPushButton { min-height: 50px; font-size: 20px; font-weight: 600; color: #f8f8f8; background-color: #555555; border: 2px solid #888888; border-radius: 10px; padding: 10px 24px; } QPushButton:hover { background-color: #636363; border-color: #aaaaaa; } QPushButton:pressed { background-color: #3d3d3d; border-color: #5a9fcf; } QPushButton:disabled { color: #808080; background-color: #404040; border-color: #555555; } /* ------ 输入框 ------ */ QLineEdit { min-height: 44px; font-size: 18px; color: #f2f2f2; background-color: #3a3a3a; border: 2px solid #707070; border-radius: 8px; padding: 4px 12px; } QLineEdit:focus { border-color: #5a9fcf; } /* ------ 下拉框 ------ */ QComboBox { min-height: 44px; font-size: 18px; color: #f2f2f2; background-color: #3a3a3a; border: 2px solid #707070; border-radius: 8px; padding: 4px 12px; } QComboBox:hover { border-color: #aaaaaa; } QComboBox QAbstractItemView { background-color: #3a3a3a; color: #f2f2f2; selection-background-color: #2f6f91; border: 1px solid #707070; font-size: 18px; } /* ------ 列表控件 ------ */ QListWidget { min-height: 300px; max-width: 500%; background-color: #3a3a3a; color: #f2f2f2; border: 2px solid #707070; border-radius: 8px; font-size: 18px; outline: none; } QListWidget::item { min-height: 40px; padding: 4px 10px; border-radius: 4px; } QListWidget::item:selected { background-color: #2f6f91; color: #ffffff; } QListWidget::item:selected QLabel { color: #ffffff; } QListWidget::item:hover { background-color: #505050; } """ ) wifi_layout = QVBoxLayout(wifi_widget) wifi_layout.setContentsMargins(16, 16, 16, 16) wifi_layout.setSpacing(14) wifi_title = QLabel("WiFi设置") wifi_title.setStyleSheet("color: #f2f2f2; font-size: 26px; font-weight: 700;") wifi_layout.addWidget(wifi_title) self.current_status_label = QLabel("当前连接:未知") self.current_status_label.setStyleSheet("color: #cccccc; font-size: 19px; font-weight: 500;") wifi_layout.addWidget(self.current_status_label) # 显示保存的WiFi列表 saved_title = QLabel("已保存网络") saved_title.setStyleSheet("color: #dcdcdc; font-size: 22px; font-weight: 600;") wifi_layout.addWidget(saved_title) self.saved_wifi_list = DraggableListWidget() wifi_layout.addWidget(self.saved_wifi_list) saved_buttons_layout = QHBoxLayout() saved_buttons_layout.setSpacing(12) connect_saved_button = QPushButton("连接到此网络") connect_saved_button.clicked.connect(self.connect_to_saved_wifi) saved_buttons_layout.addWidget(connect_saved_button) remove_saved_button = QPushButton("删除选中") remove_saved_button.clicked.connect(self.remove_selected_saved_wifi) saved_buttons_layout.addWidget(remove_saved_button) wifi_layout.addLayout(saved_buttons_layout) nearby_title = QLabel("附近网络") nearby_title.setStyleSheet("color: #dcdcdc; font-size: 22px; font-weight: 600;") wifi_layout.addWidget(nearby_title) self.nearby_wifi_list = DraggableListWidget() self.nearby_wifi_list.itemClicked.connect(self.fill_ssid_from_scan) wifi_layout.addWidget(self.nearby_wifi_list) self.scan_button = QPushButton("扫描网络") self.scan_button.clicked.connect(self.scan_nearby_wifi) wifi_layout.addWidget(self.scan_button) # 连接新WiFi connect_title = QLabel("连接新网络") connect_title.setStyleSheet("color: #dcdcdc; font-size: 22px; font-weight: 600;") wifi_layout.addWidget(connect_title) form = QFormLayout() form.setLabelAlignment(Qt.AlignmentFlag.AlignRight) form.setFormAlignment(Qt.AlignmentFlag.AlignLeft) form.setHorizontalSpacing(16) form.setVerticalSpacing(12) # 表单标签使用浅色 ssid_label = QLabel("SSID") ssid_label.setStyleSheet("color: #d0d0d0; font-size: 19px; font-weight: 500;") self.ssid_input = QLineEdit() self.ssid_input.setStyleSheet("max-width: 400%;") self.ssid_input.setPlaceholderText("输入WiFi名称") self.ssid_input.installEventFilter(self) self.ssid_input.textChanged.connect(self._on_ssid_text_changed) form.addRow(ssid_label, self.ssid_input) auth_label = QLabel("认证方式") auth_label.setStyleSheet("color: #d0d0d0; font-size: 19px; font-weight: 500;") self.auth_combo = QComboBox() self.auth_combo.setStyleSheet( """ QComboBox { max-width: 400%; font-size: 22px; min-height: 44px; } """ ) # 直接设置下拉列表视图的样式,避免被父级样式覆盖 self.auth_combo.view().setStyleSheet( """ QListView { font-size: 24px; min-height: 50px; padding: 6px 12px; } QListView::item { min-height: 50px; padding: 8px 12px; } """ ) self.auth_combo.addItem("开放网络(无密码)", "open") self.auth_combo.addItem("WPA/WPA2-PSK", "psk") self.auth_combo.addItem("WPA-EAP (PEAP/MSCHAPv2)", "eap") self.auth_combo.currentIndexChanged.connect(self.update_auth_fields) form.addRow(auth_label, self.auth_combo) identity_label = QLabel("身份") identity_label.setStyleSheet("color: #d0d0d0; font-size: 19px; font-weight: 500;") self.identity_label = identity_label self.identity_input = QLineEdit() self.identity_input.setStyleSheet("max-width: 400%;") self.identity_input.setPlaceholderText("企业网络用户名/身份") self.identity_input.installEventFilter(self) form.addRow(identity_label, self.identity_input) password_label = QLabel("密码") password_label.setStyleSheet("color: #d0d0d0; font-size: 19px; font-weight: 500;") self.password_label = password_label self.password_input = QLineEdit() self.password_input.setStyleSheet("max-width: 400%;") self.password_input.setPlaceholderText("输入WiFi密码") self.password_input.installEventFilter(self) self.password_input.setEchoMode(QLineEdit.EchoMode.Password) form.addRow(password_label, self.password_input) wifi_layout.addLayout(form) # 连接按钮使用醒目的强调色 connect_button = QPushButton("连接") connect_button.setStyleSheet( """ QPushButton { min-height: 52px; font-size: 22px; font-weight: 700; color: #ffffff; background-color: #2f6f91; border: 2px solid #4a9fc8; border-radius: 10px; padding: 10px 24px; } QPushButton:hover { background-color: #3a85b3; border-color: #6fb8dd; } QPushButton:pressed { background-color: #1e4d66; border-color: #2f6f91; } """ ) connect_button.clicked.connect(self.connect_to_wifi) wifi_layout.addWidget(connect_button) wifi_layout.addStretch() self.settings_stack.addWidget(wifi_widget) self.update_auth_fields() self.refresh_saved_wifi() self.refresh_current_status() def init_todo_settings(self): todo_widget = QWidget() todo_widget.setStyleSheet( """ QLabel { color: #e4e4e4; } QPushButton { min-height: 50px; font-size: 20px; font-weight: 600; color: #f8f8f8; background-color: #555555; border: 2px solid #888888; border-radius: 10px; padding: 10px 24px; } QPushButton:hover { background-color: #636363; border-color: #aaaaaa; } """ ) todo_layout = QVBoxLayout(todo_widget) todo_layout.setContentsMargins(20, 20, 20, 20) label = QLabel("其它配置项待定") label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setStyleSheet("color: #cecece; font-size: 26px; font-weight: 600;") todo_layout.addWidget(label) hint = QLabel("更多设置项将在后续版本中添加") hint.setAlignment(Qt.AlignmentFlag.AlignCenter) hint.setStyleSheet("color: #909090; font-size: 18px; margin-top: 12px;") todo_layout.addWidget(hint) todo_layout.addStretch() self.settings_stack.addWidget(todo_widget) def refresh_saved_wifi(self): try: saved_networks = self.wifi_manager.list_saved_networks() except Exception as e: self._styled_message(QMessageBox.Icon.Critical, self, "错误", f"无法加载保存的WiFi: {str(e)}") return # 比较与上次缓存的网络列表是否有变化 cache_key = [(n.get("network_id"), n.get("ssid"), n.get("flags")) for n in saved_networks] if cache_key == self._saved_networks_cache: return # 无变化,不清空列表 self._saved_networks_cache = cache_key # 列表有变化时才真正刷新 current_item = self.saved_wifi_list.currentItem() current_net_id = current_item.data(Qt.ItemDataRole.UserRole).get("network_id") if current_item else None self.saved_wifi_list.clear() for network in saved_networks: item_text = f"[{network.get('network_id', '-')}] {network.get('ssid', '')} {network.get('flags', '')}" item = QListWidgetItem(item_text) item.setData(Qt.ItemDataRole.UserRole, network) self.saved_wifi_list.addItem(item) # 恢复选中 if current_net_id is not None and network.get("network_id") == current_net_id: self.saved_wifi_list.setCurrentItem(item) def scan_nearby_wifi(self): """在后台线程中扫描WiFi,防止界面卡死""" self.nearby_wifi_list.clear() # 把焦点交给页面自身,防止跳到输入框导致画面跳动 self.setFocus() self.scan_button.setEnabled(False) self.scan_button.setText("扫描中……") self._scan_thread = QThread() self._scan_worker = WifiScanWorker(self.wifi_manager) self._scan_worker.moveToThread(self._scan_thread) self._scan_thread.started.connect(self._scan_worker.run) self._scan_worker.scan_finished.connect(self._on_scan_finished) self._scan_worker.scan_error.connect(self._on_scan_error) # 清理线程资源 self._scan_worker.scan_finished.connect(self._scan_thread.quit) self._scan_worker.scan_error.connect(self._scan_thread.quit) self._scan_worker.scan_finished.connect(self._scan_worker.deleteLater) self._scan_worker.scan_error.connect(self._scan_worker.deleteLater) self._scan_thread.finished.connect(self._scan_thread.deleteLater) self._scan_thread.start() def _on_scan_finished(self, networks): """扫描完成后的UI更新(主线程中执行)""" self.scan_button.setEnabled(True) self.scan_button.setText("扫描网络") processed = self._deduplicate_networks(networks) if not processed: self._styled_message(QMessageBox.Icon.Information, self, "提示", "未扫描到可用网络") return for network in processed: ssid = network.get("ssid", "") if not ssid: continue decoded_ssid = self._decode_ssid(ssid) signal = network.get("signal_level", "") # 自定义列表项:SSID靠左,信号强度靠右 item_widget = QWidget() item_widget.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) # 为了比较好看的列表项目,下面的不要删 item_widget.setStyleSheet(""" QWidget { min-height: 40px; padding: 4px 10px; border-radius: 4px; } QWidget:selected { background-color: #2f6f91; color: #ffffff; } QWidget:selected QLabel { color: #ffffff; } QWidget:hover { background-color: #505050; } """) item_layout = QHBoxLayout(item_widget) item_layout.setContentsMargins(8, 2, 12, 2) ssid_label = QLabel(decoded_ssid) ssid_label.setStyleSheet("background: transparent; color: #f2f2f2; font-size: 18px;") signal_label = QLabel(f"{signal} dBm" if signal else "") signal_label.setStyleSheet("background: transparent; color: #aaaaaa; font-size: 16px;") item_layout.addWidget(ssid_label) item_layout.addStretch() item_layout.addWidget(signal_label) item = QListWidgetItem() item.setData(Qt.ItemDataRole.UserRole, network) item.setSizeHint(item_widget.sizeHint()) self.nearby_wifi_list.addItem(item) self.nearby_wifi_list.setItemWidget(item, item_widget) def _on_scan_error(self, error_msg): """扫描出错后的UI恢复(主线程中执行)""" self.scan_button.setEnabled(True) self.scan_button.setText("扫描网络") self._styled_message(QMessageBox.Icon.Critical, self, "错误", f"扫描网络失败: {error_msg}") def _on_ssid_text_changed(self, text): """SSID输入框文本变化时,如果清空则重置为开放网络""" if not text.strip(): self.auth_combo.blockSignals(True) self.auth_combo.setCurrentIndex(0) self.auth_combo.blockSignals(False) self.update_auth_fields() @staticmethod def _decode_ssid(ssid): """尝试解码非英文WiFi名称(处理 \\xe9\\x83\\xbd 等转义序列)""" if not ssid: return ssid # 尝试 unicode_escape 解码(处理 \x 转义序列,返回 bytes) try: decoded = ssid.encode('latin-1').decode('unicode-escape').encode('latin-1').decode() if decoded != ssid: return decoded except Exception: pass # 尝试 latin-1 → UTF-8 双重转换 try: decoded = bytes(ssid, encoding='utf-8').decode('utf-8') if decoded != ssid: return decoded except Exception: pass return ssid @staticmethod def _deduplicate_networks(networks): """去重同名网络,每个SSID只保留信号最强的一个""" best = {} for net in networks: ssid = net.get("ssid", "") if not ssid: continue raw = net.get("signal_level", -100) try: signal = int(raw) except (ValueError, TypeError): signal = -100 if ssid not in best or signal > best[ssid].get("_signal_int", -100): net["_signal_int"] = signal best[ssid] = net return list(best.values()) @staticmethod def _detect_auth_mode(network): """根据 wpa_supplicant 返回的标准 flags 判断认证方式""" flags = network.get("flags", "").strip() # 无加密标记 → 开放网络 if not flags or flags in ("", "[ESS]", "[NONE]", "NONE"): return "open" # 检查是否含企业级认证标记 eap_keywords = ( "WPA2-EAP", "WPA-EAP", "WPA3-EAP", "EAP", "SUITE-B", "802.1X", "IEEE8021X", "ENTERPRISE", "FT/EAP", ) if any(kw in flags.upper() for kw in eap_keywords): return "eap" # 检查是否含 PSK 类标记(个人级加密) psk_keywords = ( "PSK", "SAE", "WPA2", "WPA3", "WPA", "CCMP", "TKIP", ) if any(kw in flags.upper() for kw in psk_keywords): return "psk" # 兜底:有标记但无法识别,默认 psk return "psk" def fill_ssid_from_scan(self, item): network = item.data(Qt.ItemDataRole.UserRole) or {} ssid = network.get("ssid", "") if ssid: decoded = self._decode_ssid(ssid) self.ssid_input.setText(decoded) # 根据网络标志自动选择认证方式 auth_mode = self._detect_auth_mode(network) index = self.auth_combo.findData(auth_mode) if index >= 0: self.auth_combo.blockSignals(True) self.auth_combo.setCurrentIndex(index) self.auth_combo.blockSignals(False) self.update_auth_fields() def update_auth_fields(self): auth_mode = self.auth_combo.currentData() if auth_mode == "open": self.identity_label.setVisible(False) self.identity_input.setVisible(False) self.password_label.setVisible(False) self.password_input.setVisible(False) elif auth_mode == "psk": self.identity_label.setVisible(False) self.identity_input.setVisible(False) self.password_label.setVisible(True) self.password_input.setVisible(True) else: self.identity_label.setVisible(True) self.identity_input.setVisible(True) self.password_label.setVisible(True) self.password_input.setVisible(True) def refresh_current_status(self): try: status = self.wifi_manager.get_current_status() ssid = status.get("ssid", "未连接") ip_addr = status.get("ip_address", "-") state = status.get("wpa_state", "UNKNOWN") self.current_status_label.setText(f"当前连接:{ssid} | IP: {ip_addr} | 状态: {state}") except Exception: self.current_status_label.setText("当前连接:未知") def _start_status_timer(self): """启动定时器,每秒刷新已保存网络列表和当前连接状态""" self._status_timer = QTimer(self) self._status_timer.timeout.connect(self._on_status_timer_tick) self._status_timer.start(1000) def _on_status_timer_tick(self): self.refresh_saved_wifi() self.refresh_current_status() def connect_to_saved_wifi(self): """连接已保存列表中选中的网络""" item = self.saved_wifi_list.currentItem() if item is None: self._styled_message(QMessageBox.Icon.Warning, self, "提示", "请先选择一个已保存网络") return network = item.data(Qt.ItemDataRole.UserRole) or {} network_id = network.get("network_id") ssid = network.get("ssid", "") if network_id is None: self._styled_message(QMessageBox.Icon.Warning, self, "提示", "选中网络无效") return try: ok = self.wifi_manager.connect_network_id(network_id) if not ok: self._styled_message(QMessageBox.Icon.Critical, self, "错误", "连接请求下发失败") return self._styled_message(QMessageBox.Icon.Information, self, "成功", f"已发起连接: {ssid}") except Exception as e: self._styled_message(QMessageBox.Icon.Critical, self, "错误", f"连接失败: {str(e)}") def remove_selected_saved_wifi(self): item = self.saved_wifi_list.currentItem() if item is None: self._styled_message(QMessageBox.Icon.Warning, self, "提示", "请先选择一个已保存网络") return network = item.data(Qt.ItemDataRole.UserRole) or {} network_id = network.get("network_id") ssid = network.get("ssid", "") if network_id is None: self._styled_message(QMessageBox.Icon.Warning, self, "提示", "选中网络无效,无法删除") return try: self.wifi_manager.remove_network(network_id) self._styled_message(QMessageBox.Icon.Information, self, "成功", f"已删除网络: {ssid}") self.refresh_saved_wifi() self.refresh_current_status() except Exception as e: self._styled_message(QMessageBox.Icon.Critical, self, "错误", f"删除失败: {str(e)}") def connect_to_wifi(self): ssid = self.ssid_input.text().strip() password = self.password_input.text() identity = self.identity_input.text().strip() auth_mode = self.auth_combo.currentData() if not ssid: self._styled_message(QMessageBox.Icon.Warning, self, "警告", "WiFi名称不能为空!") return if auth_mode == "psk" and not password: self._styled_message(QMessageBox.Icon.Warning, self, "警告", "WPA/WPA2 认证需要密码") return if auth_mode == "eap" and (not identity or not password): self._styled_message(QMessageBox.Icon.Warning, self, "警告", "WPA-EAP 认证需要身份和密码") return try: if auth_mode == "open": ok = self.wifi_manager.connect_wifi(ssid, None) elif auth_mode == "psk": ok = self.wifi_manager.connect_wifi(ssid, password) else: ok = self.wifi_manager.connect_eap(ssid, identity, password) if not ok: self._styled_message(QMessageBox.Icon.Critical, self, "错误", "连接请求下发失败,请检查系统日志") return self._styled_message(QMessageBox.Icon.Information, self, "成功", f"已发起连接: {ssid}") self.refresh_saved_wifi() self.refresh_current_status() except Exception as e: self._styled_message(QMessageBox.Icon.Critical, self, "错误", f"连接WiFi失败: {str(e)}") def display_setting(self, index): if index < 0: return self.settings_stack.setCurrentIndex(index)