Announcement

Collapse
No announcement yet.

Center common dialog on dual display

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Center common dialog on dual display

    I usualy use either SetWindowPos or MoveWindow to center a common dialog from a dialog hook procedure (during the %WM_NOTIFY message), and everything works fine except when trying to center on the second monitor in dual display mode.

    Do you have any suggestion that will work to center a common dialog on the second display?

    ...
    Patrice Terrier
    www.zapsolution.com
    www.objreader.com
    Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

  • #2
    I once started working on a solution to this one--until the caffeine hit
    and I realized that any display on a second monitor would occur only if
    the user chose to display something on a monitor other than the primary.
    So I just centered dialogs on the window, not the monitor (with shifting
    into view if the window had been shoved partly off screen). I've pretty
    much stayed with this approach ever since.

    Of course, if you're working on display of something that spans
    monitors, this issue is more complicated. Is that what you're doing?

    Comment


    • #3
      Patrice, since you are one that usually shares and do not ask often, I can kinda see what you mean when wanting to "Center On Screen"

      In this case do you mean to center across screens? or center depending on the screen that the dialog is shown?
      I assume the latter and from my limited experience centering usually caters to center on monitor (but does not take into account if the user has more than one monitor)
      Engineer's Motto: If it aint broke take it apart and fix it

      "If at 1st you don't succeed... call it version 1.0"

      "Half of Programming is coding"....."The other 90% is DEBUGGING"

      "Document my code????" .... "WHYYY??? do you think they call it CODE? "

      Comment


      • #4
        Cliff, Greg,

        See my post there:
        http://www.powerbasic.com/support/pb...ad.php?t=34949

        I was in the hope than, since i posted the same question one year ago, things could have evolved and somebody found an answer.

        Here is the code i am using , it works well with a one single monitor, but fails on the second monitor in dual display.

        Code:
        ' Dialog hook procedure, for centering the dialog and
        ' increasing height of filetype combo (to avoid tiny scrollbuttons)
        FUNCTION zDlgHookProc(BYVAL hWnd&, BYVAL Msg&, BYVAL wParam&, BYVAL lParam&) AS LONG
        
            LOCAL rw AS RECT, rc AS RECT, ofnPtr AS OFNOTIFY PTR, zTxt AS ASCIIZ * %MAX_PATH
            LOCAL lp    AS POINTAPI
        
            STATIC hWndPreview&, SquareSize&
        
            SELECT CASE LONG Msg&
        
            CASE %WM_NOTIFY
                 ofnPtr = lParam&
                 SELECT CASE LONG @ofnPtr.hdr.Code
        
                 CASE %CDN_INITDONE
        
                      hParent& = GetParent(hWnd&)
        
                      hSysListView& = GetDlgItem(hParent&, %lst1)
        
                      CALL GetWindowRect(hSysListView&, rw)
                      lp.X = rw.nLeft: lp.Y = rw.nTop: CALL ScreenToClient(hParent&, lp) ' 11-03-2003
                      yPos& = lp.Y
                      SquareSize& = rw.nBottom - rw.nTop
                      IF GetSystemMetrics(%SM_CXSCREEN) < 801 THEN
                         SquareSize& = MIN&(150, SquareSize&)
                      END IF
        
                      CALL GetClientRect(hParent&, rc)       ' Get dialog pos. and size
                      xPos& = rc.nRight                      ' New width
        
                      Style& = %WS_CHILD OR %WS_VISIBLE ' OR %WS_BORDER
                      StyleEx& = %WS_EX_STATICEDGE
                      hWndPreview& = CreateWindowEx(StyleEx&, $GDImageClassName, _
                                         "", _               ' Optional full path name to picture
                                         Style&, _
                                         xPos&, yPos&, SquareSize&, SquareSize&, _
                                         hParent&, _
                                         %NULL, _
                                         zInstance,_
                                         BYVAL 0)                 ' creation parameters
                      CALL ZI_SetProperty(hWndPreview&, %ZI_GradientTop, GetSysColor(%COLOR_BTNSHADOW))
                      CALL ZI_SetProperty(hWndPreview&, %ZI_GradientBottom, GetSysColor(%COLOR_BTNSHADOW))
                      CALL ZI_SetProperty(hWndPreview&, %ZI_FitToWindow, %ZI_QualityDefault)
        
                    ' Set new size and center dialog in program window
                      CALL GetWindowRect(GetParent(hParent&), rc)     ' Get program pos. and size
                      W& = rc.nRight  - rc.nLeft
                      H& = rc.nBottom - rc.nTop
                      x& = rc.nLeft + (W& \ 2)                        ' Relative Center x&
                      y& = rc.nTop  + (H& \ 2)                        ' Relative Center y&
        
                      CALL GetWindowRect(hParent&, rc)                ' Get dialog pos. and size
                      W& = rc.nRight  - rc.nLeft + SquareSize& + 7    ' New width
                      H& = rc.nBottom - rc.nTop                       ' Same height
                      x& = x& - (W& \ 2)                              ' Centered in program
                      y& = y& - (H& \ 2)
        
        '              hDC& = GetDC(0)                                 ' Make sure it's on screen
        '              IF x& < 0 THEN x& = 0
        '              IF x& + W& > GetDeviceCaps(hDC&, %HORZRES) THEN x& = GetDeviceCaps(hDC&, %HORZRES) - W&
        '              IF y& < 0 THEN y& = 0
        '              IF y& + H& > GetDeviceCaps(hDC&, %VERTRES) THEN y& = GetDeviceCaps(hDC&, %VERTRES) - H&
        '              ReleaseDC 0, hDC&
        
                      CALL SetWindowPos(hParent&, hParent&, x&, y&, W&, H&, %SWP_NOZORDER) ' Resize and center
                      'CALL MoveWindow(hParent&, x&, y&, W&, H&, 0) ' Resize and center
        
                    ' INCREASE HEIGHT OF DROPPED LIST IN FILETYPE COMBO (AUTO-ADJUSTS TO ITEM COUNT)
                      hftCombo& = GetDlgItem(hParent&, %cmb1)         ' handle, Filetype combo
                      IF hftCombo& THEN                               ' if we get handle
                         CALL GetClientRect(hftCombo&, rc)            ' get combo's width and set new height
                         CALL SetWindowPos(hftCombo&, %NULL, 0, 0, rc.nRight, 200, %SWP_NOMOVE OR %SWP_NOZORDER)
                      END IF
        
                      FUNCTION = 1: EXIT FUNCTION
        
                 CASE %CDN_SELCHANGE ' Triggered when the selection changes in the file listbox
                      picFileName$ = SPACE$(%MAX_PATH)
                      df& = Sendmessage(@ofnPtr.hdr.hwndFrom, %CDM_GETFILEPATH, LEN(picFileName$), STRPTR(picFileName$))
                      IF df& > 0 THEN
                         picFileName$ = LEFT$(picFileName$, df& - 1)
                         So& = INSTR(-1, picFileName$, $Dot)
                         IF So& THEN
                            ImgType$ = UCASE$(MID$(picFileName$, So&)) + $Dot
                            ImageType& = INSTR($GDIPLUSEXT, ImgType$)
                            IF ImageType& THEN
        
                               NewImage& = zLoadImageFromFile((picFileName$), bmW&, bmH&, 0)
                               IF zSetGdipImageHandle(hWndPreview&, NewImage&) THEN CALL ZI_UpdateWindow(hWndPreview&, %TRUE)
        
                            END IF
                         END IF
        '
                      END IF
                      picFileName$ = ""
        
                 CASE %CDN_TYPECHANGE
                    ' Standard Save dialog blindly adds new extension, this changes it properly instead
                      IF @[email protected] < 5 THEN             ' ignore last one, *.*
                         hftCombo& = GetDlgItem(GetParent(hWnd&), %cmb1)  ' handle, File type combo
                         IF zOsVersion < 500 THEN ID& = %edt1 ELSE ID& = %cmb13
                         hftEdit&  = GetDlgItem(GetParent(hWnd&), ID&)    ' handle, File name text field
                         CALL GetWindowText(hftEdit&, zTxt, SIZEOF(zTxt)) ' get name in text field
                         IF LEN(zTxt) THEN                                ' if we have something
                            lRes& = INSTR(-1, zTxt, $Dot)                 ' look for prefix (file type part)
                            IF lRes& THEN zTxt = LEFT$(zTxt, lRes& - 1)   ' if success, remove prefix
                            SELECT CASE LONG @[email protected]  ' compare selection against combo list
                            CASE 1: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 1)) ' ".png"                  ' and add matching prefix
                            CASE 2: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 2)) ' ".jpg"
                            CASE 3: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 3)) ' ".bmp"
                            CASE 4: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 4)) ' ".tif"
                            CASE 5: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 5)) ' ".gif"
                            CASE 6: zTxt = zTxt + $Dot + LCASE$(PARSE$(cfgStr$(40), 6)) ' ".zmi"
                            END SELECT
                            CALL SetWindowText(hftEdit&, zTxt)            ' set corrected name to text field
                        END IF
                     END IF
                 END SELECT
        
            CASE %WM_DESTROY ' Destroy what we have created to avoid nasty memory leaks
        
            END SELECT
        
        END FUNCTION
        Patrice Terrier
        www.zapsolution.com
        www.objreader.com
        Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

        Comment


        • #5
          I am too busy to create a demo, but the following is a partial text of an email
          I sent to a user of Phoenix.

          For example, to get the monitor your control is on and its 'workarea'
          Code:
              hMonitor = MonitorFromWindow(hWnd, %MONITOR_DEFAULTTONEAREST)
              IF GetMonitorRect(hMonitor, %MONITOR_AREA OR %MONITOR_SCREEN, trcWork) THEN
          Some useful Urls(ordered most to least helpful)

          http://www.flounder.com/virtual_screen_coordinates.htm
          http://msdn.microsoft.com/en-us/library/ms534610.aspx
          http://www.vbaccelerator.com/home/Vb...rs/article.asp
          http://support.microsoft.com/kb/194578

          Code:
          '-----------------------------------------------------------------------------------
          ' BEGIN ROUTINES FOR WORKING WITH MULTIPLE MONITORS
          '-----------------------------------------------------------------------------------
          
          %MONITOR_AREA       = &H0000??          ' use monitor entire area
          %MONITOR_WORKAREA   = &H0002??          ' use monitor work area
          
          %MONITOR_SCREEN     = &H0008??          ' screen coordinates
          %MONITOR_VIRTUAL    = &H0010??          ' virtual coordinates
          
          TYPE MONITORDATA
            hMonitor    AS DWORD
            trcWork     AS RECT
            trcMonitor  AS RECT
            fPrimary    AS LONG
          END TYPE
          
          TYPE MONITORS
            cMonitors   AS LONG
            xMap        AS INTEGER
            yMap        AS INTEGER
            ptmd        AS MONITORDATA PTR
          END TYPE
          
          '----------------------------------------------------------------------
          '
          ' FUNCTION: CopyData(LONG, LONG, LONG)
          ' PURPOSE:  Copies data for source to destination.
          ' NOTES:
          ' RETURNS:
          '
          '----------------------------------------------------------------------
          
          FUNCTION CopyData ALIAS "CopyData" _
            ( _
              BYVAL lpSrc   AS LONG, _  ' Address of structure to copy from
              BYVAL lpDest  AS LONG, _  ' Address of structure to copy to
              BYVAL cblCopy AS LONG _   ' Count of bytes to copy
            ) EXPORT        AS LONG
          
            ! cld                             ; read/write forward
            ! mov ecx, cblCopy                ; put count of bytes to copy in counter
            ! mov esi, lpSrc                  ; put source address in source index
            ! mov edi, lpDest                 ; put destination address in destination index
            ! rep movsb                       ; repeat move byte from esi to edi until ecx is zero
          
          END FUNCTION
          
          ' Dual-monitor system example.
          ' (The number of monitors is immaterial)
          ' scr  = screen coordinates
          ' virt = virtual coordinates
          '
          '  scr(-1280,0) virt(0,0)    scr(0,0) virt(1280,0)    scr(1920,0) virt(3200,0)
          '            |                        |                        |
          '            +------------------------+------------------------+
          '            |  /|\                   |  /|\                   |
          '            |   |                    |   |                    |
          '            |   |                    |   |                    |
          '            |<---------1280--------->|<---------1920--------->|
          '            |   |                    |   |                    |
          '            |   |                    |   |                    |
          '            | 1024                   | 1200    primary        |
          '            |   |                    |   |                    |
          '            |   |                    |   |                    |
          '            |   |                    |   |                    |
          '            +------------------------|   |                    |
          '            |                        |  \|/                   |
          '            +------------------------+------------------------+
          '                                                  scr(1920,1200) virt(3200,1200)
          
          '----------------------------------------------------------------------
          '
          ' PROCEDURE: HeapSortMonitors
          '	PURPOSE:   Sorts a monitor table in ascending order using HeapSort.
          '            The entries are sorted on the x or y coordinate of the
          '            upper left corner of the trcWork member.
          '            The table MUST be zero-based.
          '
          '----------------------------------------------------------------------
          
          SUB HeapSortMonitors ALIAS "HeapSortMonitors" _
            ( _
            BYVAL ptmd  AS MONITORDATA PTR, _
            BYVAL N     AS LONG, _
            BYVAL fVert AS LONG _
            ) EXPORT
          
            LOCAL tmd   AS MONITORDATA
            LOCAL I     AS LONG
            LOCAL J     AS LONG
            LOCAL L     AS LONG
            LOCAL IR    AS LONG
          
            IF N <= 1 THEN EXIT SUB
          
            ' Skip heaps with size 1
            L  = N \ 2
            IR = N - 1
          
            DO
              IF L > 0 THEN
                DECR L
                CopyData VARPTR(@ptmd[L]), VARPTR(tmd), SIZEOF(tmd)
              ELSE
                CopyData VARPTR(@ptmd[IR]), VARPTR(tmd), SIZEOF(tmd)
                CopyData VARPTR(@ptmd[0]), VARPTR(@ptmd[IR]), SIZEOF(tmd)
                DECR IR
                IF IR = 0 THEN
                  CopyData VARPTR(tmd), VARPTR(@ptmd[0]), SIZEOF(tmd)
                  EXIT SUB
                END IF
              END IF
              I = L
              J = L + L + 1
          
              WHILE J <= IR
                IF J < IR THEN
                  IF fVert THEN
                    IF @ptmd[J].trcWork.nTop < @ptmd[J + 1].trcWork.nTop THEN
                      INCR J
                    END IF
                  ELSE
                    IF @ptmd[J].trcWork.nLeft < @ptmd[J + 1].trcWork.nLeft THEN
                      INCR J
                    END IF
                  END IF
                END IF
                IF fVert THEN
                  IF tmd.trcWork.nTop < @ptmd[J].trcWork.nTop THEN
                    CopyData VARPTR(@ptmd[J]), VARPTR(@ptmd[I]), SIZEOF(tmd)
                    I = J
                    J = J + J + 1
                  ELSE
                    J = IR + 1
                  END IF
                ELSE
                  IF tmd.trcWork.nLeft < @ptmd[J].trcWork.nLeft THEN
                    CopyData VARPTR(@ptmd[J]), VARPTR(@ptmd[I]), SIZEOF(tmd)
                    I = J
                    J = J + J + 1
                  ELSE
                    J = IR + 1
                  END IF
                END IF
              WEND
          
              CopyData VARPTR(tmd), VARPTR(@ptmd[I]), SIZEOF(tmd)
            LOOP
          
          END SUB
          
          '-------------------------------------------------------------------------------
          '
          ' PROCEDURE: MonitorCountEnumProc
          ' PURPOSE:
          ' RETURN:
          '
          '-------------------------------------------------------------------------------
          
          FUNCTION MonitorCountEnumProc _
            ( _
            BYVAL hMonitor  AS DWORD, _ ' handle to display monitor
            BYVAL hDC       AS DWORD, _ ' handle to monitor DC
                  trc       AS RECT, _  ' monitor intersection rectangle
            BYVAL lParam    AS LONG _   ' application-defined value
            ) AS LONG
          
            LOCAL plCount   AS LONG PTR
          
            plCount = lParam
          
            INCR @plCount
          
          
            FUNCTION = %TRUE
          
          
          END FUNCTION
          
          '-------------------------------------------------------------------------------
          '
          ' PROCEDURE: GetDisplayMonitorCount
          ' PURPOSE:
          ' RETURN:
          '
          '-------------------------------------------------------------------------------
          
          FUNCTION GetDisplayMonitorCount() AS LONG
          
            LOCAL cMonitors   AS LONG
          
            EnumDisplayMonitors %NULL, BYVAL %NULL, BYVAL CODEPTR(MonitorCountEnumProc), VARPTR(cMonitors)
          
            FUNCTION = cMonitors
          
          END FUNCTION
          
          '-------------------------------------------------------------------------------
          '
          ' PROCEDURE: MonitorEnumProc
          ' PURPOSE:
          ' RETURN:
          '
          '-------------------------------------------------------------------------------
          
          FUNCTION MonitorEnumProc _
            ( _
            BYVAL hMonitor  AS DWORD, _ ' handle to display monitor
            BYVAL hDC       AS DWORD, _ ' handle to monitor DC
                  trc       AS RECT, _  ' monitor intersection rectangle
            BYVAL lParam    AS LONG _   ' application-defined value
            ) AS LONG
          
            LOCAL tmi       AS MONITORINFO
            LOCAL iMonitor  AS LONG
          
            tmi.cbSize = SIZEOF(tmi)
            IF GetMonitorInfo(hMonitor, tmi) THEN
              iMonitor = gtmonitors.cMonitors
              [email protected][iMonitor].hMonitor   = hMonitor
              [email protected][iMonitor].trcWork    = tmi.rcWork
              [email protected][iMonitor].trcMonitor = tmi.rcMonitor
              [email protected][iMonitor].fPrimary   = (tmi.dwFlags AND %MONITORINFOF_PRIMARY)
              INCR gtmonitors.cMonitors
              FUNCTION = %TRUE
            ELSE
              FUNCTION = %FALSE
            END IF
          
          END FUNCTION
          
          '-------------------------------------------------------------------------------
          '
          ' PROCEDURE: GetDisplayMonitors
          ' PURPOSE:
          ' RETURN:
          '
          '-------------------------------------------------------------------------------
          
          FUNCTION GetDisplayMonitors() AS LONG
          
            LOCAL cMonitors     AS LONG
            LOCAL iMonitor      AS LONG
            LOCAL fNotSupported AS LONG
            LOCAL lRet          AS LONG
          
            IF gtmonitors.ptmd THEN
              HeapFree GetProcessHeap(), 0, gtmonitors.ptmd
            END IF
            cMonitors = GetDisplayMonitorCount()
          
            IF cMonitors = 0 THEN
              fNotSupported = -1
              cMonitors = 1
            END IF
          
            gtmonitors.ptmd = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, cMonitors * SIZEOF([email protected]))
            IF gtmonitors.ptmd THEN
              IF fNotSupported THEN
                gtmonitors.cMonitors = 1
                [email protected][0].hMonitor           = %NULL
                [email protected][0].trcMonitor.nLeft   = 0
                [email protected][0].trcMonitor.nTop    = 0
                [email protected][0].trcMonitor.nRight  = GetSystemMetrics(%SM_CXSCREEN)
                [email protected][0].trcMonitor.nBottom = GetSystemMetrics(%SM_CYSCREEN)
                lRet = SystemParametersInfo(%SPI_GETWORKAREA, SIZEOF([email protected][0].trcWork), BYVAL VARPTR([email protected][0].trcWork), 0)
                IF lRet = 0 THEN
                  [email protected][0].trcWork = [email protected][0].trcMonitor
                END IF
                [email protected][0].fPrimary = -1
              ELSE
                gtmonitors.cMonitors = 0
                EnumDisplayMonitors %NULL, BYVAL %NULL, BYVAL CODEPTR(MonitorEnumProc), 0
              END IF
              iMonitor = 0
          
              WHILE iMonitor < gtmonitors.cMonitors
                IF [email protected][iMonitor].fPrimary THEN
                  ' To convert
                  ' xScreen  = xVirtual - xMap
                  ' xVirtual = xScreen + xMap
                  gtmonitors.xMap = [email protected][iMonitor].trcWork.nLeft
                  gtmonitors.yMap = gtmo[email protected][iMonitor].trcWork.nTop
                  EXIT LOOP
                END IF
                INCR iMonitor
              WEND
          
            END IF
          
          END FUNCTION
          
          '-------------------------------------------------------------------------------
          '
          ' PROCEDURE: GetMonitorRect
          ' PURPOSE:
          ' RETURN:    Nonzero on success, zero on failure.
          '
          '-------------------------------------------------------------------------------
          
          FUNCTION GetMonitorRect _
            ( _
            BYVAL hMonitor  AS DWORD, _ ' [in]
            BYVAL dwFlags   AS DWORD, _ ' [in]
                  trc       AS RECT _   ' [out]
            ) AS LONG
          
            LOCAL iMonitor  AS LONG
            LOCAL lRet      AS LONG
          
            iMonitor = 0
          
            WHILE iMonitor < gtmonitors.cMonitors
              IF [email protected][iMonitor].hMonitor = hMonitor THEN
                ' To convert
                ' xScreen  = xVirtual - xMap
                ' xVirtual = xScreen + xMap
                IF (dwFlags AND %MONITOR_WORKAREA) THEN
                  trc.nLeft   = [email protected][iMonitor].trcWork.nLeft
                  trc.nTop    = [email protected][iMonitor].trcWork.nTop
                  trc.nRight  = [email protected][iMonitor].trcWork.nRight
                  trc.nBottom = [email protected][iMonitor].trcWork.nBottom
                ELSE
                  trc.nLeft   = [email protected][iMonitor].trcMonitor.nLeft
                  trc.nTop    = [email protected][iMonitor].trcMonitor.nTop
                  trc.nRight  = [email protected][iMonitor].trcMonitor.nRight
                  trc.nBottom = [email protected][iMonitor].trcMonitor.nBottom
                END IF
                IF (dwFlags AND %MONITOR_SCREEN) THEN
                  trc.nLeft   = trc.nLeft   - gtmonitors.xMap
                  trc.nTop    = trc.nTop    - gtmonitors.yMap
                  trc.nRight  = trc.nRight  - gtmonitors.xMap
                  trc.nBottom = trc.nBottom - gtmonitors.yMap
                END IF
                lRet = %TRUE
                EXIT LOOP
              END IF
              INCR iMonitor
            WEND
          
            FUNCTION = lRet
          
          END FUNCTION
          
          '-----------------------------------------------------------------------------------
          ' END ROUTINES FOR WORKING WITH MULTIPLE MONITORS
          '-----------------------------------------------------------------------------------
          
          GLOBAL gtmonitors             AS MONITORS
          
            ' This should be called in control InitXXX procedure or during WM_CREATE.
            ' It should also be called in response to WM_DISPLAYCHANGE
            ' WM_DISPLAYCHANGE needs to be forwarded to control
            GetDisplayMonitors
          Dominic Mitchell
          Phoenix Visual Designer
          http://www.phnxthunder.com

          Comment


          • #6
            Dominic,

            All i have tryed to change the location of a common Open/Save file dialog on my second monitor display failed, using either MoveWindow or SetWindowPos.

            I even tryed to change the location from another thread, without success.

            Thank you anyway.
            Last edited by Patrice Terrier; 11 Nov 2008, 08:26 AM.
            Patrice Terrier
            www.zapsolution.com
            www.objreader.com
            Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

            Comment

            Working...
            X