In diesem Tutorial zeige ich dir, wie man vorhandene Segmente in der UI Maske auflisten kann und dann nach einer entsprechenden Auswahl, daraus ein Dach Konstruieren kann.
Zuerst schauen wir uns einmal an, was wir so alles brauchen. Um ein einfaches Pultdach zu bauen, brauchen einen Grundriss, dann ein linkes Seitensegment, ein mittleres Segment, sowie ein rechtes Seitensegment. Also sollten wir bei der Konstruktion unserer Maske dieses auch entsprechend berücksichtigen. Ich werde nur mit dem einfachen Grundriss arbeiten, daher kann ich mir eine Auswahl für Grundrisse sparen. Aber die linken, mittleren und rechten Segmente möchte ich schon gerne zur Auswahl stehen haben.
Ich verwende in der UI 3 List Widgets. Bei diesen List-Widgets habe ich diverse Einstellungen vorgenommen, die nicht Pflicht sind, in meiner Maske aber vermutlich besser aussehen, als der Standard.
Zum Einen habe eine ICON-Size festgelegt. Damit werden die Vorschaubilder der Segmente in der gegebenen Größe dargestellt. Ferner habe ich das Scroll-Verhalten angepasst. Ich mag es einfach lieber, wenn die Listen Pixel für Pixel scrollen, anstatt (so hakelig) von einem Element zum nächsten zu springen.
Den „flow“ habe ich von Top->Down auf Left->Right gestellt, da ich in der UI die Widgets ja in die Breite gezogen habe. So werden die Icons dann nebeneinander angezeigt, anstatt untereinander. Beim View Mode habe ich auf IconMode gestellt, vielleicht ändere ich das aber noch. Das ist nur dafür da, ob der Text der jeweiligen Listen-Einträge auch dargestellt werden soll, oder eben nur das Icon-Bild.
Also, alles reine Geschmackssache.
Sobald wir diese UI fertig gestellt haben, können wir dann auch schon ein einfach In-Skript erstellen.
import kkpimport SegmentConfig as SCimport oleimport xml.etree.ElementTree as ETimport syssys.path.append(kkp.Get_Systemgeberdir() + „/ui“)XML_PARAM = „“““““def createXML():try: iObjNr = int(XML_PARAM)except: iObjNr = 0sc = SC.SegmentConfig(iObjNr)sXml = sc.toXml()return sXmlif __name__ == ‚__main__‘:sXml = createXML()print(sXml)
Als nächstes brauchen wir eine Funktion, um die linken Seitensegmente auswählen zu können. Die Auswahl der verwendbaren Segmente ist abhängig vom gewählten Profilsystem, also müssen wir daran denken, die Serie abzufragen, und je nachdem andere Segmente zu laden.
import kkpimport SegmentConfig as SCimport oleimport xml.etree.ElementTree as ETimport syssys.path.append(kkp.Get_Systemgeberdir() + „/ui“)XML_PARAM = „“““““def initSegmenteLinks():iSerie = kkp.Get_Profilserie()if iSerie == 0: #WApass #TODOif iSerie == 1: #WIpass #TODOdef createXML():try: iObjNr = int(XML_PARAM)except: iObjNr = 0sc = SC.SegmentConfig(iObjNr)initSegmenteLinks()sXml = sc.toXml()return sXmlif __name__ == ‚__main__‘:sXml = createXML()print(sXml)
Soweit so gut. Dann können wir uns dort, wo aktuell noch TODO steht, die Pfade notieren, wo wir die Segmente in der jeweiligen Serie finden können. Hier bekommen wir im KKP System übrigens ein Problem, das andere System nicht haben. Hier befinden sich die Segmente aus verschiedenen Serien im gleichen Ordner. Wir müssen im KKP-System also leider die Kennziffern filtern. Aber auch das ist machbar. Zuerst einmal die Pfade.
def initSegmenteLinks():iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“
Bei anderen Systemen wären die Pfade unterschiedlich und wir bräuchten keine weitere Unterscheidung zu machen. Wie wir die Segmente hier im KKP System filtern können, zeige ich gleich. Zuerst brauchen wir aber eine Funktion um alle verfügbaren Segmente in dem Pfad überhaupt aufzulisten.
import osXML_PARAM = „“““““def listFiles(sPfadRoot , sPfad):sPath = (sPfadRoot + „/“ + sPfad).replace(„\\“ , „/“)listFiles = os.listdir(sPath)files = []for file in listFiles:file = file.lower()if file.endswith(„.png“):if len(file) == 23:files.append(file[:-4])return filesdef initSegmenteLinks():iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“sSystemPfad = kkp.Get_Systemgeberdir()listeSegmente = listFiles(sSystemPfad , strPfadZuSegmenten)
Achtung! Wir brauchen hier das zusätzliche Modul os, daher müssen wir es importieren. Wir lesen nur die Dateien ein, die auch ein Icon (eine PNG-Datei) besitzen. Dadurch gehen wir sicher, dass wir in unserer UI später nicht einfach irgend ein Segment zur Auswahl haben aber wegen des fehlenden Icons nicht erkennen können, was wir da überhaupt auswählen.
Jetzt, da wir eine Liste mit verfügbaren Segmenten haben, könnten wir diese eigentlich bereits im List Widget anzeigen. Da das KKP System die Segmente aber alle im gleichen Verzeichnis gespeichert hat, müssen wir noch etwas mehr filtern. Zum Glück sind die Segmente so abgespeichert, dass alle Segmente das WA Systems im 3. Kennziffernblock .010. stehen haben wohingegen die WI Segmente eine .020. verwenden. Wenn wir also genau zählen (z.B. 900.001.010.510.101 vs. 900.001.020.510.101) stellen wir fest, dass wir nach dem Zeichen mit Index 9 (mit 0 anfangen zu zählen!) schauen müssen. Ist das eine 1 ist das Segment für das WA System gedacht, ist es eine 2, dann ist es für das WI System gedacht. Wie gesagt, diesen Aufwand muss man eigentlich nicht betreiben, den habe nur ich hier im KKP-System.
def initSegmenteLinks():iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“sSystemPfad = kkp.Get_Systemgeberdir()listeSegmente = listFiles(sSystemPfad , strPfadZuSegmenten)listeGefiltert = []for tag in listeSegmente:c = tag[9]if c == „1“ and iSerie == 0: listeGefiltert.append(tag)if c == „2“ and iSerie == 1: listeGefiltert.append(tag)
Dann können wir ja nun endlich unsere Funktion schreiben um das List-Widget zu befüllen. Da wir das ganze 3 Mal machen müssen, erstelle ich mir eine entsprechende Funktion, damit ich den Code nicht 3 Mal aufschreiben muss. Da in der Funktion ja das ListWidget befüllt werden soll, brauche ich das Objekt sc (SystemConfig) also muss ich das im Skript auch per Parameter übergeben. Hier das gesamte Skript soweit:
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCimport oleimport xml.etree.ElementTree as ETimport syssys.path.append(kkp.Get_Systemgeberdir() + „/ui“)import osXML_PARAM = „“““““def listFiles(sPfadRoot , sPfad):sPath = (sPfadRoot + „/“ + sPfad).replace(„\\“ , „/“)listFiles = os.listdir(sPath)files = []for file in listFiles:file = file.lower()if file.endswith(„.png“):if len(file) == 23:files.append(file[:-4])return filesdef fillListWidget(sc , name , path , files):nodes = []for file in files:n = sc.Node(„QListWidgetItem“)filename = path + „/“ + file + „.png“n.setProperty(„icon“ , filename)n.setProperty(„data“ , file)nodes.append(n)sc.initList(name , nodes)def initSegmenteLinks(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“sSystemPfad = kkp.Get_Systemgeberdir()listeSegmente = listFiles(sSystemPfad , strPfadZuSegmenten)listeGefiltert = []for tag in listeSegmente:c = tag[9]if c == „1“ and iSerie == 0: listeGefiltert.append(tag)if c == „2“ and iSerie == 1: listeGefiltert.append(tag)fillListWidget(sc , „listLinks“ , strPfadZuSegmenten , listeGefiltert)def createXML():try: iObjNr = int(XML_PARAM)except: iObjNr = 0sc = SC.SegmentConfig(iObjNr)initSegmenteLinks(sc)sXml = sc.toXml()return sXmlif __name__ == ‚__main__‘:sXml = createXML()print(sXml)
Wenn wir das Skript ausführen sieht unsere Maske anschließend so aus:
Schon ziemlich gut, und mit einer kleinen Einstellung in der Maske, bekommen wir das auch hin, dass alle Elemente in einer Zeile stehen.
und schon sieht unsere Maske so aus:
Und genau das gleiche machen wir nun auch für die Mitte und die rechte Seite. Dabei können wir unseren Code wieder etwas optimieren, damit wir den Filter und alles nicht 3 mal aufschreiben müssen.
Hier das komplette Skript:
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCimport oleimport xml.etree.ElementTree as ETimport syssys.path.append(kkp.Get_Systemgeberdir() + „/ui“)import osXML_PARAM = „“““““def listFiles(sPfadRoot , sPfad):sPath = (sPfadRoot + „/“ + sPfad).replace(„\\“ , „/“)listFiles = os.listdir(sPath)files = []for file in listFiles:file = file.lower()if file.endswith(„.png“):if len(file) == 23:files.append(file[:-4])return filesdef fillListWidget(sc , name , path , files):nodes = []for file in files:n = sc.Node(„QListWidgetItem“)filename = path + „/“ + file + „.png“n.setProperty(„icon“ , filename)n.setProperty(„data“ , file)nodes.append(n)sc.initList(name , nodes)def erstelleListe(sc , iSerie, strPfadZuSegmenten , nameListeWidget):sSystemPfad = kkp.Get_Systemgeberdir()listeSegmente = listFiles(sSystemPfad , strPfadZuSegmenten)listeGefiltert = []for tag in listeSegmente:c = tag[9]if c == „1“ and iSerie == 0: listeGefiltert.append(tag)if c == „2“ and iSerie == 1: listeGefiltert.append(tag)fillListWidget(sc , nameListeWidget, strPfadZuSegmenten , listeGefiltert)def initSegmenteLinks(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listLinks“)def initSegmenteMitte(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Grundsegmente“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Grundsegmente“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listMitte“)def initSegmenteRechts(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Rechts“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Rechts“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listRechts“)def createXML():try: iObjNr = int(XML_PARAM)except: iObjNr = 0sc = SC.SegmentConfig(iObjNr)initSegmenteLinks(sc)initSegmenteMitte(sc)initSegmenteRechts(sc)sXml = sc.toXml()return sXmlif __name__ == ‚__main__‘:sXml = createXML()print(sXml)
Und unsere Maske sieht so aus:
Jetzt denken wir mal ein wenig in die Zukunft. Stellen wir uns vor, wir hätten schon das Out-Skript geschrieben und wenn wir eine gewisse Auswahl getroffen haben, wir das Dach gebaut. Nun öffnen wir die Maske erneut und möchten gerne, dass die Segmente, die in der Zeichnung vorhanden sind, hier in der Maske bereits vorausgewählt werden. Auch das ist ziemlich einfach. Man kann jedem dieser QListWidgetItem – Objekte, die wir zum Befüllen der Liste verwenden das Attribut „Selected“ mitgeben. Wir müssen also nur fragen, ob das Segment, welchen wir zur Auswahl anbieten, in der Konstruktion bereits vorhanden ist.
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCimport oleimport xml.etree.ElementTree as ETimport syssys.path.append(kkp.Get_Systemgeberdir() + „/ui“)import osXML_PARAM = „“““““def listFiles(sPfadRoot , sPfad):sPath = (sPfadRoot + „/“ + sPfad).replace(„\\“ , „/“)listFiles = os.listdir(sPath)files = []for file in listFiles:file = file.lower()if file.endswith(„.png“):if len(file) == 23:files.append(file[:-4])return filesdef fillListWidget(sc , name , path , files , selected):nodes = []for file in files:n = sc.Node(„QListWidgetItem“)filename = path + „/“ + file + „.png“n.setProperty(„icon“ , filename)n.setProperty(„data“ , file)if file in selected: n.setProperty(„selected“ , „1“) # <<— Wenn Kennziffer von Segment in Konstruktion vorhanden, dann vorauswählennodes.append(n)sc.initList(name , nodes)def isFileInConstruction(files): #<<– prüft, ob Kennziffer als Segment in Konstruktion vorhandenexisting = []for tag in files:tpl = kkp.Objektliste_Erstellen(tag)if len(tpl) > 0: existing.append(tag)return existingdef erstelleListe(sc , iSerie, strPfadZuSegmenten , nameListeWidget):sSystemPfad = kkp.Get_Systemgeberdir()listeSegmente = listFiles(sSystemPfad , strPfadZuSegmenten)listeGefiltert = []for tag in listeSegmente:c = tag[9]if c == „1“ and iSerie == 0: listeGefiltert.append(tag)if c == „2“ and iSerie == 1: listeGefiltert.append(tag)selected = isFileInConstruction(listeGefiltert) #<<– gewählte Segmente auflistenfillListWidget(sc , nameListeWidget, strPfadZuSegmenten , listeGefiltert , selected)def initSegmenteLinks(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Links“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listLinks“)def initSegmenteMitte(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Grundsegmente“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Grundsegmente“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listMitte“)def initSegmenteRechts(sc):iSerie = kkp.Get_Profilserie()strPfadZuSegmenten = „“if iSerie == 0: #WAstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Rechts“if iSerie == 1: #WIstrPfadZuSegmenten = „Varianten/Segmente/Abschluss_Rechts“erstelleListe(sc , iSerie , strPfadZuSegmenten , „listRechts“)def createXML():try: iObjNr = int(XML_PARAM)except: iObjNr = 0sc = SC.SegmentConfig(iObjNr)initSegmenteLinks(sc)initSegmenteMitte(sc)initSegmenteRechts(sc)sXml = sc.toXml()return sXmlif __name__ == ‚__main__‘:sXml = createXML()print(sXml)
Dann sind wir mit dem In-Skript auch soweit erst einmal fertig. Kommen wir also zum Out-Skript. Auch hier starten wir mit einem bescheidenen Grundgerüst
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCif __name__ == ‚__main__‘:sc = SC.SegmentConfig()sc.fromfile(kkp.Get_Projektdir() + „\\segmentConfig_ui.xml“)
Zuerst müssen wir in der Skript einen Grundriss laden, damit wir anschließend die Segmente darauf platzieren können. Übrigens dazu habe ich bereits ein Tutorial erstellt Segmente auf Grundriss laden
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCdef ladeGrundriss(tag):kkp.Load_3D_File(tag)if __name__ == ‚__main__‘:sc = SC.SegmentConfig()sc.fromfile(kkp.Get_Projektdir() + „\\segmentConfig_ui.xml“)ladeGrundriss(„900.001.999.200.010“)
Dann brauchen wir eine Funktion mit der auslesen können welche Kennziffer wir für Links, Mitte und Rechts gewählt haben.
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCdef ladeGrundriss(tag):kkp.Load_3D_File(tag)def leseSegmentauswahlAus(sc , name):n = sc.findByName(name)if n is None: return „“for item in n.m_children:if item.findProperty(„selected“) is not None:sTag = item.findProperty(„data“)[„value“]return sTagreturn „“if __name__ == ‚__main__‘:sc = SC.SegmentConfig()sc.fromfile(kkp.Get_Projektdir() + „\\segmentConfig_ui.xml“)ladeGrundriss(„900.001.999.200.010“)tagMitte = leseSegmentauswahlAus(sc, „listMitte“)tagLinks = leseSegmentauswahlAus(sc, „listLinks“)tagRechts = leseSegmentauswahlAus(sc , „listRechts“)
Und diese Kennziffer müssen wir dann nur noch auf den Grundriss einfügen. Hiier das vollständige Skript.
# -*- coding: utf-8 -*-import kkpimport SegmentConfig as SCdef ladeGrundriss(tag):kkp.Load_3D_File(tag)def leseSegmentauswahlAus(sc , name):n = sc.findByName(name)if n is None: return „“for item in n.m_children:if item.findProperty(„selected“) is not None:sTag = item.findProperty(„data“)[„value“]return sTagreturn „“def insertSegment(kennzifferSegment , kennzifferGrundrissflaeche):objektnummerGrundrissflaeche = kkp.Objektliste2Erstellen(100 , kennzifferGrundrissflaeche)[0][0]iObjNrSegment = kkp.Segment_Auf_Grundriss_Einfuegen(kennzifferSegment , objektnummerGrundrissflaeche , kkp.eKT_Hauptgruppe)[0]if __name__ == ‚__main__‘:sc = SC.SegmentConfig()sc.fromfile(kkp.Get_Projektdir() + „\\segmentConfig_ui.xml“)ladeGrundriss(„900.001.999.200.010“)tagMitte = leseSegmentauswahlAus(sc, „listMitte“)tagLinks = leseSegmentauswahlAus(sc, „listLinks“)tagRechts = leseSegmentauswahlAus(sc , „listRechts“)insertSegment(tagMitte , „999.001.200.510“)insertSegment(tagLinks , „999.001.200.520“)insertSegment(tagRechts , „999.001.200.530“)
Bitte schaue dir unbedingt das Tutorial Segmente auf Grundriss laden an, da ich hier noch wesentlich detaillierter darauf eingehe, wie man Segmente auf einem Grundriss einfügen kann. Dort erkläre ich auch noch diverse Sonderbedingungen, die ich hier entsprechend nicht wiederholt habe.