QT, DLL, interfejs: eksponowanie sygnału

0

Pytanie jest dość mocno specyficzme dla QT, nie wiem w sumie czy to jeszcze jest C++. Ad rem:
piszę plugin-widget dla QT designera, w formie DLLki. Założenie jest takie, że on nie będzie w ogóle dostępny w compile-timie, jedynie przez dynamiczne wczytywanie pliku UI.
DLLka kompiluje się ok, dodaje się do designera, layout się wczytuje.
No i teraz tak: chciałbym wykesponować sobie "na zewnątrz" libki sygnały. Bez nich, interfejs wygląda tak:


class DLL_EXPORT Interface : public QAbstractButton
{
public:
    using QAbstractButton::QAbstractButton;
    virtual ~Interface() = default;
public slots:
    virtual void mySlot(bool x) = 0;

};

Q_DECLARE_INTERFACE(Interface, "alagner.if.test/1.0")

To wszystko działa, mogę podłączać sygnały z QAbstractButton, sielanka.
Ale teraz chciałbym dopisać sobie coś w stylu:

signals:
    mySignal(bool x);

i tu zaczyna się jazda. Muszę dołożyć makro Q_OBJECT. Wtedy odpala się MOC, marudzi o brak implementacji. Zrozumiałe.
No to wyrzucam Q_OBJECT, a pomny tego, że signal to w sumie generowana metoda, robię tak

class DLL_EXPORT Interface : public QAbstractButton
{
Q_OBJECT
// CIACH
signals:
    virtual void mySignal(bool x) = 0;

To się kompiluje ...tak długo jak nie próbuję podpiąć mySignal, wtedy się wywala.
No i pytanie: czy da się kompilatorowi powiedzieć: "ten signal jest w DLL"? Próbowałem connect zarówno ze składnią "makrową/tekstową" jak i wskaźnikową.

Workaround to zawrapować connect wewnątrz publicznej metody, typu QMetaObject::Connection connectToMySignal(QObject receiver, const char* slot);. Mało to eleganckie, ale działa. Pytanie, czy da się lepiej.

@MarekR22 może Ty będziesz wiedzieć?

0

czy mogę z ciekawości zapytać czemu taki patent wymyśliłeś ? Do czego to ma służyć ?

0

Nie ja to wymyśliłem ;)
A ogólnie chodzi +- o coś takiego, że jest sobie layout robiony w designerze z customowymi widgetami ładowany niezależnie od logiki. Chodzi o możliwość podmiany kontrolek po prostu.

0

Wywala się podczas kompilacji czy w czasie działania? Jeśli podczas kompilacji to jaki jest komunikat?

0

Nie mówi, bo "wywala"="przestaje się kompilować" ;) Wrzucę zaraz na czym kompilacja pada.

0

mam jeszcze jedno pytanie w związku z tym.

Czy jest możliwość napisania DLL-k w Qt która będzie w sobie zawierać layouty, widgety i całą obsługę i potem podpiąć do głównego programu aby np wzbogacić program o dodatkowe okna które zawierają jakąś funkcjonalność ?

Bo wyobraziłem sobie taki scenariusz. Mam program główny i mam jakąś funkcjonalność ale ta funkcjonalność nie jest aktywna dopóki nie dostarczę tej funkcjonalności w bibliotece DLL (mam na myśli całe GUI)

Czy jest to możliwe ?

0

hm, a jaki sens ma robienie sygnału jako czysto wirtualny?

0

@_dominik: nie odpalasz MOC.
Błąd
`
In file included from D:\Qt\5.12.7\mingw73_64\include/QtGui/qtguiglobal.h0,
from D:\Qt\5.12.7\mingw73_64\include/QtWidgets/qtwidgetsglobal.h:43,
from D:\Qt\5.12.7\mingw73_64\include\QtWidgets/qapplication.h:43,
from D:\Qt\5.12.7\mingw73_64\include\QtWidgets/QApplication:1,
from ..\layout_and_widgets\loadable_layout\main.cpp
D:\Qt\5.12.7\mingw73_64\include/QtCore/qobject.h: In instantiation of 'static QMetaObject::Connection QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, const typename QtPrivate::FunctionPointer<Func2>::Object*, Func2, Qt::ConnectionType) [with Func1 = void (Interface::)(bool); Func2 = void (Interface::)(bool); typename QtPrivate::FunctionPointer<Func>::Object = Interface; typename QtPrivate::FunctionPointer<Func2>::Object = Interface]':
..\layout_and_widgets\loadable_layout\main.cpp134: required from here
D:\Qt\5.12.7\mingw73_64\include/QtCore/qglobal.h49: error: static assertion failed: No Q_OBJECT in the class with the signal

define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)

                                             ^

D:\Qt\5.12.7\mingw73_64\include/QtCore/qobject.h9: note: in expansion of macro 'Q_STATIC_ASSERT_X'
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
^~~~~~~~~~~~~~~~~
mingw32-make[1]: *** [Makefile.Debug debug/main.o] Error 1
`

Wygląda mi na to, że on ma problem z wzięciem adresu czysto wirtualnego slotu...

0

Sygnał jest generowany przez MOC, dlaczego jest czysto wirtualny?

0

Sygnał jest w skompilowanej DLLce ładowanej jako plugin, ona nie jest nawet nigdzie jawnie linkowana. Ja chcę go tylko zdefiniować. I to nawet ma sens w takiej sytuacji, że &Interface::mySignal się wykłada. Pytanie czy to co chcę uzyskać jest w ogóle wykonalne przy sygnałach...
EDIT właśnie chodzi o to, żeby MOC go ** nie ** generował :)

0

Nie wiem jaka jest praktyka dla abstrakcyjnych interfejsów i makra Q_OBJECT. A jakbyś dodał też to makro do klasy, która implementuje Interface?

0

Wjedzie MOC i, o ile pamiętam, powie, że sygnał nie może być wirtualny. Próbowałem już tak.

0

no ale, gdzieś w końcu ten MOC musi wygenerować ten sygnał, więc skoro on zgłasza, że sygnał nie może być wirtualny to chyba nie da rady tego tak zrobić.

1

Ok, zupełnie nie rozumiem co chcesz zrobić. Sygnały są generowane przez moc. Jak chcesz go generować samodzielnie to nie deklaruj go jako sygnału.

0

Zrobiłem. Problem okazał się leżeć... w build systemie, wygląda na to, że po moich kombinacjach z różnymi plikami nagłówkowymi, linkowaniem na różne sposoby itd. coś się musiało popsuć w mechanizmie cache'owania i na którymś etapie nie doczyściło się do końca (rebuild/clean z poziomu QT Creatora nie pomagały). Wyrzuciłem katalog build, skasowałem plik .user, to wymusiło rekonfigurację projektu na poziomie IDE i poszło; jedynie z wykorzystaniem makr SIGNAL i SLOT, ale poszło. Nie wiem w sumie czy to moja wina, (qmake zawiera jeden plik cpp, jeden zmieniany przeze mnie co jakiś czas header i różne konfiguracje linkera, tyle). W innym projekcie ostatnio odkryłem, że w zależności do build systemu QTCreator różnie ustala domyślne ścieżki systemowe i dostarczany przez QT plik BAT do ich ustawienia wcale nie musi odpowiadać temu co robi IDE -_-. Odkryłem to w sumie kompilując na innym komputerze po świeżym git clone.

@kq co chciałem zrobić.

Mam plugin do QT designera w formie DLL. Tenże zawiera customowy widget, jego loader dla designera itd.
Rzeczony widget ma już wygenerowane przez MOC wszystkie sygnały. Siedzą w DLLce. To, czego potrzebowałem do niego w appce, to interfejs. Interfejs w rozumieniu QT, czyli potrzebowałm móc dostać się do sygnałów, nie tylko slotów.
Być może udałoby mi się i bez tego, z wykorzystaniem metaobjektów tworzonych przez QT, ale imho to mało eleganckie.
Jak to działa z poziomu aplikacji:
Przez QUiloader::load wczytuję zewnętrzny pliczek UI zawierający te customowe widgety, plugin w założeniu "dogrywa" się sam bez explicite linkowania go, korzystając z mechanizmów QT i QUiLoader::addPluginPath.

Poczyszczę kod do formy prostej i wrzucę go tutaj za jakiś czas dla potomności. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1