Add way for JS to stop event processing in QObject::event() (#850)

This adds a couple small methods on `QObject` which makes it possible for
JS code to indicate to the currently running `QObject::event()` override
method whether it should allow more processing of an event or to stop
processing and not call super class `event()` method. This is Qt recommended
(C++) way of overriding event behaviour and stopping default behaviour.
This commit is contained in:
Simon Edwards 2021-07-10 20:49:43 +02:00 committed by GitHub
parent 281a89508b
commit 4eebad6f5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 7 deletions

View File

@ -15,7 +15,7 @@ class DLL_EXPORT EventWidget {
void subscribeToQtEvent(std::string evtString);
void unSubscribeToQtEvent(std::string evtString);
void event(QEvent* event);
bool event(QEvent* event);
void connectSignalsToEventEmitter();

View File

@ -52,7 +52,9 @@
#ifndef EVENTWIDGET_IMPLEMENTATIONS
#define EVENTWIDGET_IMPLEMENTATIONS(BaseWidgetName) \
bool event(QEvent* event) override { \
EventWidget::event(event); \
if (EventWidget::event(event)) { \
return true; \
} \
return BaseWidgetName::event(event); \
}

View File

@ -28,7 +28,7 @@ void EventWidget::unSubscribeToQtEvent(std::string evtString) {
}
}
void EventWidget::event(QEvent* event) {
bool EventWidget::event(QEvent* event) {
if (this->emitOnNode) {
try {
QEvent::Type evtType = event->type();
@ -40,11 +40,13 @@ void EventWidget::event(QEvent* event) {
std::vector<napi_value> args = {Napi::String::New(env, eventTypeString),
nativeEvent};
this->emitOnNode.Call(args);
Napi::Value returnCode = this->emitOnNode.Call(args);
return returnCode.As<Napi::Boolean>().Value();
} catch (...) {
// Do nothing
}
}
return false;
}
void EventWidget::connectSignalsToEventEmitter() {

View File

@ -35,19 +35,28 @@ view.addEventListener(WidgetEventTypes.MouseMove, () => {
*/
export abstract class EventWidget<Signals extends unknown> extends Component {
private emitter: EventEmitter;
private _isEventProcessed = false;
constructor(native: NativeElement) {
super();
if (native.initNodeEventEmitter) {
this.emitter = new EventEmitter();
this.emitter.emit = wrapWithActivateUvLoop(this.emitter.emit.bind(this.emitter));
const logExceptions = (event: string | symbol, ...args: any[]): boolean => {
// Preserve the value of `_isQObjectEventProcessed` as we dispatch this event
// to JS land, and restore it afterwards. This lets us support recursive event
// dispatches on the same object.
const previousEventProcessed = this._isEventProcessed;
this._isEventProcessed = false;
try {
return this.emitter.emit(event, ...args);
this.emitter.emit(event, ...args);
} catch (e) {
console.log(`An exception was thrown while dispatching an event of type '${event.toString()}':`);
console.log(e);
}
return false;
const returnCode = this._isEventProcessed;
this._isEventProcessed = previousEventProcessed;
return returnCode;
};
native.initNodeEventEmitter(logExceptions);
} else {
@ -56,12 +65,41 @@ export abstract class EventWidget<Signals extends unknown> extends Component {
addDefaultErrorHandler(native, this.emitter);
}
/**
* Get the state of the event processed flag
*
* See `setEventProcessed()`.
*
* @returns boolean True if the current event is flagged as processed.
*/
eventProcessed(): boolean {
return this._isEventProcessed;
}
/**
* Mark the current event as having been processed
*
* This method is used to indicate that the currently dispatched event
* has been processed and no further processing by superclasses is
* required. It only makes sense to call this method from an event
* handler.
*
* When set, this flag will cause NodeGui's `QObject::event()` method to
* return true and not call the superclass `event()`, effectively preventing
* any further processing on this event.
*
* @param isProcessed true if the event has been processed.
*/
setEventProcessed(isProcessed: boolean): void {
this._isEventProcessed = isProcessed;
}
/**
*
@param signalType SignalType is a signal from the widgets signals interface.
@param callback Corresponding callback for the signal as mentioned in the widget's signal interface
@returns void
For example in the case of QPushButton:
```js
const button = new QPushButton();