Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Scrolling Window

rtsmith
Beginner
584 Views
Further to my previous attempts to get my scrolling window working with help from members of this forum, I am still having problems. Jugoslav gave me a very helpful method using an edit window in my dialog box and I got this working fine. Unfortunately, as I developed the operating code around it, I realised that I needed to have the scrolling window separate from the dialog box. I was earlier given some code to enable me to use the scrolling window, but I had trouble implementing it, even though I understood its main functionality.
So I have cut my program down to a very simple operation.
I have copied a standard winmain program and am calling dlgmodal to put up my dialog box. I have set callbacks to dlg_ok and dlg_cancel, the only 2 buttons on display.
When I click OK it goes to dlg_ok to open a scrolling window, write 30 lines to it and then call asexit to ask if it is OK.
There are 2 problems. If someone could spare a few minutes, with all your experience of programming in windows Fortran (of which I have very little), could you correct my code to make it work. These are the 2 problems I cannot resolve.
1. The scrolling window will not scroll. I can write to it, but when it hits the bottom, it carries on out of view. I do know there is code in function textproc which can do it, but it needs access to WM_CREATE and WM_PAINT and I am not sure how to handle these. The code in the CASE sections has been commented out at the moment.
2. When the 30 lines have been written to the scrolling window, it goes straight to subroutine asexit. In this there is a call to messagebox to ask if all is OK. The message box will not appear until I click X to clear the scrolling window. I need to have the message box appearing on top of the scrolling window to await a reply with the scrolling window in view under the message box.
If someone could correct my code, I would be most grateful. I have made it as simple as possible.
The attached file z.zip contains z.f (all the fortran in one file), script1.rc (the dialog box), resource.h (for script1.rc) and z.dsp (to build the program). I have put the contents of resource.fd directly into the code to save another file.
Thank you very much.
0 Kudos
6 Replies
anthonyrichards
New Contributor III
584 Views
If you add
res = DefWindowProc (hWnd, msg, wParam, lParam)
at the end of the commented-out WM_PAINT code, the message box appears.
0 Kudos
rtsmith
Beginner
584 Views
Anthony.
Thanks for the help. I have added the DefWindowProc as suggested and I now get the closing messagebox appearing when the scrolling window completes. I have been able to follow your original notes on how to access the WM_PAINT code from a sendmessage and have used this along with my scroll subroutine to send a print request to the scrolling window. This is now accessing the WM_PAINT section of the CASE to request a print into the scrolling window.
In this development, I wanted to start the writing to the window from the top and then to continue to write a new line below the last. When I hit the bottom of the window, I wanted the window to scroll up a line and then the latest line to be printed. I then wanted to be able to scroll back old listed lines.
I have hit a problem which I cannot overcome. This is the code I have used.
iret = GetClientRect (hwnd, crect)
hdc = BeginPaint (hwnd, ps)
iret = SelectObject (hdc, textfont)
iret = SetBkMode (hdc, OPAQUE)
iret = SetTextAlign (hdc, IOR(TA_LEFT, TA_TOP))
c**** count lines (saved variable)
nlines = nlines + 1
c**** how many lines will the window take
numlin = crect%bottom / cychar
c**** a little left margin
xpos = ps%rcPaint%left + 4
if(nlines.le.numlin) then
c**** print one line below another
ypos = (nlines-1) * cychar
else
c**** when the rest works, I'll worry about scrolling here
ypos = numlin * cychar
endif
c**** display colors
bk_color = rgb(255,255,255)
iret = MSFWIN$SetBkColor (hdc, bk_color)
fg_color = rgb(0,0,0)
iret = MSFWIN$SetTextColor (hdc, fg_color)
nprint = LEN_TRIM(prline)
iret = TextOut (hdc, xpos, ypos, prline, nprint)
c**** clean up
iret = EndPaint (hwnd, ps)
res = defwindowproc(hwnd,msg,wparam,lparam)
You will recognise most of this.
This is what it should produce:
22:04 RESTART STAGE 0 COMPLETED
22:04 RESTART STAGE 1 COMPLETED
22:04 RESTART STAGE 2 COMPLETED
22:04 RESTART STAGE 3 COMPLETED
22:04 RESTART STAGE 4 COMPLETED
22:04 RESTART STAGE 5 COMPLETED
22:04 RESTART STAGE 6 COMPLETED
22:04 RESTART STAGE 9 COMPLETED
22:04 SECTION 1 COMPLETED
22:04 RESTART STAGE 10 COMPLETED
22:04 SECTION 1 COMPLETED
22:04 RESTART STAGE 11 COMPLETED
22:04 SECTION 1 COMPLETED
22:04 RESTART STAGE 12 COMPLETED
22:04 RESTART STAGE 16 COMPLETED
22:04 RESTART STAGE 17 COMPLETED
22:04 RESTART STAGE 20 COMPLETED
22:04 RESTART STAGE 21 COMPLETED
22:04 THERE WERE 0 WARNINGS AND 0 ERRORS
BUT, I only get the first line at the top of the window. The YPOS value does increase as NLINES increments, but the rest of the lines are not printed. I have tried playing with the code, but I cannot get the rest of the lines to list. I have set CYCHAR from values of 10 to 100 but it does not help. (I have not got a routine FONTSIZES to determine the font height so have used an arbitrary value).
Can you shed any light on this problem please?
0 Kudos
Jugoslav_Dujic
Valued Contributor II
584 Views
I didn't have time to take a look at the rest of the code, but I can see two problems immediately:
1) WM_PAINT handling is supposed to redraw contents of the window. DefWindowProc on WM_PAINT merely fills in the update rectangle with the brush defined in WNDCLASS%hbrBackground. So, if youreally do something on WM_PAINT (at least BeginPaint+EndPaint), you should not call DefWindowProc on the end; it could easily erase your previous work.
2) Since WM_PAINT can be called almost arbitrarily by the system (it is called whenever (a portion of) the window is revealedfor any reason), you must not place any coding logic within its handling. Namely, you should not have:
c**** count lines (saved variable)
nlines = nlines + 1
Since you cannot predict when WM_PAINT will be called, such code has always be split into two parts:
a) the part which updates the "document", i.e. some internal data structure
b) on WM_PAINT, you should just "render" the document above onto the given hDC.
Part "a)" has to occur whenever you want to update your window appearance, e.g (simplified):
module drawing
integer, save:: nLines
character(60), save:: sLines(max_Lines)
end module drawing
subroutine AddLine(text)
use drawing
nLines = nLines + 1
sLines(nLines) = text
iret = InvalidateRect(hWnd, NULL, .FALSE.)
end subroutine AddLine
On part "b)" you just develop the logic to visualize your data structure:
integer function MyWindowProc(...)
use drawing
....
use drawing
case (WM_PAINT)
hDC = BeginPaint(...)
ypos = 0
do i=1,nLines
ypos = ypos + cychar
ret = MSFWIN$TextOut(hDC, xpos, ypos, sLine(i), len_trim(sLine(i)))
end do
ret = EndPaint(...)
In other words, on WM_PAINT you have to just draw all that you have to draw. InvalidateRect API is the missing chain -- it will force the WM_PAINT to be generated, i.e. it will cause the window to redraw when you update your data structure (in this case, nLines and sLines(:)).
A good test whether you imple mented painting correctly is to show and hide your window several times (e.g. via Alt+Tab) and check if it keeps appearing correctly.
HTH
Jugoslav
0 Kudos
anthonyrichards
New Contributor III
584 Views
I bow to Jugoslav's much greater experience here. The question remaining is why does the message box not appear when the WM_PAINT case arises and res=1 (or res=0) is returned? I find that if you comment out CASE(WM_PAINT) i.e. do not deal with it at all, then default handling by DefWindowProc takes place and the message box appears. What is preventing the message box from appearing otherwise?
0 Kudos
Jugoslav_Dujic
Valued Contributor II
584 Views
To Tony:
short answer: I don't know :-)
long answer: I played a bit with Richard's code and Winspector spy. I concluded that the message box never gets a ShowWindow(SW_SHOW) for itself. The real answer is burried somewhere in MessageBox's message loop (since it's a modal dialog, it has a message loop of its own) -- it probably waits to reach an "idle" state (no messages in the queue, i.e. GetMessage() does not generate WM_PAINT) before it shows itself; since GetMessage always generates a WM_PAINT (there's no code to validate the window), it waits infinitely. I modified the code slightly to read:
Code:
case(WM_PAINT)
   count = count+1
   if (count.gt.1000000) then
      res = DefWindowProc (hWnd, msg, wParam, lParam)
   else
      res = 1
   end if
i.e. after a million tries, it will finally obey (that last about acouple ofseconds on my computer) and voila, the message box shows up :-).
to all:
I created a sample workspace for Richard (sent via private correspondence) demonstrating a proper do-it-yourself logging (use WM_PAINT, handle scrollbar, store the strings in an array -- a linked list would be better but more complicated). It is attached, in case someone can make use of it.
Jugoslav
0 Kudos
rtsmith
Beginner
584 Views
I am still struggling with this scrolling window. I now understand the comment Jugoslav has made (Private email) about having to store the window contents and to display it each time I come to a WM_PAINT. I now have this part working, but am still having a problem displaying the scrolled information.
In the example I am using, I want to display 3 different lines. I enter the WM_PAINT clause and TEXTOUT the first line to the top of the window. Fine. I enter WM_PAINT again with the second line. The first line is in my internal buffer, now with the second line. I TEXTOUT two lines, one below the other. I then do the same with 3 lines. BUT, when I run the program, only the first line displays. BUT, if I put a break-point in the WM_PAINT clause to check that it is working satisfactorily, run to the third entry and then clear the break-point and run to completion, the 3 lines appear in the window.
There obviously seems to be something to do with the interaction between my scrolling window and my moving over to the debug code window.
Jugoslav made a comment about using InvalidateRect. I have tried using this (because it seems that I need it to repaint what has been produced), but I am not sure where to put it. I tried in the WM_PAINT clause, but the window scrolled perpetually, and this makes sense reading the description in the help system.
Is InvalidateRect the answer to my problem, and if so, where should it go?
Or is there another solution?
This is my WM_PAINT clause
CASE (WM_PAINT)
hdc = BeginPaint (hwnd, ps)
iret = SelectObject (hdc, textfont) ! textfont generated earlier
ipos = 0
xpos = 0
ypos = 0
cy = 16
do i = 1,nrows
iret = lstrcpyn(loc(prline),matpos+ipos,133)
prline(133:133) = ' '
nprint = LEN_TRIM(prline)
iret = TextOut (hdc, xpos, ypos, prline, nprint)
ipos = ipos + 132
ypos = ypos + cy
enddo
iret = EndPaint (hwnd, ps)
0 Kudos
Reply