Ocena wątku:
  • 0 Głosów - 0 Średnio
  • 1
  • 2
  • 3
  • 4
  • 5
Auto edycja warstwy
03-04-2013, 11:29,
#1
Auto edycja warstwy
Od jakiegoś czasu zgłębiam tajniki QGIS i większość odpowiedzi znalazłem już tu na forum lub w dokumentacji Quantuma.

Otóż:
Mam bardzo duży projekt - ponad 40 warstw do których zrobiłem personalizowane formularze edycji. W większości starałem się unikać Pythona. Przy takiej ilości danych mam ustawione otwieranie bezpośrednio formularza obiektu oraz wyszukiwanie wyników identyfikacji od góry do dołu.
Przy odpowiednim układzie warstw fajnie to działa - kliknięcie na mapie otwiera formularz pierwszego znalezionego obiektu.

I tutaj problem - warstw jest tyle że ciężko teraz odnaleźć w legendzie warstwę do której należy obiekt, do tego trzeba włączyć edycję - wybrać obiekt jeszcze raz...

Pomysł mi zaświtał żeby w funkcji inicjującej formularz umieścić fragment włączający edycję danej warstwy i po zakończeniu "OK" - zapis, "Cancel" - powrót. Znalazłem odpowiednie klasy i z konsoli Pythona potrafię coś takiego zrobić. Czy funkcja inicjująca może wogóle takie rzeczy obsługiwać? Tutaj mi się nie udało dotychczas znaleźć odpowiedzi a dokumentacja w tym kierunku jest raczej skąpa. Trochę mnie przeraża szukanie odpowiedzi w kodzie źródłowym qgisa Smile

Będę wdzięczny za podpowiedzi. Może jest inna droga?
03-04-2013, 12:58,
#2
RE: Auto edycja warstwy
Nie mam pod ręką stabilnego Quantuma, tylko rozgrzebaną alfę 2.0, ale nie powinno być z tym problemu. W funkcji inicjującej włączasz tryb edycji oraz podłączasz sygnały z klawiszy OK i Cancel do dwóch kolejnych funkcji, w których implementujesz koniec trybu edycji. Z grubsza powinno to wyglądać jak w tym przykładzie:

http://nathanw.net/2011/09/05/qgis-tips-...hon-logic/

tylko zamiast funkcji validate() tworzysz np. zaakceptowano() i odrzucono(), w których wywołujesz warstwa.commitChanges() i warstwa.rollBack(). A skąd wziąć w nich warstwę? Zwróć uwagę na zmienne globalne (tutaj nameField i myDialog) - do zmiennej globalnej np. warstwa w funkcji inicjącej zapiszesz warstwę, żeby móc ją wywołać w tych dwóch pozostałych funkcjach.

Ważna uwaga: niestety po każdej zmianie w pliku zawierającym funkcję inicjującą MUSISZ przeładować QGISa, żeby zobaczył zmianę. Dlatego próby wygodniej jest robić w konsoli.

Ważna uwaga 2: API QGIS-a 1.x i nadchodzącego wielkimi krokami 2.x się różnią, więc przeglądając dokumentację online zwracaj na to uwagę. Np. w adresie: http://www.qgis.org/api/1.8/classQgsVectorLayer.html jest człon 1.8 - bez niego wyświetli się API gałęzi master, czyli alphy 2.0.
Zasadnicza różnica przy formularzach jest taka, że w QGIS-ie 1.x do funkcji inicjującej przekazywane są id warstwy i obiektu, czyli musisz znaleźć warstwę po id. Nie pamiętam teraz, jak to najłatwiej zrobić, pewnie trzeba szukać w klasie QgsMapLayerRegistry albo QgsMapCanvas. Natomiast w QGIS-ie rozwojowym/nocnym, czyli przyszłym 2.0, do funkcji inicjującej przekazywane są już nie id warstwy i obiektu, tylko warstwa i obiekt we własnych osobach, czyli obiekty klasy QgsVectorLayer i QgsFeature. Dzięki temu można od razu wywołać warstwa.startEditing()
03-04-2013, 22:24,
#3
RE: Auto edycja warstwy
Działa! Dziękuję bardzo za rzeczową odpowiedź!

Wszystko to gdzieś czytałem i jakoś mi to nie chciało działać. Twój post pomógł mi to usystematyzować. To że zmiany nie łapią już wyczytałem i przy takim projekcie to upierdliwe, fakt.

Obiekt typu QgsVectorLayer udało mi się wydłubać z mapCanvas().layers() według znanej nazwy Smile - działa też z legendInterface().layers()

O zmianach w funkcji inicjującej w wersji 2.0 znalazłem i uprościło by to mój kod (swoją drogą to jedna z niewielu informacji które można znaleźć na temat inicjacji formularzy poza linkiem do blogu Nathana który podałeś...)

ALE
Teraz jeszcze jedna zagadka: Qgis otwiera formularze w 2 sposoby - zależnie czy edycja jest włączona czy nie. No i mimo że wszystko fajnie, edycja włącza się tak jak zakładałem - to formularz ma wyłączone pola i przycisk "OK". Da się w tym stanie wybrać drugi formularz na tej samej warstwie i ten już jest aktywny, "OK" i "Cancel" działa prawidłowo. Tylko potem "Cancel" w pierwszym formularzu wywala QGIS Smile

Jeżeli tego nie da się przeskoczyć to marny pożytek z tej możliwości.
03-04-2013, 23:02,
#4
RE: Auto edycja warstwy
Hmmm, no tak, skoro funkcja inicjująca dostaje jako pierwszy parametr okno formularza, to ono już musi być wcześniej otwarte. Takie gorące pomysły rozwiązania, pewnie wyjdą przy nich kolejne problemy:

1. Pierwszy jest partyzancki. Można spróbować na wszystkich widgetach w oknie wywołać metodę setEnabled(True), a potem uczynić okno modalnym, żeby uniemożliwić otwarcie drugiego:
Kod:
for widzet in dialog.findChildren(QLineEdit): widzet.setEnabled(True)
for widzet in dialog.findChildren(QComboBox): widzet.setEnabled(True)
itd.
dialog.setModal(True)
Zamiast kolejno wywoływać klasy widgetów można niby zastosować dialog.children(), ale to zwróci tylko najwyższy poziom, czyli np. QGridLayout i dopiero w nim, albo jeszcze głębiej, trzeba by szukać docelowych widgetów). Genralnie, nie wiem, czy to wszystko zadziała, ale wygląda obiecująco

2. Można spróbować w metodzie inicjującej zamknąć ten dialog, włączyć tryb edycji i spróbować go jakoś wywołać ponownie. Nie jestem pewien, czy gdziekolwiek w API jest wystawiona taka możliwość. Jeśli jest, to powinno to być rozwiązanie prostsze i czystsze od poprzedniego. Jeśli nie ma, to w zasadzie niemożliwe.

3. Najelegantsze ale i najbardziej pracochłonne: dać sobie spokój ze standardowym narzędziem do odpytywania i napisać wtyczkę, która tworzy własne narzędzie (potomka QgsMapTool), a wtedy można już robić co dusza zapragnie.
04-04-2013, 11:09,
#5
RE: Auto edycja warstwy
Niestety, powalczyłem i odpuściłem.
1. sposób działa o tyle że QGIS chowa przycisk "OK" a zdefiniowanie swojego przycisku do slotu accepted() nie zapisuje wyników edycji.
2. openFeatureForm zastosowany w funkcji inicjującej zawiesza całego Qgisa.
3. Może w przyszłym projekcie, już planuję naukę pisania własnych wtyczek. Podstawy Pythona już opanowałem. Jeszcze raz dziekuję za pomoc. Fajnie że ktoś z Polski jest w ekipie rozwojowej QGIS - to wielkie wsparcie, bo dokumentacja w wielu przypadkach jest bardzo skąpa.
04-04-2013, 11:30,
#6
RE: Auto edycja warstwy
Dzięki :-)

Co do pkt 1) to może ten klawisz jest tylko schowany. Nie pamiętam, czy to jest QPushButton, czy QToolButton:
Kod:
for widzet in dialog.findChildren(QPushButton): widzet.show()
for widzet in dialog.findChildren(QToolButton): widzet.show()
04-04-2013, 21:53, (Ten post był ostatnio modyfikowany: 04-04-2013, 21:54 {2} przez jakosek.)
#7
RE: Auto edycja warstwy
Poszukałem dziś jeszcze trochę i znalazłem trochę informacji, tak jak by ktoś potrzebował.

Za rysowanie okna formularza odpowiada klasa QgsAttributeDialog i w niej zawarte są całe sztuczki.

Kod:
buttonBox->setStandardButtons( QDialogButtonBox::Cancel );

W ten sposób są chowane przyciski buttonBox'a. Załatwiłem to szybko i wszystko widać:
Kod:
buttonbox.setStandardButtons(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)

Ale zapis zmienionych atrybutów nadal nie działa - chyba nie jest odpowiednio przekazywany spowrotem sygnał accept()...

Próbowałem nawet przenieść do Pythona poniższy fragment:
Kod:
const QgsFields& fields = mLayer->pendingFields();
   for ( int idx = 0; idx < fields.count(); ++idx )
   {
     QVariant value;

     if ( QgsAttributeEditor::retrieveValue( mProxyWidgets.value( idx ), mLayer, idx, value ) )
       mFeature->setAttribute( idx, value );
   }

Ale sobie odpuściłem, nie do końca wiem jak obsłużyć to w Pythonie (o ile wogóle się da). Problemem tu jest przekazanie konkretnego QWidget do QgsAttributeEditor.retrieveValue() bo resztę mniej - więcej kojarzę.

Dlatego temat odpuszczam, szkoda życia. Prędzej by było skompilować QGIS z drobnymi zmianami Smile
05-04-2013, 09:59,
#8
RE: Auto edycja warstwy
Ja się właśnie zbieram do Valmiery [1] (straszyli łotewskimi drogami, to ruszamy pięć dni wcześniej l-) ) więc już też nie spojrzę, w którym momencie to utyka. Jeśli dotarłeś do granic możliwości tego dostosowywania formularzy, to pozostaje wtyka albo właśnie przeróbka w kodzie. Można by ją wprowadzić na stałe, tylko chyba ten przypadek nie jest zbyt typowy...

[1] http://hub.qgis.org/wiki/quantum-gis/9_Q...miera_2013
05-04-2013, 21:50, (Ten post był ostatnio modyfikowany: 06-04-2013, 16:47 {2} przez jakosek.)
#9
RE: Auto edycja warstwy
Cytat:Można by ją wprowadzić na stałe, tylko chyba ten przypadek nie jest zbyt typowy...

Właściwie to w starszych wersjach QGIS było tylko okno edycji, potem to rozdzielono. Generalnie ma to sens, tylko mi w tym jednym przypadku nie pasuje.

[1] Niezła zakładka 5 dni Big Grin

UPDATE:

Udało mi się osiągnąć efekt zupełnie inną drogą. Efekty są nawet lepsze od oczekiwanych. Dodałem do wszystkich warstw akcję otwierającą formularz edycyjny _PO_ włączeniu edycji. Jak komuś brakowało możliwości otwierania formularza z akcji to może sobie coś wyłowić z tego kodu Smile (chyba nawet ktoś postulował o dodanie tego do domyślnych akcji).

Reszta bajeru która powoduje że korzysta się z tego przyjemnie to wtyczka "Hotlink" - klikając na mapie wyświetla listę dostępnych akcji na wszystkich widocznych warstwach.

Akcja w Pythonie:
Kod:
layers = qgis.utils.iface.mapCanvas().layers()
for layer in layers:
    layerType = layer.type()
    if layerType == QgsMapLayer.VectorLayer:
        layerId = layer.id()
        if layerId == 'budynki20130301104122791': //tutaj podałem ręcznie id dla danej warstwy, bo przez "Hotlink" nie można pobrać [% $layerid %]
            warstwa = layer
warstwa.startEditing()
pv = warstwa.dataProvider()
feat = QgsFeature()
while pv.nextFeature(feat):
    feat.id() == [% $id %]
qgis.utils.iface.openFeatureForm(warstwa, feat)
warstwa.commitChanges()


Podobne wątki
Wątek: Autor Odpowiedzi: Wyświetleń: Ostatni post
  auto obtót warstwy wg pozycji gps gajowwy 0 6 536 22-06-2013, 23:48
Ostatni post: gajowwy
  edycja warstwy wektorowej pitt 3 16 985 22-07-2011, 10:33
Ostatni post: pitt

Skocz do: