Announcement

Collapse
No announcement yet.

Center common dialog on dual display

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

  • Patrice Terrier
    replied
    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, 07:26 AM.

    Leave a comment:


  • Dominic Mitchell
    replied
    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 = [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

    Leave a comment:


  • Patrice Terrier
    replied
    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

    Leave a comment:


  • Cliff Nichols
    replied
    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)

    Leave a comment:


  • Greg Turgeon
    replied
    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?

    Leave a comment:


  • Patrice Terrier
    started a topic Center common dialog on dual display

    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?

    ...
Working...
X