import sys
import psutil
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QTableWidget, QTableWidgetItem, QHeaderView, QComboBox, QHBoxLayout, QLabel, QLineEdit
from PySide6.QtCore import QTimer, Qt, QThread, Signal
from PySide6.QtGui import QIcon, QPixmap
from collections import defaultdict
import win32gui
import win32ui
from PIL import Image

def make_transparent(image):
    # 将图像转换为带有透明通道的格式
    image = image.convert("RGBA")
    
    # 获取图像的数据
    datas = image.getdata()
    
    # 创建新的图像数据，将黑色背景转换为透明
    new_data = []
    for item in datas:
        if item[0] == 0 and item[1] == 0 and item[2] == 0:  # 黑色
            new_data.append((255, 255, 255, 0))  # 透明
        else:
            new_data.append(item)
    
    # 更新图像数据
    image.putdata(new_data)
    return image

class NetworkMonitorThread(QThread):
    update_signal = Signal(list)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.last_process_net_io = {}
        self.total_process_net_io = defaultdict(lambda: {'bytes_recv': 0, 'bytes_sent': 0})
        self.running = True
        self.process_cache = {}
        self.update_interval = 2  # 更新间隔设为5秒

    def run(self):
        while self.running:
            current_process_net_io = self.get_process_net_io()
            sorted_data = self.process_data(current_process_net_io)
            self.update_signal.emit(sorted_data)
            self.msleep(self.update_interval * 1000)

    def get_process_net_io(self):
        process_net_io = {}
        active_connections = psutil.net_connections()
        active_pids = set(conn.pid for conn in active_connections if conn.pid is not None)
        
        for pid in active_pids:
            try:
                proc = psutil.Process(pid)
                if pid in self.process_cache:
                    name = self.process_cache[pid]
                else:
                    name = proc.name()
                    self.process_cache[pid] = name
                
                io_counters = proc.io_counters()
                process_net_io[pid] = {
                    'name': name,
                    'bytes_recv': io_counters.read_bytes,
                    'bytes_sent': io_counters.write_bytes
                }
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass
        return process_net_io

    def process_data(self, current_process_net_io):
        sorted_data = []
        for pid, current in current_process_net_io.items():
            last = self.last_process_net_io.get(pid, current)

            download_speed = (current['bytes_recv'] - last['bytes_recv']) / (self.update_interval * 1024)  # KB/s
            upload_speed = (current['bytes_sent'] - last['bytes_sent']) / (self.update_interval * 1024)  # KB/s

            self.total_process_net_io[pid]['bytes_recv'] += current['bytes_recv'] - last['bytes_recv']
            self.total_process_net_io[pid]['bytes_sent'] += current['bytes_sent'] - last['bytes_sent']

            total_downloaded = self.total_process_net_io[pid]['bytes_recv'] / (1024 * 1024)
            total_uploaded = self.total_process_net_io[pid]['bytes_sent'] / (1024 * 1024)

            if download_speed > 0 or upload_speed > 0 or total_downloaded > 0 or total_uploaded > 0:
                sorted_data.append((current['name'], download_speed, upload_speed, total_downloaded, total_uploaded))

        self.last_process_net_io = current_process_net_io

        sort_by = self.parent().sort_combo.currentIndex()
        sorted_data.sort(key=lambda x: (x[1], x[0]) if sort_by == 0 else (x[0], x[1]), reverse=sort_by == 0)
        return sorted_data[:20]  # 只返回前20个进程

    def stop(self):
        self.running = False

class NetworkMonitor(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Network Traffic Monitor")
        self.setGeometry(100, 100, 800, 600)

        self.table = QTableWidget(self)
        self.table.setColumnCount(6)
        self.table.setHorizontalHeaderLabels(["Icon", "Process", "Download Speed (KB/s)", "Upload Speed (KB/s)", "Downloaded (MB)", "Uploaded (MB)"])
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        layout = QVBoxLayout()
        layout.addWidget(self.table)

        self.sort_combo = QComboBox()
        self.sort_combo.addItem("Sort by Download Speed")
        self.sort_combo.addItem("Sort by Process Name")
        self.sort_combo.currentIndexChanged.connect(self.update_network_info)

        self.filter_input = QLineEdit(self)
        self.filter_input.setPlaceholderText("Filter by process name")
        self.filter_input.textChanged.connect(self.update_network_info)

        sort_layout = QHBoxLayout()
        sort_layout.addWidget(QLabel("Sort by:"))
        sort_layout.addWidget(self.sort_combo)
        sort_layout.addWidget(QLabel("Filter:"))
        sort_layout.addWidget(self.filter_input)
        layout.addLayout(sort_layout)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.network_thread = NetworkMonitorThread(self)
        self.network_thread.update_signal.connect(self.update_table)
        self.network_thread.start()

        self.icon_cache = {}
        self.default_icon = QIcon("default_icon.png")  # 默认图标路径

    def update_table(self, sorted_data):
        filter_text = self.filter_input.text().lower()
        filtered_data = [data for data in sorted_data if filter_text in data[0].lower() or not filter_text]

        self.table.setRowCount(len(filtered_data))
        for row, data in enumerate(filtered_data):
            process_name = data[0]
            icon_item = QTableWidgetItem()
            icon = self.get_exe_icon(process_name)
            if icon:
                icon_item.setIcon(icon)
            else:
                icon_item.setIcon(self.default_icon)  # 使用默认图标
            self.table.setItem(row, 0, icon_item)

            for col, value in enumerate(data):
                self.table.setItem(row, col + 1, QTableWidgetItem(f"{value:.2f}" if isinstance(value, float) else str(value)))

    def get_exe_icon(self, process_name):
        if process_name in self.icon_cache:
            return self.icon_cache[process_name]

        try:
            # 获取进程的完整路径
            exe_path = None
            for proc in psutil.process_iter(['pid', 'name', 'exe']):
                if proc.info['name'] == process_name:
                    exe_path = proc.info['exe']
                    break

            if not exe_path:
                return None

            # 获取exe文件的图标
            large, small = win32gui.ExtractIconEx(exe_path, 0)
            if not large:
                return None

            # 创建一个设备上下文
            hdc = win32gui.GetDC(0)
            hdc = win32ui.CreateDCFromHandle(hdc)
            hbmp = win32ui.CreateBitmap()
            hbmp.CreateCompatibleBitmap(hdc, 32, 32)

            # 在设备上下文中绘制图标
            hdc = hdc.CreateCompatibleDC()
            hdc.SelectObject(hbmp)
            hdc.DrawIcon((0, 0), large[0])

            # 保存图标到本地文件
            bmpinfo = hbmp.GetInfo()
            bmpstr = hbmp.GetBitmapBits(True)
            img = Image.frombuffer(
                'RGB',
                (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
                bmpstr, 'raw', 'BGRX', 0, 1)

            # 处理图像以去除黑色背景
            img = make_transparent(img)

            # 将图像转换为QPixmap
            img_path = f'temp_icon_{process_name}.png'
            img.save(img_path)
            pixmap = QPixmap(img_path)

            icon = QIcon(pixmap)
            self.icon_cache[process_name] = icon
            return icon
        except Exception as e:
            print(f"Error extracting icon: {e}")
            return None

    def update_network_info(self):
        pass

    def closeEvent(self, event):
        self.network_thread.stop()
        self.network_thread.wait()
        super().closeEvent(event)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = NetworkMonitor()
    window.show()
    sys.exit(app.exec())
。。。。。。。。。。。。
有的程序明明使用网络进行下载或上传，但是我的软件监控显示这个程序下载速度或上传速度是0，解决思路是：某些程序可能使用低级网络驱动程序或特殊的网络栈，绕过了常规的网络监控方法。考虑使用更底层的网络监控技术，如  Npcap。
。 。。。。。。。。
现在我已经安装了Npcap，请修改代码利用scapy库解决问题，我是否应该抛弃 psutil库，完全使用scapy来监控网络活动，（注意避免主界面卡顿。     
）。。。。。。现在应该怎么修改我的代码