2 votes

wxTimer n'appelle pas la fonction Notify() qui est surchargée

Je rencontre un problème où j'ai implémenté une classe wxTimer dérivée pour surcharger l'appel Notify() puisque je n'utilise pas une implémentation propriétaire telle que décrite dans le document la documentation .

Lorsque je débogue l'exécution, je vois

  • la minuterie est en cours d'instanciation
  • my_timer_instance->IsRunning() retourne true
  • MyTimer::Notify() n'est jamais appelé

Cela m'amène à penser que la minuterie est activée et fonctionne, mais qu'à l'expiration de la minuterie il appelle la procédure Notify() de la classe de base et non ma surcharge il n'appelle pas notify() mais je ne sais pas trop pourquoi.

EDIT : J'ai ajouté frame->getTimer()->Notify(); à mon application et le correctes a été appelée. Par conséquent, la minuterie n'appelle tout simplement pas Notify lorsqu'elle expire.

EDIT2 : J'ai ajouté cet exemple de travail minimal, et la minuterie fonctionne comme prévu. Je vais essayer de comparer les deux et voir quel est le problème.

MonApp.hpp

#pragma once

#ifndef __NONAME_H__
#define __NONAME_H__

#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/statusbr.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/frame.h>
#include <wx/timer.h>
///////////////////////////////////////////////////////////////////////////

class MyTimerClass : public wxTimer
{
    wxFrame* MyFrame;
public:
    MyTimerClass(wxFrame* frame): MyFrame(frame) {};

    void Notify() override;
};
///////////////////////////////////////////////////////////////////////////////
/// Class MyFrame1
///////////////////////////////////////////////////////////////////////////////
class MyFrame1 : public wxFrame
{
private:

protected:
    wxStatusBar* m_statusBar1;
    MyTimerClass* MyTimer;
public:
    void StartTimer(int TimeInSeconds);
    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);

    ~MyFrame1();

};

#endif //__NONAME_H__

MonApp.cpp

#include "MyApp.hpp"
#include "wx/wxprec.h"
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

///////////////////////////////////////////////////////////////////////////
void MyTimerClass::Notify()
{
    MyFrame->SetStatusText("Timer popped", 0);
}
MyFrame1::MyFrame1(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
{
    MyTimer = new MyTimerClass(this);
    this->SetSizeHints(wxDefaultSize, wxDefaultSize);

    m_statusBar1 = this->CreateStatusBar(1, wxSTB_SIZEGRIP, wxID_ANY);

    this->Centre(wxBOTH);

    this->StartTimer(5);
}
void MyFrame1::StartTimer(int TimeInSeconds)
{
    SetStatusText("Timer started with " + std::to_string(TimeInSeconds) + " seconds.");
    MyTimer->Start(TimeInSeconds * 1000);
}
MyFrame1::~MyFrame1()
{
}

// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------

// the application icon (under Windows it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
#include "../sample.xpm"
#endif

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

class MyApp : public wxApp
{
public:
    virtual bool OnInit() wxOVERRIDE;
};

enum
{
    // menu items
    Minimal_Quit = wxID_EXIT,
    Minimal_About = wxID_ABOUT
};

wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit()
{
    // call the base class initialization method, currently it only parses a
    // few common command-line options but it could be do more in the future
    if (!wxApp::OnInit())
        return false;

    // create the main application window
    MyFrame1 *frame = new MyFrame1(NULL, -1, "Test Frame");
    frame->Show(true);

    return true;
}

2voto

Igor Points 1671

@BobbyTables,

Extrait de la documentation :

Ce membre doit être remplacé par l'utilisateur. a été utilisé et que SetOwner() n'a pas été appelé.

Est-ce le cas ?

1voto

hleinone Points 480

Il n'y a rien d'anormal dans le code que vous montrez (même si je changerais quelques éléments, comme l'utilisation d'un pointeur brut pour le code my_timer_instance ), le problème doit donc être ailleurs. Comme d'habitude, le mieux serait de trouver un SSCCE Sans cela, je ne peux qu'émettre des hypothèses sur la nature du problème.

La boucle d'événements est-elle en cours d'exécution ? Les minuteries ne se déclenchent que lorsqu'elles sont en cours d'exécution, donc si vous bloquez l'exécution d'un calcul, cela ne se produira pas.

De même, qu'est-ce que frame en Notify() ? S'agit-il d'un paramètre global (je préférerais le passer en paramètre à MyTimer ctor) ?

0voto

Bobby Tables Points 90

Ainsi, après avoir imité le code fourni dans la question, les modifications suivantes ont été apportées :

~~

Au lieu d'utiliser un getter et un setter pour accéder au membre timer privé, j'utilise plutôt
void refreshTimer(int time_in_seconds) dans ma classe de cadre parent et créer le timer dans le constructeur du cadre parent plutôt que de laisser l'application le créer et le transmettre.

~~

Je ne vois pas pourquoi l'une ou l'autre de ces deux choses changerait le comportement de la minuterie, mais la minuterie fonctionne maintenant comme prévu. Je m'excuse de ne pas avoir pu identifier un bogue concret comme source du problème.

NOTE : Ce comportement est dû à l'invocation de la minuterie à l'extérieur le fil de la fenêtre wxwindow. Soyez prudent lorsque vous créez des programmes multithreads utilisant les wxwidgets comme interface graphique. Pour contourner ce problème, puisque j'avais besoin que la minuterie soit invoquée dans un autre thread, j'ai créé ma propre classe de minuterie qui fonctionne correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X