Александр (sandy) Илюшенко любезно предоставил статью о том, как настроить класc wxGrid под свои нужды:
Захотелось мне как-то, чтобы в гриде были не номера строк, а маркер.
К тому же очень хотелось, чтобы незаполненное пространство грида было не белым, а, примерно, как на рисунке ниже.
Навеяно это было в основном аналогичными и другими классами, предоставляемыми MFC. Тут же и вспомнилось, что подобные классы также прдоставляют очень полезные методы для хранения дополнительных не отображаемых данных, такие как SetData() или GetData().
Вначеле даже была мысль, использовать для этого wxGrid::SetRowLabelValue(), с учетом того, что перерисовку лэйбла я собирался переопределить. Но, покурив исходники грида, я обнаружил, что в функциях bool InsertRows(int pos = 0, int numRows = 1, bool updateLabels = true) и bool DeleteRows(int pos = 0, int numRows = 1, bool updateLabels = true), третий аргумент не используется. А это значит, что при вставке или удалении строки у меня все посыпется. К тому же неизвестно, как в будущем этот аргумент будет использоваться.
Потому не нашел я ничего лучшего, как переопределить грид и снабдить его необходимыми функциями.
wxGridCtrl.h
#pragma once
#include < wx/wx.h >
#include < wx/grid.h >
#include < map >
class wxGridCtrl: public wxGrid {
std::map< int, int > m_mRowData;
DECLARE_DYNAMIC_CLASS(wxGridCtrl)
protected:
virtual void DrawRowLabel(wxDC& dc, int row);
virtual void OnLabelLeftClick(wxGridEvent& event);
virtual void OnSelectCell(wxGridEvent& event);
DECLARE_EVENT_TABLE();
public:
wxGridCtrl();
wxGridCtrl(wxWindow* parent, const long& id);
/// Override
bool CreateGrid(int numRows, int numCols,
wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
bool AppendRows(int numRows = 1, bool updateLabels = true);
bool InsertRows(int pos = 0, int numRows = 1, bool updateLabels = true);
bool DeleteRows(int pos = 0, int numRows = 1, bool updateLabels = true);
/// New
void SetRowData(const int& row, const int& data);
int GetRowData(const int& row);
};
Теперь, как это все реализовано:
DrawRowLabel – это функция, реализующая перерисовку лэйбла грида, а именно, рисующая маркер в лэйбле.OnLabelLeftClick – усталавливает визуальный курсор в первую колонку, выделенной строки.OnSelectCell – функция, без которой я не смог обойтись, чтобы все хорошо работало:)Несколько слов о контейнере std::map m_mRowData:
Этот контейнер, имеющий ключем номер строки, и содержит значения, присваиваемые функцией SetRowData. И, чтобы данные соответствовали строками после создания грида, добаления, вставки и удаления записей, пришлось переопределить соответсвующие функции: CreateGrid, AppendRows, InsertRows, DeleteRows. Получить данные для соответствующей строки, как и сами догадываетесь, можно функцией GetRowData.
wxGridCtrl.cpp
#include "wxGridCtrl.h"
#include "cursor.xpm"
IMPLEMENT_DYNAMIC_CLASS(wxGridCtrl, wxGrid);
wxGridCtrl::wxGridCtrl()
{
}
wxGridCtrl::wxGridCtrl(wxWindow* parent, const long& id):
wxGrid(parent,id,wxDefaultPosition,wxDefaultSize)
{
}
BEGIN_EVENT_TABLE(wxGridCtrl, wxGrid)
EVT_GRID_LABEL_LEFT_CLICK(wxGridCtrl::OnLabelLeftClick)
EVT_GRID_SELECT_CELL(wxGridCtrl::OnSelectCell)
END_EVENT_TABLE();
void wxGridCtrl::DrawRowLabel(wxDC& dc, int row)
{
if (GetRowHeight(row)<=0 || m_rowLabelWidth<=0)
return;
wxRect rect;
#ifdef __WXGTK20__
rect.SetX(1);
rect.SetY(GetRowTop(row)+1);
rect.SetWidth(m_rowLabelWidth-2);
rect.SetHeight(GetRowHeight(row)-2);
CalcScrolledPosition(0, rect.y, NULL, &rect.y);
wxWindowDC *win_dc=(wxWindowDC*)&dc;
wxRendererNative::Get().DrawHeaderButton(win_dc->m_owner, dc, rect, 0);
#else
int rowTop=GetRowTop(row),
rowBottom=GetRowBottom(row)-1;
dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID));
dc.DrawLine(m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom);
dc.DrawLine(0, rowTop, 0, rowBottom);
dc.DrawLine(0, rowBottom, m_rowLabelWidth, rowBottom);
dc.SetPen(*wxWHITE_PEN);
dc.DrawLine(1, rowTop, 1, rowBottom);
dc.DrawLine(1, rowTop, m_rowLabelWidth - 1, rowTop);
#endif
if (row==GetGridCursorRow()) {
dc.DrawBitmap(wxBitmap(cursor_xpm),0,GetRowTop(row),true);
}
}
void wxGridCtrl::OnLabelLeftClick(wxGridEvent& event)
{
if (event.GetRow() != -1) {
SetGridCursor(event.GetRow(),0);
}
event.Skip();
}
void wxGridCtrl::OnSelectCell(wxGridEvent& event)
{
GetGridRowLabelWindow()->Refresh();
event.Skip();
}
/// Override
bool wxGridCtrl::CreateGrid(int numRows, int numCols,
wxGrid::wxGridSelectionModes selmode)
{
bool bCreate=wxGrid::CreateGrid(numRows, numCols, selmode);
if (bCreate)
{
for (int i=0; i < numRows; i++)
{
m_mRowData[i]=0;
}
}
return bCreate;
}
bool wxGridCtrl::AppendRows(int numRows, bool updateLabels)
{
int nRow = GetNumberRows();
bool bAdd = wxGrid::AppendRows(numRows, updateLabels);
if (bAdd)
{
while(nRow < GetNumberRows())
{
m_mRowData[nRow]=0;
nRow++;
}
}
return bAdd;
}
bool wxGridCtrl::InsertRows(int pos, int numRows, bool updateLabels)
{
std::map< int, int > mRow;
for (int i=0; i < GetNumberRows(); i++)
{
mRow[i]=GetRowData(i);
}
bool bIns=wxGrid::InsertRows(pos,numRows,updateLabels);
if (bIns)
{
for (int i = pos + numRows; i < GetNumberRows(); i++)
{
m_mRowData[i]=mRow[i-numRows];
}
for (int i=pos; i < pos + numRows; i++)
{
m_mRowData[i]=0;
}
}
return bIns;
}
bool wxGridCtrl::DeleteRows(int pos, int numRows, bool updateLabels)
{
std::map< int, int > mRow;
for (int i = 0; i < GetNumberRows(); i++)
{
mRow[i] = GetRowData(i);
}
bool bDel = wxGrid::DeleteRows(pos,numRows,updateLabels);
if (bDel)
{
for (int i = pos; i < GetNumberRows(); i++)
{
m_mRowData[i] = mRow[i + numRows];
}
}
return bDel;
}
/// New
void wxGridCtrl::SetRowData(const int& row, const int& data)
{
if (row < GetNumberRows())
{
m_mRowData[row] = data;
}
}
int wxGridCtrl::GetRowData(const int& row)
{
int data = 0;
if (row < GetNumberRows() && m_mRowData.find(row) != m_mRowData.end())
{
data = m_mRowData[row];
}
return data;
}
Что касается цветов, это я не включил в класс. Мало ли как кому нужно будет?
Пример использования примерно следующий:
Exmple.cpp
#include "wxGridCtrl.h"
/* ... */ m_pGrid = new wxGridCtrl(this, wxID_ANY);
m_pGrid->CreateGrid(0,0);
m_pGrid->SetRowLabelSize(20);
m_pGrid->SetColLabelSize(20);
m_pGrid->DisableDragRowSize();
m_pGrid->SetDefaultCellBackgroundColour(wxColour(128,128,128));
m_pGrid->AppendCols(3);
m_pGrid->SetColLabelValue(0,wxT("A"));
m_pGrid->SetColLabelValue(1,wxT("B"));
m_pGrid->SetColLabelValue(2,wxT("C"));
wxGridCellAttr* pAttr = new wxGridCellAttr;
pAttr->SetBackgroundColour(wxColour(255,255,255));
wxGridCellAttr* pAttrBool = new wxGridCellAttr;
pAttrBool->SetBackgroundColour(wxColour(255,255,255));
pAttrBool->SetRenderer(new wxGridCellBoolRenderer());
pAttrBool->SetEditor(new wxGridCellBoolEditor());
pAttrBool->SetAlignment(wxALIGN_CENTRE,wxALIGN_CENTRE);
m_pGrid->SetColAttr(0,pAttr);
m_pGrid->SetColAttr(1,pAttr);
m_pGrid->SetColAttr(2,pAttrBool);
/* ... */ Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…
I can see that there is still a lot of topics at wxWidgets forums related…
I've just published the source code of wxToolBox component and a couple of sample apps at…
Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…
Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…