Подходы для снижения скорости роста файла ресурсов по мере расширения / расширения диалогов - PullRequest
0 голосов
/ 28 февраля 2019

В рамках расширения функциональности диалогового окна в старом приложении Windows WinAPI GUI, написанном на C, я столкнулся с еще одним добавлением нескольких флажков для каждой строки диалога ввода данных из шести строк.Я просто не выдержал хлопот с повторяющимися изменениями файлов ресурсов и файлов исходного кода и решил позаимствовать подход дизайна пользовательского интерфейса из пользовательских интерфейсов Java для создания пользовательского интерфейса из панелей.

Инструменты Visual Studio, по крайней мере Visual Studio2005, похоже, не одобряет такой подход, и в этом случае я отредактировал файл ресурсов вручную.Возможно, инструменты редактирования ресурсов Visual Studio 2017 более гибкие.

Мой вопрос заключается в том, что является альтернативой этому подходу, который, казалось бы, настолько прост и удобен и лучше соответствует философии Visual Studio..

Мне также интересно узнать о недостатках этого подхода.

Этот подход кажется необычным для приложения WinAPI Visual Studio C WinAPI, которое меня беспокоит.Я не могу утверждать, что являюсь особенно инновационным, поэтому мне интересно, чего мне не хватает, поскольку этот подход, кажется, работает хорошо, по крайней мере, при ручном редактировании файла ресурсов.

Я подумываю сделать еще одну итерацию, в которой я двигаюсьсписок элементов управления для каждой строки, который также повторяется в шаблоне немодального диалогового окна, и просто наличие исходного диалога представляет собой стек из 6 статических окон, по одному для каждой строки.

Преимущества этого подхода были меньшеи возможность повторного использования определяет.Также было проще вставить новую функциональность в существующий исходный код поведения диалога, хотя это было главным образом потому, что это были просто автоматические флажки.

Одна проблема, которую я вижу, заключается в использовании инструментов Visual Studio после внесения этого изменения,Однако файл ресурсов этого конкретного приложения не всегда хорошо работает с инструментами редактирования ресурсов Visual Studio.

Этот подход уже окупился, когда мне понадобилось добавить некоторые дополнительные флажки в немодальный шаблон диалога.Чтобы изменить файл ресурсов, мне нужно было добавить дополнительные флажки в новый шаблон диалога и отрегулировать исходный размер диалога, немодальный размер диалога и размеры статических окон, чтобы все было видно.

Реализация

Альтернатива, которую я реализовал, заключается в следующем:

  • создать шаблон диалога с набором флажков
  • изменить шаблон диалогастиль немодального диалога - WS_CHILD
  • . Создайте статическое окно в каждой из шести строк исходного диалога для нового шаблона диалога.
  • Поместите экземпляр немодального диалогового окна в статическое окно.в каждой строке

Новая версия диалога выглядит следующим образом: screen shot of new version of the data entry dialog Когда отображается исходное диалоговое окно, обработчик для сообщения диалога инициализации создает набор из шести немодальных диалоговпо одному для каждого из вновь добавленных статических окон, причем родительское окно для диалогов является статическим окном.Это помещает немодальный диалог в статическое окно, и когда статическое окно перемещается, то же самое происходит и с немодальным диалогом.

Все шесть немодальных диалогов используют один и тот же обработчик сообщений диалогового окна.Обработчик сообщений сам не обрабатывает никаких сообщений.

Шаблон немодального диалога:

IDD_A170_DAYS DIALOG DISCARDABLE  0, 0, 240, 20
STYLE  WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
    CONTROL         "Ovr",IDD_A170_STR1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,1,25,10
    CONTROL         "AND",IDD_A170_STR2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,35,1,40,10
    CONTROL         "S",IDD_A170_CAPTION1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,75,1,20,10
    CONTROL         "M",IDD_A170_CAPTION2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,1,20,10
    CONTROL         "T",IDD_A170_CAPTION3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,1,20,10
    CONTROL         "W",IDD_A170_CAPTION4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,1,20,10
    CONTROL         "T",IDD_A170_CAPTION5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,175,1,20,10
    CONTROL         "F",IDD_A170_CAPTION6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,195,1,20,10
    CONTROL         "S",IDD_A170_CAPTION7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,220,1,20,10
END

, а основной диалог со статическими окнами:

IDD_A170 DIALOG DISCARDABLE  2, 17, 530, 190
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Set Sales Code Restriction Table of PLU (AC 170)"
FONT 8, "MS Sans Serif"
BEGIN
    LTEXT           "Address              (PLU Sales Code)",IDD_A170_CAPTION1,14,10,64,20
    LTEXT           "Date",IDD_A170_CAPTION2,86,14,28,12
    LTEXT           "Day of week",IDD_A170_CAPTION3,115,10,33,21
    LTEXT           "Start hour",IDD_A170_CAPTION4,153,10,20,18
    LTEXT           "Minute",IDD_A170_CAPTION5,182,14,26,12
    LTEXT           "End hour",IDD_A170_CAPTION6,217,10,20,18
    LTEXT           "Minute",IDD_A170_CAPTION7,245,14,26,12
    LTEXT           "Override/Type",IDC_STATIC,290,14,50,12
    LTEXT           "Days To Restrict",IDC_STATIC,390,14,100,12
    LTEXT           "",IDD_A170_STR1,8,34,74,12                     // first control on line 1
    EDITTEXT        IDD_A170_DATE1,87,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_DATESPIN1,104,33,8,12,SBS_VERT
    EDITTEXT        IDD_A170_WEEK1,119,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_WEEKSPIN1,136,33,8,12,SBS_VERT
    EDITTEXT        IDD_A170_SHOUR1,151,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_SHOURSPIN1,168,33,8,12,SBS_VERT
    EDITTEXT        IDD_A170_SMINUTE1,183,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_SMINUTESPIN1,200,33,8,12,SBS_VERT
    EDITTEXT        IDD_A170_EHOUR1,214,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_EHOURSPIN1,231,33,8,12,SBS_VERT
    EDITTEXT        IDD_A170_EMINUTE1,246,33,18,12,ES_AUTOHSCROLL
    SCROLLBAR       IDD_A170_EMINUTESPIN1,263,33,8,12,SBS_VERT
    LTEXT           "D1",IDD_A170_DAYS_1,281,33,240,20             // static window to contain the modeless dialog box from the template IDD_A170_DAYS above
    //   .. repeated sequence for 5 more lines
    CONTROL         "MDC 298 - Sales Restriction Type is AND",IDD_A170_MDC_PLU5_ADR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,140,170,9
    LTEXT           "[Address :  1 - 6, Date : 0 - 31",IDD_A170_CAPTION8,9,154,99,9
    LTEXT           "Day of week : 0 - 7 (1 - Sunday, 7 - Saturday)]",IDD_A170_CAPTION9,110,154,167,9
    LTEXT           "[Hour : 0 - 24, Minute : 0 - 59 (For 0:00, enter 24:00)]",IDD_A170_CAPTION10,9,168,167,9
    PUSHBUTTON      "&Ok",IDOK,285,154,48,20
    PUSHBUTTON      "&Cancel",IDCANCEL,345,154,48,20
END

Вы можете заметить, что я только что повторно использовал некоторые определения в новом немодальном диалоговом окне, которые уже использовались в исходном диалоговом окне.Я смог сделать это, потому что идентификаторы управления являются специфическими для самого диалогового окна.Поэтому использование одного и того же определения в разных диалоговых окнах не вызывает проблем, поскольку использование GetDlgItem() для получения дескриптора окна элемента управления в диалоговом окне требует дескриптора окна конкретного экземпляра диалога.

Iзатем создал набор вспомогательных функций, которые обрабатывают экземпляр немодального диалога.

static struct {
    int   iId;
    HWND  hWnd;
} A170DlgTabs[10] = { {0, 0} };

// modeless dialog box message handler which has nothing to do but the
// WinAPI requires it.
BOOL    WINAPI  A170DlgChildProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
        return FALSE;
}

void  A170ModeLessChildDialogClear ()
{
    memset (A170DlgTabs, 0, sizeof(A170DlgTabs));
}

HWND A170ModeLessChildDialog (HWND hParentWnd, int nCmdShow, int iId)
{
    int   i;
    HWND  hWnd = DialogCreation(hResourceDll/*hActInst*/,  //RPH 4-23-03 Multilingual
                                   MAKEINTRESOURCEW(IDD_A170_DAYS),
                                   hParentWnd,
                                   A170DlgChildProc);
    hWnd && ShowWindow (hWnd, nCmdShow);
    for (i = 0; i < sizeof(A170DlgTabs)/sizeof(A170DlgTabs[0]); i++) {
        if (A170DlgTabs[i].hWnd == 0) {
            A170DlgTabs[i].iId = iId;
            A170DlgTabs[i].hWnd = hWnd;
            break;
        }
    }

    return hWnd;
}

HWND A170ModeLessChildDialogFind (int iId)
{
    int   i;
    HWND  hWnd = NULL;

    for (i = 0; i < sizeof(A170DlgTabs)/sizeof(A170DlgTabs[0]); i++) {
        if (A170DlgTabs[i].iId == iId) {
            hWnd = A170DlgTabs[i].hWnd;
            break;
        }
    }

    return hWnd;
}

USHORT A170ModeLessChildDialogSettings (int iId)
{
    int     i;
    USHORT  iBits = 0, kBits = 1;
    HWND hWnd = A170ModeLessChildDialogFind (iId);

    // least significant byte contains the bit mask for the days of the week.
    // the next higher byte contains the indicators for the override type or
    // whether MDC 298 is to be overriden or not.
    for (i = IDD_A170_CAPTION1; i <= IDD_A170_CAPTION7; i++, (kBits <<= 1)) {
        iBits |= IsDlgButtonChecked (hWnd, i) ? kBits : 0;
    }

    iBits |= iBits ? RESTRICT_WEEK_DAYS_ON : 0;

    iBits |= IsDlgButtonChecked(hWnd, IDD_A170_STR1) ? KBITS_RESTRICT_OVERRIDE_ANDOR : 0;
    iBits |= IsDlgButtonChecked(hWnd, IDD_A170_STR2) ? KBITS_RESTRICT_OVERRIDE_AND : 0;

    return iBits;
}


USHORT A170ModeLessChildDialogSettingsSetMask (int iId, USHORT  usMask)
{
    int     i;
    USHORT  k = 1;
    HWND    hWnd = A170ModeLessChildDialogFind (iId);

    CheckDlgButton(hWnd, IDD_A170_STR1, (usMask & KBITS_RESTRICT_OVERRIDE_ANDOR) ? TRUE : FALSE);
    CheckDlgButton(hWnd, IDD_A170_STR2, (usMask & KBITS_RESTRICT_OVERRIDE_AND) ? TRUE : FALSE);

    for (i = IDD_A170_CAPTION1; i <= IDD_A170_CAPTION7; i++, (k <<= 1)) {
        CheckDlgButton(hWnd, i, (usMask & k) ? TRUE : FALSE);
    }

    return usMask;
}

1 Ответ

0 голосов
/ 03 марта 2019

Использование Visual Studio 2017 Community Edition позволило использовать этот подход для создания компонентов из шаблонов диалогов, которые затем используются для создания графического интерфейса пользователя.

Я сделал это грубое упражнение для проверки концепции, используя диалоговое окно "О программе", котороеавтоматически генерируется при создании нового проекта Windows Desktop Application, поскольку это было удобно.

Это был простой компонент, выражаемый в шаблоне диалога, и эта простота может сделать это доказательство неверной концепции.

Я начал с первоначального скелета Windows Desktop Application, созданного как новый проект.Затем я внес следующие изменения в диалоговое окно «О программе», которое автоматически создается в новом проекте.Я смог использовать IDE и редактор ресурсов, не редактируя файл ресурсов вручную.

Шаги были следующие:

  • с помощью редактора ресурсов измените существующий файл About.и создайте новый немодальный диалог
  • добавьте новый класс для управления новым немодальным диалогом
  • измените обработчик сообщений диалогового окна "О программе", чтобы использовать новый класс

Модификациик ресурсам диалога с помощью редактора ресурсов было довольно просто:

  • изменить автоматически сгенерированный диалог About, увеличив его и добавив два статических текстовых окна в столбец
  • указать фактические идентификаторы элемента управлениядля каждого статического текстового поля, добавленного в диалоговое окно «О программе», чтобы на них можно было ссылаться с помощью GetDlgItem(), что является важным шагом, так как в среде IDE статические окна не назначают используемые идентификаторы управления по умолчанию.
  • создал новый шаблон диалога с помощьюРедактор ресурсов после переключения в Resource View
  • Модифицированный ACНесколько атрибутов Appearance в списке Properties диалогового окна, чтобы изменить диалоговое окно на немодальное диалоговое окно без рамки
  • добавили флажки в новое диалоговое окно с помощью редактора ресурсов и удалили кнопки по умолчанию

Изменения исходного кода также были довольно просты, так как это простой элемент управления.

Новое диалоговое окно About выглядит следующим образом.Я добавил два статических окна в диалоговое окно About, сделав его больше.Каждое из статических окон имеет свой собственный экземпляр нового элемента управления на основе шаблона диалога.Обратите внимание, что размер шаблона диалога больше, чем размер статических окон, что приводит к обрезанию шаблона диалога в области отображения статического окна.

screenshot of modified About dialog

Подробная информация о том, что было сделано

Создание и изменение стилей диалога

Использование представления ресурсов Я добавил новый диалог.Я нажал на новое диалоговое окно, чтобы открыть его в редакторе ресурсов.Затем я изменил исходный модальный шаблон диалога, изменив атрибут border и атрибут style вместе с удалением кнопок по умолчанию, добавленных IDE при первом создании шаблона диалога. Я превратил шаблон диалога в немодальное диалоговое окно, пригодное для размещенияв контейнер статического окна.

screenshot of Properties screenshots of before and after of new dialog

Создать код для поведения

Затем я создал класс CDialogChild для управления этим новым немодальным диалогом со следующим источником:

#pragma once

#include "resource.h"

class CDialogChild
{
private:
    // static shared by all instances of this class
    static LRESULT CALLBACK WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

    enum {DIALOG_ID = IDD_DIALOG1};
    static const UINT idCheckBox[3];    // identifiers for the controls of the modeless dialog.

    // management data for each modeless dialog instance created.
    HINSTANCE m_hinst;       // handle to the instance resources
    HWND      m_hWnd;        // handle to the modeless dialog window
    HWND      m_hParent;     // handle to the parent of the modeless dialog, usually static window

    // operational data displayed and captured by this modeless dialog
    // this is the data for the various controls we have in the dialog template.
    bool      bCheckBox[3] = { false, false, false };

public:
    CDialogChild();
    ~CDialogChild();
    bool GetCheck(int iIndex);    // for reading checkbox value
    void GetCheckFinal(void);     // for capturing final checkbox states
    bool SetCheck(int iIndex, bool bValue);   // for writing checkbox value
    void SetCheckInitial(void);               // for setting the initial checkbox states.

    HWND Create(HWND hParent, HINSTANCE hinst);

};

с реализацией:

#include "stdafx.h"
#include "CDialogChild.h"

const UINT CDialogChild::idCheckBox[3] = { IDC_CHECK1, IDC_CHECK2, IDC_CHECK3 };


CDialogChild::CDialogChild()
{
}


CDialogChild::~CDialogChild()
{
}

HWND CDialogChild::Create(HWND hParent, HINSTANCE hinst)
{
    // called to create the modeless dialog using the dialog resource in the
    // specified resource file instance. the hParent is the container we are
    // going to put this modeless dialogbox into.
    m_hinst = hinst;
    m_hParent = hParent;
    m_hWnd = CreateDialog(hinst, MAKEINTRESOURCE(DIALOG_ID), hParent, (DLGPROC)CDialogChild::WndProc);

    ShowWindow(m_hWnd, SW_SHOW);
    return m_hWnd;
}

bool CDialogChild::GetCheck(int iIndex)
{
    if (iIndex > 0 && iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0])) {
        iIndex = 0;
    }

    bCheckBox [iIndex] = IsDlgButtonChecked(m_hWnd, idCheckBox[iIndex]);
    return bCheckBox [iIndex];
}

bool CDialogChild::SetCheck(int iIndex, bool bValue)
{
    if (iIndex > 0 && iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0])) {
        iIndex = 0;
    }

    CheckDlgButton (m_hWnd, idCheckBox[iIndex], bValue);
    bCheckBox[iIndex] = bValue;
    return bCheckBox [iIndex];
}

void CDialogChild::GetCheckFinal(void)
{
    for (int iIndex = 0; iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0]); iIndex++) {
        bCheckBox[iIndex] = IsDlgButtonChecked(m_hWnd, idCheckBox[iIndex]);
    }
}

void CDialogChild::SetCheckInitial(void)
{
    for (int iIndex = 0; iIndex < sizeof(bCheckBox) / sizeof(bCheckBox[0]); iIndex++) {
        CheckDlgButton(m_hWnd, idCheckBox[iIndex], bCheckBox[iIndex]);
    }
}

// CDialogChild class Windows message procedure to handle any messages sent
// to a modeless dialog window. This simple example there is not much to do.
LRESULT CALLBACK CDialogChild::WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    return (INT_PTR)FALSE;
}

Использование нового элемента управления в диалоге

Наконец, я изменил диалоговое окно About, чтобы использовать новый элемент управления на основе шаблона диалога.Первым делом было добавить статические окна в шаблон диалога «О программе», чтобы предоставить контейнеры для нового элемента управления, в котором было размещено то место, где я хотел бы видеть экземпляры элемента управления.

Затем я добавил исходный код для использования.новый элемент управления на основе шаблона диалога в измененном диалоговом окне «О программе».

// other source code from the Windows Desktop Application main window handler
// is above this. We are only modifying the About dialog code which is at the
// bottom of the source file.

#include "CDialogChild.h"

CDialogChild myAbout1;
CDialogChild myAbout2;

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        myAbout1.Create(GetDlgItem(hDlg, IDC_STATIC4), hInst);
        myAbout1.SetCheckInitial();
        myAbout2.Create(GetDlgItem(hDlg, IDC_STATIC5), hInst);
        myAbout2.SetCheckInitial();
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            if (LOWORD(wParam) == IDOK) {
                myAbout1.GetCheckFinal();
                myAbout2.GetCheckFinal();
            }
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...