CSpinButtonCtrlのSetRange32使用時の最大値

[戻る]
ネックス 2009/05/21(木) 17:32:29
OS:XP
Microsoft Development Environment 2003

CSpinButtonCtrlを使用し、数値を入力させています。
今まで :0〜9999までの範囲
改造内容:0〜99999

下記のように使用する関数を変更すれば単純に動作するかと考えました。
SetRange(0,9999)⇒SetRange32(0,99999)
SetPos(int)⇒SetPos32(int)
しかし、変更後も
32767を超えると4294967295まで値が飛んでしまいます。

0〜99999までの範囲で動作させるためには何が必要でしょうか?

こちらの知識がつたないため文章が稚拙になっていますが
ご教授お願いいたします。

s 2009/05/21(木) 19:52:11
stdafx.h
#ifndef _WIN32_IE
//#define _WIN32_IE 0x0400
#define _WIN32_IE 0x0500
#endif


CxxxDlg.cpp
BOOL CxxxDlg::OnInitDialog()
{
  m_spin.SetRange32(0,99999);
  m_spin.SetPos32(32765);
//m_spin.SetPos32(99997);
}

void CxxxDlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
    TRACE("%u\n",m_spin.GetPos32());
}

結果
m_spin.SetPos32(32765);設定後
ひたすら▲ボタン
32765
32766
32767
32768

m_spin.SetPos32(99997);設定後
ひたすら▲ボタン
99997
99998
99999
99999

うまく動いている感じがしますが、何か特殊なことをしていたりしませんか?

ネックス 2009/05/21(木) 21:18:20
回答ありがとうございます。

特別な事かどうか解りませんが正確に表現しますと
実際は画面の表示上は少数点です。
今まで :1.23(少数桁2桁)
改造内容:1.2345(少数桁4桁まで)

MAXを999⇒99999に変更し、
m_spin.SetRange32(0,99999);

SetPos32はソース内では以下の2種類を使用しています。
m_spin.SetPos32((int)(atof(m_Edit) * 10000 / 10000));

m_spin.SetPos32((int)(dAtai * 10000 / 10000));

今は環境がないため個所は正確ではないかも知れません。
明日できればソースを貼り付けさせていただきます。

つたない説明で申し訳ありません。

ネックス 2009/05/22(金) 09:17:30
ソースを貼り付けます。
何かお気づきの点があれば回答お願いいたします。

BOOL CRevice1Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();

                //数字・少数点のみ入力可
    VERIFY(m_Edit.SubclassEdit(IDC_EREVICE1, this, PES_JISSUU));
    //少数点4桁対応
    //m_Edit.LimitText(4);                //最大4文字まで
    m_Edit.LimitText(6);                //最大6文字まで
(0.1234)

    if (!m_SRevice.IsEmpty())            //初期値の設定
        m_Rev1 = m_SRevice;
 
                //スピンコントロールの上下限の設定
    CSpinButtonCtrl*    pSpinCtl = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN1);
    pSpinCtl->SetRange32(0, 99999);
    //少数点4桁対応
    pSpinCtl->SetPos32((int)(atof(m_Rev1) * 10000));
    //pSpinCtl->SetPos((int)(atof(m_Rev1) * 100));

    if (m_x != -1) {
        SetWindowPos(NULL, m_x, m_y, 0, 0, SWP_NOSIZE | 
SWP_NOZORDER);
    }

    UpdateData(FALSE);

    m_bInit = TRUE;

    return TRUE;
}

void CRevice1Dlg::OnChangeErevice1() 
{

    UpdateData();
//少数点4桁対応
    double        dRev = ::MyFloor(atof(m_Rev1) * 10000.0) / 10000.0;
    //double        dRev = ::MyFloor(atof(m_Rev1) * 100.0) / 100.0;

    CSpinButtonCtrl*    pSpinCtl = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN1);
//少数点4桁対応
    pSpinCtl->SetPos32((int)(dRev * 10000));
    //pSpinCtl->SetPos((int)(dRev * 100));
}

//スピンコントロール
void CRevice1Dlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    CDialog::OnVScroll(nSBCode, nPos, pScrollBar);

    if (nSBCode != SB_THUMBPOSITION)
        return;

    char        buf[16];
//少数点4桁対応
    ::sprintf(buf, "%.4lf", (double)nPos / 10000.0);
    //::sprintf(buf, "%.2lf", (double)nPos / 100.0);
    m_Rev1 = buf;

    UpdateData(FALSE);
}

MyFloorは少数点以下を切り捨てています。

ネックス 2009/05/22(金) 10:51:47
調査を進めてみました。
CRevice1Dlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
nPosをみますと2バイト分の値しか設定されていませんでした。

75300(0x12624)をSETPOS32にした後にスピンボタンの下を押下した場合、
nPosは9763(0x2323)でした。

intが環境依存はあるかと思いますが通常のwin32プログラムです。
確かにかなり昔からのプログラムに改造を繰り替えしてきたのはありますが。
int_maxも定義上は
(Limits.h)
#define MB_LEN_MAX    5             /* max. # bytes in multibyte char */
#define SHRT_MIN    (-32768)        /* minimum (signed) short value */
#define SHRT_MAX      32767         /* maximum (signed) short value */
#define USHRT_MAX     0xffff        /* maximum unsigned short value */
#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX       2147483647    /* maximum (signed) int value */
#define UINT_MAX      0xffffffff    /* maximum unsigned int value */
#define LONG_MIN    (-2147483647L - 1) /* minimum (signed) long value */
#define LONG_MAX      2147483647L   /* maximum (signed) long value */
#define ULONG_MAX     0xffffffffUL  /* maximum unsigned long value */
とあんっています。

私の勘違い誤り等あればご指摘お願いいたします。

tetrapod 2009/05/22(金) 12:55:13
Win95 の頃のコモンコントロール中のスピンボタンは、値に 16bit しか使えなかった
という歴史的事情があり、互換性維持のためにこの制約が生きている状態なんだろう。

というわけで既に s 氏から答えが出ているとおり。なわけだけど・・・
#define _WIN32_IE の値が Win95 互換モードである 0x0400 になっていないか?
と指摘されているわけだ。要確認。

ネックス 2009/05/22(金) 17:27:48
tetrapod様回答ありがとうございます。
define _WIN32_IEを検索してみました。
検索結果は以下です。
------------------------------------------------------------------------
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\include\prerelease にアクセスできません。
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\include\afxv_w32.h
(40):#define _WIN32_IE 0x0560
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\CommCtrl.h(20):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\PrSht.h(18):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\ShlGuid.h(12):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\ShlObj.h(14):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\Shlwapi.h(24):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\ShObjIdl.h(758):#define _WIN32_IE 0x0501
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\ShObjIdl.idl(23):cpp_quote("#define _WIN32_IE 0x0501")
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
\PlatformSDK\Include\WinResrc.h(25):#define _WIN32_IE 0x0501
------------------------------------------------------------------------

stdafx.hに以下の文を定義してみましたが結果は同じでした。
#ifndef _WIN32_IE
//#define _WIN32_IE 0x0400
#define _WIN32_IE 0x0500
#endif

全く関係ないかも知れませんが
ソースビルド時に以下のメッセージが出力されています。
 WINVER not defined. Defaulting to 0x0501 (Windows XP and Windows .NET Server)

私の知識が
s様、tetrapod様お二人に追いついていないため的外れな事を言っている
かも知れませんがアドバイスお願いいたします。

ネックス 2009/05/22(金) 17:47:41
先ほどの追記です。

TRACE("%d\n", _WIN32_IE);
TRACE("%d\n", WINVER);

結果は
1280(0x0500)
1281(0x0501)
でした。

何か根本の考えかたを間違っているのでしょうか?

gak 2009/05/22(金) 17:54:17
> CRevice1Dlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
> nPosをみますと2バイト分の値しか設定されていませんでした。
Win32 WM_VSCROLL メッセージの仕様。

void CRevice1Dlg::OnVScroll() {
    :
    nPos = reinteprret_cast<CSpinButtonCtrl*>(pScrollBar)->GetPos32();
    :
}

とでもして位置を取り直してやれば正常値が取れる気がする。

> 何か根本の考えかたを間違っているのでしょうか?
_WIN32_IE、WINVER は今回の件に直接の関係は無いかもしれない。

ITO 2009/05/23(土) 15:24:43
gakさんが回答を出していますが、

OnVScroll() の nPosについて

> スクロール バーのコードが SB_THUMBPOSITION または SB_THUMBTRACK の場合は、
> スクロール ボックスの現在位置を指定します。それ以外の場合は使いません。
> スクロール範囲の初期値によっては、nPos が負の値になることもあるので、
> 必要に応じて int 型へキャストしなければいけません

PATIO 2009/05/25(月) 11:08:05
ウインドウメッセージに関しては過去のしがらみがあるので
そのままの仕様になっていてそれを補助する為の関数で対応する
ケースって結構あったような気がします。
確かスクロールバーに関しても同じような事をしないといけなかったような
気がしますが、勘違いだったかな?

ネックス 2009/05/25(月) 13:38:55
[[解決]]
gak様、ITO様、PATIO様回答ありがとうございます。
gak様の方法で解決いたしました。

GetPos32で位置を取り直す事により99999までの値が正常に
取得出来るようになりました。

回答してくださった皆様ありがとうございました。

古いスレッドには追加発言できません。