widget im BoxSizer dynamisch anlegen

Plattformunabhängige GUIs mit wxWidgets.
Antworten
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

Hallo,
ich möchte 5 Bilderchen (wx.StaticBitmap) in einem frame anzeigen und habe sie zu diesem
Zweck in einen BoxSizer gesteckt. Allerdings soll das 'dynamisch' passieren können, also
nicht nur in der __init__ Methode, wie in zahlreichen Schriftstücken gezeigt.
Außer Add(...) und Clear(..) habe ich zum BoxSizer nichts gefunden, muß ich also immer erst
alles löschen und dann neu füllen?

Gruß
joh
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

joh# hat geschrieben:Hallo,
ich möchte 5 Bilderchen (wx.StaticBitmap) in einem frame anzeigen und habe sie zu diesem
Zweck in einen BoxSizer gesteckt. Allerdings soll das 'dynamisch' passieren können, also
nicht nur in der __init__ Methode, wie in zahlreichen Schriftstücken gezeigt.
Außer Add(...) und Clear(..) habe ich zum BoxSizer nichts gefunden, muß ich also immer erst
alles löschen und dann neu füllen?

Gruß
joh
Es gibt eine Remove Methode.
help(wx.BoxSizer)
...
" | Remove(*args, **kwargs)
| Remove(self, item) -> bool
|
| Removes an item from the sizer and destroys it. ...
"...
BlackJack

Es ist vielleicht einfacher die Bitmaps auszutauschen (`wx.StaticBitmap.SetBitmap()`) statt die Widgets aus dem Sizer zu entfernen und neue Widgets zu erstellen.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

BlackJack hat geschrieben:Es ist vielleicht einfacher die Bitmaps auszutauschen (`wx.StaticBitmap.SetBitmap()`) statt die Widgets aus dem Sizer zu entfernen und neue Widgets zu erstellen.
Das klingt elegant, nur wie mache ich das denn. Einfach nut SetBitmap() aufrufen führt bei mir zu
wx._core.PyDeadObjectError: The C++ part of the BoxSizer object has been deleted, attribute access no longer allowed
Da muß doch dann auch noch ein Neuaufbau des Bildes eingeleitet werden oder?

Gruß
joh
BlackJack

@joh#: Hm ohne konkreten Quelltext kann ich dazu jetzt auch nichts sagen. Bei mir funktioniert das.

Code: Alles auswählen

import random
import wx


class Main(wx.Frame):
    def __init__(self, parent, image_count=5):
        wx.Frame.__init__(self, parent)
        vsizer = wx.BoxSizer(wx.VERTICAL)
        
        sizer = wx.BoxSizer()
        bitmap = wx.BitmapFromImage(wx.Image('test0.png'))
        self.bitmaps = [wx.StaticBitmap(self, wx.ID_ANY, bitmap)
                        for dummy in xrange(image_count)]
        for bitmap in self.bitmaps:
            sizer.Add(bitmap)
        vsizer.Add(sizer)
        
        button = wx.Button(self, wx.ID_ANY, '&Random change')
        vsizer.Add(button, 0, wx.CENTRE)
        
        self.Bind(wx.EVT_BUTTON, self.OnRandomChange, button)
        
        self.SetSizer(vsizer)
        self.Fit()
    
    def OnRandomChange(self, _event):
        for bitmap in self.bitmaps:
            image = wx.Image('test%s.png' % random.randint(0, 1))
            bitmap.SetBitmap(wx.BitmapFromImage(image))


def main():
    app = wx.PySimpleApp()
    frame = Main(None)
    frame.Show()
    app.SetTopWindow(frame)
    app.MainLoop()


if __name__ == '__main__':
    main()
In diesem Beispiel ist es natürlich unsinnig die beiden Bilder immer wieder neu zu laden, die könnte man auch einmal in der `__init__()` laden und als `wx.StaticBitmap`\s an den Frame binden.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

BlackJack hat geschrieben: In diesem Beispiel ist es natürlich unsinnig die beiden Bilder immer wieder neu zu laden, die könnte man auch einmal in der `__init__()` laden und als `wx.StaticBitmap`\s an den Frame binden.
Ich wollte die Bitmaps nicht an den Frame sondern an den sizer binden, aber das geht lt. Doku nicht.
Oder gibt es da einen Trick?
BlackJack

@joh#: Ich verstehe nicht was Du damit sagen willst. Ich meinte das es bei meinem Beispiel Unsinnig ist in der `OnRandomChange()` die beiden Bilder immer neu zu laden. Ich hätte die auch in der `__init__()` in eine Liste stecken können in `OnRandomChange()` dann aus dieser Liste auswählen können. Das kommt halt darauf an, ob es möglich ist alle möglichen Bilder vorher zu laden und ob sich das lohnt, oder ob man die erst bei Bedarf lädt. Wenn ich zum Beispiel Yatzee implementieren wollte, würde ich Bilder von den Würfelseiten einmal am Anfang alle laden.

Funktioniert mein Beispiel denn bei Dir? Wenn nicht, wo hakts? Wenn's einen Traceback gibt, dann bitte den ganzen zeigen. Das Beispiel braucht zwei Bilder mit den Namen `test0.png` und `test1.png`.
joh#
User
Beiträge: 139
Registriert: Freitag 6. November 2009, 13:16

BlackJack hat geschrieben:@joh#: Ich verstehe nicht was Du damit sagen willst.
Ich hatte auf einer manual Seite gelesen, daß ein bitmap keinen
sizer als parent haben kann, nur z.B. ein panel, aber in Deinem Bsp.
geht das ja locker mit

Code: Alles auswählen

sizer.Add(bitmap)
BlackJack hat geschrieben: Funktioniert mein Beispiel denn bei Dir?
Es funktioniert bestens, und ist genau das was ich gebraucht habe. Besten Dank!
BlackJack

@joh#: Die Dokumentation stimmt schon. Meine `StaticBitmaps`\s haben ja `self` als "parent" und nicht den `Sizer`. Widgets müssen andere Widgets als "parent"s haben -- oder etwas korrekter `wx.Window`\s. `Sizer` sind selbst keine Widgets sondern Hilfsobjekte, die für Containerwidgets das Layout von deren Kindern erledigen.
Antworten