häufiger crash bei schließen eines panels mit fokussierter wxTextCtrl
-
moin zusammen,
ich habe folgendes, eigenartiges problem:
ich tausche zwei wxPanel gegeneinander aus, das zweite enthält eine wxTextCtrl. über die ESC taste stoße ich das zurück tauschen der panels wieder an.wenn im zweiten panel vor dem drücken von esc die wxTextCtrl per setFocus() oder anklicken fokussiert ist, crasht das programm häufig (nicht immer!) beim drücken von esc mit fehlermeldung in IMPLEMENT_APP(App).
mepOhneDll4.exe!wxWindow::MSWWindowProc(unsigned int message=256, unsigned int wParam=27, long lParam=65537) Zeile 2986 + 0x2b Bytes C++ mepOhneDll4.exe!wxTextCtrl::MSWWindowProc(unsigned int nMsg=256, unsigned int wParam=27, long lParam=65537) Zeile 2016 + 0x14 Bytes C++ mepOhneDll4.exe!wxWndProc(HWND__ * hWnd=0x002409d6, unsigned int message=256, unsigned int wParam=27, long lParam=65537) Zeile 2613 + 0x1c Bytes C++ user32.dll!7e368734() [Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für user32.dll] user32.dll!7e368816() user32.dll!7e3689cd() user32.dll!7e368a10() mepOhneDll4.exe!wxEventLoop::ProcessMessage(tagMSG * msg=0x0012fd18) Zeile 80 C++ mepOhneDll4.exe!wxEventLoop::Dispatch() Zeile 294 C++ mepOhneDll4.exe!wxEventLoopManual::Run() Zeile 115 + 0xd Bytes C++ mepOhneDll4.exe!wxAppBase::MainLoop() Zeile 312 + 0x15 Bytes C++ mepOhneDll4.exe!wxAppBase::OnRun() Zeile 368 C++ mepOhneDll4.exe!wxEntryReal(int & argc=1, wchar_t * * argv=0x01d855d8) Zeile 460 + 0x1b Bytes C++ mepOhneDll4.exe!wxEntry(int & argc=1, wchar_t * * argv=0x01d855d8) Zeile 209 + 0xd Bytes C++ mepOhneDll4.exe!wxEntry(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * __formal=0x00000000, HINSTANCE__ * __formal=0x00000000, int nCmdShow=1) Zeile 386 + 0xd Bytes C++ > mepOhneDll4.exe!WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00151f17, int nCmdShow=1) Zeile 49 + 0x18 Bytes C++ mepOhneDll4.exe!__tmainCRTStartup() Zeile 574 + 0x35 Bytes C mepOhneDll4.exe!WinMainCRTStartup() Zeile 399 C kernel32.dll!7c817077() mepOhneDll4.exe!wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox * pParent=0x70007000, unsigned int nIndex=553648128) Zeile 152 + 0x37 Bytes C++ 63002e00()
leider ist das programm viel zu komplex, um es hier zu posten.
da in der aufrufliste keine einzige zeile meines codes erwähnt ist, weiß ich nicht, wie ich den fehler finden könnte.was kann ich da machen?
danke!
-
Wo bleibt denn der Debugger stehen?
Und wie tauschst Du die Panels? Über RemoveChild(), AddChild()?
rya.
-
ich bin jetzt nicht so der debug könig, bisher kam ich gut damit zurecht, was mit visual studio 2008 gezeigt hat.
um auf deine frage zu antworten habe ich das programm mal mit windbg angeworfen und folgenden output bekommen:
(744.7fc): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=01dfe4f0 ebx=00000000 ecx=f33ed057 edx=00000002 esi=005197a0 edi=0012fc34 eip=00519fb0 esp=0012f668 ebp=0012fb88 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 *** WARNING: Unable to verify checksum for mepOhneDll4.exe mepOhneDll4!wxWindow::MSWWindowProc+0x730: 00519fb0 8a881c010000 mov cl,byte ptr [eax+11Ch] ds:0023:01dfe60c=??
die panels tausche ich über sizer->replace(old, new, true) im übergeordneten frame, was bisher auch immer gut gefunzt hat.
-
Ohne den Code von der entsprechenden Stelle kann ich mit dem Quote da nix anfangen...
Debugge das ganze doch mal mit Visual Studio.. das Ding hat so nen geilen Debugger, wieso qäulst Du dich mit WinDbg?
rya.
-
ich sehe leider keine anzeige, welche codezeile das problem enthalten könnte.
wie könnte ich denn visual studio mehr informationen zu dem fehler entlocken, als ich gepostet habe?
kannst du mir vielleicht einen link zu einer einführung posten, was ich deiner meinung nach über den visual studio debugger lernen müsste, um dieses problem zu lösen?
wie gesagt, bisher musste ich noch nicht so tief ins debuggen einsteigen... bin leider auch autodidakt ohne persönlichen kontakt zu anderen programmierern.
danke!!!
-
ich habe noch weitere infos:
das wechseln der panels funktioniert sehr viel häufiger ohne absturz, wenn ich wxTextCtrl->setFocus() im konstruktor raus nehme. dann kann es aber sein, dass ich beim schließen des programms einen heap corruption detected bekomme mit folgender aufrufliste:
msvcr90d.dll!009f1241() [Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für msvcr90d.dll] msvcr90d.dll!009f0fa0() msvcr90d.dll!009f3809() msvcr90d.dll!009ddd4e() msvcr90d.dll!009f3821() msvcr90d.dll!009f3818() msvcr90d.dll!009f05a3() > mepOhneDll4.exe!WinMainCRTStartup() Zeile 399 C kernel32.dll!7c817077() mepOhneDll4.exe!wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox * pParent=0x70007000, unsigned int nIndex=553648128) Zeile 152 + 0x37 Bytes C++ 63002e00()
der unterste punkt mit der wxCheckListBox ist derselbe wie in meinem ersten post. das komische ist nur, dass ich im gesamten programm keine wxCheckListBox benutze....
kann das was zur lösung des problems beitragen?
-
die ausgabe zeigt:
Eine Ausnahme (erste Chance) bei 0x00517620 in mepOhneDll4.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x01e2f034.
0x00517620 bleibt immer gleich, der letzte wert 0x01e2f034 ist immer anders. kann ich da irgendwie ansetzen?
danke!!
-
Also was du da so erzählst, da kann man auch nur raten...#
Zeigt doch mal deinen Code, und den Debugger im VS anzuwerfen wäre hier definitiv richtig.
Wenn du das noch nicht kannst, ist es Zeit es zu lernen, wird dir immer wieder eine gute Hilfe sein.
Ich bin auch einige Jahre ohne ausgekommen, aber mit ist es um einiges leichter.
-
das projekt ist wie gesagt leider recht groß, aber ich poste mal den teil, in dem der fehler geschieht:
/** \file defectmodepanel.cpp * * \brief Defect Mode Panel (Implementierung) */ #include "defectmodepanel.h" //#include "codeinputctrl.h" #include "eventproxy.h" #include "eventids.h" #include "mainframe.h" #include "indexcursor.h" #include "defectlist.h" #include "formscrolllistdefects.h" #include "wx/bookctrl.h" #include "othersconfig.h" #include "keypropagators.h" //#include <iostream> //using namespace std; BEGIN_EVENT_TABLE(DefectModePanel, wxPanel) EVT_CHAR(DefectModePanel::onQuickInputEnter) // TAB_EVT_DEFECTPANEL_SELECTION(ID_DEFECTPANEL, DefectModePanel::onDefectPanelSelection) // TAB_EVT_DEFECTPANEL_BEGINSELECTION(ID_DEFECTPANEL, DefectModePanel::onDefectPanelBeginSelection) EVT_TIMER(ID_TIMER, DefectModePanel::onTimer) END_EVENT_TABLE() DefectModePanel::DefectModePanel(ModePanelFrame* _mpf) : ModePanel(_mpf) { this->SetForegroundColour(*wxWHITE); mpf = _mpf; //wxBoxSizer *outer = new wxBoxSizer(wxVERTICAL); defNote = new notebookPropagator(this); Connect(defNote->GetId(), wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxCommandEventHandler(DefectModePanel::onNotebookChanged)); defNote->SetOwnBackgroundColour(mpf->GetParent()->GetBackgroundColour()); tpw = new TubePicWindow(defNote, wxID_ANY, wxPoint(0, 0), wxDefaultSize); defNote->AddPage(tpw, _("Rohrbild"), true); wxBoxSizer *auxPlotterSizer = new wxBoxSizer(wxVERTICAL); wxPanel *auxPanel = new wxPanel(defNote); auxPanel->SetSizer(auxPlotterSizer); defNote->AddPage(auxPanel, _("Hilfsplotter"), false); //--- Auxplotter --- setAuxPlotter(new PlotterXY(auxPanel, mpf, false)); getAuxPlotter()->SetSize(100, 100); // quadratische Grundform festlegen auxPlotterSizer->Add(getAuxPlotter(), 1, wxSHAPED | wxALIGN_BOTTOM | wxALL, 8); //--- Endbewertungsanzeige --- wxBoxSizer *totalDefectSizer = new wxBoxSizer(wxHORIZONTAL); wxStaticText* endbew = new wxStaticText(this, wxID_ANY, _("Endbewertung: ")); endbew->SetFont(wxFont(25, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); totalDefectSizer->Add(endbew, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); wxStaticText *_totalDefectLabel = new wxStaticText(this, wxID_ANY, _("-")); _totalDefectLabel->SetFont(wxFont(30, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); setTotalDefectLabel(_totalDefectLabel); totalDefectSizer->Add(_totalDefectLabel, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT); //outer->Add(auxNote, 1, wxEXPAND); if(mpf->getNotebookPageSelected() != -1) defNote->SetSelection(mpf->getNotebookPageSelected()); //--- Befundtabelle --- defList = new FormScrollListDefects(this, _("Befundliste"), *wxWHITE); wxStaticText *_quickInputLabel = new wxStaticText(this, wxID_ANY, _("Schnelleingabe:")); quickDefectInput = new textCtrlPropagator(this); //--- Sizer "Hierarchie" --- wxStaticBox *defectBox = new wxStaticBox(this, -1, _("")); wxSizer *topSizer = new wxBoxSizer(wxVERTICAL); wxStaticBoxSizer *boxed = new wxStaticBoxSizer(defectBox, wxVERTICAL); wxBoxSizer *insideBox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *defListContainer = new wxBoxSizer(wxVERTICAL); topSizer->Add(boxed, 1, wxEXPAND); boxed->Add(insideBox, 1, wxEXPAND); insideBox->Add(defNote, 1, wxEXPAND); insideBox->Add(defListContainer, 0, wxEXPAND); boxed->Add(totalDefectSizer, 0, wxALIGN_CENTER); defListContainer->Add(defList, 1, wxALIGN_CENTER | wxEXPAND | wxRIGHT | wxTOP, 5); defListContainer->Add(_quickInputLabel, 0, wxTOP | wxLEFT, 5); defListContainer->Add(quickDefectInput, 0, wxEXPAND | wxRIGHT | wxTOP, 5); SetSizer(topSizer); topSizer->SetSizeHints(this); setTimer(new wxTimer(this, ID_TIMER)); //SystemState::getInstance()->setActiveBuffer(SystemState::getInstance()->getContBuffer()); //--- Eventhandler setzen --- //keyHookManager = new KeyHookManager(this); //keyHookManager->hook(this); //getCodeInput()->SetFocus(); //SystemState::getInstance()->getMainFrame()->SendSizeEvent(); updateTotalDefect(); SystemState *ss = SystemState::getInstance(); ss->getIndexCursor()->setChoordsChangedByHand(false); ss->addObserver(this); defList->addObserver(this); ss->getOthersConfig()->addObserver(this); ss->getMainFrame()->addObserver(this); ss->getIndexCursor()->addObserver(this); ss->getIndexCursor()->getCurrentTube()->getDefectList()->addObserver(this); this->Show(); Layout(); /*wxWindow * test = FindFocus(); int test1 = 0;*/ } DefectModePanel::~DefectModePanel() { SystemState *ss = SystemState::getInstance(); //wxWindow * test = FindFocus(); //OutputDebugString("-------------------------- jetzt löschen der observer\n"); ss->deleteObserver(this); defList->deleteObserver(this); ss->getOthersConfig()->deleteObserver(this); ss->getMainFrame()->deleteObserver(this); ss->getIndexCursor()->deleteObserver(this); ss->getIndexCursor()->getCurrentTube()->getDefectList()->deleteObserver(this); //OutputDebugString("-------------------------- jetzt keyhook\n"); //delete keyHookManager; delete getTimer(); //OutputDebugString("-------------------------- ~defectModPan() ende\n"); } void DefectModePanel::onNotebookChanged(wxCommandEvent &evt){ wxNotebook *nb = (wxNotebook*) evt.GetEventObject(); setTpwVisible(nb->GetPageText(nb->GetSelection()) == _("Rohrbild")); } void DefectModePanel::onQuickInputEnter(wxKeyEvent &event) { if(event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER){ wxString str = getQuickDefectInput()->GetValue(); str.Trim(); // vor buchstabe zahlen 0-100 optional ok wxString reText = _("^(100|[0-9]{1,2})?(["); // gültige buchstabe in groß- und kleinschreibung wxArrayString allowed = SystemState::getInstance()->validDefCodes; for(unsigned int i = 0; i < allowed.GetCount(); i++){ reText += allowed.Item(i); reText += allowed.Item(i).MakeLower(); } // nach buchstabe beliebig große zahlen optional ok // größe wird später mit der rohrlänge abgeglichen reText += _("]{1})([0-9]*)$"); wxRegEx reQuickInput = reText; // falls eingabe gültig in neuen befund umwandeln if(reQuickInput.Matches(str)){ TDefectCode code; // werte extrahieren int depth = wxAtoi(reQuickInput.GetMatch(str, 1)); wxString codeStr = reQuickInput.GetMatch(str, 2).MakeUpper(); int pos = wxAtoi(reQuickInput.GetMatch(str, 3)); // ------------- tiefe ------------------- // nur i und a speichern tiefe if(codeStr != _("I") && codeStr != _("A")) depth = 0; // aus i oder a ohne tiefe wird 1I bzw. 1A if(depth == 0 && (codeStr == _("A") || codeStr == _("I"))) depth = 10; // ------------- code ------------------- if(codeStr != _("I") && codeStr != _("A")) code = stringToDefectCode(codeStr); else code = stringToDefectCode(wxString::Format(_("%d"), DefectRecord::getDepthRoundedTenths(depth)) + codeStr); // ------------- position ------------------- // p, x und s speichern keine position if(codeStr == _("P") || codeStr == _("X") || codeStr == _("S")) pos = 0; // neuen DefectRecord in DefectList DefectRecord dr = DefectRecord(depth, code, pos); SystemState::getInstance()->getIndexCursor()->getCurrentTube()->getDefectList()->add(dr); defList->addRow(4, pos, code, depth, 0); // quickInput leeren getQuickDefectInput()->Clear(); getQuickDefectInput()->SetFocus(); } } event.Skip(); } void DefectModePanel::updateTotalDefect() { TDefectCode code = SystemState::getInstance()->getIndexCursor()->getCurrentTube()->getDefectList()->findTotalDefect(); if(code == DC_NONE) code = DC_P; getTotalDefectLabel()->SetLabel(defectCodeToString(code)); } void DefectModePanel::onTimer(wxTimerEvent &event) { int tmpStop = playStart + (150 * SystemState::getInstance()->getPlotterConfig()->getReplaySpeed()); if(tmpStop > playStop) tmpStop = playStop; getAuxPlotter()->doStep(playStart, tmpStop); mpf->getMainPlotter()->doStep(playStart, tmpStop); playStart = tmpStop; if(playStart == playStop){ getTimer()->Stop(); mpf->getPlayButton()->Enable(true); } } void DefectModePanel::replaySignal() { XytPanel* xytp = (XytPanel*) mpf->getXytPanel(); playStart = xytp->getPlayStartSmpl(); playStop = xytp->getPlayStopSmpl(); clearPlotters(); mpf->getPlayButton()->Enable(false); mpf->getPauseButton()->Enable(true); getTimer()->Start(1); } void DefectModePanel::clearPlotters() { mpf->getMainPlotter()->doClear(); getAuxPlotter()->doClear(); } void DefectModePanel::update(EventObject *eo) { DefectList *list = SystemState::getInstance()->getIndexCursor()->getCurrentTube()->getDefectList(); switch(eo->getEventId()) { case EI_SYS_PREP_TUBE_CHANGE: case EI_MF_COMMIT_CHANGES: //list->sort(); //ic->getCurrentTube()->getDefectList()->copyFrom(this->getDefectList()); break; //case EI_SYS_BUNDLE_TUBE_CHANGED: case EI_SYS_TUBE_CHANGED: //setDefectList(ic->isSingleTubeSelected() || ic->getBundleTube() == NULL ? new DefectList() : new DefectList(ic->getBundleTube()->getDefectList())); list->addObserver(this); this->getAuxPlotter()->doClear(); mpf->getXytPanel()->doClear(); updateTotalDefect(); break; case EI_DEFECTLIST_CHANGED: // vorerst keinen Eintrag auswählen! Andernfalls wird kein Auswahl-Event // mehr generiert, wenn in der neuen Liste der gleiche Eintrag vorgewählt // wird, wie in der aktuellen bzw. alten Version //getDefectPanel()->setSelectedDefect(-1); updateTotalDefect(); Layout(); break; case EI_OC_CONFIG_CHANGED: Layout(); break; } }
wie im ersten post beschrieben passiert der crash wenn überhaupt nur, wenn die wxTextCtrl namen quickDefectInput beim schließen des panel den focus hat.
was meinst du mit "debugger im vs anwerfen"? mit f5 das "debugging starten" hat die oben geposteten fehlermeldungen generiert.
ich würde sehr gerne lernen, wie ich diese fehlermeldung selber debugge, deswegen auch die frage in einem vorherigen post nach einem tutorial. nur weiß ich leider gar nicht, wo ich da ansetzen soll, weil die fehlermeldungen sich nicht auf meinen code beziehen. wie im ersten post zu sehen ist, stehen in der aufrufliste ausschließlich wx funktionen oder user32.dll. das programm bricht mit verweis auf IMPLEMENT_APP(App) ab, liefert also auch keine infos, oder?ich habe auch schon versucht, den fehler in einem minimalen testprogramm zu isolieren, dort trat er aber leider nicht auf.
könnt ihr mir vielleicht irgendeinen ansatzpunkt sagen, wie ich im debugging weiter komme? ich drehe mich hier im kreis und bin schon seit tagen erfolglos dabei, irgendwelche infos im netz zu suchen.
vielen dank!!!
-
Es ist schwer Dir bei einem Projekt einer solchen Größe zu helfen wie Du es andeutest.
Die obigen Meldungen bringt Dir der Debugger zwar, aber das hilft nicht auf einem fremden Rechner. Das ist nur der Callstack. Der hilft uns nicht weiter, wenn wir den Code nicht kennen :). Du musst mit dem Debugger dein Programm analysieren und herausfinden wodurch die Zugriffsverletzung ausgelöst wird. Wie man ihn benutzt?
Ja, das ist schwer zu erklären. Wichtig wären zum einen Breakpoints, die dein Programm stoppen in dem Moment wo Du es beendest. Am besten direkt am Deconstrutor der geposteten Klasse. Und dann Schrittweise durchgehen. Findet der Crash vorher statt, dann könnte es in wxWidgets passieren und wir reden von einem wxWidgets Bug.
Zudem gefällt mirdelete getTimer();
nicht. Ich weiss nicht wie der Standard hier definiert ist, ob das funktioniert, aber mir gefällts nicht. Losch die Variable direkt die von getTimer() zurückgegeben wird. Und das nächste mal bitte nicht [ code ] sondern [ cpp ]verwenden danke :D.
Wenn Dein Programm nur wxWidgets als Abhängigkeit hat, könnte ich Dir eventuell beim Debuggen helfen.. weiss ja nicht ob das Programm weitergabefähig ist.
Ist es vllt OpenSource? Kann man es sich irgendwo vom SVN ziehen?Die beste Lösung:
Versuche ein minimales Sample zusammenzustellen, in dem Du NUR das Interface genauso nachbaust wie der Crash auftritt. Sprich das Panel mit deinen Controls etc Funktioniert das, weisst Du dass es nicht an wxWidgets liegt. So würde ich es angehen wenn ich es partout nicht finden würde.
Bei Youtube hab ich übrigens einige Videos zu Visual Studio gefunden.
http://www.youtube.com/watch?v=kr4TkcNTdHQ
rya.
-
vielen dank für deine ausführliche antwort!
die grundlegenden debugger funktionen wie z.b. breakpoints, die in dem youtube video erklärt werden, sind mir gut vertraut. bisher (die letzten 1,5 jahre vollzeit programmieren) konnte ich auch alle fehler damit finden. falls du dich fragst "wie konnte der typ 1,5 jahre ohne fundiertes debugging wissen vollzeit programmieren?!": ich bin einziger programmierer in einer kleinen firma, die firmenintern diese software benutzt.
leider hat mein programm nicht nur wxWidgets als abhängigkeit, sondern auch noch eine umfangreiche national instruments bibliothek mit einem simulierten hardware gerät. das ist sehr aufwändig einzurichten. aber vielen dank für dein angebot!wie man am call stack im ersten post sehen kann, sind leider keine meiner programmzeilen zum zeitpunkt des crashs noch direkt aktiv. wenn ich einen breakpoint setze und mit F10 immer einen schritt weiter gehe, dann ende ich nach sehr viel klicken an einer stelle, an der der code nicht angezeigt werden kann.
das
delete getTimer()
löscht den im konstruktor erzeugten
setTimer(new wxTimer(this, ID_TIMER));
es macht hier keinen unterschied, ob ich timer direkt lösche, oder das über getTimer() mache.
das mit dem minimalen sample habe ich schon versucht, nur leider trat der fehler nicht auf. ich starte nochmal einen neuen versuch, der hoffentlich noch näher an das problem im original programm ran kommt.
ich poste dann das ergebnis.danke!!
-
Nimm das mal raus, könnte sein das wxWidgets den Timer schon selber löscht.
-
@phlox81: danke für die idee, das habe ich schon getestet, der timer wird nicht automatisch gelöscht.
ich bin durch ein minimales projekt schon näher an der lösung, der crash scheint mit events zu tun zu haben. zumindest bekomme ich im minimalen projekt eine extrem ähnliche aufrufliste bei crash an derselben stelle. ein hinweis darauf scheint auch wxEventLoop in der aufrufliste in meinem ersten post zu sein.
ich melde mich, sobald ich mehr infos habe oder das problem gelöst ist.danke!
-
ich komme nicht mehr weiter.
hier ist ein minimales projekt, in dem zunächst das austauschen der panels funktioniert:
noname.h
#ifndef __noname__ #define __noname__ /////////////////////////////////////////////////////////////////////////// class textCtrlPropagator; class MyFrame1 : public wxFrame { private: DECLARE_EVENT_TABLE() wxBoxSizer *changeContainer; wxPanel *shownPanel; protected: void onButtonClick(wxCommandEvent &event); public: MyFrame1( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,300 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); void changePanel(bool toMyPanel3); void onMyKeyDown(wxKeyEvent &event); }; ///////////////////////////// class textCtrlPropagator : public wxTextCtrl { public: textCtrlPropagator(wxWindow *parent) : wxTextCtrl(parent, wxID_ANY){ Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(textCtrlPropagator::OnKeyDown)); levelsFromMyFrame1 = 1; while(dynamic_cast<MyFrame1*>(parent) == NULL){ parent = parent->GetParent(); levelsFromMyFrame1++; } } protected: int levelsFromMyFrame1; private: void OnKeyDown(wxKeyEvent& event){ event.ResumePropagation(levelsFromMyFrame1); event.Skip(); } }; ///////////////////////////////////////// class MyPanel2 : public wxPanel { public: MyPanel2::MyPanel2(wxWindow* par) : wxPanel(par) { wxTextCtrl *quickDefectInput = new textCtrlPropagator(this); quickDefectInput->SetFocus(); } }; /////////////////////////////////////////////////////////////////////////////// class MyPanel1 : public wxPanel { private: MyFrame1 *par; protected: wxStaticText* m_staticText1; public: MyPanel1( MyFrame1* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,300 ), long style = wxTAB_TRAVERSAL ) : wxPanel( parent, id, pos, size, style ) { this->SetSizer( new wxBoxSizer( wxVERTICAL ) ); Layout(); }; ~MyPanel1(){}; }; ///////////////////////////////////////////////////// class App : public wxApp { bool OnInit() { // Hauptfenster initialisieren wxFrame *mainFrame = new MyFrame1(NULL); mainFrame->Show(); SetTopWindow(mainFrame); return TRUE; } }; IMPLEMENT_APP(App) #endif //__noname__
noname.cpp:
#include "noname.h" void MyFrame1::onMyKeyDown(wxKeyEvent &event){ if(event.GetKeyCode() == WXK_ESCAPE){ changePanel(dynamic_cast<MyPanel2*>(shownPanel) != NULL); Refresh(); } //event.StopPropagation(); //event.Skip(); } void MyFrame1::changePanel(bool toMyPanel1){ wxPanel *newPanel; if(toMyPanel1) newPanel = new MyPanel1(this); else newPanel = new MyPanel2(this); changeContainer->Replace(shownPanel, newPanel, true); changeContainer->Layout(); delete shownPanel; shownPanel = newPanel; } MyFrame1::MyFrame1( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, wxFULL_REPAINT_ON_RESIZE | wxDEFAULT_FRAME_STYLE ) { changeContainer = new wxBoxSizer(wxVERTICAL); shownPanel = new MyPanel2(this); changeContainer->Add(shownPanel); wxStaticText *m_staticText1 = new wxStaticText( this, wxID_ANY, wxT("press esc"), wxDefaultPosition, wxDefaultSize, 0 ); changeContainer->Add(m_staticText1); SetSizer(changeContainer); } BEGIN_EVENT_TABLE(MyFrame1, wxFrame) EVT_KEY_DOWN(MyFrame1::onMyKeyDown) END_EVENT_TABLE()
entfernt man nun den kommentar in der cpp in zeile 9 von event.skip(), so kommt eine fehlermeldung, die der in meinem programm sehr nahe kommt (siehe erstes posting).
hat jemand eine idee, wie ich hier weiter komme?!?! hat es eventuell mit dem resumePropagation() in textCtrlPropagator::OnKeyDown zu tun? ich hielt das bisher für notwendig, damit das event bis zu MyFrame1 durch kommt.
maximalsten dank!
-
dazu sollte ich vielleicht noch erwähnen, dass die offensichtliche maßnahme, einfach auf event.skip() zu verzichten, in meinem programm nicht greift. dort ist gar kein event.skip in der fraglichen funktion enthalten.
was könnte dieses problem, das im minimalen test durch event.skip() ausgelöst wird, noch auslösen?
die frage ist natürlich auch, ob es wirklich derselbe fehler wie im ersten post ist, oder nur ein sehr ähnlicher..... seufz....
-
ok, das problem scheint gelöst.
falsch war, dass das panel mit dem wxTextCtrl per key down sein eigenes löschen getriggert hat. wenn ich im minimaltest in changePanel statt delete shownpanel einfach shownpanel->hide() einsetze, dann läuft alles.weiß vielleicht jemand, warum das bei wxTextCtrl der fall ist? das löschen war von anderen controls aus nie ein problem, auch wenn die auslösenden controls selber dabei gelöscht wurden. kann ich mir das so erklären, dass das event, wenn es von einem wxTextCtrl ausgelöst wurde, nochmal zum wxTextCtrl zurück muss?!?
danke für eure mühe.