[C++] Window/Dialog: Which do I use and how?

Pages: 12
I'm trying to learn the Win32 API, and since internet tutorials can only get you so far, I thought I'd take one of my console programs and convert it. (Yes, I've been on Google a lot)

For this application, I want a settings window, whether it's a dialog, or a window: I know not what I need. But what I want to to be able to do is have text and edit boxes, perhaps some check boxes, and it needs to scroll. Reason being that will be a good 30+ options, and I don't want a dialog box that long. (Not even sure if that'd fit on my screen.)

So the question is, what do I need to use, and where do I Start? I can use Google just fine, but when I don't know what I'm looking for, it's difficult. So please give me where to start, things to research, etc.

Thanks!
You don't see many scrolling dialogboxes.

What you do see are propertysheets - (which is a tabbed dialogbox).
If you open Internet Explore and bring up the options dialog - you will see what I mean.

You group your controls onto the various tabs.

But using a propertysheet dialog is more work.
Okay, so a window is what I need. However, I don't want tabs, what I need is kind of like what ID has in their advanced tab: the one where all those check box options are. However, I don't need check boxes, I need [Text] [Editbox] [Editbox] And I might need one or two checkboxes.
What you are describing I do very frequently meesa. I do it in Windows CE for data recorder programs because the screen is like three inches by three inches or so. Other than code directly from one of my Windows CE programs, I don't believe I have a simple C/C++ Sdk demo of this but I do have an exact demo of it in the PowerBASIC language that is however exactly like C or C++ Sdk style except there are no semicolons at the ends of PowerBASIC lines.

Unless you are an experienced Sdk Api coder you won't understand one single thing about what I am going to describe, but perhaps the combination of my description and your desire to do it will suffice. Here goes.

A parent window is first created. A 'pane' window is then created as a child of the parent; however, it is created much larger than the parent; in fact large enough to contain hundreds or even thousands of text boxes if you want; The text boxes and labels (or check boxes, whatever), are then created as childs of the pane. You put a scroll bar on the parent, and move the pane about to bring various child window controls into view (the ones outside the parent are clipped and not visible). This is made possible by the fact that the x/y coordinates of a window in both the CreateWindow() call and the MoveWindow() call are typed as ints, which is a signed quantity, and so the pane can be scrolled within the parent's view space in negative and positive directions. I have a nice demo and detailed tutorial of this at a PowerBASIC website here....

http://www.jose.it-berater.org/smfforum/index.php?topic=2981.0

Its my tutorial #11 : Scrolling Controls In A Window

Again, while it isn't C code, it will translate line for line exactly to C (with minor modifications). However, if you don't know Sdk style Api coding you are likely to have problems. I believe all the code is there to be copied; you shouldn't have to join up at that forum (for members my programs can be downloaded as they are in zips). I probably ought to translate it to C/C++. Probably take me an hour.
Last edited on
Couldn't the ScrollDC function be useful in this situation??
(I haven't looked at your code so I don't know if you have mentioned/used this particular function)
Last edited on
You've got me gustgulkan! I never used ScrollDC. I'm pretty sure I used MoveWindow() in that example. There might be a MoveWindowEx(). Not sure. I'd have to check.

I did check out ScrollDC() just now in msdn and the parameters and usage look pretty similiar to ScrollWindow() and ScrollWindowEx(), which I frequently use for scrolling lines of text because it produces a much better and smoother scroll than outputting lines of text with a for loop or whatever.

I'm just not sure how well it would work scrolling controls however. The example I posted was a result of my need to accomplish what the original poster wanted, but I had to do it for Windows CE devices where the screen is quite small. Your recommendation of a tabbed dialog is also a good idea and workable. After I created my various apps with my window scrolling technique I did wonder if a tabbed dialog would be a better solution. Just the other day another fellow and I were discussing this exact issue, and he told me he implemented a Windows CE app with the tabbed dialog technique, but thought my solution might be a bit better. So I don't know which is best.
Thanks guys, I'll be looking into both methods, and I'll report back on the one I use. Your help is much appreciated.
Here's an exact line for line translation of the PowerBASIC code. Compiled with 32 bit XP SP3 Code::Blocks 8.05....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//ScrollControls  -- Main.cpp
#include          <windows.h>
#include          <tchar.h>
#define           ID__PANE              1500
#define           IDC_FIRST_NAME        1505
#define           IDC_MIDDLE_NAME       1510
#define           IDC_LAST_NAME         1515
#define           IDC_ADDRESS1          1520
#define           IDC_ADDRESS2          1525
#define           IDC_CITY              1530
#define           IDC_STATE             1535
#define           IDC_COUNTRY           1540
#define           IDC_ZIP               1545
#define           IDC_EMAIL             1550
#define           IDC_TELEPHONE         1555
#define           IDC_INTERESTS         1560
#define           IDC_SUBMIT            1565

typedef struct    WindowsEventArguments      //Just collecting Window Procedure
{                                            //parameters into a type
 HWND             hWnd;
 WPARAM           wParam;
 LPARAM           lParam;
 HINSTANCE        hIns;
}WndEventArgs,    *lpWndEventArgs;


struct EVENTHANDLER
{
 unsigned int    Code;
 long            (*fnPtr)(lpWndEventArgs);
}EventHandler[3];


LRESULT CALLBACK fnPaneProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_COMMAND && LOWORD(wParam)==IDC_SUBMIT)
    MessageBox(NULL,_T("You Apparently Want To Submit The Information!"),_T("Here Is What You Want..."),MB_OK);

 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


continued...
Last edited on
...continued from above...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
 HWND hCtrl,hPane;
 TCHAR szPane[8];
 SCROLLINFO vsi;
 WNDCLASSEX wc;
 RECT rc;

 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
 //Set up 'Pane' class
 _tcscpy(szPane,_T("Pane"));
 wc.cbSize=sizeof(WNDCLASSEX);
 wc.style=CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc=fnPaneProc;
 wc.cbClsExtra=0;
 wc.cbWndExtra=0;
 wc.hInstance=Wea->hIns;
 wc.hIcon=0;
 wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;
 wc.lpszMenuName=NULL;
 wc.lpszClassName=szPane;
 wc.hIconSm=0;
 RegisterClassEx(&wc);
 hPane=CreateWindowEx(0,szPane,_T(""),WS_CHILD|WS_VISIBLE,0,0,325,490,Wea->hWnd,(HMENU)ID__PANE,Wea->hIns,0);
 SetWindowLong(Wea->hWnd,0,(long)hPane);

 //Create all the child window controls on the 'Pane'
 hCtrl=CreateWindowEx(0,_T("static"),_T("First Name"),WS_CHILD|WS_VISIBLE,10,10,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,10,150,25,hPane,(HMENU)IDC_FIRST_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Middle Name"),WS_CHILD|WS_VISIBLE,10,40,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,40,150,25,hPane,(HMENU)IDC_MIDDLE_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Last Name"),WS_CHILD|WS_VISIBLE,10,70,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,70,150,25,hPane,(HMENU)IDC_LAST_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Address1"),WS_CHILD|WS_VISIBLE,10,100,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,100,150,25,hPane,(HMENU)IDC_ADDRESS1,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Address2"),WS_CHILD|WS_VISIBLE,10,130,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,130,150,25,hPane,(HMENU)IDC_ADDRESS2,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("City"),WS_CHILD|WS_VISIBLE,10,160,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,160,150,25,hPane,(HMENU)IDC_CITY,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("State"),WS_CHILD|WS_VISIBLE,10,190,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,190,150,25,hPane,(HMENU)IDC_STATE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Country"),WS_CHILD|WS_VISIBLE,10,220,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,220,150,25,hPane,(HMENU)IDC_COUNTRY,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Zip Code"),WS_CHILD|WS_VISIBLE,10,250,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,250,150,25,hPane,(HMENU)IDC_ZIP,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Email"),WS_CHILD|WS_VISIBLE,10,280,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,280,150,25,hPane,(HMENU)IDC_EMAIL,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Telephone"),WS_CHILD|WS_VISIBLE,10,310,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,310,150,25,hPane,(HMENU)IDC_TELEPHONE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Interests"),WS_CHILD|WS_VISIBLE,10,340,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,140,340,150,100,hPane,(HMENU)IDC_TELEPHONE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("button"),_T("Submit"),WS_CHILD|WS_VISIBLE,100,455,100,25,hPane,(HMENU)IDC_SUBMIT,Wea->hIns,0);

 //Initialize Window's internal scrolling apparatus (vsi think verticle scroll info)
 GetClientRect(Wea->hWnd,&rc);       //Need size of main window's client area to determine .nMax
 vsi.cbSize=sizeof(SCROLLINFO);      //Api docs say to do this
 vsi.nMin=0;
 vsi.nMax=490-rc.bottom;
 vsi.nPos=0;
 vsi.fMask=SIF_POS|SIF_RANGE;
 SetScrollInfo(Wea->hWnd,SB_VERT,&vsi,TRUE);

 return 0;
}



long fnWndProc_OnVScroll(lpWndEventArgs Wea)
{
 SCROLLINFO vsi;
 HWND hPane;

 hPane=(HWND)GetWindowLong(Wea->hWnd,0);
 switch(LOWORD(Wea->wParam))
 {
   case SB_LINEUP:
        vsi.cbSize=sizeof(SCROLLINFO);
        vsi.fMask=SIF_POS|SIF_RANGE;
        GetScrollInfo(Wea->hWnd,SB_VERT,&vsi);
        if(vsi.nPos>0)
        {
           vsi.nPos=vsi.nPos-10;
           if(vsi.nPos<0)
              vsi.nPos=0;
           MoveWindow(hPane,0,-1*vsi.nPos,325,500,TRUE);
           vsi.fMask=SIF_POS;
           SetScrollInfo(Wea->hWnd,SB_VERT,&vsi,TRUE);
        }
        break;
   case SB_LINEDOWN:
        vsi.cbSize=sizeof(SCROLLINFO);
        vsi.fMask=SIF_POS|SIF_RANGE;
        GetScrollInfo(Wea->hWnd,SB_VERT,&vsi);
        if(vsi.nPos<vsi.nMax)
        {
           vsi.nPos=vsi.nPos+10;
           MoveWindow(hPane,0,-1*vsi.nPos,325,500,TRUE);
           vsi.fMask=SIF_POS;
           SetScrollInfo(Wea->hWnd,SB_VERT,&vsi,TRUE);
        }
        break;
 }

 return 0;
}


long fnWndProc_OnDestroy(lpWndEventArgs Wea)
{
 PostQuitMessage(0);
 return 0;
}


void AttachEventHandlers(void)         //This procedure maps windows messages to the
{                                      //procedure which handles them.
 EventHandler[0].Code=WM_CREATE,       EventHandler[0].fnPtr=fnWndProc_OnCreate;
 EventHandler[1].Code=WM_VSCROLL,      EventHandler[1].fnPtr=fnWndProc_OnVScroll;
 EventHandler[2].Code=WM_DESTROY,      EventHandler[2].fnPtr=fnWndProc_OnDestroy;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
 WndEventArgs Wea;                  //This procedure loops through the EVENTHANDER array
                                    //of structs to try to make a match with the msg parameter
 for(unsigned int i=0; i<3; i++)    //of the WndProc.  If a match is made the event handling
 {                                  //procedure is called through a function pointer -
     if(EventHandler[i].Code==msg)  //(EventHandler[i].fnPtr).  If no match is found the
     {                              //msg is passed onto DefWindowProc().
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 char szClassName[]=_T("ScrollControls");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 AttachEventHandlers();
 wc.lpszClassName=szClassName;                          wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);                         wc.style=CS_HREDRAW|CS_VREDRAW;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);               wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);            wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  wc.cbWndExtra=8;
 wc.lpszMenuName=NULL;                                  wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,100,100,350,300,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
 }

 return messages.wParam;
}
closed account (3pj6b7Xj)
Hey that code looks very familiar. :) Just note that he stores a pointer to hPane in the window extra bytes, not in the hPane class but in the class for the actual application window.
Last edited on
Wow! Thanks!

I'll try it out this week and let you guys know how it goes.

A curiosity question: Which is better, _T("text") or L"text"? Or is it a matter of preference?
TEXT() is better, because it inserts what You need. Unicode text for unicode and so on...
I want to improve that scroll code when I get a chance; hopefully tomorrow, so check back.
Didn't have to wait till tomorrow...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include          <windows.h>
#include          <tchar.h>
#define           ID__PANE              1500
#define           IDC_FIRST_NAME        1505
#define           IDC_MIDDLE_NAME       1510
#define           IDC_LAST_NAME         1515
#define           IDC_ADDRESS1          1520
#define           IDC_ADDRESS2          1525
#define           IDC_CITY              1530
#define           IDC_STATE             1535
#define           IDC_COUNTRY           1540
#define           IDC_ZIP               1545
#define           IDC_EMAIL             1550
#define           IDC_TELEPHONE         1555
#define           IDC_INTERESTS         1560
#define           IDC_SUBMIT            1565

typedef struct    WindowsEventArguments      //Just collecting Window Procedure
{                                            //parameters into a type
 HWND             hWnd;
 WPARAM           wParam;
 LPARAM           lParam;
 HINSTANCE        hIns;
}WndEventArgs,    *lpWndEventArgs;


struct EVENTHANDLER
{
 unsigned int    Code;
 long            (*fnPtr)(lpWndEventArgs);
}EventHandler[3];


LRESULT CALLBACK fnPaneProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_COMMAND && LOWORD(wParam)==IDC_SUBMIT)
    MessageBox(NULL,_T("You Apparently Want To Submit The Information!"),_T("Here Is What You Want..."),MB_OK);

 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


continued...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
 HWND hCtrl,hPane;
 TCHAR szPane[8];
 SCROLLINFO vsi;
 WNDCLASSEX wc;
 RECT rc;

 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
 _tcscpy(szPane,_T("Pane"));                           //Set up 'Pane' class
 wc.cbSize=sizeof(WNDCLASSEX),                         wc.style=CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc=fnPaneProc,                            wc.cbClsExtra=0;
 wc.cbWndExtra=0,                                      wc.hInstance=Wea->hIns;
 wc.hIcon=0,                                           wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW,             wc.lpszMenuName=NULL;
 wc.lpszClassName=szPane,                              wc.hIconSm=0;
 RegisterClassEx(&wc);
 hPane=CreateWindowEx(0,szPane,_T(""),WS_CHILD|WS_VISIBLE,0,0,325,490,Wea->hWnd,(HMENU)ID__PANE,Wea->hIns,0);
 SetWindowLong(Wea->hWnd,0,(long)hPane);

 //Create all the child window controls on the 'Pane'
 hCtrl=CreateWindowEx(0,_T("static"),_T("First Name"),WS_CHILD|WS_VISIBLE,10,10,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,10,150,25,hPane,(HMENU)IDC_FIRST_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Middle Name"),WS_CHILD|WS_VISIBLE,10,40,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,40,150,25,hPane,(HMENU)IDC_MIDDLE_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Last Name"),WS_CHILD|WS_VISIBLE,10,70,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,70,150,25,hPane,(HMENU)IDC_LAST_NAME,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Address1"),WS_CHILD|WS_VISIBLE,10,100,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,100,150,25,hPane,(HMENU)IDC_ADDRESS1,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Address2"),WS_CHILD|WS_VISIBLE,10,130,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,130,150,25,hPane,(HMENU)IDC_ADDRESS2,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("City"),WS_CHILD|WS_VISIBLE,10,160,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,160,150,25,hPane,(HMENU)IDC_CITY,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("State"),WS_CHILD|WS_VISIBLE,10,190,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,190,150,25,hPane,(HMENU)IDC_STATE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Country"),WS_CHILD|WS_VISIBLE,10,220,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,220,150,25,hPane,(HMENU)IDC_COUNTRY,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Zip Code"),WS_CHILD|WS_VISIBLE,10,250,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,250,150,25,hPane,(HMENU)IDC_ZIP,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Email"),WS_CHILD|WS_VISIBLE,10,280,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,280,150,25,hPane,(HMENU)IDC_EMAIL,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Telephone"),WS_CHILD|WS_VISIBLE,10,310,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,310,150,25,hPane,(HMENU)IDC_TELEPHONE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("static"),_T("Interests"),WS_CHILD|WS_VISIBLE,10,340,100,25,hPane,(HMENU)-1,Wea->hIns,0);
 hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,140,340,150,100,hPane,(HMENU)IDC_TELEPHONE,Wea->hIns,0);
 hCtrl=CreateWindowEx(0,_T("button"),_T("Submit"),WS_CHILD|WS_VISIBLE,100,455,100,25,hPane,(HMENU)IDC_SUBMIT,Wea->hIns,0);

 //Initialize Window's internal scrolling apparatus (vsi think verticle scroll info)
 GetClientRect(Wea->hWnd,&rc);       //Need size of main window's client area to determine .nMax
 vsi.cbSize=sizeof(SCROLLINFO);      //Api docs say to do this
 vsi.nMin=0;
 vsi.nMax=489;
 vsi.nPage=rc.bottom;
 vsi.fMask=SIF_PAGE|SIF_RANGE;
 SetScrollInfo(Wea->hWnd,SB_VERT,&vsi,TRUE);

 return 0;
}


long fnWndProc_OnVScroll(lpWndEventArgs Wea)
{
 int iVScrollPos;
 SCROLLINFO vsi;
 HWND hPane;

 ZeroMemory(&vsi, sizeof(SCROLLINFO));
 hPane=(HWND)GetWindowLong(Wea->hWnd,0);
 vsi.cbSize=sizeof(SCROLLINFO);
 vsi.fMask=SIF_ALL;   //vsi.fMask=SIF_POS|SIF_RANGE;
 GetScrollInfo(Wea->hWnd,SB_VERT,&vsi);
 iVScrollPos=vsi.nPos;
 switch(LOWORD(Wea->wParam))
 {
   case SB_LINEUP:
        if(vsi.nPos>vsi.nMin)
           vsi.nPos=vsi.nPos-10;
        break;
   case SB_PAGEUP:
        vsi.nPos = vsi.nPos - vsi.nPage;
        break;
   case SB_LINEDOWN:
        if(vsi.nPos<vsi.nMax)
           vsi.nPos=vsi.nPos+10;
        break;
   case SB_PAGEDOWN:
        vsi.nPos = vsi.nPos + vsi.nPage;
        break;
   case SB_THUMBTRACK:
        vsi.nPos=vsi.nTrackPos;
        break;
 }
 vsi.fMask=SIF_POS;
 SetScrollInfo(Wea->hWnd,SB_VERT,&vsi,TRUE);
 GetScrollInfo(Wea->hWnd, SB_VERT, &vsi);
 if(vsi.nPos != iVScrollPos)
    MoveWindow(hPane,0,-1*vsi.nPos,325,500,TRUE);

 return 0;
}


long fnWndProc_OnDestroy(lpWndEventArgs Wea)
{
 PostQuitMessage(0);
 return 0;
}


void AttachEventHandlers(void)         //This procedure maps windows messages to the
{                                      //procedure which handles them.
 EventHandler[0].Code=WM_CREATE,       EventHandler[0].fnPtr=fnWndProc_OnCreate;
 EventHandler[1].Code=WM_VSCROLL,      EventHandler[1].fnPtr=fnWndProc_OnVScroll;
 EventHandler[2].Code=WM_DESTROY,      EventHandler[2].fnPtr=fnWndProc_OnDestroy;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
 WndEventArgs Wea;                  //This procedure loops through the EVENTHANDER array
                                    //of structs to try to make a match with the msg parameter
 for(unsigned int i=0; i<3; i++)    //of the WndProc.  If a match is made the event handling
 {                                  //procedure is called through a function pointer -
     if(EventHandler[i].Code==msg)  //(EventHandler[i].fnPtr).  If no match is found the
     {                              //msg is passed onto DefWindowProc().
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 char szClassName[]=_T("ScrollControls");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 AttachEventHandlers();
 wc.lpszClassName=szClassName;                          wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);                         wc.style=CS_HREDRAW|CS_VREDRAW;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);               wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);            wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  wc.cbWndExtra=8;
 wc.lpszMenuName=NULL;                                  wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW^WS_MAXIMIZEBOX,100,100,350,300,0,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
 }

 return messages.wParam;
}
here's a straight sdk version...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include          <windows.h>
#include          <tchar.h>
#define           ID__PANE              1500
#define           IDC_FIRST_NAME        1505
#define           IDC_MIDDLE_NAME       1510
#define           IDC_LAST_NAME         1515
#define           IDC_ADDRESS1          1520
#define           IDC_ADDRESS2          1525
#define           IDC_CITY              1530
#define           IDC_STATE             1535
#define           IDC_COUNTRY           1540
#define           IDC_ZIP               1545
#define           IDC_EMAIL             1550
#define           IDC_TELEPHONE         1555
#define           IDC_INTERESTS         1560
#define           IDC_SUBMIT            1565


LRESULT CALLBACK fnPaneProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_COMMAND && LOWORD(wParam)==IDC_SUBMIT)
    MessageBox(NULL,_T("You Apparently Want To Submit The Information!"),_T("Here Is What You Want..."),MB_OK);

 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


LRESULT CALLBACK fnWndProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
    case WM_CREATE:
      {
         HWND hCtrl,hPane;
         TCHAR szPane[8];
         HINSTANCE hIns;
         SCROLLINFO vsi;
         WNDCLASSEX wc;
         RECT rc;

         hIns=((LPCREATESTRUCT)lParam)->hInstance;
         _tcscpy(szPane,_T("Pane"));                           //Set up 'Pane' class
         wc.cbSize=sizeof(WNDCLASSEX),                         wc.style=CS_HREDRAW | CS_VREDRAW;
         wc.lpfnWndProc=fnPaneProc,                            wc.cbClsExtra=0;
         wc.cbWndExtra=0,                                      wc.hInstance=hIns;
         wc.hIcon=0,                                           wc.hCursor=LoadCursor(NULL,IDC_ARROW);
         wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW,             wc.lpszMenuName=NULL;
         wc.lpszClassName=szPane,                              wc.hIconSm=0;
         RegisterClassEx(&wc);
         hPane=CreateWindowEx(0,szPane,_T(""),WS_CHILD|WS_VISIBLE,0,0,325,490,hWnd,(HMENU)ID__PANE,hIns,0);
         SetWindowLong(hWnd,0,(long)hPane);

         //Create all the child window controls on the 'Pane'
         hCtrl=CreateWindowEx(0,_T("static"),_T("First Name"),WS_CHILD|WS_VISIBLE,10,10,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,10,150,25,hPane,(HMENU)IDC_FIRST_NAME,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Middle Name"),WS_CHILD|WS_VISIBLE,10,40,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,40,150,25,hPane,(HMENU)IDC_MIDDLE_NAME,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Last Name"),WS_CHILD|WS_VISIBLE,10,70,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,70,150,25,hPane,(HMENU)IDC_LAST_NAME,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Address1"),WS_CHILD|WS_VISIBLE,10,100,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,100,150,25,hPane,(HMENU)IDC_ADDRESS1,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Address2"),WS_CHILD|WS_VISIBLE,10,130,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,130,150,25,hPane,(HMENU)IDC_ADDRESS2,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("City"),WS_CHILD|WS_VISIBLE,10,160,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,160,150,25,hPane,(HMENU)IDC_CITY,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("State"),WS_CHILD|WS_VISIBLE,10,190,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,190,150,25,hPane,(HMENU)IDC_STATE,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Country"),WS_CHILD|WS_VISIBLE,10,220,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,220,150,25,hPane,(HMENU)IDC_COUNTRY,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Zip Code"),WS_CHILD|WS_VISIBLE,10,250,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,250,150,25,hPane,(HMENU)IDC_ZIP,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Email"),WS_CHILD|WS_VISIBLE,10,280,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,280,150,25,hPane,(HMENU)IDC_EMAIL,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Telephone"),WS_CHILD|WS_VISIBLE,10,310,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER,140,310,150,25,hPane,(HMENU)IDC_TELEPHONE,hIns,0);
         hCtrl=CreateWindowEx(0,_T("static"),_T("Interests"),WS_CHILD|WS_VISIBLE,10,340,100,25,hPane,(HMENU)-1,hIns,0);
         hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,140,340,150,100,hPane,(HMENU)IDC_TELEPHONE,hIns,0);
         hCtrl=CreateWindowEx(0,_T("button"),_T("Submit"),WS_CHILD|WS_VISIBLE,100,455,100,25,hPane,(HMENU)IDC_SUBMIT,hIns,0);

         //Initialize Window's internal scrolling apparatus (vsi think verticle scroll info)
         GetClientRect(hWnd,&rc);       //Need size of main window's client area to determine .nMax
         vsi.cbSize=sizeof(SCROLLINFO); //Api docs say to do this
         vsi.nMin=0;
         vsi.nMax=489;
         vsi.nPage=rc.bottom;
         vsi.fMask=SIF_PAGE|SIF_RANGE;
         SetScrollInfo(hWnd,SB_VERT,&vsi,TRUE);
         return 0;
      }
    case WM_VSCROLL:
      {
         int iVScrollPos;
         SCROLLINFO vsi;
         HWND hPane;

         ZeroMemory(&vsi, sizeof(SCROLLINFO));
         hPane=(HWND)GetWindowLong(hWnd,0);
         vsi.cbSize=sizeof(SCROLLINFO);
         vsi.fMask=SIF_ALL;
         GetScrollInfo(hWnd,SB_VERT,&vsi);
         iVScrollPos=vsi.nPos;
         switch(LOWORD(wParam))
         {
            case SB_LINEUP:
                 if(vsi.nPos>vsi.nMin)
                    vsi.nPos=vsi.nPos-10;
                 break;
            case SB_PAGEUP:
                 vsi.nPos = vsi.nPos - vsi.nPage;
                 break;
            case SB_LINEDOWN:
                 if(vsi.nPos<vsi.nMax)
                    vsi.nPos=vsi.nPos+10;
                 break;
            case SB_PAGEDOWN:
                 vsi.nPos = vsi.nPos + vsi.nPage;
                 break;
            case SB_THUMBTRACK:
                 vsi.nPos=vsi.nTrackPos;
                 break;
         }
         vsi.fMask=SIF_POS;
         SetScrollInfo(hWnd,SB_VERT,&vsi,TRUE);
         GetScrollInfo(hWnd, SB_VERT, &vsi);
         if(vsi.nPos != iVScrollPos)
            MoveWindow(hPane,0,-1*vsi.nPos,325,500,TRUE);
         return 0;
      }
    case WM_DESTROY:
      {
         PostQuitMessage(0);
         return 0;
      }
 }

 return (DefWindowProc(hWnd, msg, wParam, lParam));
}


continued...

WinMain() didn't quite fit...


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 char szClassName[]=_T("ScrollControls");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                          wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);                         wc.style=CS_HREDRAW|CS_VREDRAW;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);               wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);            wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  wc.cbWndExtra=8;
 wc.lpszMenuName=NULL;                                  wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW^WS_MAXIMIZEBOX,100,100,350,300,0,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
 }

 return messages.wParam;
}
I can tell you that that code will definitly help! Right now I'm working on just getting everything to look right in the window, then once I get the format figured, I'll be working on the scrolling.
An interesting dilema about that is that it is possible to do without the "pane" class by just using a label control, i.e., "static" for the pane and then moving the label through its "virtual" range within the parent. That saves registering a seperate class for the "pane" and also eliminates the window procedure for the pane. However - here's the kicker - the Submit button is a child of the pane and hence the pane's Window Procedure gets WM_COMMAND messages when the button is clicked. I havn't checked how that would work by emiminating the pane and just using a label as the scrolling pane. The Window Procedure for the label is inside Windows. Granted you could hook (subclass) the label's Window Procedure, and perhaps that way catch clicks on the button. That complexity would pretty much eliminate the simplicity gained though by eliminating the pane class.
Quick question: Where did the 489 in vsi.nMax=489; come from? You said in the comments that the GetClientRect was for that variable, but then you just put a number yourself?

Edit: I noticed that hPane is where that number came from, but if that number is the same (Or actually less) than the pane, wouldn't that make scrolling pointless?
Last edited on
Pages: 12