You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PySide6 Qt中高效创建大量文本框而不卡顿

解决大量可编辑文本框的性能问题

你遇到的核心问题是一次性创建10000个独立QPlainTextEdit控件会消耗大量系统资源,导致启动慢、卡顿。下面提供几种符合你需求的高效实现方案:

方案1:模型视图架构(推荐)

Qt的模型视图框架(如QTableWidget)专为大量数据场景设计,它只会渲染当前可见区域的控件,不会一次性创建所有元素,性能优势明显。

实现代码

import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QTableWidget, QTableWidgetItem
)

DATA = ["hello\n\n"] * 10000

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.table = QTableWidget()
        self.table.setRowCount(len(DATA))
        self.table.setColumnCount(1)
        
        # 隐藏表头,让界面更接近多文本框的视觉效果
        self.table.horizontalHeader().setVisible(False)
        self.table.verticalHeader().setVisible(False)
        # 让列宽自适应窗口
        self.table.horizontalHeader().setStretchLastSection(True)
        
        # 填充数据(仅初始化模型,控件按需创建)
        for idx, text in enumerate(DATA):
            item = QTableWidgetItem(text)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.table.setItem(idx, 0, item)
        
        self.setCentralWidget(self.table)
    
    def get_current_content(self):
        """获取当前编辑的文本框内容"""
        current_item = self.table.currentItem()
        return current_item.text() if current_item else ""
    
    def get_content_by_index(self, index):
        """通过索引获取指定文本框内容"""
        if 0 <= index < len(DATA):
            item = self.table.item(index, 0)
            return item.text() if item else ""

app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

优势

  • 启动速度极快,资源占用低
  • 天然支持:单独获取内容、识别当前编辑项、Ctrl+A仅选中当前单元格内容
  • 无需处理复杂的文本分割逻辑,稳定性高

方案2:单个QPlainTextEdit模拟多文本框

通过分隔符区分不同"文本块",重写快捷键和光标逻辑,模拟多文本框的交互体验。

实现代码

import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QPlainTextEdit, QScrollArea, QWidget, QVBoxLayout
)

DATA = ["hello\n\n"] * 10000
BLOCK_SEPARATOR = "\n\n"  # 文本块分隔符

class SimulatedMultiEdit(QPlainTextEdit):
    def __init__(self, data, parent=None):
        super().__init__(parent)
        self.setPlainText(BLOCK_SEPARATOR.join(data))
        self.total_blocks = len(data)
    
    def keyPressEvent(self, event):
        # 重写Ctrl+A,仅选中当前文本块内容
        if event.key() == Qt.Key_A and (event.modifiers() & Qt.ControlModifier):
            cursor = self.textCursor()
            # 定位到当前块开头
            cursor.movePosition(cursor.StartOfBlock)
            start_pos = cursor.position()
            # 定位到当前块结尾(跳过分隔符)
            cursor.movePosition(cursor.EndOfBlock)
            if cursor.position() < self.document().characterCount() - 1:
                cursor.movePosition(cursor.NextCharacter, cursor.KeepAnchor, len(BLOCK_SEPARATOR))
            self.setTextCursor(cursor)
            return
        super().keyPressEvent(event)
    
    def get_current_block_index(self):
        """获取当前编辑的文本块索引"""
        cursor_pos = self.textCursor().position()
        content = self.toPlainText()
        accumulated_len = 0
        for idx, block in enumerate(content.split(BLOCK_SEPARATOR)):
            block_total_len = len(block) + len(BLOCK_SEPARATOR) if idx < self.total_blocks-1 else len(block)
            if accumulated_len <= cursor_pos < accumulated_len + block_total_len:
                return idx
        return -1
    
    def get_block_content(self, index):
        """通过索引获取指定文本块内容"""
        if 0 <= index < self.total_blocks:
            blocks = self.toPlainText().split(BLOCK_SEPARATOR)
            return blocks[index] if index < len(blocks) else ""
        return ""

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.scroll = QScrollArea()
        self.edit = SimulatedMultiEdit(DATA)
        
        layout = QVBoxLayout()
        layout.addWidget(self.edit)
        
        widget = QWidget()
        widget.setLayout(layout)
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(widget)
        
        self.setCentralWidget(self.scroll)
        
        # 监听当前编辑块变化
        self.edit.cursorPositionChanged.connect(lambda: print(f"当前编辑第 {self.edit.get_current_block_index()+1} 个文本框"))

app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

注意事项

  • 需要确保用户不会输入与分隔符相同的内容(可通过禁止输入连续换行或使用特殊分隔符解决)
  • 文本块数量过多时,分割内容的性能会略有下降

内容的提问来源于stack exchange,提问作者IssaRice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:30:31