Александр (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…