Hacker News new | ask | show | jobs
by throwup238 654 days ago
Thanks for the detailed response! I'm definitely feeling the majority of these paint points.

> 2) Communication between QML and C++ is finicky. You have to use macros and Qt-specific constructs (Q_PROPERTY, signals, slots) to bridge both worlds. Qt Widgets doesn't need bridging in the first place, since it's C++ all the way down.

This hurts so bad. I'm actually implementing in Rust so I've got double the pain and any Rust type is either a QVariant or *mut pointer but integrating with Serde to easily (de)serialize JS objects has mitigated some of the pain points.

> 4) The latency of interfaces built with QML is higher than the ones built with Widgets. QML's rendering engine is lagging behind in the input latency mitigation front when compared to browsers, although they've been making efforts in this area.

This one is surprising. I've had more problems with Widgets, especially when doing a lot of animations (even just scrolling big text views) on a 4K display on MacOS, but maybe I'm thinking graphics and not input lag. The software rasterizer/GPU pipeline seems to get overloaded on Mac (Great article on the rendering pipeline btw!)

The big thing that sold me on QML over Widgets - other than the latter being the redheaded step child by this point - was implementing hot reloading. Having the entire UI completely refresh when changing the QML is definitely a nice coming from browser frontend, especially given Rust compile times.

2 comments

> I've had more problems with Widgets, especially when doing a lot of animations (even just scrolling big text views) on a 4K display on MacOS, but maybe I'm thinking graphics and not input lag.

There's two things to consider when comparing rendering performance: throughput and latency. Throughput, or how much FPS the engine can sustain, is much better in QML since it's leveraging the GPU, but latency it's very platform-dependent. Mac is actually the one where QML does best in terms of latency (and by that I believe it approaches the latency of Qt Widgets), since it's synchronizing with the VBlank signal provided by CVDisplayLink. On Windows and Android the situation is worse.

Sidenote: Have you seen the new TextEdit improvements in Qt 6.7? I'm curious if that bridges the gap that you had when you started working on your app. My app is also text editing heavy so I'm hoping it's a big improvement.
I saw them, they are a very small step in what I believe is the right direction, since you can use a custom textDocument. Anyway what I think would be useful is to jailbreak the QML API. Make the QML C++ API publicly available. Let us derive from the controls, manipulate and customize them with C++, as the Qt team devs themselves do.
I've created my own block editor from scratch using Qt C++ and QML, which is way faster than a regular QML TextArea[1]. Which is funny since it's just a ListView with Blocks (that contain TextAreas).

[1] https://www.get-notes.com/

> The big thing that sold me on QML over Widgets - other than the latter being the redheaded step child by this point - was implementing hot reloading. Having the entire UI completely refresh when changing the QML is definitely a nice coming from browser frontend, especially given Rust compile times.

Interesting, are there any public examples on how to implement this? All tools I've seen to do this seemed to be commercial offerings, though maybe implementing it in an existing application is easier than I think.

actually now that I'm looking again I found https://github.com/patrickelectric/qhot, which also looks promising

It’s very easy to implement a naive version. It only took me a few hours with the help of GPT/Claude and most of that was figuring out how to save and restore all window positions.

All it is is Rust’s notify listening for any changes in my QML directory and calling a C++ function on QQmlEngine: https://pastebin.com/08QKu84H

It'll require a bit more work once I'm loading multiple root QML files but for now it works great. It doesn't explicitly restore any state, however, but I store most of my UI state in Settings and a custom component that syncs arbitrary JSON values to Sqlite so the previous state is automatically restored when the QML is reloaded.

Ah, I somehow assumed more magic would be needed, but indeed it's really as simple as deleting the top-level widget and recreating it. And then repopulating the properties is what gives it the illusion of being dynamically live-patched.

I'll take a shot at implementing this in some of my code as well. Thanks!