Hallo liebe Icons, wo seid ihr?

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,

ich habe eine kleine Frage an euch. Da mein kleines "GUI-Projekt" unter Windows funktioniert, wollte ich dieses kleine funktionslose "Programm" auch mal unter Linux testen. Bei mir läuft Debian7 unter VMWare. Das kleine "Projekt" funktioniert auch soweit, und die Icons in der ToolBar werden angezeigt, aber in meiner Menüleiste will es nicht funktionieren, obwohl es unter Windows wunderbar klappt. Wir erinnern uns, es handelt sich hier um ein MainWindow, eine ToolBar und eine Menüleiste, die ich per Hand geschrieben habe - um OOP ein wenig näher zu kommen. Damit wir einen Einblick bekommen, hier die Ausschnitte:

MDIForm.py

Code: Alles auswählen

from os import *
import sys
from PyQt4.QtGui import QMainWindow, QApplication, QAction, QMenuBar, QToolBar, QIcon, QScrollBar

class MDIFormular(QMainWindow):
    # Vererbung aktivieren, angeben, dass es keine Elternform hat
    def __init__ (self, parent=None): 
        QMainWindow.__init__(self, parent)

        self.setWindowTitle(' Xarphus Build 0.1')

        self.statusBar().showMessage('Ready')

        self.MNUL_Verwaltung = MenueLeiste() 
        self.setMenuBar(self.MNUL_Verwaltung)

        self.MNUL_Verwaltung.DoShowmnuClose.triggered.connect(self.MnuCloseMain)
        
    
        
        self.DoShowToolBar = ToolBarLeiste()
        self.addToolBar(self.DoShowToolBar)
        
        self.DoShowToolBar.actAddExit.triggered.connect(self.MnuCloseMain)

        
    def MnuCloseMain(self): 
        print "Ihr Programm wurde soeben erfolgreich beendet."
        self.close()

if __name__ == "__main__":
    print 'Dieses Programm läuft als Main.'
else:
    print 'Das Programm wird von einem anderen Modul importiert.'

app = QApplication(sys.argv)
MDIWindow = MDIFormular()
MDIWindow.showMaximized()
sys.exit(app.exec_())


MDIForm_Menue.py

Code: Alles auswählen

# -*- coding: utf-8 -*-
from os import *
import sys
from PyQt4.QtGui import QAction, QMenuBar, QIcon

class MenueLeiste(QMenuBar):
    def __init__ (self, parent=None):
        QMenuBar.__init__(self, parent)


        ##########################################################################
        ###### Menuleiste (=MNUL) "Verwaltung" #############################################
        ##########################################################################
        # Eine eigenständige Menuleiste wird erstellt. 
        self.MNUL_Verwaltung = self.addMenu('&Verwaltung')
        # Menüpunkt
        #self.DoShowmnuClose = QAction("Beenden", self)
        self.DoShowmnuClose = QAction(QIcon(path.join('Xarphus/Images/16x16/exit.png')), "Beenden", self)
        self.DoShowmnuClose.setShortcut("Ctrl+Q")
        self.DoShowmnuClose.setStatusTip("Programm beenden")
        self.MNUL_Verwaltung.addAction(self.DoShowmnuClose)

MDIForm_ToolBar.py

Code: Alles auswählen

# -*- coding: utf-8 -*-
from os import *
import sys  

from PyQt4.QtGui import QAction, QToolBar, QIcon 
from PyQt4 import QtCore

class ToolBarLeiste(QToolBar):
    def __init__ (self, parent=None):
        QToolBar .__init__(self, parent)

        # An dieser Stelle erzeugen wir eine Werkzeugleiste
        self.actAddExit = QAction(QIcon(path.join('Xarphus/Images/32x32/Exit.png')), 'Programm beenden', self)
        self.actAddExit.setStatusTip("Programm beenden")
        
        self.addAction(self.actAddExit)
Wenn wir uns mal die beiden Dateien "MDIForm_ToolBar.py" und "MDIForm_Menue.py" ansehen, so sehen wir, dass die Path-Angaben und die Ordnerstrukturen bei beiden ähnlich sind, bei Menu liegen die *.png-Dateien im Ordner "16x16" und für die Toolbar im Ordner "32x32". Und dennoch sehe ich unter Linux in meiner Menüleiste kein einziges Icon, während in der Toolbar mein Icon wunderbar zu sehen ist. Liegt es das "Problem" eher bei Debian oder bei mir?
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Code: Alles auswählen

QIcon(path.join('Xarphus/Images/32x32/Exit.png'))
Wo ist path deklariert, was ist da drin? Lass dir das Ergebnis mal in der Konsole ausgeben, da erscheint sicherlich etwas anderes, als du erwartest.

Du hast einmal Exit.png und einmal exit.png. Welcher Schreibweise folgt das denn Bild?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

`path` kommt aus dem Stern-Import von `os`. Und damit ist auch klar, dass der `join` Aufruf nichts tut weil er nur ein Argument hat.

@Sophus: Die ganzen Pfade sind relativ, also wird vom aktuellen Arbeitsverzeichnis aus gesucht.
Dann bleibt die Frage: Wo/wie startest du das Programm? Gibt es die Datei ueberhaupt? Wie die Datei aufgeloest wird, zeigt dir `os.path.abspath("Xarphus/...")`.

Da du wohl die Dateistruktur _innerhalb_ deines Quelltextes beschreibst: Startest du das auch im Projektverzeichnis?
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Madmartigan hat geschrieben:

Code: Alles auswählen

QIcon(path.join('Xarphus/Images/32x32/Exit.png'))
Wo ist path deklariert, was ist da drin? Lass dir das Ergebnis mal in der Konsole ausgeben, da erscheint sicherlich etwas anderes, als du erwartest.

Du hast einmal Exit.png und einmal exit.png. Welcher Schreibweise folgt das denn Bild?
Ich habe path.join raus genommen. Und zu den beiden Schreibweisen. Und unter Windows funktionieren die Icons noch. Ich werde das gleich mal unter Linux testen. Übrigens: Die beiden Bilder sind in unterschiedlichen Ordner, einmal in 32x32 und einmal in 16x16. Aber mal davon ab. Ist es im Grunde nicht egal wie man den Namen des Bildes schreibt? Egal ob man die Groß- und Kleinschreibung beachtet?
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

cofi hat geschrieben:`path` kommt aus dem Stern-Import von `os`. Und damit ist auch klar, dass der `join` Aufruf nichts tut weil er nur ein Argument hat.

@Sophus: Die ganzen Pfade sind relativ, also wird vom aktuellen Arbeitsverzeichnis aus gesucht.
Dann bleibt die Frage: Wo/wie startest du das Programm? Gibt es die Datei ueberhaupt? Wie die Datei aufgeloest wird, zeigt dir `os.path.abspath("Xarphus/...")`.

Da du wohl die Dateistruktur _innerhalb_ deines Quelltextes beschreibst: Startest du das auch im Projektverzeichnis?
Damit ich nicht die Ordnerstruktur aufschlüsseln muss, habe ich für euch mein bisheriges kleines funktionsloses Projekt in eine *.RAR-Datei gepackt, und darauf geachtet, dass die Ordnerstrukturen eingehalten werden. Dazu habe ich im Projektverzeichnis eine *.bat-Datei reingelegt, damit ich nicht jedesmal erst über Umwege die Datei starten muss, sondern wie unter Windows üblich mit einem einzigen Klick auf die bat-Datei. Dazu habe ich dann noch Xarphus.pyw hinzugefügt, damit beim Start des Programms nicht immer die Kommandozeilen angezeigt werden. Aber die Xarphus.py liegt weiterhin mit bei. Xarphus.pyw oder Xarphus.py sind sozusagen die "Start"-Datei. Also am besten von dort aus starten.

Hier der Link zu meinem "Projekt": http://www.file-upload.net/download-905 ... n.rar.html
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

cofi hat geschrieben:`path` kommt aus dem Stern-Import von `os`. Und damit ist auch klar, dass der `join` Aufruf nichts tut weil er nur ein Argument hat.
Das ist offensichtlich, daher meine als Hinweis gemeinte, rethorische Frage. :roll:
Allerdings macht join() schon etwas, aber sicher nicht das, was er im Sinn hatte.
Sophus hat geschrieben:Ist es im Grunde nicht egal wie man den Namen des Bildes schreibt? Egal ob man die Groß- und Kleinschreibung beachtet?
Nein! Während Windows dir gemischte Schreibweisen verzeiht und zwischen MyFile.txt und myFile.txt keinen Unterschied kennt, wage ich zu bezweifeln, dass Linux das auch so handhabt.
Vielleicht kann das jemand mit mehr Erfahrung hinsichtlich FileHandling unter Linux bestätigen/widerlegen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Madmartigan hat geschrieben:
cofi hat geschrieben:`path` kommt aus dem Stern-Import von `os`. Und damit ist auch klar, dass der `join` Aufruf nichts tut weil er nur ein Argument hat.
Das ist offensichtlich, daher meine als Hinweis gemeinte, rethorische Frage. :roll:
Allerdings macht join() schon etwas, aber sicher nicht das, was er im Sinn hatte.
Sophus hat geschrieben:Ist es im Grunde nicht egal wie man den Namen des Bildes schreibt? Egal ob man die Groß- und Kleinschreibung beachtet?
Nein! Während Windows dir gemischte Schreibweisen verzeiht und zwischen MyFile.txt und myFile.txt keinen Unterschied kennt, wage ich zu bezweifeln, dass Linux das auch so handhabt.
Vielleicht kann das jemand mit mehr Erfahrung hinsichtlich FileHandling unter Linux bestätigen/widerlegen.
Zu Join() wollte ich von dort wo die Application gestartet wird auf folgende Ordner zugreifen. In VB6 heißt das Ganze app.path, so verhindere ich einfach, dass die Path-Angaben relativ werden. Die Path-Angaben sollen immer und überall passen. Und dabei dachte ich, würde ich mit path.join('Xarphus/Images/16x16/exit.png') von dort aus zugrifen, wo die auszuführende Datei liegt. Vielleicht habe ich falsch gedacht. Aber wie gesagt, ich habe die join()-Angaben gelöscht.

Und zu den exit.png-Dateien. Nach nochmaliger Überprüfung sind die Namen alle richtig. Aber dennoch klappt es nicht unter Linux. Was ich nur komisch finde, ist, dass es in der ToolBar wunderbar klappt, aber im Menu irgendwie nicht. Ich habe die Dabei für euch hochgeladen. Ihr könnt sie euch ansehen.
EmaNymton
User
Beiträge: 174
Registriert: Sonntag 30. Mai 2010, 14:07

Neben den Problemen mit join und absoluten Pfaden liegt das Problem hier eher darin, dass unter Linux anscheinend das Attribut Qt.AA_DontShowIconsInMenus der QApplication-Instanz standardmäßig auf True gesetzt ist, d.h. es werden, wenn nicht explizit angegeben, keine Icons in Menues angezeigt:
http://qt-project.org/doc/qt-4.8/qt.htm ... ibute-enum

Das kannst du mit

Code: Alles auswählen

print app.testAttribute(Qt.AA_DontShowIconsInMenus)
unter deinem Debian überprüfen, bei mir unter Arch ist der Wert jedenfalls True. Wenn man ihn auf False setzt und deine Pfade richtig wählt, erscheinen auch die Icons.

Wie du das aktivierst überlasse ich dir als Übung, du willst ja was lernen! ;)

Außerdem würde ich dir den Qt-Designer sehr ans Herz legen, da ist deine Oberfläche in 20 Minuten zusammengebaut (mit Icons) und du hast mehr Zeit dich auf die Funktionalität zu konzentrieren sowie die Prinzipien von Qt/OOP.

Edit:
Madmartigan hat geschrieben: Nein! Während Windows dir gemischte Schreibweisen verzeiht und zwischen MyFile.txt und myFile.txt keinen Unterschied kennt, wage ich zu bezweifeln, dass Linux das auch so handhabt.
Vielleicht kann das jemand mit mehr Erfahrung hinsichtlich FileHandling unter Linux bestätigen/widerlegen.
Ja, kann ich bestätigen (auch wenn ich mir nicht anmaße mehr Erfahrung zu haben ;))
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

EmaNymton hat geschrieben:Neben den Problemen mit join und absoluten Pfaden liegt das Problem hier eher darin, dass unter Linux anscheinend das Attribut Qt.AA_DontShowIconsInMenus der QApplication-Instanz standardmäßig auf True gesetzt ist, d.h. es werden, wenn nicht explizit angegeben, keine Icons in Menues angezeigt:
http://qt-project.org/doc/qt-4.8/qt.htm ... ibute-enum

Das kannst du mit

Code: Alles auswählen

print app.testAttribute(Qt.AA_DontShowIconsInMenus)
unter deinem Debian überprüfen, bei mir unter Arch ist der Wert jedenfalls True. Wenn man ihn auf False setzt und deine Pfade richtig wählt, erscheinen auch die Icons.

Wie du das aktivierst überlasse ich dir als Übung, du willst ja was lernen! ;)
Nach ein paar Mal herum "doktoren" habe ich es hinbekommen. Ich probierte in der Datei MDIForm.py diese beiden Varianten aus.

Diese Variante wollte nicht klappen:

Code: Alles auswählen

# -*- coding: utf-8 -*-
from os import *
import sys  

from PyQt4.QtGui import QMainWindow, QApplication, QAction, QMenuBar, QToolBar, QIcon, QMdiArea, QScrollBar

from PyQt4.QtCore import Qt

from MDIForm_Menue import MenueLeiste
from MDIForm_ToolBar import ToolBarLeiste, ToolBarLeiste1


class MDIFormular(QMainWindow):
    def __init__ (self, parent=None): 
        QMainWindow.__init__(self, parent)
        
        self.setAttribute(Qt.AA_DontShowIconsInMenus, False) <-------------------- hier
        self.setWindowTitle(' Xarphus Build 0.1')
        self.statusBar().showMessage('Ready')


        self.mdiArea = QMdiArea()
        self.setCentralWidget(self.mdiArea)

        
        self.MNUL_Verwaltung = MenueLeiste() 
        self.setMenuBar(self.MNUL_Verwaltung)

        self.MNUL_Verwaltung.DoShowmnuClose.triggered.connect(self.MnuCloseMain)
        
    
        
        self.DoShowToolBar = ToolBarLeiste()
        self.addToolBar(self.DoShowToolBar)
        
        
        self.DoShowToolBar1 = ToolBarLeiste1()
        self.addToolBar(self.DoShowToolBar1)            
        
        self.DoShowToolBar1.actAddExit.triggered.connect(self.MnuCloseMain)

        
    def MnuCloseMain(self): 
        print "Ihr Programm wurde soeben erfolgreich beendet."
        self.close()


if __name__ == "__main__":
    print 'Dieses Programm läuft als Main.'
else:
    print 'Das Programm wird von einem anderen Modul importiert.'

app = QApplication(sys.argv)
MDIWindow = MDIFormular()
MDIWindow.showMaximized()
sys.exit(app.exec_())
Aber dann probierte ich hier, und es funktionierte unter Linux wunderbar:

Code: Alles auswählen

# -*- coding: utf-8 -*-
from os import *
import sys  

from PyQt4.QtGui import QMainWindow, QApplication, QAction, QMenuBar, QToolBar, QIcon, QMdiArea, QScrollBar

from PyQt4.QtCore import Qt

from MDIForm_Menue import MenueLeiste
from MDIForm_ToolBar import ToolBarLeiste, ToolBarLeiste1


class MDIFormular(QMainWindow):
    def __init__ (self, parent=None): 
        QMainWindow.__init__(self, parent)
        
        self.setWindowTitle(' Xarphus Build 0.1')
        self.statusBar().showMessage('Ready')


        self.mdiArea = QMdiArea()
        self.setCentralWidget(self.mdiArea)

        
        self.MNUL_Verwaltung = MenueLeiste() 
        self.setMenuBar(self.MNUL_Verwaltung)

        self.MNUL_Verwaltung.DoShowmnuClose.triggered.connect(self.MnuCloseMain)
        
    
        
        self.DoShowToolBar = ToolBarLeiste()
        self.addToolBar(self.DoShowToolBar)
        
        
        self.DoShowToolBar1 = ToolBarLeiste1()
        self.addToolBar(self.DoShowToolBar1)            
        
        self.DoShowToolBar1.actAddExit.triggered.connect(self.MnuCloseMain)

        
    def MnuCloseMain(self): 
        print "Ihr Programm wurde soeben erfolgreich beendet."
        self.close()


if __name__ == "__main__":
    print 'Dieses Programm läuft als Main.'
else:
    print 'Das Programm wird von einem anderen Modul importiert.'

app = QApplication(sys.argv)
app.setAttribute(Qt.AA_DontShowIconsInMenus, False) <---------------- hier
MDIWindow = MDIFormular()
MDIWindow.showMaximized()
sys.exit(app.exec_())
Mein Erklärungsversuch (schließlich möchte ich ja auch die Problemlösung verstehen :-) ) sieht wie folgt aus. In der ersten Variante schrieb ich setAttribute(Qt.AA_DontShowIconsInMenus, False) in eine Klasse. Und mit dem magischen Argument self wurde durch die Methode setAttribute die Parameter (Qt.AA_DontShowIconsInMenus, False) an die Klasse MDIFormular übergeben. Und beim Erzeugen der Klasse ist es nicht möglich, diese Einstellung an die Application zu setzen. Deshalb funktionierte es in der zweiten Variante, weil bei der Instanziierung durch die Methode setAttribute die Parameter (Qt.AA_DontShowIconsInMenus, False) direkt an die Instanz app = QApplication übergeben wurde. Na los, sag schon, dass ich total falsch liege :-)
EmaNymton
User
Beiträge: 174
Registriert: Sonntag 30. Mai 2010, 14:07

Du wirfst da einige Begrifflichkeiten durcheinander.
Sophus hat geschrieben: Mein Erklärungsversuch (schließlich möchte ich ja auch die Problemlösung verstehen :-) ) sieht wie folgt aus. In der ersten Variante schrieb ich setAttribute(Qt.AA_DontShowIconsInMenus, False) in eine Klasse. Und mit dem magischen Argument self wurde durch die Methode setAttribute die Parameter (Qt.AA_DontShowIconsInMenus, False) an die Klasse MDIFormular übergeben.
Dieses "magische Argument" stellt einfach eine Referenz auf die Instanz, also auf das konkrete Objekt dar und wird nicht an die Klasse übergeben. Klassen sind Vorlagen für Objekte. Die Klasse MDIFormular, die von QMainWindow abgeleitet ist, hat keine Methode setAttribute, somit kann das innerhalb dieser Klasse auch nicht funktionieren.
Sophus hat geschrieben: Und beim Erzeugen der Klasse ist es nicht möglich, diese Einstellung an die Application zu setzen. Deshalb funktionierte es in der zweiten Variante, weil bei der Instanziierung durch die Methode setAttribute die Parameter (Qt.AA_DontShowIconsInMenus, False) direkt an die Instanz app = QApplication übergeben wurde. Na los, sag schon, dass ich total falsch liege :-)
Siehe oben, Klassen werden nicht erzeugt (vielleicht kann man höchstens den Programmierprozess so beschreiben, der war hier aber bestimmt nicht gemeint ;)) sondern aus den Klassen werden einzelne Objekte erzeugt. Diesem Objekt (hier app) kannst du dann den Auftrag geben, die Darstellung der Icons zu aktivieren, indem du seine Methode setAttribute(...) aufrufst.

Vielleicht liest du dir nochmal diesen Thread durch, da geht es nämlich genau um die gleichen Verständnisschwierigkeiten, die du hast:
http://www.python-forum.de/viewtopic.php?f=1&t=27534
BlackJack

@EmaNymton: Klassen werden schon erzeugt, und zwar zur Laufzeit immer dann wenn eine ``class``-Anweisunge ausgeführt wird. Man kann auch welche mit der `type()`-Funktion erstellen. Ein weiteres, wahrscheinlich öfter genutztes Beispiel ist die `collections.namedtuple()`-Funktion, die ebenfalls Klassen erstellt.
Antworten