GTKmm ComboBox Eintrag finden und auswählen
-
Hi
also ich hab ne ComboBox, die ich mit Elementen fülle, die ihre Daten von Objekten beziehen. Jede Zeile (Row) hat einen Pointer auf das zugehörige Objekt als DummySpalte.
Nun suche ich einen (komfortablen) Weg ein bestimmtes solches Objekt in der Combobox zu wählen als Initialisierung zB.
Ich hatte mir gedacht, dass ich iwie nen Iterator, entweder der ComboBox oder des zugrundeliegenden ListStore bekomme, aber iwie finde ich nix bassendes wie begin() o.ä.
Nun habe ich es mit m_ListStore->foreach_iter(...) versucht. Aber das führt nach einer gewissen Zeit zu Abstürzen, und zwar nach einem erfolgreichen Vergleich der Objekte, oder auch bei Pointern auf die Objekte.Die iteratorfunktion
bool AVColorPatternSelector::forsetSelection(const Gtk::TreeModel::iterator& iter, AVColorPattern aPattern) { Gtk::TreeRow row = *iter; AVColorPattern p = *row[m_Model.pattern]; if (p == aPattern) { set_active(iter); return true; } else { return false; } }
Ich hoffe ihr könnt mir helfen oder eine andere Variante nennen, weil es muss ja möglich sein.
MfG Protogenes
-
Hallo,
ich nehme mal an, wir reden von Gtk::ComboBox? Falls ja, ein alternativer Weg, das aktuell selektierte Element herauszufinden bzw. irgendeins zu selektieren, wäre die Funktionen
int get_active_row_number() const;
void set_active(int index);herzunehmen. Wenn's nicht geht, komplierbares und minimales Beispiel posten, damit ich's durchschauen kann.
MfG
GPC
-
GPC schrieb:
Hallo,
ich nehme mal an, wir reden von Gtk::ComboBox? Falls ja, ein alternativer Weg, das aktuell selektierte Element herauszufinden bzw. irgendeins zu selektieren, wäre die Funktionen
int get_active_row_number() const;
void set_active(int index);herzunehmen. Wenn's nicht geht, komplierbares und minimales Beispiel posten, damit ich's durchschauen kann.
MfG
GPC
Dabei ist das Problem, dass ich das Element erst finden muss. Wenn es eine Möglichkeit gibt, eine Row von einem Index zu bekommen, würde ich das so machen.
MfG Protogenes
-
Okay, poste ein kompilierbares und minimales Beispiel und ich schau's mir heute Abend mal an, oder morgen
-
Jetzt habe ich es am laufen, aber ich dachte ich hätte es schonmal so gehabt -.-' nunja, ich mag C++ nicht ^^
Aber ich habe noch ein anderes Problem, dass ich zwar ein wenig ignorieren kann, aber...
Zugriffsverletzung beim Beenden des Progs.Minimalbeispiel ist etwas länger, da ich mir nicht erklären kann, wo der Fehler auftritt.
Ich habe ja mal etwas von einem Fehler in der Gdk::Pixbuf Implementireung unter Windows gehört. Keine Ahnung ob es das ist. Wenn du gewillt bist es dir anzusehen, würde ich mich freuen.MfG Protogenes
#include <gtkmm.h> #include <stdlib.h> class AVColorPattern; typedef std::list<AVColorPattern> TAVColorPatternList; TAVColorPatternList AVColorPatternList; class AVColorPattern { public: /// The type for one markers data (color values respective) typedef struct { guint8 red, green, blue; } TPatternItem; /// type for organizing markers typedef std::map<int, TPatternItem> TPatternItems; typedef sigc::signal< void, AVColorPattern& > type_sigColorPatternChanged; AVColorPattern(TAVColorPatternList& list); /// destructor virtual ~AVColorPattern(); /// adds a marker at the specified position with color value void addMarker(guint8 position, guint8 red, guint8 green, guint8 blue); /// calculates the colortable an gives an pointer to it back TPatternItem* get_ColorTable(); /// set the displayed title of the pattern void set_Title(const Glib::ustring& title); /// get the displayed title Glib::ustring get_Title() const; /// get the Preview image of the pattern Glib::RefPtr<Gdk::Pixbuf> get_Preview(); type_sigColorPatternChanged signalChanged() {return m_sigChanged;}; bool operator==(const AVColorPattern& other) const; //void operator=(const AVColorPattern& other); protected: private: /// internal markers map TPatternItems* m_Items; /// changed flag for recalculating bool m_Changed; /// colortable TPatternItem m_ColorTable[19][256]; /// displayed title Glib::ustring* m_Title; /// the preview picture Glib::RefPtr<Gdk::Pixbuf> m_Preview; /// function which mixes two colors at a specified ratio TPatternItem mixColors(TPatternItem a, TPatternItem b, guint8 ratio); type_sigColorPatternChanged m_sigChanged; }; AVColorPattern::AVColorPattern(TAVColorPatternList& list) { m_Changed = true; m_Items = new TPatternItems; char t[32]; t[0] = 0; sprintf(t, "Pattern %.8X", this); m_Title = new Glib::ustring(t); TPatternItem a, b; a.red = 0; a.green = 0; a.blue = 0; b.red = 255; b.green = 255; b.blue = 255; (*m_Items)[0] = a; (*m_Items)[255] = b; list.push_back(*this); } AVColorPattern::~AVColorPattern() { AVColorPatternList.remove(*this); delete m_Title; m_Items->clear(); delete m_Items; } void AVColorPattern::addMarker(guint8 position, guint8 red, guint8 green, guint8 blue) { TPatternItem a; a.red = red; a.green = green; a.blue = blue; (*m_Items)[position] = a; m_Changed = true; m_sigChanged.emit(*this); } AVColorPattern::TPatternItem* AVColorPattern::get_ColorTable() { if (m_Changed) { TPatternItems::iterator i, l; i = m_Items->begin(); l = m_Items->end(); for (guint16 p = 0; p<=255; p++) { if (i == m_Items->end()) { if (l == m_Items->end()) //empty list { m_ColorTable[0][p].red = 0; m_ColorTable[0][p].green = 0; m_ColorTable[0][p].blue = 0; } else { m_ColorTable[0][p] = l->second; } } else { if (l == m_Items->end()) { m_ColorTable[0][p] = i->second; } else { m_ColorTable[0][p] = mixColors(i->second, l->second, (p - l->first) * 255 / (i->first - l->first)); } if (i->first == p) { l = i; i++; } } } memcpy(&(m_ColorTable[1][0].red), &(m_ColorTable[0][0].red), sizeof(m_ColorTable[0])); memcpy(&(m_ColorTable[2][0].red), &(m_ColorTable[0][0].red), 2*sizeof(m_ColorTable[0])); memcpy(&(m_ColorTable[4][0].red), &(m_ColorTable[0][0].red), 4*sizeof(m_ColorTable[0])); memcpy(&(m_ColorTable[8][0].red), &(m_ColorTable[0][0].red), 8*sizeof(m_ColorTable[0])); memcpy(&(m_ColorTable[16][0].red), &(m_ColorTable[0][0].red), 3*sizeof(m_ColorTable[0])); m_Preview = Gdk::Pixbuf::create_from_data(&(m_ColorTable[0][0].red), Gdk::COLORSPACE_RGB, false, 8, 256, 19, sizeof(m_ColorTable[0])); m_Changed = false; } return m_ColorTable[0]; } void AVColorPattern::set_Title(const Glib::ustring& title) { m_Title->assign(title); m_sigChanged.emit(*this); } Glib::ustring AVColorPattern::get_Title() const { return *m_Title; }; Glib::RefPtr<Gdk::Pixbuf> AVColorPattern::get_Preview() { get_ColorTable(); return m_Preview; } bool AVColorPattern::operator==(const AVColorPattern& other) const { return (this == &other); } AVColorPattern::TPatternItem AVColorPattern::mixColors(TPatternItem a, TPatternItem b, guint8 ratio) { TPatternItem r; guint8 cr = 255 - ratio; r.red = (a.red * ratio + b.red * cr) / 255; r.green = (a.green * ratio + b.green * cr) / 255; r.blue = (a.blue * ratio + b.blue * cr) / 255; return r; } class AVColorPatternSelector : public Gtk::ComboBox { public: AVColorPatternSelector(TAVColorPatternList* ColorPatterns); virtual ~AVColorPatternSelector(); AVColorPattern& get_Selection(); void set_Selection(AVColorPattern& aPattern); protected: private: TAVColorPatternList* m_ColorPatterns; struct CPSModelColumns : public Gtk::TreeModelColumnRecord { Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > image; Gtk::TreeModelColumn<Glib::ustring> title; Gtk::TreeModelColumn<AVColorPattern*> pattern; CPSModelColumns() { add(image); add(title); add(pattern);} }; Glib::RefPtr<Gtk::ListStore> m_ListStore; const CPSModelColumns m_Model; void dropdown_additem(AVColorPattern& AVCP); void onItemChanged(AVColorPattern& AVCP, Gtk::TreeRow row); bool forsetSelection(const Gtk::TreeModel::iterator& iter, AVColorPattern* aPattern); }; AVColorPatternSelector::AVColorPatternSelector(TAVColorPatternList* ColorPatterns) : Gtk::ComboBox() { m_ColorPatterns = ColorPatterns; m_ListStore = Gtk::ListStore::create(m_Model); std::for_each( m_ColorPatterns->begin(), m_ColorPatterns->end(), sigc::mem_fun(*this, &AVColorPatternSelector::dropdown_additem)); this->set_model(m_ListStore); pack_start(m_Model.image, false); pack_start(m_Model.title, true); } AVColorPatternSelector::~AVColorPatternSelector() { this->clear(); } void AVColorPatternSelector::dropdown_additem(AVColorPattern& AVCP) { Gtk::TreeRow row = *(m_ListStore->append()); row[m_Model.image] = AVCP.get_Preview(); row[m_Model.title] = Glib::ustring(AVCP.get_Title()); row[m_Model.pattern] = &AVCP; AVCP.signalChanged().connect(sigc::bind<Gtk::TreeRow>(sigc::mem_fun(*this, &AVColorPatternSelector::onItemChanged), row)); } void AVColorPatternSelector::onItemChanged(AVColorPattern& AVCP, Gtk::TreeRow row) { row[m_Model.image] = AVCP.get_Preview(); row[m_Model.title] = Glib::ustring(AVCP.get_Title()); } AVColorPattern& AVColorPatternSelector::get_Selection() { Gtk::TreeRow row = *(this->get_active()); return *(row[m_Model.pattern]); } void AVColorPatternSelector::set_Selection(AVColorPattern& aPattern) { m_ListStore->foreach_iter(sigc::bind<AVColorPattern*>(sigc::mem_fun(*this, &AVColorPatternSelector::forsetSelection), &aPattern)); } bool AVColorPatternSelector::forsetSelection(const Gtk::TreeModel::iterator& iter, AVColorPattern* aPattern) { Gtk::TreeRow row = *iter; AVColorPattern* p = row[m_Model.pattern]; if (p == aPattern) { set_active(iter); return true; } else { return false; } } class AVMainWindow : public Gtk::Window { public: /// default constructor AVMainWindow(); private: AVColorPatternSelector sel1,sel2; Gtk::VBox box; }; AVMainWindow::AVMainWindow() : Gtk::Window(), sel1(&AVColorPatternList), sel2(&AVColorPatternList), box(2) { sel1.set_Selection(*(AVColorPatternList.begin())); sel2.set_Selection(*(AVColorPatternList.rbegin())); box.pack_start(sel1); box.pack_start(sel2); add(box); show_all(); } void initColorPatterns() { AVColorPattern* p = new AVColorPattern(AVColorPatternList); p->addMarker(63,0,0,255); p->addMarker(191,0,255,255); p->set_Title("Modern"); p = new AVColorPattern(AVColorPatternList); p->addMarker(0,0,0,255); p->addMarker(63,0,255,255); p->addMarker(127,0,255,0); p->addMarker(191,255,255,0); p->addMarker(255,255,0,0); p->set_Title("Regenbogen"); } int main(int argc, char *argv[]) { Gtk::Main GTKSystem(argc, argv); initColorPatterns(); AVMainWindow mainwindow; GTKSystem.run(mainwindow); return 0; }
-
Kommentiere mal Zeile 35 aus:
AVColorPatternList.remove(*this);
Dann geht's.
-
hmm stimmt.
aber werden die Objekte auch entfernt, macht das die std::list selbst? Oder wie läuft das... will ja keine Leichen darin haben.
Das Objekt instanzierungssystem von C++ ist mir auch völlig suspekt.
-
Protogenes schrieb:
hmm stimmt.
aber werden die Objekte auch entfernt, macht das die std::list selbst? Oder wie läuft das... will ja keine Leichen darin haben.Richtig. Beim Zerstören der Liste werden auch alle Objekte da drinn frei gegeben. Sonst hätte man ja auch Probleme wenn man ne Liste aus PODs macht.
-
Also, das Ganze hat nichts mit Windows zu tun, dein Beispielprogramm fliegt auch unter Linux, du hast nämlich einen ziemlichen Misch-Masch aus Zeigern und Stack-allokierten Objekten.
Im Endeffekt werden deine AVColorPattern-Objekte zweimal freigegeben - einmal durch den Destruktor der AVColorPatternList und das zweite Mal durch den Destruktor des AVColorPattern-Objekts, das gerade durch die Liste zerstört wird, sich aber nochmals aus der Liste selbst entfernt.
Früher oder später wirst du übrigens auch Gefahr laufen, dass ein oder mehrere Kopien ein AVColorPattern-Objekts denselben Titel und dieselben pattern items, welche über einen Zeiger gehalten werden, freigeben.
Du schreibst, dass dir das Objekt-Instanziierungssystem völlig suspekt ist. C++ an sich ist nicht "managed" wie java oder c# oder c++.net, wo du ein Objekt irgendwie erzeugst und es dir dann einfach egal ist, weil sich jemand anders darum kümmert. Du hast die Freiheit und damit die Verantwortung zu wählen wie du dein Objekt erzeugst und verwaltest.
Es gibt nur 2 Möglichkeiten:
- inline
- am Heap
ad 1)
inline heisst entweder am Stack oder als "Member" zusammen mit einem Objekt. Die Lebensdauer des Objekts ist an den "Scope" gebunden, in dem es erzeugt worden ist.
Wenn das Objekt z.B. in einer Funktion erzeugt wird, lebt es bis zum Ende der Funktion, wird es als Member eines anderen Objekts erzeugt, lebt es solange das umgebende Objekt lebt.
Wenn du ein Objekt an ein anderes zuweist, wird das Objekt selbst kopiert (jedenfalls grundsätzlich).ad 2)
Objekte am Heap werden mit dem operator new erzeugt, du als Programmierer bist dafür verantwortlich, es wieder freizugeben mit operator delete.
Wenn du einen Zeiger an einen anderen zuweist, wird der Zeiger kopiert, nicht das Objekt.
Wenn du keine Lust hast, selber Zeiger zu managen, wofür es viele Gründe gibt (Verständnis, Bequemlichkeit, exception safety), dann kannst du ein Wrapper-Objekt verwenden, wozu z.B. der Glib::RefPtr zählt o.ä.Wenn du einer STL-Liste eine Kopie deines Objekts gibst, dann wird die Kopie bei der Zerstörung der Liste freigegeben; wenn du der Liste Zeiger gibst, dann wird nur der Zeiger selbst freigegeben, nicht aber das Objekt auf das du zeigst, das musst dann irgendwie selbst erledigen (oder eben die oben genannten Wrapper-Objekte verwenden).
-
So wie du es erklärst (danke für die ausführliche Erläuterung, nun kann ich mir sicher sein) hatte ich mir es auch gedacht.
Ich hatte aber nur ein Phänomen, das ich mir nicht erklären konnte:
Mein Plan war auch den AVColorPattern member m_Items ganz normal als member zu instanzieren und nicht als pointer mit new zu erzeugen. Das hat soweit geklappt, ich konnte die Standardeinträge im Konstruktor anlegen.TPatternItem a, b; a.red = 0; a.green = 0; a.blue = 0; b.red = 255; b.green = 255; b.blue = 255; m_Items[0] = a; m_Items[255] = b;
War ok, funktionierte, ich hatte einen schwarz-weiß Farbverlauf.
Das Problem entstand damit, dass ich Farbverläufe standardmäßig erzeugen wollte (siehe void initColorPatterns()) und addMarker für die AVColorPattern aufrufte.void AVColorPattern::addMarker(guint8 position, guint8 red, guint8 green, guint8 blue) { TPatternItem a; a.red = red; a.green = green; a.blue = blue; m_Items[position] = a; m_Changed = true; m_sigChanged.emit(*this); }
Kompilierte und fügte die Elemente auch ein, ABER nicht in mein m_Items, sondern irgendeine andere Liste (ich hab mir die pointer im konstruktor und addMarker ausgeben lassen). Im get_ColorTable funktionierte es wieder mit dem scharz-weiß des Konstruktors.
Also, wenn du mir das erklären kannst, dann wäre ich dankbar und würde auch gern wieder auf "normale" Objekte zurückgreifen, da die Pointer schon unschön erscheinen in C++ Code, in dem das anders gedacht ist.MfG Protogenes
-
Wenn du das mal kurz durchdenkst:
in initColorPatterns() erzeugst du ein AVColorPattern am Heap. Dieses kopierst du in die globale Liste TAVColorPatternList, erst nachher rufst du für das Objekt am Heap addMarker() auf. Damit stehen die Werte natürlich nicht im Objekt aus der Liste, das ist ja ganz ein anderes als das am Heap!
Erstens hast du mit den Heap-Objekten aus initColorPatterns() ohnehin ein Problem: du gibst sie nie frei - Memoryleaks!
Ich finde es ohnehin nicht gut, dass sich das AVColorPattern-Objekt bei seiner Erzeugung gleich in die Liste einträgt, besser ist es, diese Notwendigkeit ausserhalb zu machen, ev. in einer eigenen Methode, wenn oft gebraucht.Du kannst das z.B. folgendermaßen machen:
- initColorPatterns() erzeugt ein Stack-Objekt (welches sich nicht mehr selbst in die Liste kopiert)
- initColorPatterns() ruft stack_object.addMarker() etc... auf
- initColorPatterns() fügt das neue Objekt als Kopie in die Liste ein.Achte übrigens darauf, dass auch der Titel kein Zeiger mehr ist...