child class of CListCtrl cannot refresh display but still active

57 Views Asked by At

I'm coding an app, using C++17 standards and graphical library MFC. I have two virtual classes, ViewerGet and ViewerSet, that both inherit from Viewer class, that inherits from CListCtrl class from MFC. My problem is about ViewerGet, built as such :

void ViewerGet::InitViewer(CWnd* pParent, CRect oWndRect)
{
    if (!Create(WS_TABSTOP | WS_CHILD | LVS_REPORT | LVS_OWNERDATA, oWndRect, pParent, 0))
        return;

    // Set a Global Style + add tips
    SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
    ListView_SetExtendedListViewStyleEx(*pParent, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);

    // Columns Creation
    LPTSTR lpszCols[] = { _T("Variable name"),_T("Variable path"),_T("Value read"),_T("Validity"),_T("Recording"),_T("Type"),0};
    CRect rect;
    GetWindowRect(&rect);
    int columnSize[] = { int(rect.Width() * 0.3), int(rect.Width() * 0.45), int(rect.Width() * 0.12), int(rect.Width() * 0.07), int(rect.Width() * 0.03) };
    LV_COLUMN   lvColumn;
    lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvColumn.fmt = LVCFMT_LEFT;

    for (int x = 0; lpszCols[x] != NULL; x++)
    {
        lvColumn.pszText = lpszCols[x];
        lvColumn.cx = columnSize[x];
        InsertColumn(x, &lvColumn);
    }

    m_arrowImage.Create(IDB_LOGO_LIST, 24, 0, RGB(255, 255, 255));
    SetImageList(&m_arrowImage, LVSIL_SMALL);
}

When I try to put data in my ViewerGet, I follow those steps :

  1. Select lines in yet another CListCtrl
  2. Right click to make pop-up window appear
  3. Click on the button "Add to ViewerGet" Then, the relevant lines are added to my ViewerGet. Up until now, everything is OK.

However, when I then want to select lines in ViewerGet, 3 possible behaviors :

  • Everything works out normally (I can select, remove, check checkboxes...)
  • The ViewerGet is instantly frozen (when I click on a line, it's not selected as it should)
  • The ViewerGet starts out normally, but at one point (which one, I wasn't able to pinpoint it), it freezes again I noticed that when I minimise + maximise my window, the ViewerGet is refreshed, once. But no more after that. This does not happens with ViewerSet, the other child class, only with ViewerGet I don't think it's important, but ViewerGet is supposed to receive & refresh data every 50ms, received from a CAN bus. This does not seem important as the ViewerGet freeze happens even if I'm not receiving data, even if I have no CAN bus plugged in...

Here is the method called when chosing to add a line to the ViewerGet table :

void AppDlg::OnEditOnLeftTab()
{
    m_oTabViewer.SetCurSel(0);
    OnSelchangeTabViewer(NULL, NULL);

    m_poViewGet->LockWindowUpdate();

    EnterCriticalSection(database.GetMutex());

    std::vector<IascVariable*> selVars = m_list.GetSelectedVariables();
    for (IascVariable* var : selVars)
        if (database.ReadEntryFor(var)==NULL)
            database.AddReadEntry(new ReadEntry(var));
    m_poViewGet->SetItemCount(database.ReadEntriesListCount());

    LeaveCriticalSection(database.GetMutex());
}

Expected behavior : just to have my ViewerGet work normally, being refreshed when I need it (click to change selected lines, new value refreshed in relevant column of ViewerGet when CAN communication is OK...)

What I tried :

  • Used several CListCtrl styles such as WS_CLIPCHILDREN
  • Used LockWindow() and UnlockWindow() methods
  • Used SetRedraw(FALSE) and SetRedraw(TRUE) methods
  • Verified the data was updated in the background of the display
  • Verified OnGetDispInfo notifications :
void Viewer::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
    NMLVDISPINFO* plvdi = (NMLVDISPINFO*)pNMHDR;
    if (plvdi->item.mask & LVIF_TEXT)
        lstrcpyn(plvdi->item.pszText, CellContent(plvdi->item.iItem, plvdi->item.iSubItem), plvdi->item.cchTextMax);
    if (plvdi->item.mask & LVIF_IMAGE)
    {
        plvdi->item.iImage = CellImage(plvdi->item.iItem, plvdi->item.iSubItem);
        plvdi->item.mask |= LVIF_STATE;
        plvdi->item.stateMask |= LVIS_STATEIMAGEMASK;
        plvdi->item.state = INDEXTOSTATEIMAGEMASK(CheckboxContent(plvdi->item.iItem, plvdi->item.iSubItem));
    }
    *pResult = 0;
}
  • Tried to force ViewerGet refresh with methods RedrawItems(item,item) (only one line) or even RedrawWindow() for full ViewerGet
  • Change OnCustomDraw method :
void Viewer::OnCustomDrawBgColor(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
    *pResult = 0;
    pLVCD->nmcd.rc.top += 7;
    int nItem = pLVCD->nmcd.dwItemSpec;
    int nSubItem = pLVCD->iSubItem;

    // what we do next depends on the drawing stage we are processing
    switch (pLVCD->nmcd.dwDrawStage)
        (...) //other cases, for prepaint mainly    
        case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
                this->RedrawWindow();
        break;

    case CDDS_ITEMPOSTPAINT:;
        this->RedrawWindow();
        break;
    }
}

EDIT : I may be wrong, but I don't think this is caused by deadlock. In my understanding, deadlocks would paralyze my ViewerGet, however it is still functional, it just... doesn't display want I want it to

0

There are 0 best solutions below