Hello, obligatory I am a beginner/new to C++/new to JUCE message. My code probably is quite amateurish, I hope you’ll forgive me for that! I am using Windows and VS22 if that is of any relevance.
I am currently working on a uni project, part of this project is getting files from the user and adding them to a playlist (TableListBox) which they can then select from to be played.
I have the following class which is utilising the TableListBox:
PlaylistComponent::PlaylistComponent()
{
trackTitles.push_back("Wheels on the bus");
tableComponent.getHeader().addColumn("Track Title", 1, 250);
tableComponent.getHeader().addColumn("", 2, 50);
tableComponent.getHeader().addColumn("Deck", 3, 100);
tableComponent.setModel(this);
addAndMakeVisible(tableComponent);
}
PlaylistComponent::~PlaylistComponent()
{
tableComponent.setModel(nullptr); // This is important to avoid a dangling pointer
}
void PlaylistComponent::paint (juce::Graphics& g)
{
/* This demo code just fills the component's background and
draws some placeholder text to get you started.
You should replace everything in this method with your own
drawing code..
*/
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); // clear the background
g.setColour (juce::Colours::grey);
g.drawRect (getLocalBounds(), 1); // draw an outline around the component
g.setColour (juce::Colours::white);
g.setFont (14.0f);
g.drawText ("PlaylistComponent", getLocalBounds(),
juce::Justification::centred, true); // draw some placeholder text
DBG("paint");
}
void PlaylistComponent::resized()
{
tableComponent.setBounds(0,0,getWidth(), getHeight());
DBG("resized");
}
int PlaylistComponent::getNumRows()
{
return trackTitles.size();
DBG("getNumRows");
}
void PlaylistComponent::paintRowBackground(juce::Graphics& g,
int rowNumber,
int width,
int height,
bool rowIsSelected)
{
if (rowIsSelected)
{
g.fillAll(juce::Colours::orange);
}
else {
g.fillAll(juce::Colours::darkgrey);
}
DBG("PaintRowBackground");
}
void PlaylistComponent::paintCell(juce::Graphics& g,
int rowNumber,
int columnID,
int width,
int height,
bool rowIsSelected)
{
// Debug output to log the content of each cell
DBG("Painting cell: Row = " << rowNumber << ", ColumnID = " << columnID);
// Debug output to log the track title being rendered
DBG("Track title: " << trackTitles[rowNumber]);
//Populate rows with track titles
g.drawText(trackTitles[rowNumber], 2, 0, width - 4, height, juce::Justification::centredLeft, true);
DBG("paintCell");
}
juce::Component* PlaylistComponent::refreshComponentForCell(int rowNumber,
int columnID,
bool isRowSelected,
Component* existingComponentToUpdate)
{
//Add play button
if (columnID == 2)
{
if (existingComponentToUpdate == nullptr)
{
juce::TextButton* btn = new juce::TextButton("play");
juce::String id{std::to_string(rowNumber)};
btn->setComponentID(id);
btn->addListener(this);
existingComponentToUpdate = btn;
}
}
//Add deck selector
else if (columnID == 3)
{
if (existingComponentToUpdate == nullptr)
{
juce::ComboBox* deck = new juce::ComboBox;
deck->addItem("Deck 1", 1);
deck->addItem("Deck 2", 2);
juce::String id{ std::to_string(rowNumber) };
deck->setComponentID(id);
deck->addListener(this);
existingComponentToUpdate = deck;
}
}
DBG("refreshComponentForCell");
return existingComponentToUpdate;
}
void PlaylistComponent::buttonClicked(juce::Button* button)
{
//get row ID
int id = std::stoi(button->getComponentID().toStdString());
//check which deck has been selected
if (id == deckOne)
{
DBG(trackTitles[id] << " playing on Deck 1");
//loadFromPlaylist(audioFile, deckOne);
}
else if (id == deckTwo)
{
DBG(trackTitles[id] << " playing on Deck 2");
//MainComponent.loadFromPlaylist(audioFile, deckTwo);
}
else {
//pop up box?
DBG("PlaylistComponent::buttonClicked, Deck selection not recognised");
}
}
void PlaylistComponent::comboBoxChanged(juce::ComboBox* deckMenu)
{
//assign row ID to a deck
if (deckMenu->getSelectedId() == 1)
{
deckOne = std::stoi(deckMenu->getComponentID().toStdString());
}
else if (deckMenu->getSelectedId() == 2)
{
deckTwo = std::stoi(deckMenu->getComponentID().toStdString());
}
else
{
DBG("PlaylistComponent::comboBoxChanged, Deck selection not recognised");
}
}
void PlaylistComponent::loadURL()
{
auto fileChooserFlags = juce::FileBrowserComponent::canSelectFiles;
fChooser.launchAsync(fileChooserFlags, [this](const juce::FileChooser& chooser)
{
juce::File chosenFile = chooser.getResult();
addToPlaylist(juce::URL{ chosenFile });
});
}
void PlaylistComponent::addToPlaylist(juce::URL audioFile)
{
// Check if the audioFile already exists in trackList
auto it = std::find(trackList.begin(), trackList.end(), audioFile);
if (it != trackList.end()) {
// File already exists in the playlist
DBG(audioFile.getFileName().toStdString() << " already exists in the playlist");
return;
}
// Add the file to the playlist
trackList.push_back(audioFile);
DBG(audioFile.getFileName().toStdString() << " added to playlist");
bool trackExists = false;
for (const auto& trackTitle : trackTitles) {
if (trackTitle == audioFile.getFileName().toStdString()) {
// Track exists in trackTitles
trackExists = true;
break;
}
}
if (!trackExists) {
// Track does not exist in trackTitles
DBG("Track does not exist in trackTitles.");
trackTitles.push_back(audioFile.getFileName().toStdString());
//Reset the TableListBox model
auto* model = tableComponent.getModel();
tableComponent.setModel(nullptr);
tableComponent.setModel(model);
}
else {
// Track exists in trackTitles
DBG("Track does exist in trackTitles.");
}
for (std::string title : trackTitles)
{
DBG(title);
}
int numRows = tableComponent.getNumRows();
DBG("Number of rows: " << numRows);
tableComponent.updateContent();
tableComponent.repaint();
}
In my function addToPlaylist I get the user’s file and after some checks I add this file’s name to the trackTitles vector. After this I call the updateContent and repaint to try and get the new trackTitle element to be displayed on a new row - but nothing happens. I’ve got some DBGs printing to my immediate window which resullt in the following messages being printed:
PaintRowBackground
Painting cell: Row = 0, ColumnID = 1
Track title: Wheels on the bus
paintCell
////////bunch of file warnings and assertions which don’t seem to have any affect on the function of the programme?///////
newTrack.mp3 added to playlist
Track does not exist in trackTitles.
refreshComponentForCell
refreshComponentForCell
refreshComponentForCell
refreshComponentForCell
refreshComponentForCell
refreshComponentForCell
Wheels on the bus
newTrack.mp3
Number of rows: 2
After “paintCell” is printed I press my load button, get a few warnings and then my messages start printing indicating that I’m successfully reading the file and pushing it onto my vector. But the new row doesn’t appear so I added some DBGs which show that the TableListBox does have a second row, but paintCell and paintRowBackground are not being called. I checked to see if resize would cause the second row to be painted but it wasn’t, and I also checked to see if rearranging the columns would cause the second row to be painted and it didn’t. (I saw some previous forum posts which successfully got their new rows to paint when they did this). Both times only the original “Wheels on the Bus” row was painted for me.
At this point I’m a bit stumped, I’m not sure what else to try to get the new row to paint. Any help/suggestions are appreciated.