PNG-Transparenz

Plattformunabhängige GUIs mit wxWidgets.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hallo...


ich moechte ein fast vollstaendig grafisches UI fuer mein Programm haben. Das ganze wuerde sich aus PNGs zusammensetzen. Leider scheint wxPython ein Problem damit zu haben, die Transparenz darzustellen. Außerdem muss ich eine Mask-Color festlegen, da er sonst scheinbar Weiß oder Schwarz nimmt und dadurch Bildfehler einbaut. Die groesste Sorge ist aber weiterhin, dass eigentlich Transparente Grafiken (wo nicht nur eine Farbe komplett Transparent, sondern die einzelnen Farben alphawertig sind) nicht Transparent sind.

Danke schonmal fuer Antworten...

nkoehring
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:Leider scheint wxPython ein Problem damit zu haben, die Transparenz darzustellen.
Hallo nkoehring!

Unter Windows funktioniert es, wenn ich selber zeichne. Bitte ausprobieren:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import wx

wx.SetDefaultPyEncoding("iso-8859-15")


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, title = "Example", size = wx.Size(550, 420)
    ):
        wx.Frame.__init__(self, parent, -1, title, size = size)
        
        panel = wx.Panel(self)
        panel.SetBackgroundColour("white")
        self.panel = panel
        
        self.bmp = wx.Bitmap("bild.png")
        panel.Bind(wx.EVT_PAINT, self.on_panel_paint)
    
    
    def on_panel_paint(self, event):
        event.Skip()
        
        # Mit Buffer
        dc = wx.BufferedPaintDC(self.panel, buffer = self.bmp)
        
        # Ohne Buffer
        #dc = wx.PaintDC(self.panel)
        #dc.DrawBitmap(self.bmp, 0, 0, useMask = True)


def main():
    """Testing"""
    
    app = wx.PySimpleApp()
    f = MyFrame()
    f.Center()
    f.Show()
    app.MainLoop()


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Besser so:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import wx

wx.SetDefaultPyEncoding("iso-8859-15")


class MyBitmapPanel(wx.Panel):
    
    def __init__(self, parent = None, background_color = "white", bitmap = None):
        wx.Panel.__init__(self, parent)
        self.SetBackgroundColour(background_color)
        self.bmp = bitmap
        if self.bmp:
            size = self.bmp.GetSize()
            self.SetSize(size)
            self.SetSizeHintsSz(size)
        
        self.Bind(wx.EVT_PAINT, self.on_self_paint)
    
    
    def on_self_paint(self, event):
        event.Skip()
        if self.bmp:
            dc = wx.BufferedPaintDC(self, buffer = self.bmp)
    
    

class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, title = "Example", size = wx.Size(550, 420)
    ):
        wx.Frame.__init__(self, parent, -1, title, size = size)
        
        vbox_main = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(vbox_main)
        
        bmp = wx.Bitmap("bild.png")
        
        green_panel = MyBitmapPanel(self, "green", bmp)
        vbox_main.Add(green_panel, 1, wx.EXPAND)
        
        yellow_panel = MyBitmapPanel(self, "yellow", bmp)
        vbox_main.Add(yellow_panel, 1, wx.EXPAND)
    
        self.Fit()
        self.SetSizeHintsSz(self.GetSize())


def main():
    """Testing"""
    
    app = wx.PySimpleApp()
    f = MyFrame()
    f.Center()
    f.Show()
    app.MainLoop()


if __name__ == "__main__":
    main()
Bild
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

ah vielen Dank... das sieht schonmal gut aus.

Nun muss ich nur noch viele Bilder uebereinander packen... ich hoffe dazu muss ich nicht jedesmal ein eigenes Panel definieren -.-
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hmm... also die ganze Sache hat im Moment noch den Haken, dass ich zwar nun Transparenz habe, aber nur auf die Panel-Hintergrundfarbe bezogen... nicht auf das dahinter liegende Bild :(
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:Nun muss ich nur noch viele Bilder uebereinander packen... ich hoffe dazu muss ich nicht jedesmal ein eigenes Panel definieren
Hallo nkoehring!

Wenn du Widgets auf dem Bild platzieren möchtest --> wx.Panel
Wenn du nichts mehr auf dem Bild platzieren möchtest --> wx.Window

Wenn du die Bilder in je einen Container zeichnest, dann tust du dir evt. leichter beim Abfangen von Events. Das kommt aber auch ganz auf dein Konzept und Ziel an.

Wie auch immer. Eine selbst gestrickte Programmoberfläche kostet den Programmierer viel, viel, viel mehr Arbeit und ist meist nicht so benutzerfreundlich wie eine Standard-Oberfläche.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:dass ich zwar nun Transparenz habe, aber nur auf die Panel-Hintergrundfarbe bezogen... nicht auf das dahinter liegende Bild :(
Hallo nkoehring!

NUR UNTER WINDOWS:

Code: Alles auswählen

wx.Panel.__init__(self, parent, style = wx.TRANSPARENT_WINDOW)
wxTRANSPARENT_WINDOW The window is transparent, that is, it will not receive paint events. Windows only.
Wenn das Programm auch unter Linux laufen soll, dann bleibt dir nichts anderes übrig, als alles in ein einziges Widget (Panel, Window,...) zu zeichnen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hallo nochmal...

ich habe mich eben nochmal rangesetzt und probiert... und festgestellt, dass die Transparenz generell richtig Funktioniert, wenn ich pro Bild ein eigenes Label erstelle und dem Label keine Hintergrundfarbe zuweise... quasi so (getestet unter WinVista):

Code: Alles auswählen

class MyBitmapPanel(wx.Panel):
   
    def __init__(self, parent=None, bitmap=None):
        wx.Panel.__init__(self, parent)
        self.bmp = bitmap
        if self.bmp:
            size = self.bmp.GetSize()
            self.SetSize(size)
            self.SetSizeHintsSz(size)       
        self.Bind(wx.EVT_PAINT, self.on_self_paint)

    def on_self_paint(self, event):
        event.Skip()
        if self.bmp: wx.BufferedPaintDC(self, buffer=self.bmp)

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.CAPTION
        wx.Frame.__init__(self, *args, **kwds)

        # preloades all needed Images (eg. img_bg and img_title)
        self.loadImages()

        bmp = wx.BitmapFromImage(self.img_bg)
        bmp2 = wx.BitmapFromImage(self.img_title)
        self.panel = MyBitmapPanel(self, "white", bmp)
        self.panel2 = MyBitmapPanel(self, "white", bmp2)
        self.Fit()
        self.SetSizeHintsSz(self.GetSize())

    def loadImages(self):
        # ...
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:pro Bild ein eigenes Label erstelle und dem Label keine Hintergrundfarbe zuweise... quasi so (getestet unter WinVista)
Hallo nkoehring!

1.) Welches Label? Meinst du Panel?

2.) Du darfst keine Panel übereinander (im gleichen Kontainer) anordnen, wenn du möchtest, dass dein Programm auch unter Linux und Mac funktioniert. Das ist eine der wenigen Einschränkungen, die man bedenken muss, wenn man portabel bleiben möchte.

Teste dein Programm doch auch mal unter Linux. Einfach "VirtualBox" installieren und darin z.B. "Ubuntu" als Gast installieren. Dann hast du ein Testsystem.

mfg
Gerold
:-)

PS: Mit wxPython 2.8 habe ich dieses Verhalten noch nicht unter Linux getestet. Vielleicht hat sich etwas geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

danke fuer die Tipps, bei Gelegenheit mache ich das mal. Erstmal muss das Programm einfach nur unter Windows funktionieren, von daher ist die portabilitaet bisher Nebensache, aber dennoch erklaertes Ziel fuer Spaeter.
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hallo mal wieder... da kommt schonwieder ein Problem zustande.

Wenn ich auf das Panel (nicht Label :roll: ) einen Event ausfuehre, zB wx.EVT_LEFT_DOWN, soll sich das Bild aendern.
Meine Idee: Ich haenge je Panel eine Methode an den Event, die dafuer sorgt, dass self.bmp durch eine Alternativ-Bitmap ausgetauscht wird und veranlasse einen self.Refresh().
Ich habe zwei Varianten, die beide unterschiedlich falsch Funktionieren:
In der ersten haenge ich die Methode nur an den Event, wenn eine Alternativ-Bitmap uebergeben wird. Dann passiert nichts, wenn ich klicke (der Event scheint nicht zu greifen).
In der zweiten Variante haenge ich die Methode immer an und ueberpruefe innerhalb der Methode auf die Alternativ-Bitmap. Dann verschwinden alle Panels ueber dem ersten...

Zur Veranschaulichung hier der Code fuer die erste Variante:

Code: Alles auswählen

class MyBitmapPanel(wx.Panel):
   
    def __init__(self, parent=None, bitmap=None, alternate=None):
        wx.Panel.__init__(self, parent)
        self.bmp = bitmap
        self.orig = bitmap
        self.alt = alternate
        if self.bmp:
            size = self.bmp.GetSize()
            self.SetSize(size)
            self.SetSizeHintsSz(size)
        self.Bind(wx.EVT_PAINT, self.on_self_paint)
        
        if self.alt:
            self.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
            self.Bind(wx.EVT_LEFT_UP, self.on_mouse_up)

    def on_mouse_down(self, evt):
        print "down..."
        self.bmp = self.alt
        self.Refresh()
    
    def on_mouse_up(self, evt):
        print "and up..."
        self.bmp = self.orig
        self.Refresh()
    
    def on_self_paint(self, evt):
        evt.Skip()
        if self.bmp: wx.BufferedPaintDC(self, buffer=self.bmp)
EDIT: okay, ich weiß jetzt, dass die obenliegenden Bitmaps einfach hinter das "Hintergrundbild" rutschen und dadurch unsichtbar werden. Sorge ich dafuer, dass keine Panels uebereinanderliegen, funktioniert alles so wie ich mir das vorstelle...
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Eine Frage... ist es erlaubt, das Canvas vom Frame selbst zu bemalen und dann bemalte Panels drueber zu packen? Denn das scheint gut zu funktionieren...
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:Eine Frage... ist es erlaubt, das Canvas vom Frame selbst zu bemalen und dann bemalte Panels drueber zu packen? Denn das scheint gut zu funktionieren...
Hallo nkoehring!

Das weiß ich nicht. Schiebe mal ein kleines Beispiel ins "Lodge it". Dann kann ich es ausprobieren.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:http://paste.pocoo.org/show/2102/ ...sollte klappen
Hallo nkoehring!

Eigentlich dachte ich an ein funktionierendes Beispiel. :mrgreen:

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Nagut, dann hier eine Zip mit dem Testprogramm von mir...

http://www.newagedesigns.de/bunt.zip
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:Testprogramm
Hallo nkoehring!

Na, sieht doch schon mal nicht so schlecht aus. Wenn du die Anzeigeprobleme (Transparenz) unter Windows XP in den Griff bekommen hast, dann könnte es sein, dass es auch keine Probleme mehr unter Linux gibt. :-)

Ubuntu im VirtualBox:
http://gerold.bcom.at/bilder/petool_linux_01.png
http://gerold.bcom.at/bilder/petool_linux_02.png
Windows XP:
http://gerold.bcom.at/bilder/petool_windowsxp_01.png

mfg
Gerold
:-)
Zuletzt geändert von gerold am Mittwoch 1. August 2007, 18:00, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Ah, vielen Dank fuers Testen.

Mir ist aufgefallen, dass die Transparenz unter Windows zurueckkehrt, wenn ich das Fenster am unteren Monitorrand kurz "verschwinden" lasse und dann wieder in den sichtbaren bereich hole. Was ist denn der Unterschied zwischen einem Refresh und dieser Art des Neuzeichnens? Kann ich das vielleicht direkt erzwingen oder ist es doch eine Windows-Sache?
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

nkoehring hat geschrieben:Mir ist aufgefallen, dass die Transparenz unter Windows zurueckkehrt, wenn ich das Fenster am unteren Monitorrand kurz "verschwinden" lasse und dann wieder in den sichtbaren bereich hole. Was ist denn der Unterschied zwischen einem Refresh und dieser Art des Neuzeichnens? Kann ich das vielleicht direkt erzwingen oder ist es doch eine Windows-Sache?
Hallo nkoehring!

Wenn das Fenster verdeckt wird und danach wieder in den sichtbaren Bereich vorgeholt wird, dann wird EVT_PAINT automatisch ausgelöst.

``Refresh`` sollte das eigentlich auch tun. :K Aber ``Refresh`` arbeitet erst beim nächsten Event-Loop. Wenn du einen sofortigen Refresh erzwingen willst, dann führe zuerst ``Refresh`` und sofort danach ``Update`` aus. Vielleicht sogar noch ein ``YieldIfNeeded`` nachschieben... Zumindest sollte es dann laut Doku sofort neu gezeichnet werden. Ob es in der Praxis funktioniert, werde ich von dir erfahren. ;-)

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

so, es sieht auch nach zusaetzlichem Update genauso aus wie vorher... YieldIfNeeded hab ich allerdings auch nirgends gefunden :K

EDIT: Es wird ja neugezeichnet, auch nach einem einfachen Refresh, aber dadurch wird eben die Transparenz ausgeloescht.
Ich habe das Problem jetzt so geloest, dass einfach mehrere Panels uebereinander gelegt und jeweils (un-)sichtbar geschalten werden.
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Antworten