I have a class called Grid which is composed of Cells. Each cell can have its own format (the concept is similar to MS Excel).
The format in the Grid is kept in a vector std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable
which owns all the formatting, so whenever I need to read a Cells format, I read it from the vector and whenever there is a change, it is reported back to the vector. Sorry, I am quite new to C++11 standards so my thinking might be wrong.
Since a grid is a matrix and each cell belongs to a different part of the matrix when there is a change in a cell's format it should be reflected in the correct part of the matrix, namely positioned correctly in the vector (CellFormatTable). Therefore, at this stage I cannot use the push_back
method of the vector.
The CellFormat class:
struct CellFormat
{
wxFont m_Font;
wxColor m_BackgroundColor, m_TextColor;
int m_HorizontalAlignment, m_VerticalAlignment;
CellFormat(Grid* ws) {
m_BackgroundColor = ws->GetDefaultCellBackgroundColour();
m_TextColor=ws->GetDefaultCellTextColour();
int horizontal = 0, vertical = 0;
ws->GetDefaultCellAlignment(&horizontal, &vertical);
}
CellFormat(const CellFormat& other) {
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
}
CellFormat& operator=(const CellFormat& other) {
if (this == &other) return *this;
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
return *this;
}
};
In the Grid.h
class Grid{
std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable;
//
CellFormat* GetCellFormat(int row, int column);
void SetCellFormat(int row, int column, CellFormat format);
void ApplyCellFormat(int row, int column, const CellFormat* format);
CellFormat* CreateCellFormat(int row, int column);
//rest is omitted
}
In Grid.cpp
Grid(some arguments){
m_CellFormatTable.resize(nrows*ncols);
//rest is omitted
}
CellFormat* Grid::GetCellFormat(int row, int column)
{
int ncols= GetNumberCols();
return m_CellFormatTable[row*ncols+ column].get();
}
void Grid::SetCellFormat(int row, int column, CellFormat other)
{
CellFormat* format = GetCellFormat(row, column);
if (format == 0) format = CreateCellFormat(row, column);
*format = other;
}
void Grid::ApplyCellFormat(int row, int column, const CellFormat * format)
{
if (format == 0) {
int ncols= GetNumberCols();
//Set everything to default values
//Omitted
m_CellFormatTable[row*ncols+ column].reset();
}
else {
wxColor bgcolor = format->m_BackgroundColor;
if (bgcolor.IsOk()) SetCellBackgroundColour(row, column, bgcolor);
SetCellTextColour(row, column, format->m_TextColor);
SetCellFont(row, column, format->m_Font);
SetCellAlignment(row, column, format->m_HorizontalAlignment, format->m_VerticalAlignment);
}
}
CellFormat* Grid::CreateCellFormat(int row, int column)
{
int ncols= GetNumberCols();
CellFormat* format = new CellFormat(this);
m_CellFormatTable.emplace(m_CellFormatTable.begin() + row*ncols+ column, std::move(format));
return format;
}
Whenever I format a cell, say its background color is changed, I use the following attempt:
CellFormat* format = ws->GetCellFormat(row, col);
if (format == 0) format = ws->CreateCellFormat(row, col);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(row, col, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
The code fails at ApplyCellFormat
function at the point of format->m_BackgroundColor
since the color which should have been Cell's background color is not valid. This tells me that most and highly likely CreateCellFormat
does not place CellFormat in the right location. I try to use insert
rather than emplace
but compiler (VS 2015) complained all my attempts.
Any ideas appreciated.
You have several problems.
One is that you add a CellFormat*
but your vector stores unique_ptr
;so you need std::make_unique
with the new format.
Question: are you sure you need a vector of pointers instead of objects?
Other is that you presume the vector to have all data for all cells, being 0
if they are not set yet. That's wrong. The vector only have as many elements as you have 'pushed' or 'emplaced'.
Let's say you have 'pushed' the format for cell (0,0). Now you want to set the format for (5,2) which is (say you have 10 cols) the 52th element in the vector, but you have only one. So vector[51]
is undefined (vector.at(51)
will raise an error).
Add all cell formats first, with some value = 0 to tell it has not been set yet. Or re-think your strategy.
By the way, you can use wxGridCellAttr which provides what you are coding on your own.