Listview Report-Style mit Header Control, wie Doppelklick auf Divider abfangen



  • Hallo, wie kann ich in der Headercontrol einen Doppelklick auf den Divider zweier Colums abfangen. Wenn ich per Linke-Maustaste Doppelt draufklicke, dann verringert/vergrössert sich die Spaltenbreit auf die Textbreite des grössten Listviewitems in der Spalte. Wenn ich "WM_NOTIFY" -> "HDN_BEGINTRACK" abfange kann ich das manuelle verschieben des Dividers durch "return 1" unterbinden.

    Auf welchen Event muss ich prüfen um das Ereigniss abzufangen? Ich hab jetzt mal die Headercontrol gesubclassed, und auf "WM_LBUTTONDBLCLK" geprüft. Das klappt auch soweit, wenn ich wo auch immer auf die Headercontrl doppelklicke, dann hab ich den Event. Ist das der richtige Weg? Muss ich da die Mouseposition bestimmen und errechene ob ich auf einem Divider bin? Erscheint mir recht aufwendig.

    Gibt es einen einfacheren oder richtigen Weg?



  • Du suchst HDN_DIVIDERDBLCLICK.



  • Leider kann man die Grössenänderung dadurch nicht aufhalten, da kein Rückgabewert ausgewertet wird.



  • Komisch, ich kann das sehr wohl. Ich brauche in der SubclassProc des ListViews die Notification schließlich nicht durchzureichen.



  • Wenn ich meine Listview subclasse, taucht HDN_DIVIDERDBLCLICK in der Messagequeue von WM_NOTIFY gar nicht auf. Ich erhalte HDN_DIVIDERDBLCLICK erst in der Messagqueue von Parent des Listview.



  • JohnDoooe schrieb:

    Wenn ich meine Listview subclasse, taucht HDN_DIVIDERDBLCLICK in der Messagequeue von WM_NOTIFY gar nicht auf.

    Aber selbstverständlich taucht das auf. Hast Du die SubclassProc zufällig für das falsche Fenster eingerichtet?



  • War auch mein erster Gedanke. Ich hab die Subclass-Proc geprüft und mache eine Textausgabe auf "WM_LBUTTONDBLCLK" und diese Textausgabe erscheint dann auch wenn ich in den Listview doppelklicke, also wird die Subclass-Proc durchlaufen.



  • Dann machst Du noch was anderes falsch. Leider bin ich kein Seher, kann daher nicht genauer werden.



  • Hier der Code vom gesubclasseten Listview der nicht läuft. In der Wndproc vom Hauptfenster, wird damit nach wie vor "HDN_DIVIDERDBLCLICK" erhalten. Info: ED(....) dient der Ausgabe in einem Editfeld.

    /*
    ===============================================================================
    DialogSubclass_DlgListview2
    
    ===============================================================================
    */
    LRESULT CALLBACK DialogSubclass_DlgListview2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    
    	switch(message){
    		case WM_LBUTTONDBLCLK:
    			ED("WM_LBUTTONDBLCLK\r\n", FALSE);
    //			return 1;
    			break;
    		case WM_NOTIFY:
    			switch(((LPNMHDR)lParam)->code){
    				case HDN_DIVIDERDBLCLICK:
    					ED(va("HDN_DIVIDERDBLCLICK:\t%i\r\n", ((LPNMHEADER)lParam)->iItem), FALSE);
    //					return FALSE;
    //					return TRUE;
    					break;
    				default:{
    					break;
    				}
    			}
    			break;
    		default:{
    			break;
    		}
    	}
    	return CallWindowProc(wProcListview2, hWnd, message, wParam, lParam);
    }
    

  • Mod

    Das ist der Dialog Handler. Dort kommt der HDN_DIVIDERDBLCLICK auch nicht an.

    Das Header Contorl ist ein Kind des List Controls, also kann es nur in der WndProc des List Controls ankommen, also ist ein Subclass notwendig.



  • Aber ich hab doch den Listview gesubclassed:

    wProcListview2= (WNDPROC)SetWindowLongPtr(GetDlgItem(hWnd, DLG_LISTVIEW2), GWLP_WNDPROC, (LONG_PTR)DialogSubclass_DlgListview2);
    

  • Mod

    OK. Den Namen der Prozedur habe ich anders verstanden...
    Was sagt Spy++? Irgendwohin geht doch die Nachricht?



  • Deine (gekürzte) Fassung sieht in meinen Augen so aus:

    JohnDoooe schrieb:

    /*
    ===============================================================================
    DialogSubclass_DlgListview2
    
    ===============================================================================
    */
    LRESULT CALLBACK DialogSubclass_DlgListview2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    
    	switch(message){
    		case WM_NOTIFY:
    			switch(((LPNMHDR)lParam)->code){
    				case HDN_DIVIDERDBLCLICK:
    					break;
    			}
    			break;
    	}
    	return CallWindowProc(wProcListview2, hWnd, message, wParam, lParam);
    }
    

    Du leitest die Notification also an das ListView weiter. Diese kommt auch tatsächlich dort an. It's Magic.

    Was war nochmal das Problem?



  • Nein in meiner gesubclassten Wndproc des Listviews kommt sie nicht an, aber in der ebenfalls gesubclassten Wndproc des Dialobox-Parent-Fensters des Listviews läuft sie auf, aber dort wie bereits gesagt hat ein Return TRUE oder FALSE überhaupt keine Auswirkungen ob eine Weiterverarbeitung der Nachricht unterdrückt werden kann. Und gnau so steht es auch in der Doko zu HDN_DIVIDERDBLCLICK.

    Daher wundert mich deine Aussage Mox, dass du die weitere Verarbeitung der Nachricht irgendwie beeinflussen kannst.



  • JohnDoooe schrieb:

    Nein in meiner gesubclassten Wndproc des Listviews kommt sie nicht an,

    Das heißt, Dein ListView reagiert ganz wunderbar auf HDN_DIVIDERDBLCLICK, ohne die Notification selbst jemals erhalten zu haben. Respekt.

    Wie kommt man denn nun an ein Beispiel, dass das von Dir beschriebene Verhalten illustriert?



  • Ich bin nicht derjenige der behauptet hat, das Verhalten von HDN_DIVIDERDBLCLICK anhand eines Rückgabewertes beeinflussen zu können, wohlgemerkt entgegen der Aussage was in der Microsoft Doku zu HDN_DIVIDERDBLCLICK steht. Ich sagte lediglich, dass ich HDN_DIVIDERDBLCLICK nicht beeinflussen kann, und das HDN_DIVIDERDBLCLICK bei mir nicht in der Messageque des gesubclassten Eventhadlers des Listviews auftritt. In der Messageque des gesubclassten Elternfenster des Listview tritt HDN_DIVIDERDBLCLICK sehr wohl auf, warum auch immer. Ich habe auch erklärt wie ich geprüft habe dass das Fenster korrekt gesubclasst wurde, indem ich z.B. WM_LBUTTONDBLCLK abgefangen habe und dies dort korrekt angezeigt wurde wo es zu erwarten war.

    Genau so komm ich zu einem Beispiel das dieses Verhalten illustriert.



  • JohnDoooe schrieb:

    Genau so komm ich zu einem Beispiel das dieses Verhalten illustriert.

    Wie schön für Dich. Dann behalte dieses Beispiel mal ganz allein für Dich. Ich brauche es ja nicht, denn auf meinen Rechnern funktioniert alles exakt so, wie es zu funktionieren hat. Und ja, das habe ich tatsächlich auch ausprobiert.

    Eigentlich dachte ich, Du willst eine Lösung. Wie man sich doch täuschen kann...



  • So sieht übrigens mein Test aus:

    static WNDPROC gs_wndpListView;
    
    LRESULT CALLBACK ListViewProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch(uMsg)
        {
            case WM_NOTIFY:
                if(reinterpret_cast<NMHDR*>(lParam)->code == HDN_DIVIDERDBLCLICK)
                    return 0;
                default:
                    break;
        }
    
        return CallWindowProc(gs_wndpListView, hWnd, uMsg, wParam, lParam);
    }
    
    INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM)
    {
        switch(uMsg)
        {
            case WM_INITDIALOG:
            {
                HWND hWndLV = GetDlgItem(hWnd, 12345);
    
                RECT rc;
                GetClientRect(hWndLV, &rc);
    
                LVCOLUMN lvc = {};
                lvc.mask    = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
                lvc.fmt     = LVCFMT_LEFT;
                lvc.cx      = (rc.right - rc.left - GetSystemMetrics(SM_CXVSCROLL)) / 3;
    
                lvc.pszText = TEXT("Spalte 3");
                ListView_InsertColumn(hWndLV, 0, &lvc);
                lvc.pszText = TEXT("Spalte 2");
                ListView_InsertColumn(hWndLV, 0, &lvc);
                lvc.pszText = TEXT("Spalte 1");
                ListView_InsertColumn(hWndLV, 0, &lvc);
    
                gs_wndpListView = reinterpret_cast<WNDPROC>(SetWindowLongPtr(hWndLV, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(ListViewProc)));
                return TRUE;
            }
            case WM_COMMAND:
                switch(LOWORD(wParam))
                {
                    case IDOK:
                    case IDCANCEL:
                        EndDialog(hWnd, 0);
                        return TRUE;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    
        return FALSE;
    }
    
    int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
    {
        static const BYTE s_bTemplate[] =
        {
            0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0xC8, 0x80,
            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x01,
            0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00,
            0x69, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x6F, 0x00,
            0x67, 0x00, 0x00, 0x00, 0x08, 0x00, 0x90, 0x01,
            0x00, 0x01, 0x4D, 0x00, 0x53, 0x00, 0x20, 0x00,
            0x53, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6C, 0x00,
            0x6C, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6C, 0x00,
            0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x50,
            0xCD, 0x00, 0xA2, 0x00, 0x32, 0x00, 0x0E, 0x00,
            0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
            0x4F, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x01, 0x50, 0x03, 0x01, 0xA2, 0x00,
            0x32, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x00, 0x00,
            0xFF, 0xFF, 0x80, 0x00, 0x43, 0x00, 0x61, 0x00,
            0x6E, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6C, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x81, 0x50,
            0x07, 0x00, 0x07, 0x00, 0x2E, 0x01, 0x97, 0x00,
            0x39, 0x30, 0x00, 0x00, 0x53, 0x00, 0x79, 0x00,
            0x73, 0x00, 0x4C, 0x00, 0x69, 0x00, 0x73, 0x00,
            0x74, 0x00, 0x56, 0x00, 0x69, 0x00, 0x65, 0x00,
            0x77, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00
        };
    
        INITCOMMONCONTROLSEX iccex;
        iccex.dwSize = sizeof(iccex);
        iccex.dwICC  = ICC_LISTVIEW_CLASSES;
        InitCommonControlsEx(&iccex);
        DialogBoxIndirect(hInstance, reinterpret_cast<const DLGTEMPLATE*>(s_bTemplate), nullptr, DlgProc);
        return 0;
    }
    


  • Danke Mox, dass du dir die Mühe gemacht hast deinen Code zu posten.

    Das Ergebiss überrascht mich nun sehr. Die Spalten werden kleiner und auch nicht. Wie kommt's. Ich hab deine Code in mein Projekt reinkopiert und den Rest meines Codes entfernt. Ergebniss Spalten verkleinern sich bei Doppelklick auf Divider.

    Ich hab ein neues Projekt erstellt den Code reinkopiert, Ergebiss die Spaltengrösse bleibt bei Doppelklick unverändert.

    Nach längerem Vergleich der Projekteinstellungen habe ich die eine Einstellung gefunden, die das Verhalten in die eine oder andere Richtung beeinflusst

    "Allgemein->Zeichensatz" "Unicode-Zeichensatz" zeigt das von dir beschriebene Verhalten, "Multi-Byte-Zeichensatz verwenden" oder "nicht festgelegt" ruft das von mir beschriebene Verhalten hervor.

    Seltsame Sache.



  • Ach so ist das. Dann reagiere mal in der SubclassProc sowohl auf HDN_DIVIDERDBLCLICKA als auch auf HDN_DIVIDERDBLCLICKW, damit sollte sich das Problem in Luft auflösen.


Anmelden zum Antworten