-1

我是一个爱好程序员,仍在学习 C++ 和 wxWidgets。我在 Windows 10 Pro 计算机上使用 Code::Blocks 20.3、wxWidgets 3.1.4 和 MinGW 17.1。

我正在尝试使虚拟 wxListCtrl 在 Code::Blocks 中工作,我遵循了 ListCtrl 示例中的代码和 wxWidgets 论坛中的一个简单示例。编译和工作的示例(1 个文件)代码。当我在 Code::Blocks 中开始一个新项目时,GUI APP 和 MAIN 被编码在单独的文件中。也许我需要做更多,但找不到它是什么。该项目以零错误和警告编译,但在启动时显示以下错误。我尝试将 SetItemCount() 移到 AppendCollumn() 上方,但这没有帮助。当我将 AppendColumn() 都注释掉时没有错误,但是列表当然是空的。

有人可以帮我解决我的代码中缺少的内容吗?

谢谢你,路德

错误:

A debugging check in this application has failed
../../src/cpmmon.listctrlcmn.cpp(259):
 assert "Assert Failure" failed in OnGetItemText():
 wxListCtrl::OnGetItemText not supposed to be called

图形用户界面代码:

GUIFrame::GUIFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
    this->SetSizeHints( wxDefaultSize, wxDefaultSize );

    wxBoxSizer* bSizer1;
    bSizer1 = new wxBoxSizer( wxVERTICAL );

    m_listCtrl1 = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_VIRTUAL );
    bSizer1->Add( m_listCtrl1, 1, wxALL|wxEXPAND, 10 );

    this->SetSizer( bSizer1 );
    this->Layout();

    // Connect Events
    this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
}

GUIFrame::~GUIFrame()
{
    // Disconnect Events
    this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
}

主要代码:

#include "VlistMain.h"

const wxChar *SMALL_VIRTUAL_VIEW_ITEMS[][2] =
{
    { wxT("Cat"), wxT("meow") },
    { wxT("Sheep"), wxT("baaah") }
};

VlistFrame::VlistFrame(wxFrame *frame) : GUIFrame(frame)
{
    m_listCtrl1->AppendColumn("Animal");
    m_listCtrl1->AppendColumn("Sound");
    m_listCtrl1->SetItemCount(WXSIZEOF(SMALL_VIRTUAL_VIEW_ITEMS));
}

wxString VlistFrame::OnGetItemText(long item, long column) const
{
    return SMALL_VIRTUAL_VIEW_ITEMS[item][column];
}

事件表:

wxBEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl)
    EVT_LIST_ITEM_SELECTED(wxAny, MyListCtrl::OnSelected)
wxEND_EVENT_TABLE()
4

2 回答 2

1

要使用虚拟列表控件,您需要从 wxListCtrl 派生一个类并覆盖 OnGetItemText 方法。例如:

class MyListCtrl:public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent, wxWindowID id);
    virtual wxString OnGetItemText (long item, long column) const wxOVERRIDE;
};

MyListCtrl::MyListCtrl(wxWindow *parent, wxWindowID id)
           :wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
                       wxLC_VIRTUAL | wxLC_REPORT, wxDefaultValidator,
                       "MyListCtrl")
{

}

wxString MyListCtrl::OnGetItemText(long item, long column) const
{
    return SMALL_VIRTUAL_VIEW_ITEMS[item][column];
}

您还可以覆盖OnGetItemColumnImageOnGetItemAttr以进一步自定义您的控件。


由于看起来您正在使用 wxFormbuilder,因此您可以使用自定义控件小部件来执行此操作。为此,首先您需要在项目中添加一个名为 MyListCtrl.h 的新头文件(或任何您想调用的名称)。新标头的内容应如下所示:

#ifndef MYLISTCTRL_H_INCLUDED
#define MYLISTCTRL_H_INCLUDED

#include <wx/listctrl.h>

class MyListCtrl:public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent, wxWindowID id);
    virtual wxString OnGetItemText (long item, long column) const wxOVERRIDE;
};

#endif // MYLISTCTRL_H_INCLUDED

一旦有了控件的标题,就可以使用“CustomControl”小部件。它是“附加”选项卡上的倒数第二项:

在此处输入图像描述

在属性选项卡上,您需要设置以下项目

name:          m_listCtrl1
declaration:   MyListCtrl* m_listCtrl1;
construction:  m_listCtrl1 = new MyListCtrl(m_panel1, wxID_ANY);
include:       #include "MyListCtrl.h"

像这样:

在此处输入图像描述

您可以为MyListCtrl::MyListCtrl构造函数提供代码,并MyListCtrl::OnGetItemText在与您的框架类相同的文件中。或者如果你想为每个文件维护一个类,你也可以把它放在一个新的 cpp 文件中。显然,您需要在用于将这些方法的代码放入其中的任何文件的顶部添加“#include”MyListCtrl.h”。


要使用事件表处理事件,您需要将事件处理方法的声明和wxDECLARE_EVENT_TABLE宏添加到类声明中。

class MyListCtrl:public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent, wxWindowID id);
    virtual wxString OnGetItemText (long item, long column) const wxOVERRIDE;

protected:
    void OnItemSelected(wxListEvent& event);
    // Add all other event handler method declarations here
private:
    wxDECLARE_EVENT_TABLE();
};

然后在包含代码的文件中,您将拥有如下内容:

wxBEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl)
    EVT_LIST_ITEM_SELECTED(wxID_ANY, MyListCtrl::OnItemSelected)
    /* Add all other event macros here */
wxEND_EVENT_TABLE()


void MyListCtrl::OnItemSelected(wxListEvent& event)
{
    // do something here
}

// write all other event handlers here.

就个人而言,我真的不喜欢事件表,所以我会改用动态事件绑定。为此,该类的声明应如下所示:

class MyListCtrl:public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent, wxWindowID id);
    virtual wxString OnGetItemText (long item, long column) const wxOVERRIDE;

protected:
    void OnItemSelected(wxListEvent& event);
    // declare all other event handlers here.
};

那么构造函数的代码应该是这样的:

MyListCtrl::MyListCtrl(wxWindow *parent, wxWindowID id)
           :wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
                       wxLC_VIRTUAL | wxLC_REPORT, wxDefaultValidator,
                       "MyListCtrl")
{
    Bind(wxEVT_LIST_ITEM_SELECTED, &MyListCtrl::OnItemSelected, this);
    // Add any other needed Bind statements here
}
于 2020-09-12T15:54:17.227 回答
0

这是使用 wxFormbuilder 的子类功能的第二个答案。这种方法的优点是它可以让您使用 wxFormbuilder 设置事件处理程序。首先,我们需要为派生类的构造函数声明一个稍微不同的声明

class MyListCtrl:public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent,
               wxWindowID id,
               const wxPoint& pos = wxDefaultPosition,
               const wxSize& size = wxDefaultSize,
               long style = wxLC_VIRTUAL | wxLC_REPORT);
    virtual wxString OnGetItemText(long item, long column) const wxOVERRIDE;
};

这为构造函数添加了更多参数,以便它与 wxFormbuilder 生成的代码兼容。与其他答案一样,这应该放在添加到项目中的新头文件中。

接下来在代码文件中,为构造函数添加主体

MyListCtrl::MyListCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos,
                       const wxSize& size, long style)
           :wxListCtrl(parent, id, pos, size,
                       wxLC_VIRTUAL | wxLC_REPORT, wxDefaultValidator,
                       "MyListCtrl")
{

}

请注意,这会强制子类具有样式wxLC_VIRTUAL | wxLC_REPORT,并将忽略在 wxFormbuilder 中输入的任何样式。所以如果你想改变样式,你应该在上面的代码中改变它。

或者,您可以更改wxLC_VIRTUAL | wxLC_REPORTstyle. 然后将使用在 wxFormbuilder 中输入的样式选项。但是,您需要确保这些选项始终包含 wxLC_REPORT 和 wxLC_VIRTUAL,并且不包含与这两个选项不兼容的任何其他选项。

接下来,在 wxFormbuilder 中,向表单添加一个列表控件,然后在对象属性选项卡上,将子类选项设置为

name: MyListCtrl
header: MyLstCtrl.h

在此处输入图像描述

(您可以选中或取消选中 forward_declare 选项 - 它没有任何区别)。

现在您可以为列表控件添加任何事件处理程序,就像添加任何其他小部件一样:

在此处输入图像描述

于 2020-09-13T18:53:23.213 回答