- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a Quickwin program in which I want to use the mouse to select a region of a data plot to be expanded in a replot. I can do this using a mouse click-and-drag to get and capture the coordinates of the initial and final corner of the selected region, but I want to be able to draw a rectangular "border" around the selected region that changes as the user moves the mouse. This would look similar to the "Select Graphics" option in the default Quickwin Edit menu, but I don't want to actually copy a region, I just want a rectangle that delineates the region selected by the user from which I can extract the coordinates I need.
I'm completely at a loss as how to get started on this.
I'm completely at a loss as how to get started on this.
Link Copied
7 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You need to react to the appropriate mouse events by drawing a box. Possibly a good way would be to register callbacks for left button down, left button up and mouse move, then draw a rectangle with the GDI routine DrawFocusRect and erase the previous rectangle as necessary. Keep a state variable that tells you the selection is in process, and the left mouse button goes up then you have your user selected rectangle.
James
James
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To expand on that: although in general it's not recommended to draw onto QuickWin windows with GDI, you'll be fine as long as you don't mess with WM_PAINT. Here's a fragment from a (Win32) application which does just that; it is located in callback for mouse events. It uses XFTGDI module, which you might find a bit more convenient than pure APIs. Additionally, you'll need GetDC and ReleaseDC to get the handle of the QW's DC. The sample draws the "rubber rectangle" which always keeps aspect ratio (i.e. proportional to main window dimensions). Note use of SetROP2 (equivalent XFT routine is XSetROPMode). Global logical SELECTING is set when selecting is in progress:
Of course, you'll have to adapt it to your needs but I hope it would help.
Jugoslav
INTEGER,SAVE:: iOrigMouseX,iOrigMouseY, &
iPrevXSize,iPrevYSize
TYPE(X_DC):: xMemDC
...
IF (MEvent.EQ.WM_LBUTTONDOWN) THEN
...
!The drawing begins
ELSE IF (SELECTING) THEN
iOrigMouseX=MouseX
iOrigMouseY=MouseY
iPrevXSize=0
iPrevYSize=0
...
ELSE IF (MEVENT.EQ.WM_LBUTTONUP) THEN
...
ELSE IF (SELECTING) THEN
SELECTING=.FALSE.
Do post-processing here
...
!Drawing goes here (on mouse move)
ELSE IF (SELECTING .AND. IAND(Keystate,MK_LBUTTON).NE.0) THEN
!Insert GetDC here
xMemDC%hDC = GetDC(GETHWNDQQ(whatever))
iMode=SetROP2(xMemDC%hDC,R2_XORPEN)
Dotted pen; #3F3F3F is a "magic" color :-)
CALL XSetPen(xMemDC,#3F3F3F,PS_DOT,1)
CALL XSetBrush(xMemDC,0,BS_NULL)
fAspectRatio=REAL(jWidth)/REAL(jHeight)
iXSize=IABS(iOrigMouseX-MouseX)
iYSize=IABS(iOrigMouseY-MouseY)
iXDir=ISIGN(1,MouseX-iOrigMouseX)
iYDir=ISIGN(1,MouseY-iOrigMouseY)
IF (iXSize.LT.iYSize*fAspectRatio) THEN
iXSize=iYSize*fAspectRatio*iXDir
iYSize=iYSize*iYDir
ELSE
iYSize=iXSize/fAspectRatio*iYDir
iXSize=iXSize*iXDir
END IF
!Since we're in XOR ROP mode, the next call will
!erase the previously drawn rectangle
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY, &
iOrigMouseX+iPrevXSize,iOrigMouseY+iPrevYSize)
!Draw the new rectangle on new position
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY, &
iOrigMouseX+iXSize,iOrigMouseY+iYSize)
iSt=SetROP2(xMemDC%hDC,iMode)
iX1=MIN(iOrigMouseX,iOrigMouseX+iPrevXSize,iOrigMouseX+iXSize)-2
iY1=MIN(iOrigMouseY,iOrigMouseY+iPrevYSize,iOrigMouseY+iYSize)-2
iX2=MAX(iOrigMouseX,iOrigMouseX+iPrevXSize,iOrigMouseX+iXSize)+2
iY2=MAX(iOrigMouseY,iOrigMouseY+iPrevYSize,iOrigMouseY+iYSize)+2
iPrevXSize=iXSize
iPrevYSize=iYSize
!Have to ReleaseDC
iSt = ReleaseDC(GETHWNDQQ(whatever), xMemDC%hDC)
Of course, you'll have to adapt it to your needs but I hope it would help.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
THanks, Jugoslav. I modified the text you sent me and downloaded your XFT routines. I am having problems. I am trying to select a region in a child window. I just to need to get the window coordinates of the initial and final points. I call registermouseevents with my callback routine (see below) based on your suggestion. The routine draws a rectangle, but not where I am am moving the mouse. The rectangle is lower and to the right of where the mouse cursor is. I can't find a description of what the coordinates returned by the callback routine are relative: the screen or the active window. Can you see where I went wrong?
Jim
my routine code is as follows:
subroutine selectrect(unit,MEvent,keystate,MouseX,MouseY)
use dflib
use dfwin
use XFTGDI
integer:: unit,MEvent,keystate,MouseX,MouseY,i4,I1,I2,I3
INTEGER,SAVE:: iPrevXSize,iPrevYSize,OldX,OldY
LOGICAL:: SELECTING
TYPE(X_DC):: xMemDC
common/Meventstuff/iOrigMouseX,iOrigMouseY,LastMouseX, &
LastMouseY,icase,SELECTING
IF (MEvent.EQ.1 .AND. SELECTING.EQ. .FALSE.) THEN
!The drawing begins
iOrigMouseX=MouseX
iOrigMouseY=MouseY
OldX = MouseX
OldY = MouseY
SELECTING = .TRUE.
icase = 0
ELSE IF (MEVENT.EQ.2 .and. SELECTING.EQ. .TRUE.) THEN
icase = 1
LastMouseX = MouseX
LastMouseY = MouseY
Selecting = .FALSE.
icase = 1
ELSE IF (SELECTING .AND. mevent.eq.64) THEN
!Insert GetDC here
xMemDC%hDC = GetDC(GETHWNDQQ(61))
iMode=SetROP2(xMemDC%hDC,R2_XORPEN)
!Dotted pen; #3F3F3F is a "magic" color :-)
CALL XSetPen(xMemDC,#3F3F3F,PS_DOT,1)
CALL XSetBrush(xMemDC,0,BS_NULL)
!Since we're in XOR ROP mode, the next call will
!erase the previously drawn rectangle
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY,OldX,OldY)
!Draw the new rectangle on new position
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY,MouseX,MouseY)
iSt=SetROP2(xMemDC%hDC,iMode)
OldX=MouseX
OldY=MouseY
!Have to ReleaseDC
iSt = ReleaseDC(GETHWNDQQ(61), xMemDC%hDC)
ENDIF
END SUBROUTINE selectrect
Jim
my routine code is as follows:
subroutine selectrect(unit,MEvent,keystate,MouseX,MouseY)
use dflib
use dfwin
use XFTGDI
integer:: unit,MEvent,keystate,MouseX,MouseY,i4,I1,I2,I3
INTEGER,SAVE:: iPrevXSize,iPrevYSize,OldX,OldY
LOGICAL:: SELECTING
TYPE(X_DC):: xMemDC
common/Meventstuff/iOrigMouseX,iOrigMouseY,LastMouseX, &
LastMouseY,icase,SELECTING
IF (MEvent.EQ.1 .AND. SELECTING.EQ. .FALSE.) THEN
!The drawing begins
iOrigMouseX=MouseX
iOrigMouseY=MouseY
OldX = MouseX
OldY = MouseY
SELECTING = .TRUE.
icase = 0
ELSE IF (MEVENT.EQ.2 .and. SELECTING.EQ. .TRUE.) THEN
icase = 1
LastMouseX = MouseX
LastMouseY = MouseY
Selecting = .FALSE.
icase = 1
ELSE IF (SELECTING .AND. mevent.eq.64) THEN
!Insert GetDC here
xMemDC%hDC = GetDC(GETHWNDQQ(61))
iMode=SetROP2(xMemDC%hDC,R2_XORPEN)
!Dotted pen; #3F3F3F is a "magic" color :-)
CALL XSetPen(xMemDC,#3F3F3F,PS_DOT,1)
CALL XSetBrush(xMemDC,0,BS_NULL)
!Since we're in XOR ROP mode, the next call will
!erase the previously drawn rectangle
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY,OldX,OldY)
!Draw the new rectangle on new position
iSt=XRectangle(xMemDC,iOrigMouseX,iOrigMouseY,MouseX,MouseY)
iSt=SetROP2(xMemDC%hDC,iMode)
OldX=MouseX
OldY=MouseY
!Have to ReleaseDC
iSt = ReleaseDC(GETHWNDQQ(61), xMemDC%hDC)
ENDIF
END SUBROUTINE selectrect
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hmmm, I think it should work. What you describe indeed looks like coordinate system offset, but as far as I know the mouse callback receives QW physical coordinates (origin in upper left client area corner) while XRectangle operates on XFT viewport coordinates (whose default origins are in the same upper left area corner).
GetDC is supposed to return DC whose origin is also at that point. I ommitted the call to XSetViewport from my post (call XSetViewport(xMemDC,0,0,1000,1000)) but that's probably not a problem since it is supposed to be zero-initialized anyway.
As a test 1, add a call to ordinary RECTANGLE() -- it is supposed to give the same result as XRectangle (except that it's gonna leave garbage on the screen). Does it produce the same results as XRectangle?
As a test 2, draw a fixed XRectangle at (0,0,anything,anything) -- where is the upper left corner?
BTW, you should really use .EQV. operator when comparing logicals, not .EQ.
Jugoslav
GetDC is supposed to return DC whose origin is also at that point. I ommitted the call to XSetViewport from my post (call XSetViewport(xMemDC,0,0,1000,1000)) but that's probably not a problem since it is supposed to be zero-initialized anyway.
As a test 1, add a call to ordinary RECTANGLE() -- it is supposed to give the same result as XRectangle (except that it's gonna leave garbage on the screen). Does it produce the same results as XRectangle?
As a test 2, draw a fixed XRectangle at (0,0,anything,anything) -- where is the upper left corner?
BTW, you should really use .EQV. operator when comparing logicals, not .EQ.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jugoslav
I've narrowed down the circumstances in which the rectangle drawing fails. My graphics window is larger than the screen. If I don't scroll the window, the rectangle is drawn where it's supposed to be. If I scroll to the bottom left, the rectangle is offset by about the amount I scrolled in the x and y directions. If I only scroll down in the y direction, but not in x the rectangle is drawn offset only in the y direction.
I tried your first suggested test, adding RECTANGLE to my
selectrect routine. When I scrolled the graphics window, the normal RECTANGLE drew rectangles in the correct location, but XRECTANGLE was still offset. I didn't try your second test.
Here is a simple driver program that I used to test selectrect. It simulates the way I call the graphics window in my main application.
PROGRAM DRIVER
USE DFLIB
type (qwinfo) winfo
type (wxycoord) xy
type (windowconfig) wg
TYPE (qwinfo) qwg
EXTERNAL selectrect
INTEGER I1,I2,Ievnt(5),event
integer*4 xmax, ymax
integer*2 status,x,y,res
integer result,ierr,x2,y2,i4,i3,iGU
integer icase,iOrigMouseX,iOrigMouseY,LastMouseX,LastMouseY
LOGICAL SELECTING
common /reslt/i1,i2
common/Meventstuff/iOrigMouseX,iOrigMouseY,LastMouseX,
+ LastMouseY,icase,SELECTING
SELECTING = .FALSE.
event = MOUSE$LBUTTONDOWN
event = IOR (event, MOUSE$LBUTTONUP)
event = IOR (event, MOUSE$MOVE)
xmax = 750
ymax = 500
winfo%type = QWIN$MAX
winfo%x = 100
winfo%y = 100
winfo%h = 60
winfo%w = 115
retval = SETWSIZEQQ(81,winfo)
ICASE = 0
iGU = 61
IEVNT(1) = MOUSE$LBUTTONDOWN
IEVNT(2) = MOUSE$LBUTTONUP
IEVNT(3) = MOUSE$MOVE
IEVNT(4) = MOUSE$BADUNIT
IEVNT(5) = MOUSE$BADEVENT
OPEN(UNIT=61,FILE='USER',TITLE='GRAPH')
wg.numxpixels= xmax
wg.numypixels= ymax
wg.numtextcols=-1
wg.numtextrows=-1
wg.mode = QWIN$SCROLLDOWN
wg.title='Case Graphics'C
lstatus=setwindowconfig(wg)
lstatus=setwindowconfig(wg)
lstatus=getwindowconfig(wg)
qwg.type=QWIN$SET
qwg.x=0
qwg.y=0
qwg.w= -1
qwg.h=-1
ires=setwsizeqq(iGU,qwg)
xcms = xmax * 1.15
ycms = ymax * 1.15
c xcms = xmax
c ycms = ymax
ires=setwindow(.true.,0.,0.,xcms,ycms)
retval = setactiveqq(61)
I1 = FOCUSQQ(61)
CALL CLEARSCREEN($GCLEARSCREEN)
c call setviewport(0,ymax+50,xmax+50,0)
style = #FFFF
CALL SETLINESTYLE(style)
c retVal=SETWINDOW(.true.,0,ymax,xmax,0)
i2 = SETCOLOR(0)
i2 = SETTEXTCOLOR(0)
retval = setfont("t'Arial'h14pe")
i2 = setcolor(2)
call moveto_w(dble(45),dble(50),xy)
status = lineto_w(55,50)
call moveto_w(dble(50),dble(45),xy)
status = lineto_w(50,55)
call moveto_w(dble(145),dble(150),xy)
status = lineto_w(155,150)
call moveto_w(dble(150),dble(145),xy)
status = lineto_w(150,155)
I2 = 0
I = 0
do while (icase .eq. 0)
i4 = registermouseevent(iGU,event,selectrect)
enddo
END
I've narrowed down the circumstances in which the rectangle drawing fails. My graphics window is larger than the screen. If I don't scroll the window, the rectangle is drawn where it's supposed to be. If I scroll to the bottom left, the rectangle is offset by about the amount I scrolled in the x and y directions. If I only scroll down in the y direction, but not in x the rectangle is drawn offset only in the y direction.
I tried your first suggested test, adding RECTANGLE to my
selectrect routine. When I scrolled the graphics window, the normal RECTANGLE drew rectangles in the correct location, but XRECTANGLE was still offset. I didn't try your second test.
Here is a simple driver program that I used to test selectrect. It simulates the way I call the graphics window in my main application.
PROGRAM DRIVER
USE DFLIB
type (qwinfo) winfo
type (wxycoord) xy
type (windowconfig) wg
TYPE (qwinfo) qwg
EXTERNAL selectrect
INTEGER I1,I2,Ievnt(5),event
integer*4 xmax, ymax
integer*2 status,x,y,res
integer result,ierr,x2,y2,i4,i3,iGU
integer icase,iOrigMouseX,iOrigMouseY,LastMouseX,LastMouseY
LOGICAL SELECTING
common /reslt/i1,i2
common/Meventstuff/iOrigMouseX,iOrigMouseY,LastMouseX,
+ LastMouseY,icase,SELECTING
SELECTING = .FALSE.
event = MOUSE$LBUTTONDOWN
event = IOR (event, MOUSE$LBUTTONUP)
event = IOR (event, MOUSE$MOVE)
xmax = 750
ymax = 500
winfo%type = QWIN$MAX
winfo%x = 100
winfo%y = 100
winfo%h = 60
winfo%w = 115
retval = SETWSIZEQQ(81,winfo)
ICASE = 0
iGU = 61
IEVNT(1) = MOUSE$LBUTTONDOWN
IEVNT(2) = MOUSE$LBUTTONUP
IEVNT(3) = MOUSE$MOVE
IEVNT(4) = MOUSE$BADUNIT
IEVNT(5) = MOUSE$BADEVENT
OPEN(UNIT=61,FILE='USER',TITLE='GRAPH')
wg.numxpixels= xmax
wg.numypixels= ymax
wg.numtextcols=-1
wg.numtextrows=-1
wg.mode = QWIN$SCROLLDOWN
wg.title='Case Graphics'C
lstatus=setwindowconfig(wg)
lstatus=setwindowconfig(wg)
lstatus=getwindowconfig(wg)
qwg.type=QWIN$SET
qwg.x=0
qwg.y=0
qwg.w= -1
qwg.h=-1
ires=setwsizeqq(iGU,qwg)
xcms = xmax * 1.15
ycms = ymax * 1.15
c xcms = xmax
c ycms = ymax
ires=setwindow(.true.,0.,0.,xcms,ycms)
retval = setactiveqq(61)
I1 = FOCUSQQ(61)
CALL CLEARSCREEN($GCLEARSCREEN)
c call setviewport(0,ymax+50,xmax+50,0)
style = #FFFF
CALL SETLINESTYLE(style)
c retVal=SETWINDOW(.true.,0,ymax,xmax,0)
i2 = SETCOLOR(0)
i2 = SETTEXTCOLOR(0)
retval = setfont("t'Arial'h14pe")
i2 = setcolor(2)
call moveto_w(dble(45),dble(50),xy)
status = lineto_w(55,50)
call moveto_w(dble(50),dble(45),xy)
status = lineto_w(50,55)
call moveto_w(dble(145),dble(150),xy)
status = lineto_w(155,150)
call moveto_w(dble(150),dble(145),xy)
status = lineto_w(150,155)
I2 = 0
I = 0
do while (icase .eq. 0)
i4 = registermouseevent(iGU,event,selectrect)
enddo
END
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ignorant as I am but I intend to learn a thing or two from this post regards graphics applications as I am also trying to develop one.
One thing that I noticed though was
calls to lineto_W() should have real*8 arguments. So need to use double as in moveto_W.
Also I noticed that when I set my screen to max resolution (... =-1 etc) and then call SETWINDOW, I have to increase the limit boundaries so that everything fits (scales down) in my child window. Otherwise I need to scroll right and down to see the entire graphics (which is a big pain). It does not automatically scale to the limits of my child window.
Thanks
One thing that I noticed though was
calls to lineto_W() should have real*8 arguments. So need to use double as in moveto_W.
Also I noticed that when I set my screen to max resolution (... =-1 etc) and then call SETWINDOW, I have to increase the limit boundaries so that everything fits (scales down) in my child window. Otherwise I need to scroll right and down to see the entire graphics (which is a big pain). It does not automatically scale to the limits of my child window.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, yes, scrolling, I forgot about that. When the scrollbar is present, you get mouse coordinates with offset to location of client area's upper left corner, while GetDC always returns the canvas which becomes there.
You should subtract offsets received from GetScrollPos(GETHWNDQQ(61), SB_HORZ) [and SB_VERT] in the call to XRectangle. Then everything should be OK. Alternatively, you could move the XFT viewport:
In this way, XFT and QuickWin coordinate systems will be identical.
Jugoslav
You should subtract offsets received from GetScrollPos(GETHWNDQQ(61), SB_HORZ) [and SB_VERT] in the call to XRectangle. Then everything should be OK. Alternatively, you could move the XFT viewport:
USE DFWIN ... xDC%hDC = GetDC(... iXOffset = GetScrollPos(GETHWNDQQ(61), SB_HORZ) iYOffset = GetScrollPos(GETHWNDQQ(61), SB_VERT) CALL XSetViewport(xDC, -iXOffset, -iYOffset, 1000, 1000) ...
In this way, XFT and QuickWin coordinate systems will be identical.
Jugoslav
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page