Как изменить стиль элемента управления (CListBox), инициализированного с помощью DDX_Control, перед вызовом DDX_Control - PullRequest
1 голос
/ 25 мая 2019

Я изменяю существующий проект, и в диалоговом окне есть элементы управления. В некоторых случаях я подклассифицирую в тему по-другому (в других случаях я оставлю это полностью один).К тому времени, когда DDX_Control() вызывается во время DoDataExchange(), hwnd для ListBox уже имеет примененные стили.В частности, в настоящее время, даже если я SetWindowLongPtr(), LBS_OWNERDRAWFIXED не работает.Под «не работает» я подразумеваю, что, хотя стиль применяется, сообщения рисования владельца не принимаются CListBox.

И наоборот, если я избегаю DDX_Control() и просто делаю создание, ListBox делаетполучать сообщения и могут быть отозваны владельцем.Но если я сделаю это, то теперь будет два HWND, только один из которых будет возвращен GetDlgItem().Я полагаю, что могу сделать эту работу при необходимости, но мне было интересно, есть ли секрет, чтобы перехватить создание HWND элементов управления в диалоге (на самом деле CPropertyPage).

Ниже приведен код, который не работает,с более прокомментированным кодом, который «работает», но не так, как я хотел, чтобы он работал, если это возможно.

void CMyPropertySheet::DoDataExchange(CDataExchange* pDX)
{
    HWND hWndCtrl;
    pDX->m_pDlgWnd->GetDlgItem(IDC_LIST1, &hWndCtrl);

    if (themed) {
        DWORD style = GetWindowLongPtr(hWndCtrl, GWL_STYLE) | LBS_OWNERDRAWFIXED;
        SetWindowLongPtr(hWndCtrl, GWL_STYLE, style);
        DDX_Control(pDX, IDC_LIST1, m_listbox);
        //RECT wr;
        //::GetWindowRect(hWndCtrl, &wr);
        //m_listbox.Create(style, wr, this, IDC_LIST1);
    } else {
        DDX_Control(pDX, IDC_LIST1, m_listbox);
    }

Я, вероятно, должен добавить, что я попытался создать подкласс окна, но это не помогло, иCMyPropertySheet::PreSubclassWindow тоже было недостаточно скоро.

Ответы [ 2 ]

1 голос
/ 27 мая 2019

Некоторые флаги создания, такие как LBS_OWNERDRAWFIXED и LBS_SORT, кэшируются, и их последующее изменение не имеет никакого эффекта.Вы должны изменить шаблон или просто сделать копию списка.Скопируйте стиль старого списка, затем скройте его, измените его идентификатор и создайте новый список на основе старого.Затем вы должны удалить DDX_Control(pDX, IDC_LIST1, m_listbox)

Пример ниже начинается со стандартного списка, в котором установлен флаг сортировки.Он дублирует список и отключает опцию сортировки.

Для простоты в этом примере не используется LBS_OWNERDRAWFIXED, вместо него используется LBS_SORT.

class CMyPropertyPage : public CPropertyPage
{
public:
    CListBox m_listbox;
    int m_listbox_index;

    CMyPropertyPage(int idd) : CPropertyPage(idd)
    {
        m_listbox_index = 1;
    }   

    void DoDataExchange(CDataExchange* pDX)
    {
        //This function is automatically called before 
        //CPropertyPage::OnInitDialog is complete
        //On the first call, IDC_LIST1 will point to the template listbox
        if(m_listbox.m_hWnd)
        {
            //m_listbox is ready, 
            //IDC_LIST1 will refer to the new listbox
            DDX_LBIndex(pDX, IDC_LIST1, m_listbox_index);
        }
    }

    BOOL OnInitDialog()
    {
        CPropertyPage::OnInitDialog();

        CListBox* old_listbox = (CListBox*)GetDlgItem(IDC_LIST1);
        if(old_listbox)
        {
            DWORD style = ~LBS_SORT & GetWindowLongPtr(old_listbox->m_hWnd, GWL_STYLE);
            CRect rc;
            old_listbox->GetWindowRect(&rc);
            ScreenToClient(&rc);
            old_listbox->SetDlgCtrlID(0);//change the old ID to something unused
            old_listbox->ShowWindow(SW_HIDE); //hide the old listbox
            m_listbox.Create(style | WS_BORDER, rc, this, IDC_LIST1);
            m_listbox.SetFont(GetFont());
        }

        ASSERT(m_listbox.GetDlgCtrlID() == IDC_LIST1);
        m_listbox.AddString(L"2");
        m_listbox.AddString(L"1");
        m_listbox.AddString(L"0");

        UpdateData(FALSE);

        return TRUE;
    }
};

class CMyWinApp : public CWinApp
{
    BOOL InitInstance()
    {
        CWinApp::InitInstance();
        CPropertySheet sh;
        CMyPropertyPage page(IDD_PAGE1);
        sh.AddPage(&page);
        sh.DoModal();
        return TRUE;
    }
} myapp;
0 голосов
/ 26 мая 2019

ОК, я не уверен, что рекомендую это кому-либо, но я наконец нашел способ изменить шаблон.Мне пришлось использовать VirtualProtect, чтобы разблокировать память шаблона.

for (int i = 0; i < m_pages.GetSize(); i++) {
    CPropertyPage* pPage = GetPage(i);
    PROPSHEETPAGE* tpsp = &pPage->m_psp;

    const DLGTEMPLATE* pTemplate;
    if (tpsp->dwFlags & PSP_DLGINDIRECT) {
        pTemplate = tpsp->pResource;
    } else {
        HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG);
        if (hResource == NULL) return false;
        HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource);
        if (hTemplate == NULL) return false;
        pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate);
        if (pTemplate == NULL) return false;
    }

    if (afxOccManager != NULL) {
        DLGITEMTEMPLATE *pItem = _AfxFindFirstDlgItem(pTemplate);
        DLGITEMTEMPLATE *pNextItem;
        BOOL bDialogEx = IsDialogEx(pTemplate);

        int iItem, iItems = DlgTemplateItemCount(pTemplate);

        for (iItem = 0; iItem < iItems; iItem++) {
            pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx);
            DWORD dwOldProtect, tp;
            if (bDialogEx) {
                _DialogSplitHelper::DLGITEMTEMPLATEEX *pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX *)pItem;
                if (pItemEx->id == IDC_LIST1) {
                    if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) {
                        pItemEx->style |= LBS_OWNERDRAWFIXED;
                        VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp);
                    }
                }
            } else {
                if (pItem->id == IDC_LIST1) {
                    if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) {
                        pItem->style |= LBS_OWNERDRAWFIXED;
                        VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp);
                    }
                }
            }
            pItem = pNextItem;
        }
    }
}
return true;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...