Błąd: "wrapped C/C++ object of type QgsVectorLayer has been deleted w QGIS"

0

Witam,

Mam problem w QGIS z

RuntimeError: wrapped C/C++ object of type QgsVectorLayer has been deleted.

Potrzebuje dodać warunki else do funkcji:

ptpla = QgsProject.instance().mapLayersByName('OT_PTPL_A plac') # warstwa jest na liście w Programie QGIS
if ptpla: # Place
            ptpl = ptpla[0]
            unikalny_idensimc = set()
            unikalny_idenulic = set()
            if ptpl and ptpl.isValid() and self.modelSimcPtpl.rowCount() < 1: #próbowałem też tu
            # Pobierz atrybuty z warstwy i dodaj je do modelu. Ładuje się tylko raz na początku
                for feature in ptpl.getFeatures():
                    idenulic = str(feature.attributes()[ptpl.fields().indexFromName('IDENTYFIKATORULIC')])
                    idensimc  = str(feature.attributes()[ptpl.fields().indexFromName('IDENTYFIKATORSIMC')])
                    self.modelSimcPtpl.sort(0)
                    self.modelUlicPtpl.sort(0)
                    self.dlg.comboBox_29.setModel(self.modelSimcPtpl) 
                    self.dlg.comboBox_30.setModel(self.modelUlicPtpl)
                    
                    if idensimc not in unikalny_idensimc:
                        unikalny_idensimc.add(idensimc)
                        if idensimc != 'NULL':
                            self.modelSimcPtpl.appendRow(QStandardItem(idensimc))
                    if idenulic not in unikalny_idenulic:
                        unikalny_idenulic.add(idenulic)
                        if idenulic != 'NULL':
                            self.modelUlicPtpl.appendRow(QStandardItem(idenulic))
                self.dlg.pushButton_47.clicked.connect(self.zaznaczPtpl) # ta linia była początkowo po za If-em, ale nie rozwiązała problemu       

Pozwalającej uniknąć powyższy błąd w przypadku, gdy użytkownik usunie warstwę z listy Warstw, a pozostawi włączoną wtyczkę- która wciąż zawiera dane z usuniętej warstwy.

Warunki:

   else: # od if ptpl and ptpl.isValid()...
      print ('Tabela OT_PTPL_A nie występuje!')                 
else: # od if ptpla... 
   print("Warstwa OT_PTPL_A plac nie występuje na spisie!")    

Nie do końca rozwiązują ten problem.

Dodatkowo błąd ten pojawia się gdy chce uruchomić funkcję do aktualizacji wartości zgromadzonych w comboBox_29 i 30.

Kod wygląda tak (jest to wnętrze funkcji zaznaczPtpl):

liczba = 0
ptpl = ptpla[0]
simcPtpl = self.dlg.comboBox_29.currentText()
ulicPtpl = self.dlg.comboBox_30.currentText()
wyrazenie= f'IDENTYFIKATORSIMC= {simcPtpl} AND IDENTYFIKATORULIC = {ulicPtpl}' 

ptpl.selectByExpression(wyrazenie) #błąd po usunięciu tabeli wywala się tutaj- ptpl zostało usunięte, ale dopisanie if-a w #tym miejscu nie rozwiązuje problemu
danePtpl = []
if self.model8.rowCount() > 0:
            # Usunięcie wszystkich rekordów z modelu6
            self.model8.removeRows(0, self.model8.rowCount())
if ptpl and ptpl.isValid():
        # Pobierz atrybuty z warstwy i dodaj je do modelu
    for feature in ptpl.getFeatures():
                idenulic = str(feature.attributes()[ptpl.fields().indexFromName('IDENTYFIKATORULIC')])
                idensimc  = str(feature.attributes()[ptpl.fields().indexFromName('IDENTYFIKATORSIMC')])
                placcecha = str(feature.attributes()[ptpl.fields().indexFromName('PLACCECHA')]) #...

Możliwe, że trzeba coś dodać do warunków if, żeby zabezpieczyć wtyczkę przed tym błędem - przypadkowym usunięciem warstwy źródłowej przez użytkownika.

Z góry dziękuje za każdą pomoc

PS. AI słabo podpowiada (możliwe, że źle definiuje problem?)

2

Możesz podać problme w ten sposób, żeby sie dało łatwo zreprodukować? Inaczej, można prosić
https://stackoverflow.com/help/minimal-reproducible-example ?

0

To podaję wersję skróconą tego co powyżej:

Celem jest usunięcie błędu: RuntimeError: wrapped C/C++ object of type QgsVectorLayer has been deleted.

Pojawia się on, gdy Użytkownik (jestem w fazie testów) usunie warstwę QGIS z listy warstw, a pozostawi włączoną wtyczkę, która wciąż przechowuje dane z warstw, mimo że ta została usunięta.

ptpla = QgsProject.instance().mapLayersByName('OT_PTPL_A plac') # warstwa jest na liście w Programie QGIS
if ptpla: # Place
            ptpl = ptpla[0]
            unikalny_idensimc = set()
            unikalny_idenulic = set()
            if ptpl and ptpl.isValid() and self.modelSimcPtpl.rowCount() < 1: #próbowałem dodać else również do tego
            # Pobierz atrybuty z warstwy i dodaj je do modelu. Ładuje się tylko raz na początku
                for feature in ptpl.getFeatures():
                    idenulic = str(feature.attributes()[ptpl.fields().indexFromName('IDENTYFIKATORULIC')])
                     #...
                self.dlg.pushButton_47.clicked.connect(self.zaznaczPtpl) # ta linia była początkowo po za If-em, ale nie rozwiązała problemu  

Błąd pojawia się przy zmiennej ptpla- jeśli warstwa, którą pobierała została usunięta zmienna staje się pusta.

Próbowałem z warunkami else (przykład w poprzednim poście), ale do nie daje efektu.

Błąd ten pojawia się również w funkcji "zaznaczPtpl" (2 niezależne miejsce)
Funkcja wyzwalana jest wraz z przyciskiem (pushButton), który pobiera dane ze wpisanej wyżej comboBox. Szerzej poniżej

ptpl = ptpla[0]
simcPtpl = self.dlg.comboBox_29.currentText()
ulicPtpl = self.dlg.comboBox_30.currentText()
wyrazenie= f'IDENTYFIKATORSIMC= {simcPtpl} AND IDENTYFIKATORULIC = {ulicPtpl}' #po usunięciu warstwy comboBox-y dalej przechowują dane, ale nie pobierają się do zapytania

ptpl.selectByExpression(wyrazenie) #błąd po usunięciu warstwy z listy QGIS wywala się tutaj, ale dopisanie else dla tego warunku w tym miejscu nie rozwiązuje problemu
danePtpl = []
if self.model8.rowCount() > 0:
#...

Mam nadzieję że teraz będzie prościej.

1

ALe jak to zreprodukować, np., co to za obiekt: QgsProject?

0

Chyba OP nie obejrzał linka który podałeś :(

0
Marius.Maximus napisał(a):

Chyba OP nie obejrzał linka który podałeś :(

Przeczytałem, ale prościej wytłumaczyć nie potrafię.

1
Karol Śpila napisał(a):
Marius.Maximus napisał(a):

Chyba OP nie obejrzał linka który podałeś :(

Przeczytałem, ale prościej wytłumaczyć nie potrafię.

Po prostu podaj na tyle danych, żebyśmy mogli zreprodukowac problem u siebie

0
lion137 napisał(a):

ALe jak to zreprodukować, np., co to za obiekt: QgsProject?

QgsProject to część składni Pythona QGIS- programu do tworzenia i przetwarzania map

Zastanawiam się czy nie dodać słówka pass, ale nie mam pewności czy to w pełni rozwiąże problem?

2

W programowanie nie za bardzo jest miejsce na zgadywanie,
albo wiesz
albo zrozumiesz
albo poprosisz kogoś kto ma większa wiedzę i Ci pomoże
albo nie dotykaj bo bardziej popsujesz 😉 i ktoś będzie musiał to poprawiać
Na pewno jest gdzieś debugger i zobacz co się dzieje w zwolnionym tępie 😄

Proszenie Ci trochę nie wychodzi bo nie potrafisz przygotować minimal-reproducible-example, w biurze to podjedzie kolega osiądzie na minutę i pokaże palcem "TU! masz bląd".

0

A nie pokazuje dokładnie gdzie mam błąd?

Mi chodziło o punkt 3 z twej listy (albo poprosisz kogoś kto ma większa wiedzę i Ci pomoże).

Próbowałem w między czasie z pass, ale to też nie rozwiązało problemu.

1

Ale nie wiadomo co powoduje błąd, daj taki kod, żeby każdy mógł zreprodukować problem

0

To już go dałem :-D Funkcja ta działa dopóki ktoś nie usunie warstwy z listy warstw QGIS.

Kwestia jest że osoba, musi znać się GIS-ie, a szczególnie na tworzeniu wtyczek z wykorzystaniem Pythona w QGIS.

2

@Karol Śpila: jeżeli to jest Minimal, Reproducible Example to proponuję zrób tak:

  • zrób nowy projekt
  • używając tylko kodu który podałeś w tym wątku spróbuj powtórzyć błąd
  • napisz czy ci się udało
  • i czy już rozumiesz co to jest Minimal, Reproducible Example ?

A na razie powiem pass

0

Spróbuje pomoc choć nie mogę zreprodukować tego błędu lub debugować... Jeśli to jest wtyczka to powinny być jakieś klasy. Nie wiem czy to jest wszystko w jednej klasie i module czy nie... Tu sa operacje na atrybutach, ale trudno zgadywać skad sie one biorą i jak wyglada przykładowa warstwa (z atrybutami) na której sa prowadzone operacje.

Dla uproszczenia użyłem tego jako skryptu w QGIS. Z tego co pisze dokumentacja do Qgis3.x. Nakreślę do czego sie dokopałem:

mapLayersByName - Pobiera listę pasujących zarejestrowanych warstw według nazwy warstwy.

czyli wychodzi cos takiego

ptpla = QgsProject.instance().mapLayersByName('korekta_ekrany_do_usunięcia')
[<QgsMapLayer: 'korekta_ekrany_do_usunięcia' (ogr)>]

spróbuj może tak:

ptpla = QgsProject.instance().mapLayersByName('korekta_ekrany_do_usunięcia')[0] # dodane [0]
if ptpla is not None:  # Sprawdz jawnie (explicit) czy obiekt warstwa nie jest typem None ( czy istnieje)
    # zrob cos z ta warstwa
else:
    print("Brak warstwy z ta nazwa")

wtedy to już nie będzie lista z obiektem, tylko sam obiekt. ptpla posiada referencje do obietu warswtwy (lub None jesli nie ma warstwy). Natomiast dalej masz metode .isValid() i chyba tego nie sprawdza (nie jestem pewien bo nie zaglebialem sie w deklaracje zmiennej QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL)

i nie trzeba już pisać w drugim kodzie:

ptpl = ptpla[0]

bo ptpla juz jest to jest ta wybrana warstwa

a jeśli będzie jakiś obiekt warstwy to jest on już podany np:

<QgsMapLayer: 'korekta_ekrany_do_usunięcia' (ogr)>

można jeszcze pokombinować z blokiem

try:
	print('example')
except RuntimeError:
	print('example')

Nie wiem czy to pomoże i czy poszedłem w dobrym kierunku.

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