Qt Designer无法显示网络扫描结果的问题求助
网络检测应用扫描结果不显示问题排查与修复
问题描述
我正在用Python3在PyCharm中开发一款网络检测应用,基于nmap实现扫描功能。目前遇到的问题是:点击扫描按钮后扫描能正常完成,但Qt Designer设计的界面上没有任何扫描结果展示。
代码文件
主页面 main.py
class Home(QtWidgets.QMainWindow): def __init__(self): super(Home, self).__init__() self.stacked_widget = QtWidgets.QStackedWidget() self.setCentralWidget(self.stacked_widget) self.pages = {} self.home_page(Dashboard(self), 'dashboard') self.home_page(Stats(), 'stats') self.home_page(Details(), 'details') self.home_page(Data(), 'data') self.home_page(Threats(), 'threats') self.goto('dashboard') def home_page(self, page, name): self.pages[name] = page self.stacked_widget.addWidget(page) if isinstance(page, PageWindow): page.gotoSignal.connect(self.goto) @QtCore.pyqtSlot(str) def goto(self, name): if name in self.pages: self.stacked_widget.setCurrentWidget(self.pages[name]) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) home = Home() dashboard = Dashboard(home) dashboard.show() dashboard.showMaximized() sys.exit(app.exec_())
扫描线程页面 scan_thread.py
class ScanThread(QtCore.QThread): scan_complete = QtCore.pyqtSignal(list) def __init__(self, parent=None): super(ScanThread, self).__init__(parent) self.parent = parent def __def__(self): self.wait() def run(self): nm = nmap.PortScanner() nm.scan(hosts='192.168.1.0/24', arguments='-p- --open -sV') self.results = [] for host in nm.all_hosts(): for proto in nm[host].all_protocols(): lport = nm[host][proto].keys() sorted(lport) for port in lport: result = dict() result['Host'] = host result['Port'] = port result['Protocol'] = proto result['State'] = nm[host][proto][port]['state'] result['Address'] = ', '.join(nm[host][proto][port].get('addresses', {}).values()) result['OP System'] = nm[host][proto][port].get('osmatch', [{'name': ''}])[0]['name'] result['Product'] = nm[host][proto][port].get('product', '') self.results.append(result) self.scan_complete.emit(self.results)
仪表盘页面 dashboard_page.py
class Dashboard(PageWindow): def __init__(self, home): super(Dashboard, self).__init__() self.resultsTable = None self.scanThread = ScanThread(self) uic.loadUi('ui/dashboard.ui', self) self.home = home self.display_results([]) self.statsMenu.mousePressEvent = lambda event: self.goto_page('stats') self.detailsMenu.mousePressEvent = lambda event: self.goto_page('details') self.dataMenu.mousePressEvent = lambda event: self.goto_page('data') self.threatsMenu.mousePressEvent = lambda event: self.goto_page('threats') self.scanBtn.clicked.connect(self.scan_host) def goto_page(self, event): self.goto(event) def scan_host(self): self.scanBtn.setEnabled(False) self.scanBtn.setText('Scanning...') self.scanThread = ScanThread(self) self.scanThread.scan_complete.connect(self.display_results) self.scanThread.scan_complete.connect(self.update_scan_results) self.scanThread.scan_complete.connect(self.scan_finished) self.scanThread.start() def display_results(self, results): if not self.resultsTable: self.resultsTable = QTableWidget(self) self.layout().addWidget(self.resultsTable) self.resultsTable.setColumnCount(8) self.resultsTable.setRowCount(len(results)) for i, result in enumerate(results): self.resultsTable.setItem(i, 0, QtWidgets.QTableWidgetItem(result['Host'])) self.resultsTable.setItem(i, 1, QtWidgets.QTableWidgetItem(result['State'])) self.resultsTable.setItem(i, 5, QtWidgets.QTableWidgetItem(' ')) self.resultsTable.setItem(i, 6, QtWidgets.QTableWidgetItem(result['OP System'])) open_ports = 0 closed_ports = 0 scanned_ports = 0 for port in result.get('ports', []): if port.get('state', '') == 'open': open_ports += 1 elif port.get('state', '') == 'closed': closed_ports += 1 scanned_ports = len(result.get('ports', [])) self.resultsTable.setItem(i, 2, QtWidgets.QTableWidgetItem(str(open_ports))) self.resultsTable.setItem(i, 3, QtWidgets.QTableWidgetItem(str(closed_ports))) self.resultsTable.setItem(i, 4, QtWidgets.QTableWidgetItem(str(scanned_ports))) self.scanBtn.setEnabled(True) self.scanBtn.setText('Scan') def update_scan_results(self, results): self.display_results(results) # Display the new scan results for i, result in enumerate(results): self.resultsTable.setItem(i, 0, QtWidgets.QTableWidgetItem(result['Host'])) self.resultsTable.setItem(i, 1, QtWidgets.QTableWidgetItem(result['State'])) self.resultsTable.setItem(i, 5, QtWidgets.QTableWidgetItem(' ')) self.resultsTable.setItem(i, 6, QtWidgets.QTableWidgetItem(result['OP System'])) open_ports = 0 closed_ports = 0 scanned_ports = 0 for port in result.get('ports', []): if port.get('state', '') == 'open': open_ports += 1 elif port.get('state', '') == 'closed': closed_ports += 1 scanned_ports = len(result.get('ports', [])) self.resultsTable.setItem(i, 2, QtWidgets.QTableWidgetItem(str(open_ports))) self.resultsTable.setItem(i, 3, QtWidgets.QTableWidgetItem(str(closed_ports))) self.resultsTable.setItem(i, 4, QtWidgets.QTableWidgetItem(str(scanned_ports))) def scan_finished(self): self.scanThread.scan_complete.disconnect(self.display_results) self.scanThread.scan_complete.disconnect(self.update_scan_results) self.scanThread.scan_complete.disconnect(self.scan_finished) self.scanThread.deleteLater() def clear_scan_results(self): self.resultsTable.clearContents() self.resultsTable.setRowCount(0)
问题排查与修复方案
核心问题点
- 数据结构不匹配:扫描线程返回的是每个端口一条记录,但仪表盘代码试图从每个结果中读取不存在的
ports字段,导致端口统计全为0,表格数据异常。 - 主入口窗口错误:单独创建并显示Dashboard实例,而非Home中已关联栈窗口的实例,导致界面上下文混乱。
- 重复UI更新逻辑:
display_results和update_scan_results代码完全重复,同时触发会导致冗余更新。 - 表格初始化问题:未设置列标题,布局可能存在问题导致表格不显示;另外osmatch字段获取层级错误,取不到操作系统信息。
修复后的代码
1. 主页面 main.py(修正入口)
if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) home = Home() home.show() home.showMaximized() sys.exit(app.exec_())
2. 扫描线程页面 scan_thread.py(修正数据结构与字段获取)
class ScanThread(QtCore.QThread): scan_complete = QtCore.pyqtSignal(list) def __init__(self, parent=None): super(ScanThread, self).__init__(parent) self.parent = parent def __del__(self): self.wait() def run(self): nm = nmap.PortScanner() nm.scan(hosts='192.168.1.0/24', arguments='-p- --open -sV') self.results = [] # 按主机分组整理结果,避免同一主机多条重复条目 for host in nm.all_hosts(): host_info = { 'Host': host, 'State': nm[host].state(), 'OP System': nm[host].get('osmatch', [{'name': ''}])[0]['name'], 'ports': [] } for proto in nm[host].all_protocols(): lport = sorted(nm[host][proto].keys()) # 正确排序端口 for port in lport: port_info = { 'Port': port, 'Protocol': proto, 'State': nm[host][proto][port]['state'], 'Product': nm[host][proto][port].get('product', '') } host_info['ports'].append(port_info) self.results.append(host_info) self.scan_complete.emit(self.results)
3. 仪表盘页面 dashboard_page.py(简化逻辑,优化表格显示)
class Dashboard(PageWindow): def __init__(self, home): super(Dashboard, self).__init__() self.resultsTable = None uic.loadUi('ui/dashboard.ui', self) self.home = home # 初始化表格(优先使用UI文件中的控件,没有则创建) self.resultsTable = self.findChild(QtWidgets.QTableWidget, "resultsTable") if not self.resultsTable: self.resultsTable = QtWidgets.QTableWidget(self) layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.resultsTable) self.resultsTable.setColumnCount(7) # 设置列标题 self.resultsTable.setHorizontalHeaderLabels([ '主机', '状态', '开放端口', '关闭端口', '扫描总数', '预留', '操作系统' ]) # 自动调整列宽 self.resultsTable.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) self.display_results([]) # 菜单跳转逻辑简化 self.statsMenu.mousePressEvent = lambda event: self.goto('stats') self.detailsMenu.mousePressEvent = lambda event: self.goto('details') self.dataMenu.mousePressEvent = lambda event: self.goto('data') self.threatsMenu.mousePressEvent = lambda event: self.goto('threats') self.scanBtn.clicked.connect(self.scan_host) def scan_host(self): self.scanBtn.setEnabled(False) self.scanBtn.setText('扫描中...') self.scanThread = ScanThread(self) self.scanThread.scan_complete.connect(self.display_results) self.scanThread.scan_complete.connect(self.scan_finished) self.scanThread.start() def display_results(self, results): self.resultsTable.setRowCount(len(results)) for i, result in enumerate(results): # 填充基础主机信息 self.resultsTable.setItem(i, 0, QtWidgets.QTableWidgetItem(result['Host'])) self.resultsTable.setItem(i, 1, QtWidgets.QTableWidgetItem(result['State'])) self.resultsTable.setItem(i, 5, QtWidgets.QTableWidgetItem(' ')) self.resultsTable.setItem(i, 6, QtWidgets.QTableWidgetItem(result['OP System'])) # 统计端口状态 open_ports = 0 closed_ports = 0 scanned_ports = len(result.get('ports', [])) for port in result['ports']: if port['State'] == 'open': open_ports += 1 elif port['State'] == 'closed': closed_ports += 1 # 填充统计数据 self.resultsTable.setItem(i, 2, QtWidgets.QTableWidgetItem(str(open_ports))) self.resultsTable.setItem(i, 3, QtWidgets.QTableWidgetItem(str(closed_ports))) self.resultsTable.setItem(i, 4, QtWidgets.QTableWidgetItem(str(scanned_ports))) self.scanBtn.setEnabled(True) self.scanBtn.setText('开始扫描') def scan_finished(self): self.scanThread.deleteLater() def clear_scan_results(self): self.resultsTable.clearContents() self.resultsTable.setRowCount(0)
修复说明
- 修正主入口逻辑,确保显示的是Home中管理的Dashboard实例,避免窗口上下文混乱。
- 重新组织扫描结果的数据结构,按主机分组,添加
ports字段,让仪表盘代码能正确统计端口。 - 移除重复的
update_scan_results方法,简化UI更新逻辑。 - 为表格添加列标题并优化布局,确保控件可见;修正osmatch字段的获取层级,正确读取操作系统信息。
- 修复扫描线程中排序端口的代码错误,以及析构函数的拼写错误。
内容的提问来源于stack exchange,提问作者Corey G
相关产品推荐
相关产品推荐

