cengels/skywriter

Extreme performance impact in large files

Closed this issue · 4 comments

Check the performance in large files. In skywriter-javafx a VirtualizedScrollPane was used that only rendered the text actually on the screen. In Qt, such a component does not exist, but it is possible that Qt somehow handles this problem internally automatically. If that's the case, no further action is required.

This issue also concerns the parsing performance of large Markdown files.

Large files cannot be loaded at all. The application will simply freeze indefinitely if a sufficiently large file (>10,000 words) is loaded.

The exact problem is unknown, however it is clear that QTextEdit does not suffer from this problem, only TextEdit. Unfortunately switching to QTextEdit is impossible as QTextEdit is a widget and Qt Widgets cannot be easily used in a QML application due to using a different rendering graph.

One thing that is certain: the Markdown parsing is not the cause as parsing a large file using QTextDocument::setMarkdown() only causes freezing when the QTextDocument is attached to a RichEdit instance. Therefore, it's likely that the problem lies in the rendering process (i.e. replacing all the text blocks in the UI).

One Qt Jira issue suggested that a TextEdit does in fact not use any kind of virtualization, i.e. that it lays out and renders the entire document at all times, rather than only the text blocks that are actually visible on the screen. This seems to be true as loading a small document and filling it with a lot of text also results in extremely choppy text input.

If this is the case, there may not be an easy solution. It may be necessary to implement a solution that uses a QQuickPaintedItem to paint a QTextDocument backed by a QTextEdit instance and forwards any necessary events to the QTextEdit.

If this does not work, it may be necessary to reimplement the entire user interface in Qt Widgets.

I finally managed to integrate the QTextEdit into a QQuickPaintedItem so that the QTextEdit receives the forwarded events and responds to them. Not all events work yet, nor is the text edit looking quite right, but this is a good beginning that likely means I won't have to reimplement the entire user interface in Qt Widgets.

This is a plus because QtQuick is definitely the future where Qt is concerned, boasting significant performance improvements over Qt Widgets (except, of course, for editable text areas). This means that, if the TextEdit or TextArea component is ever updated to work with large documents, replacing the current implementation will be a breeze.

Unfortunately, after further research, it turns out even QTextEdit does not support several functions that are essential for the editor. For instance, this includes the ability to temporarily prevent new items from being added to the undo stack, as well as the ability to change several formatting aspects of the text area (like alignment) independently of any specific text block.

Since I'm out of any other options, I'm going to try to look into implementing a completely custom text area. I wish I could directly append to the Qt Scene Graph, but all QSG nodes that would allow text insertion are private. Because of course they are.

I won't lie. While I was initially enthusiastic about Qt and I'm grateful I got the opportunity to learn it, I'm starting to regret my decision to move to Qt from JavaFX. There is no longer any discernible benefit to using Qt over JavaFX.

Resolution

Implementing painting for a custom text area was not as difficult as I originally imagined, all mostly thanks to the QQuickTextNode, a private QSG class I was only able to use by including private headers in the project. While I would have preferred to stick to public headers, there was simply no reasonable way to do so. The guys who developed Qt Widgets did a great job, but I feel like the guys who wrote Qt Quick were a little overzealous with their "code safekeeping" and chose to make even things that you could have used and needed in an application of your own private.