Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Getting a disabled CView to give a strong visual cue of being disabled, so that the user understands that it isn't a bug that it's disabled.

Getting a disabled CView to give a strong visual cue of being disabled, so that the user understands that it isn't a bug that it's disabled.

Scheduled Pinned Locked Moved C / C++ / MFC
helpquestionc++database
10 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Sternocera
    wrote on last edited by
    #1

    Hello, I'm developing an MFC application, an enterprise database accessing program where the user is potentially denied access to some of the views that appear in the right hand splitter pane (all of which are classes derived from my own custom base class that is derived from CFormView). I call EnableWindow(FALSE) from within the right hand views where appropriate (from my custom base class) to disable the view entirely, including making it impossible to tab to the view. So far, so good. However, the problem of there being no obvious visual indication of *why* the view is locked, and that it is supposed to be locked, persists. Examples of appropriate strong visual cues include: 1. Darkening the View 2. Making the view grayscale 3. Making the mouse cursor appear as a padlock or somesuch when it overlays the view. 4. When the user clicks on the view, display a messagebox that explains that access is denied. How can I achieve any of these visual cues? The problem is, because I've disabled the view, through the call to EnableWindow(FALSE), I cannot do a whole lot. I cannot change the mouse cursor in the usual way. I can provide implementations of any Cview/CWnd virtual functions, such as OnDraw(), but I cannot seem to Draw to my CViews in any useful way, as can be done with a CScrollView. How can I create any of these strong visual cues? Regards, Sternocera

    M S 2 Replies Last reply
    0
    • S Sternocera

      Hello, I'm developing an MFC application, an enterprise database accessing program where the user is potentially denied access to some of the views that appear in the right hand splitter pane (all of which are classes derived from my own custom base class that is derived from CFormView). I call EnableWindow(FALSE) from within the right hand views where appropriate (from my custom base class) to disable the view entirely, including making it impossible to tab to the view. So far, so good. However, the problem of there being no obvious visual indication of *why* the view is locked, and that it is supposed to be locked, persists. Examples of appropriate strong visual cues include: 1. Darkening the View 2. Making the view grayscale 3. Making the mouse cursor appear as a padlock or somesuch when it overlays the view. 4. When the user clicks on the view, display a messagebox that explains that access is denied. How can I achieve any of these visual cues? The problem is, because I've disabled the view, through the call to EnableWindow(FALSE), I cannot do a whole lot. I cannot change the mouse cursor in the usual way. I can provide implementations of any Cview/CWnd virtual functions, such as OnDraw(), but I cannot seem to Draw to my CViews in any useful way, as can be done with a CScrollView. How can I create any of these strong visual cues? Regards, Sternocera

      M Offline
      M Offline
      Michael Dunn
      wrote on last edited by
      #2

      You should still be able to change the cursor. Handle WM_SETCURSOR in the form class and return a different cursor if the form is disabled.

      --Mike-- New sig under construction...

      S 1 Reply Last reply
      0
      • M Michael Dunn

        You should still be able to change the cursor. Handle WM_SETCURSOR in the form class and return a different cursor if the form is disabled.

        --Mike-- New sig under construction...

        S Offline
        S Offline
        Sternocera
        wrote on last edited by
        #3

        Mike, Thanks for getting back to me. You're right - I made the mistake of not putting the message map entry in the derived class, just the base. Thanks, Sternocera

        S 1 Reply Last reply
        0
        • S Sternocera

          Hello, I'm developing an MFC application, an enterprise database accessing program where the user is potentially denied access to some of the views that appear in the right hand splitter pane (all of which are classes derived from my own custom base class that is derived from CFormView). I call EnableWindow(FALSE) from within the right hand views where appropriate (from my custom base class) to disable the view entirely, including making it impossible to tab to the view. So far, so good. However, the problem of there being no obvious visual indication of *why* the view is locked, and that it is supposed to be locked, persists. Examples of appropriate strong visual cues include: 1. Darkening the View 2. Making the view grayscale 3. Making the mouse cursor appear as a padlock or somesuch when it overlays the view. 4. When the user clicks on the view, display a messagebox that explains that access is denied. How can I achieve any of these visual cues? The problem is, because I've disabled the view, through the call to EnableWindow(FALSE), I cannot do a whole lot. I cannot change the mouse cursor in the usual way. I can provide implementations of any Cview/CWnd virtual functions, such as OnDraw(), but I cannot seem to Draw to my CViews in any useful way, as can be done with a CScrollView. How can I create any of these strong visual cues? Regards, Sternocera

          S Offline
          S Offline
          Stuart Dootson
          wrote on last edited by
          #4

          How about overlaying the view with a 50% gray, 50% opaque window (see WS_EX_LAYERED[^] and SetLayeredWindowAttributes[^])? That's kind of what Safari (the web browser) does when you click on a bookmarked site that it has a preview for - looks kind of cool.

          Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p

          S 1 Reply Last reply
          0
          • S Sternocera

            Mike, Thanks for getting back to me. You're right - I made the mistake of not putting the message map entry in the derived class, just the base. Thanks, Sternocera

            S Offline
            S Offline
            Sternocera
            wrote on last edited by
            #5

            Hmm. It seems that the disabled CViews do not change cursor, only the enabled ones. Are you sure that it is as you've described? Regards, Sternocera

            1 Reply Last reply
            0
            • S Stuart Dootson

              How about overlaying the view with a 50% gray, 50% opaque window (see WS_EX_LAYERED[^] and SetLayeredWindowAttributes[^])? That's kind of what Safari (the web browser) does when you click on a bookmarked site that it has a preview for - looks kind of cool.

              Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p

              S Offline
              S Offline
              Sternocera
              wrote on last edited by
              #6

              Stuart, That's interesting. How could this overlaying effect be achieved? calls to CWnd::SetLayeredWindowAttributes() don't seem to be affect my CView in anyway:

              SetLayeredWindowAttributes(RGB(50,50,50), 100, WS_EX_LAYERED);

              Equally, calling the Win32 API equivalents doesn't have any discernable effect:

              HWND hwnd = GetSafeHwnd();
              ::SetWindowLong(hwnd, GWL_EXSTYLE,
              ::GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

              ::SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);

              Regards, Sternocera

              S 1 Reply Last reply
              0
              • S Sternocera

                Stuart, That's interesting. How could this overlaying effect be achieved? calls to CWnd::SetLayeredWindowAttributes() don't seem to be affect my CView in anyway:

                SetLayeredWindowAttributes(RGB(50,50,50), 100, WS_EX_LAYERED);

                Equally, calling the Win32 API equivalents doesn't have any discernable effect:

                HWND hwnd = GetSafeHwnd();
                ::SetWindowLong(hwnd, GWL_EXSTYLE,
                ::GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

                ::SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);

                Regards, Sternocera

                S Offline
                S Offline
                Stuart Dootson
                wrote on last edited by
                #7

                Sorry - wasn't quite clear enough. Create another window. Make it the same size and position as your view, but put it on top of it. Make it layered, 50% gray, 50% opaque. The reason your trials didn't work is (I think) because you can't apply WS_EX_LAYERED to a child window - my own experiments (with a trial SDI app) indicate that. So, you'd need to set that style on your CMainFrame.

                Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p

                S 1 Reply Last reply
                0
                • S Stuart Dootson

                  Sorry - wasn't quite clear enough. Create another window. Make it the same size and position as your view, but put it on top of it. Make it layered, 50% gray, 50% opaque. The reason your trials didn't work is (I think) because you can't apply WS_EX_LAYERED to a child window - my own experiments (with a trial SDI app) indicate that. So, you'd need to set that style on your CMainFrame.

                  Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p

                  S Offline
                  S Offline
                  Sternocera
                  wrote on last edited by
                  #8

                  Sorry Stuart, but I'm going to need you to be clearer still. What sort of window class would I create, and how? What about resizing of my CMainFrame, wouldn't I have to resize my overlaying windows as my underlying view changed shape? Regards, Sternocera

                  S 1 Reply Last reply
                  0
                  • S Sternocera

                    Sorry Stuart, but I'm going to need you to be clearer still. What sort of window class would I create, and how? What about resizing of my CMainFrame, wouldn't I have to resize my overlaying windows as my underlying view changed shape? Regards, Sternocera

                    S Offline
                    S Offline
                    Stuart Dootson
                    wrote on last edited by
                    #9

                    Sternocera wrote:

                    Sorry Stuart, but I'm going to need you to be clearer still. What sort of window class would I create, and how?

                    This (Win32 code) seems to work nicely enough and shows how to register the window class and create the window:

                    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                    {
                    // Don't let the window close - might want to modify slightly...
                    if (message == WM_CLOSE) return 0;
                    return DefWindowProc(hWnd, message, wParam, lParam);
                    }

                    BOOL CreateLayeredWindow(HINSTANCE hInstance, int nCmdShow)
                    {
                    HWND hWnd;

                    WNDCLASSEX wcex;
                    wcex.cbSize = sizeof(WNDCLASSEX);
                    wcex.style = CS_HREDRAW | CS_VREDRAW;
                    wcex.lpfnWndProc = &WndProc;
                    wcex.cbClsExtra = 0;
                    wcex.cbWndExtra = 0;
                    wcex.hInstance = hInstance;
                    wcex.hIcon = 0;
                    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
                    wcex.hbrBackground = (HBRUSH)(COLOR_BTNTEXT+1);
                    wcex.lpszMenuName = 0;
                    wcex.lpszClassName = _T("layered");
                    wcex.hIconSm = 0;

                    RegisterClassEx(&wcex);

                    const DWORD screenWidth = GetSystemMetrics(SM_CXSCREEN);
                    const DWORD screenHeight = GetSystemMetrics(SM_CYSCREEN);

                    hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TOOLWINDOW, _T("layered"), _T("layered"), WS_POPUPWINDOW,
                    screenWidth/4, screenHeight/4, screenWidth/2, screenHeight/2, NULL, NULL, hInstance, NULL);

                    if (!hWnd)
                    {
                    return FALSE;
                    }

                    SetLayeredWindowAttributes(hWnd, 0, 0xc0, LWA_ALPHA);
                    ShowWindow(hWnd, nCmdShow);

                    return TRUE;
                    }

                    You will probably need to replace hInstance by AfxGetModuleState()->m_hCurrentInstanceHandle and there're probably advantages to making the layered windows parent be one of your application's windows (mainly ensuring the window z-order is sane).

                    Sternocera wrote:

                    What about resizing of my CMainFrame, wouldn't I have to resize my overlaying windows as my underlying view changed shape?

                    Yes - that's not too much of a problem - in your view's OnSize handler, just get the view's window rect (GetWindowRect) and tell the overlay to move itself there. You also need to handle the main frame's OnMove handler similarly - here's what I've got in a sample app:

                    // Main-frame OnMove handler
                    void CMainFrame::OnMove(int x, int y)
                    {
                    CFrameWndEx::OnMove(x, y);

                    if (const MSG* msg = GetCurrentMessage())
                    {

                    S 1 Reply Last reply
                    0
                    • S Stuart Dootson

                      Sternocera wrote:

                      Sorry Stuart, but I'm going to need you to be clearer still. What sort of window class would I create, and how?

                      This (Win32 code) seems to work nicely enough and shows how to register the window class and create the window:

                      LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                      {
                      // Don't let the window close - might want to modify slightly...
                      if (message == WM_CLOSE) return 0;
                      return DefWindowProc(hWnd, message, wParam, lParam);
                      }

                      BOOL CreateLayeredWindow(HINSTANCE hInstance, int nCmdShow)
                      {
                      HWND hWnd;

                      WNDCLASSEX wcex;
                      wcex.cbSize = sizeof(WNDCLASSEX);
                      wcex.style = CS_HREDRAW | CS_VREDRAW;
                      wcex.lpfnWndProc = &WndProc;
                      wcex.cbClsExtra = 0;
                      wcex.cbWndExtra = 0;
                      wcex.hInstance = hInstance;
                      wcex.hIcon = 0;
                      wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
                      wcex.hbrBackground = (HBRUSH)(COLOR_BTNTEXT+1);
                      wcex.lpszMenuName = 0;
                      wcex.lpszClassName = _T("layered");
                      wcex.hIconSm = 0;

                      RegisterClassEx(&wcex);

                      const DWORD screenWidth = GetSystemMetrics(SM_CXSCREEN);
                      const DWORD screenHeight = GetSystemMetrics(SM_CYSCREEN);

                      hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TOOLWINDOW, _T("layered"), _T("layered"), WS_POPUPWINDOW,
                      screenWidth/4, screenHeight/4, screenWidth/2, screenHeight/2, NULL, NULL, hInstance, NULL);

                      if (!hWnd)
                      {
                      return FALSE;
                      }

                      SetLayeredWindowAttributes(hWnd, 0, 0xc0, LWA_ALPHA);
                      ShowWindow(hWnd, nCmdShow);

                      return TRUE;
                      }

                      You will probably need to replace hInstance by AfxGetModuleState()->m_hCurrentInstanceHandle and there're probably advantages to making the layered windows parent be one of your application's windows (mainly ensuring the window z-order is sane).

                      Sternocera wrote:

                      What about resizing of my CMainFrame, wouldn't I have to resize my overlaying windows as my underlying view changed shape?

                      Yes - that's not too much of a problem - in your view's OnSize handler, just get the view's window rect (GetWindowRect) and tell the overlay to move itself there. You also need to handle the main frame's OnMove handler similarly - here's what I've got in a sample app:

                      // Main-frame OnMove handler
                      void CMainFrame::OnMove(int x, int y)
                      {
                      CFrameWndEx::OnMove(x, y);

                      if (const MSG* msg = GetCurrentMessage())
                      {

                      S Offline
                      S Offline
                      Sternocera
                      wrote on last edited by
                      #10

                      Thanks a lot for that Stuart. I'll see what I can come up with, Regards, Sternocera

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups