0

Excel の特定のセルのチェックボックスの状態を読み書きする必要がある問題に取り組んでいます。

COM/OLE を使用して ActiveX コントロールにアクセスできることを知っています。ただし、この問題の解決策を見つけることができませんでした。実際、行と列を使用してチェックボックスにアクセスできるかどうかさえわかりません。activeX チェックボックスのプロパティを調べました。上と左のプロパティが見つかりましたが、row-column ではありません

1.これを行う直接的な方法はありますか。2.そうでない場合は、間接的な方法で、何らかの方法で上/左の列を取得し、次に行/列の位置を取得して2つを比較します。3. フォーム コントロールで同じことを行う方法はありますか?

4

3 に答える 3

2

返信ありがとうございます。MSDN で役に立つものを見つけました。それを少し編集してあなたと共有しました..皆さんのサポートに感謝します

(整形は許して)

msdn の Autowrap() 関数は完全に未編集です。

HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...) {
// Begin variable-argument list...
va_list marker;
va_start(marker, cArgs);

if(!pDisp) {
    MessageBox(NULL, "NULL IDispatch passed to AutoWrap()", "Error", 0x10010);
    _exit(0);
}

// Variables used...
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
HRESULT hr;
char buf[200];
char szName[200];


// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

// Get DISPID for name passed...
hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
if(FAILED(hr)) {
    sprintf(buf, "IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx", szName, hr);
    MessageBox(NULL, buf, "AutoWrap()", 0x10010);
    _exit(0);
    return hr;
}

// Allocate memory for arguments...
VARIANT *pArgs = new VARIANT[cArgs+1];
// Extract arguments...
for(int i=0; i<cArgs; i++) {
    pArgs[i] = va_arg(marker, VARIANT);
}

// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;

// Handle special-case for property-puts!
if(autoType & DISPATCH_PROPERTYPUT) {
    dp.cNamedArgs = 1;
    dp.rgdispidNamedArgs = &dispidNamed;
}

// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);
if(FAILED(hr)) {
    sprintf(buf, "IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx", szName, dispID, hr);
    MessageBox(NULL, buf, "AutoWrap()", 0x10010);
    _exit(0);
    return hr;
}
// End variable-argument section...
va_end(marker);

delete [] pArgs;

return hr;
}

編集された main() 関数は次のとおりです。

int main()
{
 // Initialize COM for this thread...
   CoInitialize(NULL);

   // Get CLSID for our server...
   CLSID clsid;
   HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);

   if(FAILED(hr)) {

      ::MessageBox(NULL, "CLSIDFromProgID() failed", "Error", 0x10010);
      return -1;
   }

   // Start server and get IDispatch...
   IDispatch *pXlApp;
   hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);

   if(FAILED(hr)) {
      ::MessageBox(NULL, "Excel not registered properly", "Error", 0x10010);
      return -2;
   }

   // Make it visible (i.e. app.visible = 1)
   {
      VARIANT x;
      x.vt = VT_I4;
      x.lVal = 1;
      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);
   }

   // Make it visible (i.e. app.visible = 1)
   {
      VARIANT x;
      x.vt = VT_BSTR;
      x.bstrVal = ::SysAllocString (L"D:\\");
      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"DefaultFilePath", 1, x);
   }

   // Get Workbooks collection
   IDispatch *pXlBooks;
   {
      VARIANT result;
  VariantInit(&result);
  AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
  pXlBooks = result.pdispVal;
   }

   // Call Workbooks.Add() to get a new workbook...
   IDispatch *pXlBook;
   {
      VARIANT parm;
  parm.vt = VT_BSTR;
  parm.bstrVal = ::SysAllocString(L"a.xlsx");

  VARIANT result;
  VariantInit(&result);
  AutoWrap(DISPATCH_METHOD, &result, pXlBooks, L"Open", 1,parm);
  pXlBook = result.pdispVal;
    }

   // Get ActiveSheet object
   IDispatch *pXlSheet;
   {
enter code here
  VARIANT result;
  VariantInit(&result);
  AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBook, L"ActiveSheet",0);
  if(result.pdispVal != NULL)
    pXlSheet = result.pdispVal;
   }

   //Get shapes collection..
    IDispatch *pShapes;
    {
       VARIANT result;
   VariantInit(&result);
   AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Shapes",0);
   pShapes = result.pdispVal;
}

int nControls;  
{
   VARIANT result;
   VariantInit(&result);
   AutoWrap(DISPATCH_PROPERTYGET, &result, pShapes, L"Count",0);
   if(result.vt == VT_I4)
       nControls = result.lVal;
}

for(int i = 1; i <= nControls; ++i) {

    IDispatch * pShape;

    {  
        VARIANT x;
        x.vt = VT_I4;
        x.lVal = i;

        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_METHOD, &result, pShapes, L"Item",1, x);
        pShape = result.pdispVal;
    }   

    IDispatch *pControlFormat = NULL;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pShape, L"Type",0);

        // msoFormControl
        if(result.lVal == 8)
        {
            VARIANT result0;
            VariantInit(&result0);
            AutoWrap(DISPATCH_PROPERTYGET, &result0, pShape, L"FormControlType",0);

            // xlCheckBox
            if(result0.lVal == 1) {

                // Get range containing cell to be tested
                VARIANT result2;
                VariantInit(&result2);
                IDispatch * range;
                {
                    VARIANT param1;
                    param1.vt= VT_BSTR;
                    param1.bstrVal = ::SysAllocString(L"F5");

                    VARIANT result3;
                    VariantInit(&result3);
                    AutoWrap(DISPATCH_PROPERTYGET, &result3, pXlSheet,L"Range",1,param1);
                    range = result3.pdispVal;
                }

                // Get the top, left, bottom, right of cell
                DOUBLE top, left, bottom, right;
                {
                    VARIANT result4;
                    VariantInit(&result4);

                    AutoWrap(DISPATCH_PROPERTYGET,&result4, range,L"Top",0);
                    top = result4.dblVal;

                    AutoWrap(DISPATCH_PROPERTYGET,&result4, range,L"Left",0);
                    left = result4.dblVal;

                    AutoWrap(DISPATCH_PROPERTYGET,&result4, range,L"Height",0);
                    bottom = top + result4.dblVal;

                    AutoWrap(DISPATCH_PROPERTYGET,&result4, range,L"Width",0);
                    right = left + result4.dblVal;
                }
                range->Release();

                // Get the top, left of checkbox
                FLOAT shapetop, shapeleft;
                {
                    VARIANT result5;
                    VariantInit(&result5);

                    AutoWrap(DISPATCH_PROPERTYGET,&result5, pShape,L"Top",0);
                    shapetop = result5.fltVal;

                    AutoWrap(DISPATCH_PROPERTYGET,&result5, pShape,L"Left",0);
                    shapeleft = result5.fltVal;
                }

                // Get hold of control format
                VARIANT result1;
                VariantInit(&result1);
                AutoWrap(DISPATCH_PROPERTYGET, &result1, pShape, L"ControlFormat",0);
                pControlFormat = result1.pdispVal;



                // Check if the checkbox if within the range boundary. If yes, then check it, else dont
                if((top <= shapetop) && (bottom >= shapetop) && (left <= shapeleft) && (right >= shapeleft)) {

                    // Perpare the parameter
                    VARIANT parm;
                    VARIANT_BOOL t = VARIANT_TRUE;;
                    parm.vt = VT_BOOL;
                    parm.pboolVal = &t;

                    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pControlFormat, L"Value", 1, parm);
                }                   
            }
        }
    }

    if(pControlFormat != NULL) pControlFormat->Release();
    pShape->Release();
}

   // to save when we tell Excel to quit...
   {
       VARIANT x;
  x.vt = VT_I4;
  x.lVal = 1;
  AutoWrap(DISPATCH_METHOD, NULL, pXlBook, L"Save", 0);
    }

   // Wait for user...
   ::MessageBox(NULL, "All done.", "Notice", 0x10000);

   // Tell Excel to quit (i.e. App.Quit)
   AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);

   // Release references...

   pShapes->Release();

   pXlSheet->Release();
   pXlBook->Release();
   pXlBooks->Release();
   pXlApp->Release();


   // Uninitialize COM for this thread...
   CoUninitialize();

   return 0;
}

詳細については、
http ://support.microsoft.com/kb/216686
http://msdn.microsoft.com/en-us/library/office/bb149081%28v=office.12%29.aspxを参照してください。

于 2013-04-09T06:40:13.993 に答える
0

チェックボックスが「セル内」にあるとは思いません。値を取得できる方法がいくつかあります(私が考えることができます)。

最初:チェックボックスの値をチェックしないで、リンクされたセルの値をチェックします(割り当てられている場合)

2 番目: 次の疑似コードのようなものを使用して、どのコントロールがどこにあるかを判断します。

ForEach Sheet.Controls As Control
  If Control.Type = Checkbox Then
    Row = 1
    YPos = 0
    Do
      If YPos + Sheet.Rows(Row).RowHeight > Control.Top Then
        Exit Do
      Else
        YPos = YPos + Sheets.Rows(Row).RowHeight
      End If
    Loop
    Column = 1
    XPos = 0
    Do
      If XPos + Sheet.Columns(Column).ColumnWidth > Control.Left Then
        Exit Do
      Else
        XPos = XPos + Sheets.Columns(Column).ColumnWidth
      End If
    Loop
    Debug.Print Control.Name & " is in Cell(" & XPos & ", " & YPos & ")"
  End If
End ForEach
于 2013-04-05T13:26:47.453 に答える