Windows 随着对话框的增强/扩展,降低资源文件增长率的方法

Windows 随着对话框的增强/扩展,降低资源文件增长率的方法,windows,visual-studio,winapi,dialog,Windows,Visual Studio,Winapi,Dialog,作为扩展用C编写的旧Windows WinAPI GUI应用程序中对话框功能的一部分,我再次面临为六行数据输入对话框的每行添加多个复选框的问题。我无法忍受重复的资源文件和源代码文件更改带来的麻烦,决定借用JavaUI的UI设计方法,从窗格构建UI VisualStudio工具(至少是VisualStudio2005)似乎不鼓励这种方法,在本例中,我手工编辑了资源文件。Visual Studio 2017的资源编辑工具可能更灵活 我的问题是,这种方法的替代方案是什么,它似乎同样容易做到,并且更符合

作为扩展用C编写的旧Windows WinAPI GUI应用程序中对话框功能的一部分,我再次面临为六行数据输入对话框的每行添加多个复选框的问题。我无法忍受重复的资源文件和源代码文件更改带来的麻烦,决定借用JavaUI的UI设计方法,从窗格构建UI

VisualStudio工具(至少是VisualStudio2005)似乎不鼓励这种方法,在本例中,我手工编辑了资源文件。Visual Studio 2017的资源编辑工具可能更灵活

我的问题是,这种方法的替代方案是什么,它似乎同样容易做到,并且更符合VisualStudio的理念

我还想知道这种方法的缺点

对于困扰我的VisualStudioC WinAPI GUI应用程序来说,这种方法似乎不常见。我不能说自己特别有创新性,所以我想知道我遗漏了什么,因为这种方法似乎工作得很好,至少在手工编辑资源文件时是如此

我正在考虑进行另一次迭代,将重复出现的每一行的控件列表移动到无模式对话框模板中,并使原始对话框成为6个静态窗口的堆栈,每一行一个

这种方法的好处是定义更少,并且能够重用定义。将新功能插入现有的对话框行为源代码也更容易,尽管这主要是因为这些只是简单的自动复选框

我看到的一个问题是在进行此更改后使用VisualStudio工具。但是,这个特定应用程序的资源文件无论如何都不能与VisualStudio资源编辑工具配合使用

当我需要向无模式对话框模板添加一些额外的复选框时,这种方法已经有了回报。我要做的资源文件更改是在新对话框模板中添加额外的复选框,并调整原始对话框大小、无模式对话框大小和静态窗口的大小,以使所有内容都可见

实施

我实施的替代方案是:

  • 使用一组复选框创建对话框模板
  • 将无模式对话框的对话框模板样式修改为WS\u CHILD
  • 为新对话框模板在原始对话框的六行中的每一行上创建一个静态窗口
  • 在每行的静态窗口中放置无模式对话框的实例
对话框的新版本如下所示 当显示原始对话框时,init dialog消息的处理程序将创建一组六个无模式对话框,每个新添加的静态窗口一个,对话框的父窗口为静态窗口。这会将无模式对话框放置在静态窗口中,当静态窗口移动时,无模式对话框也会移动

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;
}
所有六个无模式对话框都使用相同的对话框消息处理程序。消息处理程序本身不处理任何消息

无模式对话框模板是:

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()
获取对话框中控件的窗口句柄需要特定对话框实例的窗口句柄

然后,我创建了一组帮助函数,用于处理无模式对话框的实例

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;
}
静态结构{
国际iId;
HWND-HWND;
}A170DlgTabs[10]={{0,0};
//无模式对话框消息处理程序,除了
//WinAPI需要它。
布尔WINAPI A170DlgChildProc(HWND hDlg、UINT wMsg、WPARAM WPARAM、LPARAM LPARAM)
{
返回FALSE;
}
无效A170ModelsChildDialogClear()
{
memset(A170DlgTabs,0,sizeof(A170DlgTabs));
}
HWND A170ModeLessChildDialog(HWND hParentWnd、int nCmdShow、int iId)
{
int i;
HWND HWND=对话框创建(hResourceDll/*hActInst*/,//RPH 4-23-03多语言
MAKEINTRESOURCEW(国际直拨电话170天),
hParentWnd,
A170DlgChildProc);
hWnd和ShowWindow(hWnd、nCmdShow);
对于(i=0;i对于(i=IDD_A170_CAPTION1;i使用Visual Studio 2017 Community Edition使得从对话框模板创建组件的方法变得更容易,然后使用对话框模板构建GUI

我使用About对话框做了这个粗略的概念验证练习,该对话框是在创建新的Windows桌面应用程序项目时自动生成的,因为它很方便

这是一个在对话框模板中表达的简单组件,而且非常简单
#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;
}
// 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;
}