Add class 'AsyncEvent'.
This commit is contained in:
parent
595ee7f98e
commit
10b20c2512
137
QtComponets/AsyncEvent.h
Normal file
137
QtComponets/AsyncEvent.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#ifndef ASYNCEVENT_H
|
||||||
|
#define ASYNCEVENT_H
|
||||||
|
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <boost/signals2/signal.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace Amass {
|
||||||
|
|
||||||
|
template <typename Functor, typename... Args>
|
||||||
|
class AsyncEvent : public QEvent {
|
||||||
|
public:
|
||||||
|
using Arguments = std::tuple<std::decay_t<Args>...>;
|
||||||
|
AsyncEvent(Functor &&functor, Args &&...args)
|
||||||
|
: QEvent(static_cast<QEvent::Type>(QEvent::registerEventType())), m_functor(std::forward<Functor>(functor)),
|
||||||
|
m_args(std::forward<Args>(args)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncEvent() {
|
||||||
|
// LOG(debug) << "AsyncEvent::~AsyncEvent: " << this;
|
||||||
|
if (QCoreApplication::closingDown()) {
|
||||||
|
LOG(warning) << "QCoreApplication closed,skip handle task.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::apply(m_functor, std::move(m_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Functor m_functor;
|
||||||
|
Arguments m_args;
|
||||||
|
};
|
||||||
|
|
||||||
|
using HighPriority = std::true_type;
|
||||||
|
using LowPriority = std::false_type;
|
||||||
|
template <typename Priority = LowPriority, typename Functor, typename... Args>
|
||||||
|
inline void executeAtObjectThread(QObject *target, Functor &&functor, Args &&...args) {
|
||||||
|
if (QCoreApplication::closingDown()) {
|
||||||
|
LOG(warning) << "QCoreApplication closed,skip handle task.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (std::is_same_v<Priority, HighPriority> && target->thread() == QThread::currentThread()) {
|
||||||
|
std::invoke(std::forward<Functor>(functor), std::forward<Args>(args)...);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto event = new AsyncEvent<Functor, Args...>(std::forward<Functor>(functor), std::forward<Args>(args)...);
|
||||||
|
QCoreApplication::postEvent(target, event,
|
||||||
|
std::is_same_v<Priority, LowPriority> ? Qt::LowEventPriority : Qt::NormalEventPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
class MemberFunctionArgumentsTraits;
|
||||||
|
|
||||||
|
template <typename Object, typename Ret, typename... Args>
|
||||||
|
class MemberFunctionArgumentsTraits<Ret (Object::*)(Args...)> {
|
||||||
|
public:
|
||||||
|
using FunctionPointerType = Ret (Object::*)(Args...);
|
||||||
|
|
||||||
|
static auto wrapper(std::shared_ptr<Object> instance, FunctionPointerType function) {
|
||||||
|
return [instanceWeakPointer{std::weak_ptr{instance}}, function](Args &&...args) {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
executeAtObjectThread(
|
||||||
|
instance.get(),
|
||||||
|
[instanceWeakPointer, function](Args &&...args) {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
(instance.get()->*function)(std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Ld>
|
||||||
|
struct LambdaTraits : LambdaTraits<decltype(&Ld::operator())> {};
|
||||||
|
|
||||||
|
template <class Ret, class Object, class... Args>
|
||||||
|
struct LambdaTraits<Ret (Object::*)(Args...) const> {
|
||||||
|
template <typename T = std::false_type>
|
||||||
|
static auto wrapper(std::shared_ptr<QObject> instance, Object &&function) {
|
||||||
|
return [instanceWeakPointer{std::weak_ptr<QObject>{instance}}, function = std::move(function)](Args &&...args) {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
executeAtObjectThread<T>(
|
||||||
|
instance.get(),
|
||||||
|
[instanceWeakPointer, function = std::move(function)](Args &&...args) {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
function(std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Ret, class Object, class... Args>
|
||||||
|
struct LambdaTraits<Ret (Object::*)(Args...)> {
|
||||||
|
|
||||||
|
template <typename T = std::false_type>
|
||||||
|
static auto wrapper(std::shared_ptr<QObject> instance, Object &&function) {
|
||||||
|
return [instanceWeakPointer{std::weak_ptr<QObject>{instance}}, function = std::move(function)](Args &&...args) {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
executeAtObjectThread<T>(
|
||||||
|
instance.get(),
|
||||||
|
[instanceWeakPointer, function = std::move(function)](Args &&...args) mutable {
|
||||||
|
if (instanceWeakPointer.expired()) return;
|
||||||
|
auto instance = instanceWeakPointer.lock();
|
||||||
|
function(std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename SignalType, class Function, class Object>
|
||||||
|
boost::signals2::connection connect(SignalType &signal, std::shared_ptr<Object> target, Function Object::*function) {
|
||||||
|
using Traits = Amass::MemberFunctionArgumentsTraits<decltype(function)>;
|
||||||
|
|
||||||
|
return signal.connect(typename SignalType::slot_type(Traits::wrapper(target, function)).track_foreign(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = std::false_type, typename SignalType, class Function>
|
||||||
|
boost::signals2::connection connect(SignalType &signal, std::shared_ptr<QObject> target, Function &&function) {
|
||||||
|
using Traits = LambdaTraits<Function>;
|
||||||
|
return signal.connect(
|
||||||
|
typename SignalType::slot_type(Traits::template wrapper<T>(target, std::move(function))).track_foreign(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Amass
|
||||||
|
#endif // ASYNCEVENT_H
|
@ -3,6 +3,7 @@ find_package(Qt6 COMPONENTS Gui REQUIRED)
|
|||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
add_library(QtComponets
|
add_library(QtComponets
|
||||||
|
AsyncEvent.h
|
||||||
QClassStdStream.h QClassStdStream.cpp
|
QClassStdStream.h QClassStdStream.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user