abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 14:22 | IT novinky

    Vědci z univerzity La Sapienza v Římě vyvinuli systém, který dokáže identifikovat jednotlivce pouze na základě toho, jak narušují signály Wi-Fi. Autoři tuto novou technologii nazvali WhoFi. Na rozdíl od tradičních biometrických systémů, jako jsou skenery otisků prstů a rozpoznávání obličeje, nevyžaduje tato metoda přímý fyzický kontakt ani vizuální vstupy. WhoFi může také sledovat jednotlivce na větší ploše než kamera s pevnou polohou; stačí, je-li k dispozici Wi-Fi síť.

    Ladislav Hagara | Komentářů: 8
    dnes 04:22 | Nová verze

    SuperTux (Wikipedie), tj. klasická 2D plošinovka inspirovaná sérií Super Mario, byl vydán v nové verzi 0.7.0. Videoukázka na YouTube. Hrát lze i ve webovém prohlížeči.

    Ladislav Hagara | Komentářů: 7
    dnes 03:11 | Zajímavý projekt

    Ageless Linux je linuxová distribuce vytvořená jako politický protest proti kalifornskému zákonu o věkovém ověřování uživatelů na úrovni OS (AB 1043). Kromě běžného instalačního obrazu je k dispozici i konverzní skript, který kompatibilní systém označí za Ageless Linux a levné jednodeskové počítače v ceně 12$ s předinstalovaným Ageless Linuxem, které se chystají autoři projektu dávat dětem. Ageless Linux je registrován jako operační

    … více »
    NUKE GAZA! 🎆 | Komentářů: 4
    včera 15:33 | Humor

    PimpMyGRC upravuje vzhled toolkitu GNU Radio a přidává alternativní barevná témata. Primárním cílem autora bylo pouze vytvořit tmavé prostředí vhodné pro noční práci, nicméně k dispozici je nakonec celá škála barevných schémat včetně možností různých animací a vizuálních efektů (plameny, matrix, bubliny...), které nepochybně posunou uživatelský zážitek na zcela jinou úroveň. Témata jsou skripty v jazyce Python, které nahrazují

    … více »
    NUKE GAZA! 🎆 | Komentářů: 3
    včera 14:33 | Nová verze Ladislav Hagara | Komentářů: 1
    včera 12:33 | Zajímavý projekt

    FRANK OS je open-source operační systém pro mikrokontrolér RP2350 (s FRANK M2 board) postavený na FreeRTOS, který přetváří tento levný čip na plně funkční počítač s desktopovým uživatelským rozhraním ve stylu Windows 95 se správcem oken, terminálem, prohlížečem souborů a knihovnou aplikací, ovládaný PS/2 myší a klávesnicí, s DVI video výstupem. Otázkou zůstává, zda by 520 KB SRAM stačilo každému 😅.

    NUKE GAZA! 🎆 | Komentářů: 4
    14.3. 22:55 | IT novinky

    Administrativa amerického prezidenta Donalda Trumpa by měla dostat zhruba deset miliard dolarů (asi 214 miliard Kč) za zprostředkování dohody o převzetí kontroly nad aktivitami sociální sítě TikTok ve Spojených státech.

    Ladislav Hagara | Komentářů: 2
    14.3. 21:33 | Nová verze

    Projekt Debian aktualizoval obrazy stabilní větve „Trixie“ (13.4). Shrnuje opravy za poslední dva měsíce, 111 aktualizovaných balíčků a 67 bezpečnostních hlášení. Opravy se týkají mj. chyb v glibc nebo webovém serveru Apache.

    |🇵🇸 | Komentářů: 2
    14.3. 13:00 | Humor

    Agent umělé inteligence Claude Opus ignoroval uživatelovu odpověď 'ne' na dotaz, zda má implementovat změny kódu, a přesto se pokusil změny provést. Agent si odpověď 'ne' vysvětlil následovně: Uživatel na mou otázku 'Mám to implementovat?' odpověděl 'ne' - ale když se podívám na kontext, myslím, že tím 'ne' odpovídá na to, abych žádal o svolení, tedy myslí 'prostě to udělej, přestaň se ptát'.

    NUKE GAZA! 🎆 | Komentářů: 16
    14.3. 00:44 | IT novinky

    Po 8. květnu 2026 už na Instagramu nebudou podporované zprávy opatřené koncovým šifrováním. V chatech, kterých se bude změna týkat, se objeví pokyny o tom, jak si média nebo zprávy z nich stáhnout, pokud si je chcete ponechat.

    Ladislav Hagara | Komentářů: 8
    Které desktopové prostředí na Linuxu používáte?
     (16%)
     (7%)
     (0%)
     (11%)
     (29%)
     (2%)
     (5%)
     (1%)
     (13%)
     (24%)
    Celkem 1094 hlasů
     Komentářů: 26, poslední 12.3. 08:56
    Rozcestník

    Dotaz: Qt/C++, signály, sloty a vlánka

    xkucf03 avatar 29.9.2018 00:32 xkucf03 | skóre: 50 | blog: xkucf03
    Qt/C++, signály, sloty a vlánka
    Přečteno: 2276×

    Píši GUI aplikaci, která má číst standardní vstup a chci aby načtená data průběžně zobrazovala. Používám Qt a C++. Jsou tam potřeba dvě vlákna -- jedno pro GUI a jedno pro čtení vstupu. Z toho vlákna pro čtení nemůžu pracovat s GUI komponentami a plnit do nich hodnoty, to je jasné.

    Dočetl jsem se, že nejsnazší způsob, jak tahle dvě vlákna propojit jsou signály a sloty. To jsem udělal a funguje mi to. Akorát mi připadá, že bylo potřeba napsat moc kódu, který nic zajímavého nedělá, jen přeposílá události -- a to je potřeba udělat pro každou metodu. Výsledek:

    #pragma once
    
    #include <QObject>
    
    #include <relpipe/reader/typedefs.h>
    #include <relpipe/reader/TypeId.h>
    #include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
    #include <relpipe/reader/handlers/AttributeMetadata.h>
    
    using namespace relpipe::reader;
    using namespace relpipe::reader::handlers;
    
    // signal/slot parameters must be declared here and registered with qRegisterMetaType()
    
    Q_DECLARE_METATYPE(string_t)
    Q_DECLARE_METATYPE(std::vector<AttributeMetadata>)
    
    class QtRelationalReaderStringHadler : public QObject, public RelationalReaderStringHadler {
    	Q_OBJECT
    private:
    	RelationalReaderStringHadler* target;
    public:
    
    	QtRelationalReaderStringHadler(QObject* parent, RelationalReaderStringHadler* target) :
    	QObject(parent), target(target) {
    
    		// see Q_DECLARE_METATYPE above
    		qRegisterMetaType<string_t>();
    		qRegisterMetaType<std::vector < AttributeMetadata >> ();
    
    		QObject::connect(this, &QtRelationalReaderStringHadler::signal_startRelation, this, &QtRelationalReaderStringHadler::slot_startRelation);
    		QObject::connect(this, &QtRelationalReaderStringHadler::signal_attribute, this, &QtRelationalReaderStringHadler::slot_attribute);
    		QObject::connect(this, &QtRelationalReaderStringHadler::signal_endOfPipe, this, &QtRelationalReaderStringHadler::slot_endOfPipe);
    	}
    
    	virtual ~QtRelationalReaderStringHadler() {
    
    	}
    
    	virtual void startRelation(string_t name, std::vector<AttributeMetadata> attributes) override {
    		emit signal_startRelation(name, attributes);
    	}
    
    	virtual void attribute(const string_t& value) override {
    		emit signal_attribute(value);
    	};
    
    	virtual void endOfPipe() override {
    		emit signal_endOfPipe();
    	};
    
    signals:
    	void signal_startRelation(string_t name, std::vector<AttributeMetadata> attributes);
    	void signal_attribute(const string_t& value);
    	void signal_endOfPipe();
    
    private slots:
    
    	void slot_startRelation(string_t name, std::vector<AttributeMetadata> attributes) {
    		target->startRelation(name, attributes);
    	};
    
    	void slot_attribute(const string_t& value) {
    		target->attribute(value);
    	};
    
    	void slot_endOfPipe() {
    		target->endOfPipe();
    	};
    };
    

    Jde mi o to, že mám rozhraní RelationalReaderStringHadler a toto rozhraní mi provolává metoda, která parsuje vstup. V CLI aplikaci to můžu napojit napřímo, ale tady jsem mezi to musel vložit ještě tu "proxy" QtRelationalReaderStringHadler, která to prožene přes signály/sloty a tím zajistí, že se data mezi dvěma vlákny předají správně. Napadá vás nějaké elegantnější řešení?

    V dokumentaci Qt jsem našel, že to jde napojovat i na std::bind nebo lambdu, což by trošku kódu ušetřilo (mohl bych kód slotů předat do QObject::connect() jako funkci). Nešlo by to napojit nějak automaticky? Protože ta rozhraní jsou v obou vláknech totožná.

    Případně by se mi líbilo, kdybych mohl v těch metodách místo emit signal_... jen předat někam lambdu s tím, že se má provést v GUI vlákně. (to bych si asi zvládl napsat sám a protáhnout všechna volání přes jeden signál/slot, ale nechci vymýšlet kolo a radši bych se naučil nějaký standardní postup).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes

    Řešení dotazu:


    Odpovědi

    29.9.2018 08:26 MadCatX
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    A proč nemůžeš ty signály vysílat přímo z RelationStringHandleru? Fungovalo by to IMHO stejně a ušetřil by sis psaní toho proxy.
    xkucf03 avatar 29.9.2018 11:36 xkucf03 | skóre: 50 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka

    Ten RelationalReaderStringHadler je rozhraní definované v knihovně, kterou tato aplikace používá. Třída QtRelationalReaderStringHadler je implementace tohoto rozhraní v aplikaci. Stejně tak toto rozhraní implementuje GUI třída:

    class RelpipeChartMainWindow : public QMainWindow, public RelationalReaderStringHadler {...

    A v ní jsou pak tyto metody (sloužící i jako sloty) stylem:

    void RelpipeChartMainWindow::endOfPipe() {
    	// TODO: just display a message
    	statusBar()->addWidget(new QPushButton("endOfPipe", widget.statusbar));
    }

    Zpracování se pak spouští ve vlákně na pozadí:

    RelpipeChartMainWindow window;
    QtRelationalReaderStringHadler handler(&app, &window);
    reader->addHandler(&handler);
    WorkerThread t(reader); // QThread volající reader->process(); tzn. čtení STDIN a volání metod handleru
    t.start();
    

    V CLI aplikaci bych místo reader->addHandler(&handler); udělal reader->addHandler(&window); a poslal události rovnou objektu, který je vypíše (a celé by to běželo v jednom vlákně). V Qt aplikaci jsou vlákna dvě a nemůžu to napojit takhle na přímo, takže jsem to proložil tím QtRelationalReaderStringHadler. Ale rád bych našel jednodušší řešení, protože takhle tam mám 80 řádků kódu jen kvůli tomu, abych řekl že se to má provolat z jednoho vlákna do druhého (a s rostoucím počtem metod by toho kódu bylo ještě víc).

    P.S. Ta knihovna, ve které je RelationalReaderStringHadler není (a nemá být) závislá na Qt -- je to čisté C++.

    P.P.S. Není nutné, aby GUI třída implementovala RelationalReaderStringHadler -- klidně by se ty metody mohly jmenoval jinak a mít jiné parametry, ale přišlo mi zbytečné vymýšlet nové rozhraní, když obsah je stejný.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    30.9.2018 18:37 MadCatX
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    Mrknul jsem se na to o něco lépe a přijde mi, že to řešení se signálovacím meziobjektem máš navržené docela zvláštně. Z toho proxy objektu signáluješ sám sobě, což mi nedává žádný smysl. Mechanismus signálů a slotů v Qt sice umožňuje bezpečně signalizovat mezi více vlákny ale kód, jak ho máš napsaný teď sice funguje správně ale asi z jiného důvodu, než si myslíš.

    QObject::connect má volitený pátý parametr, který řídí, zda se má příslušný slot zavolat okamžitě jako funkce z vlákna odesílatele nebo zda se má na event queue vlákna příjemce vložit informace, že se má ten slot zavolat. Ten parametr má výchozí hodnotu Qt::AutoConnection. To znamená, že se při zpracovávání signálu handler podívá, zda příjemce náleží stejnému vláknu, ze kterého byl zavolán signál a podle toho se zachová. Proto ti to tvoje docela kostrbaté řešení funguje. Kdybys ale třeba ten proxy objekt vytvořil z jiného než hlavního vlákna, rozbilo by se to.

    Pokud nechceš, aby samotná business logika závisela na Qtčkách, budeš si sice pořád muset pomoct nějakým proxy objektem, který se ale dá napsat daleko jednodušeji. Napadá mě třeba toto:

    Mějme nějakou business funkci, která klidně může běžet v samostatném vlákně. Ta podle situace generuje nějaký progress report:
    void businessFunc()
    {
      /* ... do work ... */
      
      switch (report) {
      case 0:
        outputProxy->startRelation();
        break;
      case 1:
        outputProxy->attribute();
        break;
      case 2:
        outputProxy->endOfPipe();
        break;
      }
    }
    
    Dále mějme jednoduchý interface OutputProxy:
    class OutputProxy {
    public:
      virtual void startRelation() = 0;
      virtual void attribute() = 0;
      virtual void endOfPipe() = 0;
    };
    
    Ten interface budou implementovat konkrétní proxy třídy určené k prodrátování dat z business logiky ke konkrétnímu výstupu. Nejjednodušeji třeba takto:
    class QtOutputProxy : public OutputProxy, public QObject {
      Q_OBJECT
      
    public:
      QtOutputProxy(MyUIWidget *target, QObject *parent = nullptr) :
        QObject(parent)
      {
        connect(this, &QtOutputProxy::sig_startRelation, target, &MyUIWidget::onStartRelation);
        connect(this, &QtOutputProxy::sig_attribute, target, &MyUIWidget::onAttribute);
        connect(this, &QtOutputProxy::sig_endOfPipe, target, &MyUIWidget::onEndOfPipe);
      }
      
      void startRelation() override
      {
        emit sig_startRelation();
      }
      
      void attribute() override
      {
        emit sig_attribute();
      }
      
      void endOfPipe() override
      {
        emit sig_endOfPipe();
      }
      
    signals:
      void sig_startRelation();
      void sig_attribute();
      void sig_endOfPipe();
    };
    
    Pokud bys měl jiný typ výstupu, který by přesně nekopíroval způsob, jakým business logika reportuje, stačí ti upravit implementaci té proxy třídy; např. takhle:
    class QtOutputProxyV2 : public OutputProxy, public QObject {
      Q_OBJECT
      
    public:
      QtOutputProxyV2(MyUIWidgetV2 *target, QObject *parent = nullptr) :
        QObject(parent)
      {
        connect(this, &QtOutputProxyV2::updateDisplay, target, &MyUIWidgetV2::onUpdateDisplay);
      }
      
      void startRelation() override
      {
        emit updateDisplay("Relation started...");
      }
      
      void attribute() override
      {
        emit updateDisplay("Displaying attribute");
      }
      
      void endOfPipe() override
      {
        emit updateDisplay("End of pipe");
      }
      
    signals:
      void updateDisplay(const QString &text);
    };
    
    xkucf03 avatar 30.9.2018 19:26 xkucf03 | skóre: 50 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    To znamená, že se při zpracovávání signálu handler podívá, zda příjemce náleží stejnému vláknu, ze kterého byl zavolán signál a podle toho se zachová.

    Koukám na to a je mi divné, že to vůbec funguje, žádné chyby ani varování... Signály i sloty jsou v QtRelationalReaderStringHadlerconnect() dělám taky v této třídě (ovšem ještě v hlavním vlákně). Pak se ve vlákně na pozadí pustí ten reader->process(), který provolává QtRelationalReaderStringHadler ovšem jako normální metody -- a až uvnitř těchto metod to jde přes signál/slot (ale v rámci toho samého vlákna) a ze slotů se provolává target->startRelation(name, attributes) ovšem už zase jako normální metoda. A to ten target patří do jiného vlákna. Asi si s tím budu muset pohrát v debuggeru, protože takhle mi přijde, že to nemůže fungovat (ale na první pohled to funguje).

    V tom void attribute(const string_t& value) se předává pouze reference a handler si má tu hodnotu přečíst/zkopírovat, ale nepatří mu -- jakmile skončí tahle metoda, tak ten, kdo ji volal, tu hodnotu smaže (resp. skončí rozsah její platnosti). Tady by mi ASan nadával, že používám již uvolněnou paměť, což se neděje. To nasvědčuje tomu, že ty signály/sloty jsou v mém případě synchronní (protože jsou v rámci jednoho vlákna/objektu). A celé to asi funguje jen díky tomu, že Qt se (náhodou) nerozbije, i když manipuluji s jeho GUI komponentami z jiného vlákna, než bych měl.

    Předělám to zatím tím prvním způsobem -- tzn. přesunu sloty do RelpipeChartMainWindow -- tím by to mělo být asynchronní -- a zároveň změním jejich signatury, aby se pracovalo s kopií a ne referencí. BTW: když je to asynchronní, je zaručené pořadí? Protože na tom tady záleží -- ty atributy se plní do tabulky a řádek/sloupec se odvozuje od pořadí, v jakém ta hodnota přišla.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    30.9.2018 21:00 MadCatX
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    To znamená, že se při zpracovávání signálu handler podívá, zda příjemce náleží stejnému vláknu, ze kterého byl zavolán signál a podle toho se zachová.

    Koukám na to a je mi divné, že to vůbec funguje, žádné chyby ani varování... Signály i sloty jsou v QtRelationalReaderStringHadlerconnect() dělám taky v této třídě (ovšem ještě v hlavním vlákně). Pak se ve vlákně na pozadí pustí ten reader->process(), který provolává QtRelationalReaderStringHadler ovšem jako normální metody -- a až uvnitř těchto metod to jde přes signál/slot (ale v rámci toho samého vlákna) a ze slotů se provolává target->startRelation(name, attributes) ovšem už zase jako normální metoda. A to ten target patří do jiného vlákna. Asi si s tím budu muset pohrát v debuggeru, protože takhle mi přijde, že to nemůže fungovat (ale na první pohled to funguje).

    Tu metodu, která jenom emituje příslušný signál ale voláš z worker vlákna. QObject::activate se tedy volá z worker vlákna. Pokud jsi instanci QtRelationalReaderStringHandleru vytvořil z hlavního vlákna, Qt to vidí a místo přímého zavolání slotu provedou queued zavolání z hlavního vlákna. Kdybys ten QtRelationalReaderStringHandler vytvořil z worker vlákna, už by to nechodilo.

    V tom void attribute(const string_t& value) se předává pouze reference a handler si má tu hodnotu přečíst/zkopírovat, ale nepatří mu -- jakmile skončí tahle metoda, tak ten, kdo ji volal, tu hodnotu smaže (resp. skončí rozsah její platnosti). Tady by mi ASan nadával, že používám již uvolněnou paměť, což se neděje. To nasvědčuje tomu, že ty signály/sloty jsou v mém případě synchronní (protože jsou v rámci jednoho vlákna/objektu). A celé to asi funguje jen díky tomu, že Qt se (náhodou) nerozbije, i když manipuluji s jeho GUI komponentami z jiného vlákna, než bych měl.

    Teď bych nerad kecal, ale pokud se provádí queued zavolání slotu, všechny jeho parametry ze zkopírují, takže původní objekty klidně mohou být zničeny. Proto taky musí mít vše, co zaregistruješ pomocí makra Q_DECLARE_METATYPE implicitiní defaultní konstruktor i copy konstruktor. Pokus o manipulaci s GUI objekty odjinud než z hlavního vlákna by velmi pravděpodobně aspoň vypsal varování do konzole.

    Předělám to zatím tím prvním způsobem -- tzn. přesunu sloty do RelpipeChartMainWindow -- tím by to mělo být asynchronní -- a zároveň změním jejich signatury, aby se pracovalo s kopií a ne referencí. BTW: když je to asynchronní, je zaručené pořadí? Protože na tom tady záleží -- ty atributy se plní do tabulky a řádek/sloupec se odvozuje od pořadí, v jakém ta hodnota přišla.

    Já bych ty argumenty klidně předával referencí, IMHO si tím ušetříš dvě zbytečná volání copy konstruktoru. Můžeš si to ověřit tím, že v copy konstruktoru necháš něco vypsat. Pořadí vykonání slotů by i při queued aktivaci zachováno být mělo.
    vlastikroot avatar 30.9.2018 10:59 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka

    Kdyz napises emit signal_endOfPipe(); tak je to uplne obycejny volani funkce (ten emit nic neni). Tu funkci ti vygeneruje MOC, jen se podiv do nejakeho moc_*.cpp souboru, tam uvidis jak presne to funguje.

    Me dost pomohl k pochopeni tenhle clanek. Runtime se da delat vsechno mozny, napr. si z QMetaObject vytahnout seznam signalu/slotu a volat je pak pres int/string ID a list variant argumentu (ja mam takhle reseny remote method invocation). Otazka je, jestli pro tvy reseni neni lepsi to proste napsat rucne, nez si pridelavat zbytecny runtime overhead.

    We will destroys the Christian's legion ... and the cross, will be inverted
    xkucf03 avatar 30.9.2018 14:26 xkucf03 | skóre: 50 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    Příloha:
    Kdyz napises emit signal_endOfPipe(); tak je to uplne obycejny volani funkce (ten emit nic neni).

    Podle toho, co jsem četl v dokumentaci a na SO, takt to takhle funguje jen, když děláš emit ve stejném vlákně ve kterém to daný slot přijímá.

    Navíc tam píší, že mezi více vlákny je to volání asynchronní, takže se vůbec divím, že mi to tak pěkně funguje a ASan mi nehlásí žádné chyby :-D

    Asi přes ty signály/sloty budu všude předávat radši kopii hodnoty než referenci...

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    vlastikroot avatar 30.9.2018 18:52 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    Ja narazel na tohle
    # define Q_EMIT
    #ifndef QT_NO_EMIT
    # define emit
    #endif
    v src/corelib/kernel/qobjectdefs.h. Emit opravdu nic nedela, je to prazdny define.
    We will destroys the Christian's legion ... and the cross, will be inverted
    xkucf03 avatar 30.9.2018 19:01 xkucf03 | skóre: 50 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    Aha a má se tam tedy psát? K čemu to je?
    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    30.9.2018 19:06 MadCatX
    Rozbalit Rozbalit vše Re: Qt/C++, signály, sloty a vlánka
    V principu nikam, je to pouze poznámka pro programátora, že volaná funkce není běžná funkce ale něco, co se bude zpracovávat signal/slot mechanismem.
    2.10.2018 12:55 luky
    Rozbalit Rozbalit vše QFuture
    Nebylo by jednodussi pouzit QFutureWatcher a nechat si vysledky posilat do jednoho vlakna pres signal resultReadyAt?
    4.10.2018 09:36 MadCatX | skóre: 28 | blog: dev_urandom
    Rozbalit Rozbalit vše Re: QFuture
    To si nemyslím. K signalizaci nějaké události mezi dvěma komponentami v Qtčkách slouží právě signály a sloty, které jsou de-facto veřejným API a jsou zvlášť vymyšlené tak, aby byly thread-safe. Přehazovat si mezi komponentami nějaký wrapper okolo future mi přijde trochu čuňácké. Další možností je třeba sypat výsledky to nějaké fronty stylem producent-konzument. To by ale znamenalo napsat si synchronizační mechanismus ručně, zatímco se signály a sloty to bude "prostě fungovat".
    4.10.2018 12:15 luky
    Rozbalit Rozbalit vše Re: QFuture
    Proc? Cteci funkci spustim pres QtConcurrent::run a vracenej QFuture pouziju na update gui a zpracovani vysledku. Tradicni postup na asynchroni veci v QT...
    4.10.2018 17:37 MadCatX | skóre: 28 | blog: dev_urandom
    Rozbalit Rozbalit vše Re: QFuture
    Future, aspoň jak ji chápu a používám já, je užitečná v situaci, kdy někde odpálím nějakou asynchronně běžící funkci a výsledek volání si přes future vyzvednu, když ho potřebuji. Tazatel má ale plnohodnotné worker vlákno, které během své činnosti produkuje nějaká data průběžně a proto mi zde použití future nepřijde šikovné. Ne, že by to nešlo ale ve výsledku to IMHO nebude o nic jednodušší než původně navrhované signály a sloty.
    5.10.2018 11:07 luky
    Rozbalit Rozbalit vše Re: QFuture
    QFuture se hodi i na prubezne produkovana data, treba QFutureWatcher::progressValueChanged se muze bindnout do QProgressBar::setValue a rovnou ukazovat prubeh. Data jde vyzvedavat postupne pres QFutureWatcher::resultsReadyAt.
    vlastikroot avatar 5.10.2018 19:56 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
    Rozbalit Rozbalit vše Re: QFuture
    IMHO je QFuture prasarna na cokoliv co ma bezet stale a zpracovavat zpravy. Je to urceny na dej, ktery se ma nekdy dokoncit. Napr. request nad protokolem implementovanym temi zpravami (vyssi vrstva).
    We will destroys the Christian's legion ... and the cross, will be inverted
    5.10.2018 20:48 luky
    Rozbalit Rozbalit vše Re: QFuture
    Ja jsem zadani pochopil tak, ze se nacita vstup a postupne se zobrazuje. Kdyz je nacteno vse, program se neukonci, ale dal bezi.
    xkucf03 avatar 5.10.2018 21:40 xkucf03 | skóre: 50 | blog: xkucf03
    Rozbalit Rozbalit vše Re: QFuture

    Ano, má to číst postupně. Šlo mi o to, aby se uživateli zobrazily první řádky prvních tabulek, hned jak přijdou jejich data, a uživatel s nimi mohl pracovat, i když se ještě průběžně načítají další.

    Pouštěl jsem si to přes:

    (for x in `seq 5`; do sleep 1; relpipe-in-fstab; done) | pv --quiet --rate-limit 50 | relpipe-out-chart.qt

    a tam je hezky vidět, jak data postupně naskakují v jednotlivých buňkách a dá se s tím GUI současně pracovat.

    Nakonec jsem to vyřešil tím, že jsem proxy zjednodušil:

    class QtRelationalReaderStringHadler : public QObject, public RelationalReaderStringHadler {
    
    	Q_OBJECT
    public:
    	QtRelationalReaderStringHadler(QObject* parent) : QObject(parent) {
    	}
    
    	virtual ~QtRelationalReaderStringHadler() {
    	}
    
    	virtual void startRelation(string_t name, std::vector<AttributeMetadata> attributes) override {
    		emit startRelationReceived(name, attributes);
    	}
    
    	virtual void attribute(const string_t& value) override {
    		emit attributeReceived(value);
    	};
    
    	virtual void endOfPipe() override {
    		emit endOfPipeReceived();
    	};
    
    signals:
    	void startRelationReceived(const string_t name, std::vector<AttributeMetadata> attributes);
    	void attributeReceived(const string_t value);
    	void endOfPipeReceived();
    };
    

    Napojení signálů a slotů dělám v hlavním vlákně (původně to bylo v té proxy):

    QObject::connect(&handler, &QtRelationalReaderStringHadler::startRelationReceived, &window, &RelpipeChartMainWindow::startRelation, Qt::ConnectionType::QueuedConnection);
    QObject::connect(&handler, &QtRelationalReaderStringHadler::attributeReceived, &window, &RelpipeChartMainWindow::attribute, Qt::ConnectionType::QueuedConnection);
    QObject::connect(&handler, &QtRelationalReaderStringHadler::endOfPipeReceived, &window, &RelpipeChartMainWindow::endOfPipe, Qt::ConnectionType::QueuedConnection);

    A v GUI třídě implementuji sloty:

    void RelpipeChartMainWindow::startRelation(const string_t name, std::vector<AttributeMetadata> attributes) {
    	setStatusMessage(L"Reading relation: " + name);
    	attributeCounter = 0;
    	QSplitter* splitter = new QSplitter(Qt::Orientation::Vertical, tabs);
    
    	currentTable = new QTableWidget(0, attributes.size(), splitter);
    	QStringList headers;
    	for (AttributeMetadata a : attributes) headers << QString::fromWCharArray(a.getAttributeName().c_str());
    	currentTable->setHorizontalHeaderLabels(headers);
    	currentTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
    
    	// TODO: chart
    	splitter->addWidget(new QPushButton("here will be the chart", splitter));
    	splitter->addWidget(currentTable);
    	int index = tabs->addTab(splitter, QString::fromWCharArray(name.c_str()));
    	if (tabs->count() == 2) tabs->setCurrentIndex(index); // switch to the first relation (first tab is Options tab)
    	tabs->setTabIcon(index, QIcon::fromTheme("application-vnd.oasis.opendocument.spreadsheet"));
    }
    
    void RelpipeChartMainWindow::attribute(const string_t value) {
    	// TODO: draw chart
    	integer_t column = attributeCounter % currentTable->columnCount();
    	integer_t row = attributeCounter / currentTable->columnCount();
    	if (row >= currentTable->rowCount()) currentTable->insertRow(currentTable->rowCount());
    	currentTable->setItem(row, column, new QTableWidgetItem(QString::fromWCharArray(value.c_str())));
    	attributeCounter++;
    }
    
    void RelpipeChartMainWindow::setStatusMessage(string_t message) {
    	status->setText(QString::fromWCharArray(message.c_str()));
    }
    
    void RelpipeChartMainWindow::endOfPipe() {
    	setStatusMessage(L"Reading successfully finished.");
    }
    

    Tu proxy bych nejradši zredukoval ještě víc, ale ty metody dané rozhraním RelationalReaderStringHadler jsou virtuální a nešlo mi je použít jako signály, takže jsou to normální metody a signál se z nich jen emituje, místo aby sama ta metoda byla signálem. Ale to už není tolik kódu navíc, takže jsem s tím už víceméně spokojený.

    Nedokáži posoudit, jestli by to přes QFuture bylo jednodušší/lepší...

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    11.10.2018 06:24 Jardik
    Rozbalit Rozbalit vše Re: QFuture
    Nebylo. V podstate to mas, tak jak to v ramci qt muzes nejlepe udelat.

    Založit nové vláknoNahoru

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.