window.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,123 行 · 第 1/5 页

CPP
2,123
字号

inline int GetScrollPosition(HWND hWnd, int wOrient)
{
#ifdef __WXMICROWIN__
    return ::GetScrollPosWX(hWnd, wOrient);
#else
    WinStruct<SCROLLINFO> scrollInfo;
    scrollInfo.cbSize = sizeof(SCROLLINFO);
    scrollInfo.fMask = SIF_POS;
    ::GetScrollInfo(hWnd, wOrient, &scrollInfo);

    return scrollInfo.nPos;
#endif
}

int wxWindowMSW::GetScrollPos(int orient) const
{
    HWND hWnd = GetHwnd();
    wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );

    return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
}

// This now returns the whole range, not just the number
// of positions that we can scroll.
int wxWindowMSW::GetScrollRange(int orient) const
{
    int maxPos;
    HWND hWnd = GetHwnd();
    if ( !hWnd )
        return 0;
#if 0
    ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
                     &minPos, &maxPos);
#endif
    WinStruct<SCROLLINFO> scrollInfo;
    scrollInfo.fMask = SIF_RANGE;
    if ( !::GetScrollInfo(hWnd,
                          orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
                          &scrollInfo) )
    {
        // Most of the time this is not really an error, since the return
        // value can also be zero when there is no scrollbar yet.
        // wxLogLastError(_T("GetScrollInfo"));
    }
    maxPos = scrollInfo.nMax;

    // undo "range - 1" done in SetScrollbar()
    return maxPos + 1;
}

int wxWindowMSW::GetScrollThumb(int orient) const
{
    return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
}

void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
{
    HWND hWnd = GetHwnd();
    wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );

    WinStruct<SCROLLINFO> info;
    info.nPage = 0;
    info.nMin = 0;
    info.nPos = pos;
    info.fMask = SIF_POS;
    if ( HasFlag(wxALWAYS_SHOW_SB) )
    {
        // disable scrollbar instead of removing it then
        info.fMask |= SIF_DISABLENOSCROLL;
    }

    ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
                    &info, refresh);
}

// New function that will replace some of the above.
void wxWindowMSW::SetScrollbar(int orient,
                               int pos,
                               int pageSize,
                               int range,
                               bool refresh)
{
    WinStruct<SCROLLINFO> info;
    info.nPage = pageSize;
    info.nMin = 0;              // range is nMax - nMin + 1
    info.nMax = range - 1;      //  as both nMax and nMax are inclusive
    info.nPos = pos;
    info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
    if ( HasFlag(wxALWAYS_SHOW_SB) )
    {
        // disable scrollbar instead of removing it then
        info.fMask |= SIF_DISABLENOSCROLL;
    }

    HWND hWnd = GetHwnd();
    if ( hWnd )
    {
        // We have to set the variables here to make them valid in events
        // triggered by ::SetScrollInfo()
        *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;

        ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
                        &info, refresh);
    }
}

void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
{
    RECT rect;
    RECT *pr;
    if ( prect )
    {
        rect.left = prect->x;
        rect.top = prect->y;
        rect.right = prect->x + prect->width;
        rect.bottom = prect->y + prect->height;
        pr = &rect;
    }
    else
    {
        pr = NULL;

    }

#ifdef __WXWINCE__
    // FIXME: is this the exact equivalent of the line below?
    ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
#else
    ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
#endif
}

static bool ScrollVertically(HWND hwnd, int kind, int count)
{
    int posStart = GetScrollPosition(hwnd, SB_VERT);

    int pos = posStart;
    for ( int n = 0; n < count; n++ )
    {
        ::SendMessage(hwnd, WM_VSCROLL, kind, 0);

        int posNew = GetScrollPosition(hwnd, SB_VERT);
        if ( posNew == pos )
        {
            // don't bother to continue, we're already at top/bottom
            break;
        }

        pos = posNew;
    }

    return pos != posStart;
}

bool wxWindowMSW::ScrollLines(int lines)
{
    bool down = lines > 0;

    return ScrollVertically(GetHwnd(),
                            down ? SB_LINEDOWN : SB_LINEUP,
                            down ? lines : -lines);
}

bool wxWindowMSW::ScrollPages(int pages)
{
    bool down = pages > 0;

    return ScrollVertically(GetHwnd(),
                            down ? SB_PAGEDOWN : SB_PAGEUP,
                            down ? pages : -pages);
}

// ---------------------------------------------------------------------------
// subclassing
// ---------------------------------------------------------------------------

void wxWindowMSW::SubclassWin(WXHWND hWnd)
{
    wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );

    HWND hwnd = (HWND)hWnd;
    wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );

    wxAssociateWinWithHandle(hwnd, this);

    m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);

    // we don't need to subclass the window of our own class (in the Windows
    // sense of the word)
    if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
    {
        wxSetWindowProc(hwnd, wxWndProc);
    }
    else
    {
        // don't bother restoring it neither: this also makes it easy to
        // implement IsOfStandardClass() method which returns true for the
        // standard controls and false for the wxWidgets own windows as it can
        // simply check m_oldWndProc
        m_oldWndProc = NULL;
    }
}

void wxWindowMSW::UnsubclassWin()
{
    wxRemoveHandleAssociation(this);

    // Restore old Window proc
    HWND hwnd = GetHwnd();
    if ( hwnd )
    {
        SetHWND(0);

        wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );

        if ( m_oldWndProc )
        {
            if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
            {
                wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc);
            }

            m_oldWndProc = NULL;
        }
    }
}

void wxWindowMSW::AssociateHandle(WXWidget handle)
{
    if ( m_hWnd )
    {
      if ( !::DestroyWindow(GetHwnd()) )
        wxLogLastError(wxT("DestroyWindow"));
    }

    WXHWND wxhwnd = (WXHWND)handle;

    SetHWND(wxhwnd);
    SubclassWin(wxhwnd);
}

void wxWindowMSW::DissociateHandle()
{
    // this also calls SetHWND(0) for us
    UnsubclassWin();
}


bool wxCheckWindowWndProc(WXHWND hWnd,
                          WXFARPROC WXUNUSED(wndProc))
{
// TODO: This list of window class names should be factored out so they can be
// managed in one place and then accessed from here and other places, such as
// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()

#ifdef __WXWINCE__
    extern       wxChar *wxCanvasClassName;
    extern       wxChar *wxCanvasClassNameNR;
#else
    extern const wxChar *wxCanvasClassName;
    extern const wxChar *wxCanvasClassNameNR;
#endif
    extern const wxChar *wxMDIFrameClassName;
    extern const wxChar *wxMDIFrameClassNameNoRedraw;
    extern const wxChar *wxMDIChildFrameClassName;
    extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
    wxString str(wxGetWindowClass(hWnd));
    if (str == wxCanvasClassName ||
        str == wxCanvasClassNameNR ||
#if wxUSE_GLCANVAS
        str == _T("wxGLCanvasClass") ||
        str == _T("wxGLCanvasClassNR") ||
#endif // wxUSE_GLCANVAS
        str == wxMDIFrameClassName ||
        str == wxMDIFrameClassNameNoRedraw ||
        str == wxMDIChildFrameClassName ||
        str == wxMDIChildFrameClassNameNoRedraw ||
        str == _T("wxTLWHiddenParent"))
        return true; // Effectively means don't subclass
    else
        return false;
}

// ----------------------------------------------------------------------------
// Style handling
// ----------------------------------------------------------------------------

void wxWindowMSW::SetWindowStyleFlag(long flags)
{
    long flagsOld = GetWindowStyleFlag();
    if ( flags == flagsOld )
        return;

    // update the internal variable
    wxWindowBase::SetWindowStyleFlag(flags);

    // now update the Windows style as well if needed - and if the window had
    // been already created
    if ( !GetHwnd() )
        return;

    WXDWORD exstyle, exstyleOld;
    long style = MSWGetStyle(flags, &exstyle),
         styleOld = MSWGetStyle(flagsOld, &exstyleOld);

    if ( style != styleOld )
    {
        // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
        // this function so instead of simply setting the style to the new
        // value we clear the bits which were set in styleOld but are set in
        // the new one and set the ones which were not set before
        long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
        styleReal &= ~styleOld;
        styleReal |= style;

        ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
    }

    // and the extended style
    if ( exstyle != exstyleOld )
    {
        long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
        exstyleReal &= ~exstyleOld;
        exstyleReal |= exstyle;

        ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);

        // we must call SetWindowPos() to flush the cached extended style and
        // also to make the change to wxSTAY_ON_TOP style take effect: just
        // setting the style simply doesn't work
        if ( !::SetWindowPos(GetHwnd(),
                             exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
                                                         : HWND_NOTOPMOST,
                             0, 0, 0, 0,
                             SWP_NOMOVE | SWP_NOSIZE) )
        {
            wxLogLastError(_T("SetWindowPos"));
        }
    }
}

WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
{
    // translate common wxWidgets styles to Windows ones

    // most of windows are child ones, those which are not (such as
    // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
    WXDWORD style = WS_CHILD;

    // using this flag results in very significant reduction in flicker,
    // especially with controls inside the static boxes (as the interior of the
    // box is not redrawn twice).but sometimes results in redraw problems, so
    // optionally allow the old code to continue to use it provided a special
    // system option is turned on
    if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
            || (flags & wxCLIP_CHILDREN) )
        style |= WS_CLIPCHILDREN;

    // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
    // don't support overlapping windows and it only makes sense for them and,
    // presumably, gives the system some extra work (to manage more clipping
    // regions), so avoid it alltogether


    if ( flags & wxVSCROLL )
        style |= WS_VSCROLL;

    if ( flags & wxHSCROLL )
        style |= WS_HSCROLL;

    const wxBorder border = GetBorder(flags);

    // WS_BORDER is only required for wxBORDER_SIMPLE
    if ( border == wxBORDER_SIMPLE )
        style |= WS_BORDER;

    // now deal with ext style if the caller wants it
    if ( exstyle )
    {
        *exstyle = 0;

#ifndef __WXWINCE__
        if ( flags & wxTRANSPARENT_WINDOW )
            *exstyle |= WS_EX_TRANSPARENT;
#endif

        switch ( border )
        {
            default:
            case wxBORDER_DEFAULT:
                wxFAIL_MSG( _T("unknown border style") );
                // fall through

            case wxBORDER_NONE:
            case wxBORDER_SIMPLE:
                break;

            case wxBORDER_STATIC:
                *exstyle |= WS_EX_STATICEDGE;
                break;

            case wxBORDER_RAISED:
                *exstyle |= WS_EX_DLGMODALFRAME;
                break;

            case wxBORDER_SUNKEN:
                *exstyle |= WS_EX_CLIENTEDGE;
                style &= ~WS_BORDER;
                break;

            case wxBORDER_DOUBLE:
                *exstyle |= WS_EX_DLGMODALFRAME;
                break;
        }

        // wxUniv doesn't use Windows dialog navigation functions at all
#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
        // to make the dialog navigation work with the nested panels we must
        // use this style (top level windows such as dialogs don't need it)
        if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
        {
            *exstyle |= WS_EX_CONTROLPARENT;
        }
#endif // __WXUNIVERSAL__

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?