Search code examples
c++wxwidgets

wxWidgets - Adding data to DataViewListCtrl


I'm trying to make a application for managing audio sample library using wxWidgets, I have a DirCtrl on left and a DataViewListCtrl on right, when user navigates to a folder and double clicks on a file it should extract its tags and audio properties using taglib and add them to specific columns. I'm having some trouble figuring out how do I add the data to the DataViewListCtrl I did something similar in python recently, and python used a 2D list, to add data to it.

The application looks like this (this is from me tying it out in python) enter image description here

And the function I have to add the data to DataViewListCtrl in C++

void Browser::OnClickDirCtrl(wxCommandEvent& event)
{
    TagLib::FileRef File (DirCtrl->GetFilePath());
    TagLib::String Artist = File.tag()->artist();
    TagLib::String Album = File.tag()->album();
    TagLib::String Genre = File.tag()->genre();
    TagLib::String Title = File.tag()->title();
    TagLib::String Comment = File.tag()->comment();
    int Bitrate = File.audioProperties()->bitrate();
    int Channels = File.audioProperties()->channels();
    int Length = File.audioProperties()->lengthInMilliseconds();
    int LengthSec = File.audioProperties()->lengthInSeconds();
    int SampleRate = File.audioProperties()->sampleRate();

    std::cout << "Artist: " << Artist << std::endl;
    std::cout << "Album: "<< Album << std::endl;
    std::cout << "Genre:" << Genre << std::endl;
    std::cout << "Title: " << Title << std::endl;
    std::cout << "Comment: " << Comment << std::endl;
    std::cout << "Bitrate: " << Bitrate << std::endl;
    std::cout << "Channels: " << Channels << std::endl;
    std::cout << "Length: " << Length << std::endl;
    std::cout << "Length in seconds: " << LengthSec << std::endl;
    std::cout << "Sample rate: " << SampleRate << std::endl;

    std::vector<DataView> Data;
//    wxVector<wxVariant> Data;
    Data.clear();
//    Data.push_back(Artist);
    Data.push_back({false, Title, Artist, Channels, Length, SampleRate, Bitrate, Comment});
}

Where DataView is a struct declared inside the same class.

        struct DataView
        {
            bool Fav;
            TagLib::String Title;
            TagLib::String Artist;
            int Channel;
            int Length;
            int SampleRate;
            int Bitrate;
            TagLib::String Comment;
        };

But I get an error when trying to build this saying

../src/Browser.cpp: In member function ‘void Browser::OnClickDirCtrl(wxCommandEvent&)’:
../src/Browser.cpp:267:32: error: cannot convert ‘std::vector<Browser::DataView>’ to ‘const wxVector<wxVariant>&’
  267 |     SampleListView->AppendItem(Data);
      |                                ^~~~
      |                                |
      |                                std::vector<Browser::DataView>

But if I try to use wxVector<wxVariant> instead, I get an error saying

../src/Browser.cpp: In member function ‘void Browser::OnClickDirCtrl(wxCommandEvent&)’:
../src/Browser.cpp:266:90: error: cannot convert ‘<brace-enclosed initializer list>’ to ‘const value_type&’ {aka ‘const wxVariant&’}
  266 |     Data.push_back({false, Title, Artist, Channels, Length, SampleRate, Bitrate, Comment});
      |                                                                                          ^

Solution

  • Based on the way you're trying to add data to the list view, I'm assuming that the columns were set up something like this:

    m_dataViewListCtrl->AppendToggleColumn("Fav");
    m_dataViewListCtrl->AppendTextColumn("Title");
    m_dataViewListCtrl->AppendTextColumn("Artist");
    m_dataViewListCtrl->AppendTextColumn("Channels");
    m_dataViewListCtrl->AppendTextColumn("Length");
    m_dataViewListCtrl->AppendTextColumn("SampleRate");
    m_dataViewListCtrl->AppendTextColumn("Bitrate");
    m_dataViewListCtrl->AppendTextColumn("Comment");
    

    Even though things like Channels and Bitrate are numbers, since wxDataViewListCtrl only offers a few types of columns, I'm guessing that text was used. I'm also using m_dataViewListCtrl for the name of the control. Be sure to change it to the name you're using.

    In order to add data to the control, you'll first need a utility function to convert TagLib strings to wxStrings.

    wxString TagLibTowx(const TagLib::String& in)
    {
        return wxString::FromUTF8(in.toCString(true));
    }
    

    Then to add data to the control, you would do something like this:

    void Browser::OnClickDirCtrl(wxCommandEvent& event)
    {
        TagLib::FileRef File (DirCtrl->GetFilePath());
        
        TagLib::String Artist = File.tag()->artist();
        TagLib::String Title = File.tag()->title();
        TagLib::String Comment = File.tag()->comment();
        int Bitrate = File.audioProperties()->bitrate();
        int Channels = File.audioProperties()->channels();
        int LengthSec = File.audioProperties()->lengthInSeconds();
        int SampleRate = File.audioProperties()->sampleRate();
    
        wxVector<wxVariant> data;
    
        data.push_back(false);
        data.push_back(TagLibTowx(Title));
        data.push_back(TagLibTowx(Artist));
        data.push_back(wxString::Format("%d",Channels));
        data.push_back(wxString::Format("%d",LengthSec));
        data.push_back(wxString::Format("%d",SampleRate));
        data.push_back(wxString::Format("%d",Bitrate));
        data.push_back(TagLibTowx(Comment));
    
        m_dataViewListCtrl->AppendItem(data);
    }
    

    If you have other columns using the other data you pulled out of the file, hopefully it's clear how to adjust this for the columns you have.

    By the way, does the line TagLib::FileRef File (DirCtrl->GetFilePath()); work for you? I had to add a cast to const char* in order to get TagLib to accept the filename.