2022. február 2., szerda

PyQT5 ügyek

Meglehetősen kezdő vagyok a fent említett rendszerben. Eddigi működésem során két olyan nyögvenyelős témába botlottam, amikről úgy gondoltam, tovább adok némi információt. A nagyon profik talán nem érzik úgy, amikor magyarázzák, hogy ezek a dolgok problémásak, a dokumentáció pedig nem túl bőbeszédű.

Az egyik ilyen a drag and drop - magyarabbul a húzd és ejtsd - műveletek megvalósítása. Nekem kisebb méretű képek mozgatására volt szükségem, és egy darabig keresőztem, mire bele kellett nyugodnom, hogy önmagukban nincsenek ilyenre felkészítve. Kellő elszántsággal valószínűleg ki lehetne terjeszteni a QImage vagy QPixmap osztályokat úgy, hogy önmagukban is húzhatók legyenek. De egyszerűbbnek tűnt ráültetni QLabel widgetre, az pedig alkalmas húzásra és ejtés fogadására is. A ráültetés a setPixmap(pixmap) tagfüggvény útján lehetséges. A neten lelhető példák bonyolultsága nem sokkal múlja felül a Hello, World szintet. Ráteszik a képet a QLabel elemre, hozzáadják a szülőhöz, és íme, látható. Ami a hozzám hasonló zöldfülűnek nem nyilvánvaló, az az, hogy ez a paintEvent függvény eredeti működését feltételezi. Ha azt az ember egyéb okból felülírja, akkor bele kell tennie a QPixmap kirajzolását is a megjelenéshez.
A húzás megkezdésekor lenyomjuk az egér bal gombját. A mousePressEvent függvénybe lehet beleírni, hogy mentse el a kezdő pozíciót - már ha szükségünk van ilyenre. A mouseMoveEvent függvényben pedig először is tisztázzuk, hogy le van-e nyomva a bal gomb, aztán létrehozunk egy QDrag objektumpéldányt. Ez fogja eljuttatni a célba azokat az adatokat, amelyeket szeretnénk. Ehhez alapesetben kell egy QMimeData típusú konténer. A Mime adattípusok szabványosak, így lehet másik alkalmazásba/ból is húzogatni dolgokat. Nekem a képre csak a felhasználó szemének vidítására volt szükségem, ezért a kínálatból a szöveg (text) adattípust választottam, ebbe kódoltam bele az átjuttatni kívánt adataimat. A drag objektumhoz hozzá lehet rendelni egy független QPixmap képet is, ez az, amit mozogni látunk a képernyőn. (Ide került az én képecském.) A drag exec_(mód) függvényével működtetjük a húzási effektust. A paraméterrel választhatunk, hogy pl. másoljuk a vonszolt adatcsomagot, vagy mozgatjuk. (Nekem QT.CopyAction.)
Az ejtés fogadásához, amely nálam szintén QLabel, kell egy kis előkészület: a setAcceptDrops(True) meghívása. A dragEnterEvent függvényben vizsgálatokat végezhetünk, hogy az adott érkező kívánatos-e. Ha igen, event.accept(), ha nem, event.ignore() . Végül aztán a dropEvent függvényben további vizsgálódás után kinyerjük a mimeData tartalmát és felhasználjuk. Megint csak accept-tel zárunk, ha minden rendben, és ignore, ha valamely szükséges feltétel nem teljesül.

A másik tárgykör, ami sok fejtörést okozott, a dialógusablak használata és a válasz birtokbavétele. Odáig sima ügy, hogy kapunk egy QDialog nevű alaposztályt, amely üres, tehát öröklés útján építünk rá egy sajátot, amely tartalmazza a megfelelő beviteli eszközöket, és kezelőgombokat. Utóbbiakhoz jól használható a QDialogButtonBox, ehhez jár többféle előre elkészített típus (OK, Cancel, Save, stb.). Ha használjuk, a buttonbox szignáljait csatlakoztatjuk az ablak accept, ill. reject slotjaihoz. Itt jött a bonyodalom, mert ha a slot függvényekbe tettem saját kódot, akkor sose sikerült tisztességes visszaadott értéket kapni. Akkor se, ha beleírtam az ősosztály meghívását. Pedig azt hittem, hogy a saját bekért adataimat ott kellene return-ba tenni. Az adatok visszaadásáról igazán írhattak volna valamit a dokumentációba. Végül a megoldást az jelentette, hogy egy külön függvénybe tettem ezt a return-t, az accept és a reject pedig felülíratlan maradt. Ilyen módon az ablak indítása (exec_) után a visszakapott eredményt a QDIalog.Accepted értékkel hasonlítva eldönthető, hogy kell-e értelmes adatot találni, és a külön visszaadó függvénytől (respond-nak neveztem) vesszük át az adatot. Nekem ugyan nem világos, hogy az ablak becsukódása után hogyan lehet még függvényt hívni benne, de működik.

A szemléltető programrészeket inkább képként illesztem be. Nincs kedvem a python program rendezett és színezett megjelenítésével vesződni, bár úgy sejtem, lehetséges.