Arbeiten mit Bildern

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

mir ist noch nicht so ganz der Unterschied aufgefallen. Wenn man auf seiner Form über QT-Designer Icons oder Bilder hinzufügen will, hat man gleich zwei Wege. Einmal über die Ressourcendatei oder eben das man die Bilder direkt sucht und auswählt. Wo genau liegen da Vor- und Nachteile. Sowohl bei Ressourcendatei als auch über den direkten Weg müssen sich die Bilder an Ort und Stelle befinden. Und später, wenn ich die Anwendung in eine EXE-Datei umwandle, müssen die Bilder kopiert werden, damit man das Programm ordnungsgemäß weitergeben kann. Bis jetzt verfahre ich immer so, dass ich die Bilder direkt auswähle, also nicht über die Resourcendatei.

Wenn ich mir also die Ressourcendatei anschaue:

Code: Alles auswählen

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>images/copy.png</file>
    <file>images/cut.png</file>
    <file>images/new.png</file>
    <file>images/open.png</file>
    <file>images/paste.png</file>
    <file>images/save.png</file>
</qresource>
</RCC>
Dann sehe ich, dass diese *.png-Dateien im Ordner images liegen. Die Ressourcendatei bezieht die Bilder aus diesem Ordner. Wenn ich also über die Ressourcendatei arbeite, und das Projekt ist fertig und für die Verbreitung bereit, dann muss ich den Ordner images genauso hinzufügen, richtig?

Mir will es einfach nicht einleuchten, was ich mir über diesem Weg der Ressourcendatei verspreche.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

In C++ Qt ist da ein Unterschied: die Resourcendatei bewirkt, dass die png-Dateien in das Programm "hineinkompiliert" werden. Damit brauchst Du die Bilder dann nicht mehr zusätzlich zum Executable zu verteilen.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@MagBen: Ich könnte getrost den Ordner images löschen, nachdem ich über QT-Designer eine Ressourcen-Datei angelegt habe? Und wie arbeitet man mit einer qrc-Datei in Python?

Auf meine Weise, wenn ich im Python-Quelltext mit Bildern arbeite, dann sieht es wie folgt aus:

Code: Alles auswählen

getPath_icon = os.path.abspath(os.path.join('files', 'images', 'img_24x24', 'Search.png'))
self.ui_pp_search.setWindowIcon(QIcon(getPath_icon))
Und du sagtest, es wird "hineinkompiliert". Was für Vorteile erschaffe ich mir dabei? Ist der andere Weg, die Bilddateien direkt zu suchen und auszuwählen fehleranfällig?

In einigen Youtube-Videos werden die qrc-Dateien nochmal in *.py-Dateien umgewandelt. Ist das nicht genauso quatsch, wie beim Versuch aus einer *.ui-Datei in eine *.py-Datei umzuwandeln?
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Sophus hat geschrieben:Ich könnte getrost den Ordner images löschen, nachdem ich über QT-Designer eine Ressourcen-Datei angelegt habe?
Nein, höchstens nach dem Kompilieren, aber das wäre so, als wenn Du den Quellcode nach dem Kompilieren löschen würdest (braucht man ja nicht mehr, man hat ja nun das Programm).

Code: Alles auswählen

os.path.abspath(os.path.join('files', 'images', 'img_24x24', 'Search.png')) 
Das funktioniert nur, wenn Dein Programm oder der Benutzer das aktuelle Arbeitsverzeichnis nicht ändern kann. In meinen PyQt Programmen kann der Benutzer das aber, deshalb gebe ich den Pfad zu den Resourcen relativ zum Quellcode an. Über die variable __file__ hat die Python-Datei Zugriff auf ihren eigenen Ort, das könnte dann z.B. so aussehen:

Code: Alles auswählen

imgafile=os.path.join(os.path.split(__file__)[0], "../../../files/images/img_24x24/Search.png")
Sowohl Python als auch Qt kommen unter Windows wunderbar mit "/" zurecht, Du musst deshalb nicht alles einzeln in join eintragen.
Ein bisschen Tricky wird dieser Ansatz, wenn man sein Pythonprogramm mit py2exe weitergibt, denn py2exe packt die ganzen pyc Dateien in eine Zip-Datei, dorthin müssen dann auch die Resourcen. Die URL zu einer Resource in einer Zip-Datei sieht anders aus.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Sophus hat geschrieben:Und du sagtest, es wird "hineinkompiliert". Was für Vorteile erschaffe ich mir dabei?
Dein fertig kompiliertes C++ Qt-Programm ist genau eine Datei und sonst nichts und nicht ein ganzer Verzeichnisbaum wie mit Python.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

MagBen hat geschrieben:

Code: Alles auswählen

imgafile=os.path.join(os.path.split(__file__)[0], "../../../files/images/img_24x24/Search.png")
Also, wenn ich deine Art und Weise anschaue, sehe ich ein weiteres Problem. Das Arbeiten mit dem Pfad ist keineswegs plattformunabhänig. Oder irre ich mich?
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Sophus hat geschrieben:Das Arbeiten mit dem Pfad ist keineswegs plattformunabhänig. Oder irre ich mich?
"/" funktioniert sehr gut unter Windows
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@MagBen: Über eine Sache bin ich rein vom Verständnis gestolpert. Du sagtest, wenn ein Benutzer das Arbeitsverzeichnis ändert, bekomme ich unter meiner Variante meine Probleme. Wie soll ich es verstehen? Mal angenommen, mein Python-Programm befindet sich zur Zeit unter D:\Work\Program
Und nun geht der Benutzer hin und ändert den Ordner 'Work' in 'Holiday'. Dann sähe das Verzeichnis wie folgt aus: D:\Holiday\Program
Aber mal allgemein gefragt. Welcher Benutzer kommt auf die Idee, und versucht die Verzeichnisnamen eines Programmes zu verändern? Und inwiefern hätte deine Variante dort einen Vorteil?

Code: Alles auswählen

imgafile=os.path.join(os.path.split(__file__)[0], "../../../files/images/img_24x24/Search.png")
Wenn der Benutzer also hingeht, und aus 'file' nun 'dateien' macht, dann bricht deine Variante genauso zusammen?
BlackJack

@Sophus: Jup, das ist nicht wirklich plattformunabhängig. Ich würde statt `os.path.split()` auch `os.path.dirname()` verwenden.

Es geht nicht um das Verändern von irgendwelchen Verzeichnisnamen auf dem Datenträger sondern was das aktuelle Arbeitsverzeichnis des Prozesses ist. Man kann das Programm ja auch von einem anderen Verzeichnis aus starten als dem wo die Programmdatei liegt.

@MagBen: Du möchtest vielleicht noch mal über die Bedeutung von „plattformumabhängig” nachdenken. ;-)
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Wenn ich dich richtig verstanden habe, würdest du eher diese Variante vorziehen:

Code: Alles auswählen

os.path.dirname(os.path.abspath(__file__))
Aber wie bekomme ich meine Verzeichnisse dort hinein?

Code: Alles auswählen

my_path= os.path.abspath(os.path.join('files', 'images', 'img_24x24', 'Search.png'))
Hier habe ich mein Pfad mit os.join() zusammengesetzt. Wie kriege ich dies in der ersten von dir vorgeschlagenen Variante im Sinne der Plattformunabhängigkeit untergebracht?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Dann übernehm ich mal wieder die Rolle des bösen Bullen :evil:

@Sophus
Doku lesen - schauen, was die Funktionen an Argumenten erwarten und was sie zurückgeben - auf eigenes Problem übertragen und entsprechend anwenden
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: Deine ständig wechselnden Variablennamen für die Bilder, habe eins gemeinsam, sie sind alle schlecht und entweder falsch oder nichtssagen.
Normalerweise legt man sich eine sinnvolle Anzahl an Konstanten zurecht:

Code: Alles auswählen

BASE_PATH = os.path.dirname(os.path.abspath(__file__))
IMAGE_PATH = os.path.join(BASE_PATH, 'files', 'images')
...
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@jerch: Hallo böser Bulle, ich trau mich ja gar nicht, meinen Versuch vorzutragen. Bitte, pack' deinen Schlagstock wieder beiseite :-)

Also, wenn ich BlackJack richtig verstanden habe, brachte er diese Idee ein:

Code: Alles auswählen

os.path.dirname(os.path.abspath(__file__))
Dies war meine bisherige Variante mit Dateien zu arbeiten.

Code: Alles auswählen

os.path.abspath(os.path.join('files', 'images', 'img_24x24', 'Search.png'))

Nun habe ich mir überlegt, wie ich BlackJacks Idee und meine Variante vereinen kann?

Ich habe also BlackJacks Idee versucht zu extrahieren, und zwar so:

Code: Alles auswählen

os.path.dirname(__file__)
Denn ich dachte mir os.path.abspath benutze ich ja schon in meiner Variante. Wieso alles doppelt und dreifach? Und das Extrahierte habe ich dann in meine Variante eingeschoben, und zwar vor meinen Verzeichnissen, denn erst brauche ich einen Ausgangspunkt, um von dort aus auf meine Verzeichnisse zugreifen zu können:

Mein vorläufiges Ergebnis wäre dann das hier:

Code: Alles auswählen

os.path.abspath(os.path.join(os.path.dirname(__file__), 'files', 'images', 'img_24x24', 'Search.png'))
Und ich wette, dass jerch gleich mit seiner Polizei-Triller-Pfeife und mit seinem Schlagstock um die Ecke kommen wird.
Zuletzt geändert von Sophus am Donnerstag 16. April 2015, 18:19, insgesamt 1-mal geändert.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Sirius3: Du warst schneller. Hab' gar nicht mitbekommen, dass du bereits einen Post abgesendet hast.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Sophus:
Die Idee, wie es verknüpfst, ist richtig. Allerdings agieren diese Funktionen nur auf Zeichenkettenebene und splitten plattformkonform am letzten Pfadtrenner. `dirname` gibt dann den vorderen Teil, `basename` den hinteren Teil zurück. Daher wird Deine Version nicht wie gewünscht funktionieren (`__file__` dürfte was in der Form 'xyz.py' sein, also ohne volle Pfadangabe). Abhilfe schafft `abspath` vor `dirname`, also wie bei Sirius.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@jerch: os.path.dirname arbeitet genausogut mit relativen Pfaden, also auch leeren Pfadangaben. Das abspath ist also eigentlich überflüssig, wenn nicht irgendwo doch chdir benutzt wird.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@jerch: Danke für die Ausführung:

Code: Alles auswählen

BASE_PATH = os.path.dirname(os.path.abspath(__file__))
IMAGE_PATH = os.path.join(BASE_PATH, 'files', 'images')
print "Sirius3s Version ", IMAGE_PATH
Ausgabe:
Sirius3s Version D:\Dan\Python\Übung\files\images

Code: Alles auswählen

IMAGE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'files', 'images', 'img_24x24', 'Search.png'))
print "Sophus' Version:", IMAGE_PATH 
Ausgabe:
Sophus' Version: D:\Dan\Python\Übung\files\images\img_24x24\Search.png
Also bei der Ausgabe konnte ich sowohl bei Siruis3 als auch bei mir keinen Unterschied feststellen. Es "scheint" beides ähnlich zu wirken - mal abgesehen davon, dass Sirius3s Pfad anders konstruiert ist. Ab welchem konkreten Fall würde meine Version nicht funktionieren? Ich habe mir zwar deine Ausführung durchgelesen, jedoch konnte ich beim Anblick beider Print-Anweisungen keine schlüssige Schlussfolgerungen ziehen.

Und eine weitere Frage, was ist, wenn Pfadangaben Werte außerhalb von ASCII-Werten enthält? Erledigt abspath das für mich oder sollte ich den Pfad lieber in unicode() umwandeln?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: Du bekommst mit Deiner Variante auch keine Probleme, nur Du hast viel Arbeit, wenn Du Deine Pfade mal anpassen willst. Und das mit dem Unicode hatten wir doch schon im anderen Thread.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Sirius3:

Pfade anpassen? Meinst du etwa, wenn neue Ordner hinzukommen, vorhandene Ordner umbenannt werden? Ich verstehe nicht, worin viel Arbeit bestünde? Konkretes Beispiel-Szenario?
Antworten