[Python] PyQt6 QTextEdit won't expand as much as it should

Discussão em 'Python' iniciado por Stack, Agosto 18, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to create a UI that resembles OpenAI's, where code and markdown snippets follow each other and markdown and the code are parsed/syntax highlighted accordingly. I've been using PyQt6 and my subclass of QTextEdit to resemble the text snippets that may either be code or plain text (not markdown for now).

    Syntax highlighting and markdown parsing aside, I am failing to understand why FormattedSnippet does not take as much space as it can in the QVBoxLayout. By changing the size of my test_doc (with *=) I got the impression that the FormattedSnippet widgets squeeze each other as I add more of them to Window. Which results in my FormattedSnippets being scrollable. Instead, I need the Window to expand as I add each FormattedSnippet and I the user should be able to see each snippet by scrolling through Window, not the individual FormattedSnippets

    You can see everything I have been working with below (except my QSyntaxHighlighter subclass because it isn't relevant), though the problem probably lies in the FormattedSnippet or Window classes. I tried subclassing QLabel instead of QTextEdit instead since it is not scrollable and it actually lays out its content fully, just as I want it to. However, as I understand it, QLabel does not support rich text so syntax highlighting is off the table.

    I am pretty new to PyQt6 so please correct me if any of my explanations/understandings are wrong.

    Here is what the UI currently looks like. Each snippet has its scroll bar on the far-right: [​IMG]

    class Snippet:
    class Type(Enum):
    CODE = "CODE"
    PLAINTEXT = "PLAINTEXT"

    def __init__(self, type: Type, text: str):
    self.type = type
    self.text = text

    class FormattedSnippet(QTextEdit):
    def __init__(self, snippet: Snippet):
    super().__init__()
    self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum)
    self.setReadOnly(True)

    if snippet.type == Snippet.Type.CODE:
    language, code = parse_snippet(snippet.text)
    self.setText(code)

    font = QFont("Courier New")
    font.setStyleHint(QFont.StyleHint.Monospace)
    self.setFont(font)
    self.setStyleSheet(
    """
    QTextEdit {
    background-color: #000000;
    color: #dcdcdc;
    border-radius: 4px;
    padding: 4px;
    }
    """
    )
    else:
    self.setText(snippet.text)
    self.setStyleSheet(
    """
    QTextEdit {
    background-color: transparent;
    color: #E0E0E0;
    border: none;
    padding: 4px;
    }
    """
    )

    def parse_snippet(snippet: str):
    """
    Parse a fenced code block:
    ```lang
    code here
    ```
    Returns (language, code).
    """
    pattern = re.compile(r"```(\w+)\s*(.*?)\s*```", re.DOTALL)
    match = re.search(pattern, snippet.strip())
    if match:
    lang, code = match.groups()
    return lang.strip(), code.strip()
    return "text", snippet # fallback


    def extract_snippets(document: str) -> list[Snippet]:
    # Split the document by code fence markers
    parts = re.split(r"(```\w+[\s\S]*?```)", document)

    snippets = []
    for part in parts:
    if part.strip():
    if part.startswith("```") and part.endswith("```"):
    snippets.append(Snippet(Snippet.Type.CODE, part))
    else:
    snippets.append(Snippet(Snippet.Type.PLAINTEXT, part))

    return snippets

    class Window(QScrollArea):
    def __init__(self, test_doc):
    super().__init__()

    layout = QtWidgets.QVBoxLayout(self)
    frame = QtWidgets.QFrame()
    self.setWidgetResizable(True)
    frame.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
    self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
    frame.setLayout(layout)
    self.setWidget(frame)
    snippets = extract_snippets(test_doc)
    for snippet in snippets:
    formatted_snippet = FormattedSnippet(snippet)
    layout.addWidget(formatted_snippet)

    if __name__ == "__main__":
    test_doc = """Here is some text
    Here is some text
    Here is some text
    Here is some text
    Here is some text
    ```python
    def hello(document: str):
    print("world") # Prints 'world'
    print("world")
    a = "hello"
    print(a)

    def test():
    return
    ```

    More text here

    ```java
    import java.util.Random;

    public class RandomSnippet {

    public static void main(String[] args) {
    // Generate a random element from an array
    String[] colors = {"red", "green", "blue"};
    int randomIndex = random.nextInt(colors.length);
    String randomColor = colors[randomIndex];
    System.out.println("Random color: " + randomColor);


    // Example of generating multiple random numbers
    System.out.println("Generating 5 random numbers:");
    for (int i = 0; i < 5; i++) {
    System.out.println(random.nextInt(100)); // Generates random numbers between 0 and 99
    }
    }
    }

    ```
    Final text"""

    test_doc *= 1
    app = QtWidgets.QApplication(["Test"])
    window = Window(test_doc)
    window.resize(800, 600)
    window.show()
    sys.exit(app.exec())

    Continue reading...

Compartilhe esta Página