wxTimer 不调用重写的 Notify()
wxTimer not calling overriden Notify()
我 运行 遇到一个问题,我实现了派生的 wxTimer class 来覆盖 Notify() 调用,因为我没有使用 [=] 中描述的所有者实现13=]。
当我调试 运行 时,我可以看到
- 正在实例化定时器
- my_timer_instance->IsRunning() returns 真
- MyTimer::Notify() 从未被调用
这让我相信计时器正在设置并且 运行ning,但是当它到期时 它正在调用基础 class Notify() 过程而不是我的覆盖 它没有调用 notify() 但我不确定为什么。
编辑: 我将 frame->getTimer()->Notify();
添加到我的应用程序中并调用了 correct 程序。因此,计时器在到期时不会调用 Notify。
EDIT2: 添加了这个最小的工作示例,计时器按预期工作。我将尝试比较两者,看看问题出在哪里。
MyApp.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__
MyApp.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;
}
@BobbyTables,
来自文档:
This member should be overridden by the user if the default
constructor was used and SetOwner() wasn't called.
是这样吗?
您显示的代码似乎没有任何问题(尽管我会更改一些内容,例如 my_timer_instance
使用原始指针),所以问题一定出在其他地方。像往常一样,最好是想出一个 SSCCE,没有它我只能提供一些关于实际问题的猜测。
你是运行事件循环吗?计时器只会在 运行 时触发,因此如果您阻止进行某些计算,则不会发生这种情况。
另外,Notify()
中的frame
是什么?这是全局的吗(我宁愿将它作为参数传递给 MyTimer
ctor)?
所以模仿题中提供的代码后,做了如下改动:
我没有使用 getter 和 setter 来访问私人计时器成员,而是使用
void refreshTimer(int time_in_seconds)
在我的父框架 class 中,并在父框架的构造函数中创建计时器,而不是让应用创建它并将其传入。
我不明白为什么这两件事中的任何一个都会改变计时器的行为,但计时器现在按预期工作。对于无法确定具体错误是问题的根源,我深表歉意。
注意:此行为是由在 wxwindow 线程外部调用计时器引起的。使用 wxwidgets 作为 GUI 创建多线程程序时要小心。为了避免这个问题,因为我需要在不同的线程中调用计时器,我创建了自己的计时器 class,它可以正常工作。
我 运行 遇到一个问题,我实现了派生的 wxTimer class 来覆盖 Notify() 调用,因为我没有使用 [=] 中描述的所有者实现13=]。
当我调试 运行 时,我可以看到
- 正在实例化定时器
- my_timer_instance->IsRunning() returns 真
- MyTimer::Notify() 从未被调用
这让我相信计时器正在设置并且 运行ning,但是当它到期时 它正在调用基础 class Notify() 过程而不是我的覆盖 它没有调用 notify() 但我不确定为什么。
编辑: 我将 frame->getTimer()->Notify();
添加到我的应用程序中并调用了 correct 程序。因此,计时器在到期时不会调用 Notify。
EDIT2: 添加了这个最小的工作示例,计时器按预期工作。我将尝试比较两者,看看问题出在哪里。
MyApp.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__
MyApp.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;
}
@BobbyTables,
来自文档:
This member should be overridden by the user if the default constructor was used and SetOwner() wasn't called.
是这样吗?
您显示的代码似乎没有任何问题(尽管我会更改一些内容,例如 my_timer_instance
使用原始指针),所以问题一定出在其他地方。像往常一样,最好是想出一个 SSCCE,没有它我只能提供一些关于实际问题的猜测。
你是运行事件循环吗?计时器只会在 运行 时触发,因此如果您阻止进行某些计算,则不会发生这种情况。
另外,Notify()
中的frame
是什么?这是全局的吗(我宁愿将它作为参数传递给 MyTimer
ctor)?
所以模仿题中提供的代码后,做了如下改动:
我没有使用 getter 和 setter 来访问私人计时器成员,而是使用
void refreshTimer(int time_in_seconds)
在我的父框架 class 中,并在父框架的构造函数中创建计时器,而不是让应用创建它并将其传入。
我不明白为什么这两件事中的任何一个都会改变计时器的行为,但计时器现在按预期工作。对于无法确定具体错误是问题的根源,我深表歉意。
注意:此行为是由在 wxwindow 线程外部调用计时器引起的。使用 wxwidgets 作为 GUI 创建多线程程序时要小心。为了避免这个问题,因为我需要在不同的线程中调用计时器,我创建了自己的计时器 class,它可以正常工作。