KDBindings
repository·main·Indexed 43 days ago
https://github.com/kdab/kdbindingsA header-only C++17 library providing reactive programming features, including signals, slots, and property bindings with lazy or immediate evaluation. It allows developers to implement data binding and the observer pattern without requiring the Qt framework, though it remains compatible with it.
What's inside KDBindings
- KDBindings is a standalone, header-only C++ library that provides reactive programming and data binding capabilities. It allows developers to implement Signals + Slots, templated Properties, and reactive Property bindings with lazy evaluation. It is designed to be lightweight and does not require a heavy Qt dependency, though it remains compatible with Qt.
Use KDBindings Signals to implement the observer pattern
mainKDBindings Signals are templated objects that can be used anywhere in your code without requiring the Qt Meta Object Compiler (MOC). They allow you to declare events that can be observed by 'Slots' (functions, lambdas, or objects implementing
operator()).To use a Signal:
- Define a
KDBindings::Signal<T>whereTis the type of value emitted. - Connect a slot using
.connect(). - Emit the signal using
.emit()with the appropriate arguments.
#include <kdbindings/signal.h> using namespace KDBindings; Signal<const std::string&> mySignal; // Connect a lambda as a slot mySignal.connect([](const std::string& value){ std::cout << value << std::endl; }); // Emit the signal mySignal.emit("Hello World!");- Define a
Use deferred evaluation for bindings
mainTo control the frequency of updates or avoid unnecessary re-evaluations (e.g., in UI applications to prevent 60Hz updates), you can use deferred evaluation.
To enable this, pass a
KDBindings::BindingEvaluatortomakeBoundProperty. The binding will only be recalculated whenevaluateAll()is called on the evaluator instance.Avoid and handle broken bindings
mainIn KDBindings, assigning a concrete value to a property that is currently the result of a data binding is prohibited to prevent accidentally breaking the binding. This operation will throw a
KDBindings::ReadOnlyPropertyerror.- To prevent errors: Do not assign values to properties created via
makeBoundPropertyunless you intend to replace the binding. - To intentionally remove a binding: Use the
reset()method on thePropertyinstance.
#include <kdbindings/binding.h> using namespace KDBindings; Property<int> value = 2; Property<int> result = makeBoundProperty(2 * value); // result is now 4 result = 5; // this will throw a KDBindings::ReadOnlyProperty error!- To prevent errors: Do not assign values to properties created via
Best practices for Signal mutability in classes
mainBecause functions that modify a Signal (like
connect) are notconst, adding a Signal as a member of a class typically requires that the class itself be non-const to allow connections.To allow connecting to a Signal within a
constcontext (for example, when the Signal is part of aProperty), it is recommended to use the C++mutablekeyword for the Signal member. This accurately reflects that connecting to the signal does not change the logical state of the enclosing object.What are KDBindings Properties
mainProperties are values that can notify observers of changes, making them suitable for use in data bindings.
Key differences from Qt Properties:
- They do not require a Meta Object Compiler (MOC).
- They are available in pure C++17.
- They can be used as free values outside of classes.
Install KDBindings on Windows
mainTo install KDBindings on Windows, navigate to the repository folder and create a
builddirectory. Open a command window in that directory (e.g., usingShift+Right Click>Open command window here) and run the CMake build and install commands.cmake .. cmake --build . --target installLink KDBindings using CMake
mainOnce installed, you can integrate KDBindings into your CMake projects using the
find_packagedirective. This exposes theKDAB::KDBindingstarget.Note: KDBindings requires C++17 or later. Ensure you set
CMAKE_CXX_STANDARDto at least 17 in yourCMakeLists.txt.set(CMAKE_CXX_STANDARD 17) find_package(KDBindings) target_link_libraries(${PROJECT_NAME} KDAB::KDBindings)Reassign a binding to an existing property
mainIf you need to change the logic of an existing binding rather than creating a new property, you have two options:
KDBindings::makeBinding: Use this to add a new binding to an existingProperty. This replaces the current binding logic without throwing an exception.KDBindings::makeBoundProperty: You can move-assign a new property into an existing one. Warning: This completely replaces the existingPropertyinstance, meaning all existing signals will be disconnected and any other bindings depending on the old property will be removed.
Rule of thumb: Use
makeBoundPropertyto create a new property; usemakeBindingto update the binding of an existing property.#include <kdbindings/binding.h> using namespace KDBindings; Property<int> value = 2; auto result = makeBoundProperty(2 * value); // result is 4 result = makeBinding(3 * value); // Replaces binding logic, no exception. result is 6 result = makeBoundProperty(4 * value); // Overrides the entire property instance. result is 8How to use KDBindings with Qt
mainKDBindings uses
emitas a function name. Because Qt definesemitas a keyword, they are incompatible by default.To use both in the same project, you must define
QT_NO_EMITorQT_NO_KEYWORDSand omit theemitkeyword in your Qt code.If you are using CMake, you can easily enable this compatibility by setting the following option:
KDBindings_QT_NO_EMITThis option defines the necessary macros for all dependents of KDBindings.
Perform basic data binding with makeBoundProperty
mainData binding in KDBindings allows you to create properties that automatically update when their input dependencies change. You can use arithmetic operators or combinations of properties and constants to define these relationships. Use the
KDBindings::makeBoundPropertyfunction to create a new property that is bound to an expression.Supported operations include most arithmetic operators and combinations of properties with constant values.
#include <kdbindings/binding.h> using namespace KDBindings; Property<int> width(2); Property<int> height(3); Property<int> area = makeBoundProperty(width * height); std::cout << area << std::endl; // will print 6 width = 5; std::cout << area << std::endl; // will print 15Manage connections with ConnectionHandle
mainThe
connect()function returns aKDBindings::ConnectionHandle. Unlike Qt, KDBindings does not automatically manage the lifecycle of connections.Critical: You must manually disconnect a connection using the
ConnectionHandleif any of the bound arguments (like the object containing the slot) are destroyed. If you do not call disconnect before the slot's owner goes out of scope, emitting the signal will result in a dangling pointer and undefined behavior.