Qt4: egyszerű grafikus objektumok inputja

 ( Joejszaka | 2009. június 22., hétfő - 21:24 )

Sziasztok!

Nem vagyok valami nagy GUI-expert, ezért a segítségeteket kérem.

Van egy Widget-em, ami képeket jelenít meg és egyszerű rajzokat rajzol rá (polygon-ok, egyenesek, körök).

Képzeljétek el, hogy van egy dialógusablak, amin látható a fenti Widget és mondjuk két gomb, a "Get Line" és "Get Polygon".

A cél a következő: Ha a user benyomja pl. a "Get Polygon" gombot, akkor a dialógusablak disable-be vált egész addig, amig a Widgetre egérkattintással fel nem rajzoltunk egy polygont.

Ezt "aktív várással" szeretném megoldani. Meg szeretnék hívni egy metódust, ami nem tér vissza addig, ami a user fel nem rajzolta a polygont. Nem a rajzolás a probléma, hanem az eseménykezelő megfelelő használata.

Ilyesmit szeretnék írni a kódban:

// Ez a sajat polygon osztalyom, ez jo es szep :)
CPolygon my_polygon;

// Ez pedig vagy megfogja az esemenykezelot, vagy indit egy sajatot, nem tudom.
// A lenyeg, hogy csak akkor ter vissza, ha a polygon le van rakva a kepernyore.
p_widget->GetPolygon( my_polygon );

A program belső használatra készül, ezért fejlesztési időre optimalizálok. Ezért keresek ilyen megoldást.

Valami ilyesmit csinál a QDialog is, de nem találtam értelmes doksit a működéséről.

Köszi az ötleteket, linkeket.

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Többször is elolvastam, próbáltam pontosan értelmezni a lényege, lehet hogy a többiek jobban átlátják, nekem kicsit ködös.

Számomra a fő kérdés, hogy mit takar pontosan az hogy a dialogus disabled állapotba kerül? Mit szeretnél elkerülni? A többi gomb aktiválását? A dialogus bezárását? Szerintem ezen kérdés körül van a kutya elásva, de lehet hogy rosszul látom.

lehet sajat esemenykezelot hasznalni, az is megoldhato hogy ne reagaljon semmi esemenyre, de mi ertelme? igy meg az egerkattintasrol sem ertesulsz
szerintem nagyon rossz nyomon jarsz, inkabb ird le hogy pontosan mit szeretnel elerni

dii kérdései jogosak.

Nem nagyon látom, hogy hogyan oldhatnád meg a leírt dolgot Qt-ben, mivel ha nem térsz vissza, akkor nem fut az event loop, tehát nem kapsz egéreseményeket sem.

QEventLoop-pal persze indíthatsz sajátot (QDialog is ezt csinálja), de szerintem te valami olyasmit akarsz ami a Qt, és úgy az egész GUI felfogás megerőszakolása...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Tegnap marhára este volt már, bocs, hogy nem voltam világos. :)

Pont az van, hogy saját eventloop-ot szeretnék indítani, mint ahogy QDialog teszi.

Valójában valószínűleg egy QEventLoop-ot doksira/példára lenne leginkább szükségem, de tegnap nem találtam ilyet a google-lel. QDialog kódja nem ér.
Nekem ez perifériás project, nincsennek rá óráim, hogy visszafejtegessek forrásokat. Nem Qt-és alkalmazást fejlesztek, hanem a tesztprogramjaimhoz használok Qt-t. :-)

Honnan tudja a Widget-em, hogy most már a saját, lokális Event Loopjához tartozik? Hogyan lehet kilépni ebből a lokális Event Loopból? Na, ilyen kérdések tisztázására kéne doksi.

Köszi.

Ne haragudj, de még mindig pontosíthatnánk a problémát szerintem, mert a baj az lehet hogy nem igazán Qt-ben gondolkodsz, és ezért már a probléma szemlélete sem biztos hogy helytálló.

Főleg az utolsó mondat miatt mondom ezt. Nem hiszem hogy az event loopokat kéne macerálnod, jól elvannak azok maguktól is.

Egyrészt minden objektumnak tudod kezelni az eseményeit. El tudod kapni az egér, billentyű, stb dolgokat. Tudsz időzített (ismétlődő) feladatot is nagyon egyszerűen készíteni, ami lefut az adott objektumban. Láthatod a hasFocus() függvénnyel, hogy azon van-e a fókusz. Stb stb.

Próbáljunk a probléma gyökeréhez visszatérni. Van egy QDialog, amiben mutatsz néhány gombot, meg egy képet (QImageView?). Ha megnyomják a gombot, belekezdel egy poligon rajzolásba. Eközben valami problémád van a QDialoggal? Vagy a poligon rajzolás nem úgy megy mint ahogy kéne?

Félreértesz. Semmi problémám nincs a rajzolással, csak a macerát akarom elkerülni, akár azon az áron is, hogy csúnya lesz a program működése, ugyanis a programot én fogom használni, senki más.

Az alapproblámám az, hogy néha egy képen ki kell jelölnöm egy polygont, egy pontot, vagy egy egyenest.

Ez gyakran megesik, és nem akarok minden egyes alkalommal a form programozásakor fölöslegesen adminisztrálni.

Szép GUI-s megoldást már írtam, de túl sokat kell gépelni (az - egyelőre nem létező - blokkolós megoldáshoz képest plusz egy connect és plusz egy slot form-onként).

Azt szeretném, hogy ha rákattintok egy gombra, akkor kijelölhessem a polygon-t a képen, és amíg kijelölöm, addig a teljes egyéb GUI blokkolódjon. És ehhez elég legyen a programkódba a megfelelő helyre egy sort beírni.

Pl. a QFileDialog is blokkolja a teljes GUI-t. Viszont én nem akarom, hogy új ablak jöjjön fel, azt szeretném, hogy a saját, kényelmes képmegjelenítő Widgetem blokkolná a programot, amíg tart a bevitel.

Remélem így már érthető. :-)

Igen érthető nagyjából :)

Még egy kérdést szeretnék feltenni: amíg a poligont rajzolod, addig mit csinál(hat) a GUI maradék része? Valami automatikus feladat zajlik benne (képek beolvasása pl)?

Csak mert a QFileDialog-nál annyi a trükk, hogy az objektum az exec() hívással indul és akkor kényszeríti a fókuszt a megjelenő ablakra. Amennyire én tudom, ez nem jelenti azt, hogy a szülő ablak "befagy", csak nem kapja meg az egér és billentyű eseményeket.

Az okosság után valami hasznosat is próbálok mondani. Megteheted azt, hogy a leimplementálod a QDialog::event() funkcióját mégpedig valahogy úgy, hogy ha a poligon, pont, egyenes van fókuszban, akkor minden event megy a kukába, egyébként meg elfogadod.

De lehet hogy sötétben tapogatózom :) majd a kollégák kisegítenek :)

Amíg a polyfont rajzolom, addig a GUI maradék része csöndben van, semmi dolga sincs :-)

Hát pedig marhaság azt mondanod, hogy a QDialog kódja nem ér, mert teljesen átlátható és érthető:

int QDialog::exec()
{
    Q_D(QDialog);

...

    bool wasShowModal = testAttribute(Qt::WA_ShowModal);
    setAttribute(Qt::WA_ShowModal, true);
    setResult(0);

    show();

    QEventLoop eventLoop;
    d->eventLoop = &eventLoop;
    QPointer guard = this;
    (void) eventLoop.exec(QEventLoop::DialogExec);
    if (guard.isNull())
        return QDialog::Rejected;
    d->eventLoop = 0;

    setAttribute(Qt::WA_ShowModal, wasShowModal);

    int res = result();

...

    return res;
}

Szóval a trükk:

    setAttribute(Qt::WA_ShowModal, true);

    QEventLoop eventLoop;
    eventLoop.exec();

    setAttribute(Qt::WA_ShowModal, false);

Azaz az aktuális widgetnek modality-t állítasz, ami nemes egyszerűséggel letiltja a többi widgetet. Meghívod az eventloop::exec-et, ami addig fut, amíg meg nem hívod az exit-jét.

A modality nem tudom mennyire fog működni, ha a widget egy hierarchia része, én egyszer rég simán setEnabled(false)-t hívtam a szülőkre.

De szerintem ha tudod szépen, inkább úgy csináld, az ilyen "megírom csúnyán, úgyis csak nekem kell" hozzáállás megbosszulja magát.
Úgyis csak egyszer kell megírnod, ha véletlenül a jövőben megint kell, akkor már csak copy+paste...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Kezdem az egesz problemat nem erteni. Atolvasgattam itt a dolgokat, de akkor sem. Ahogy en csinalnam:
Van egy form egy gombbal, 'Draw', 'Get Polygon'.
Ha a gomb megnyomattatik, disable, QImageView enable.
Minden esemenyt egy fuggvenyre kell iranyitani, ami az egesz rajzolasi folyamatot ertelmezi. Mivel elvben egy vonal (geometriai nyelven egy szakasz) is polygon (ket sarka van, egy ellel), ezert felesleges ennyire tulbonyolitani, majd kiszamolod, hogy a rajzolas soran mik tortentek.

Kulonben, van egy nagyon jo rajzprogram a Qt peldai kozt; plugandpaint a neve. Nezegesd annak a forrasat. Szerintem ez igy, ahogy meg akarod valositani, valami hihetetlen bonyolult lesz, es a vegen magad sem fogod erteni,
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.