CreateCaret zeigt keine Wirkung



  • Moin,

    hat schon jemand Erfahrung mit CreateCaret gesammelt?
    Ich will im RichEdit ein eigenes Caret erstellen (einen Block)

    CreateCaret(RichEdit1, 0, 11, 11 );
    ShowCaret(RichEdit1);
    HideCaret(RichEdit1);
    

    Ausprobiert habe ich meinen Code in:
    RichEdit1Change
    RichEdit1KeyDown
    RichEdit1KeyPress
    RichEdit1KeyUp
    RichEdit1SelectionChange
    aber ich habe immer nur den senkrenchten Strich.

    Was habe ich übersehen? 🙄

    Danke im Voraus
    DG2003



  • Hallo,

    in der Funktion CreateCaret (u. anderen) ist das Handle des Fensters zu setzen.
    Ausserdem zeigst du das Caret an und versteckst es sofort wieder.

    Beispiel für einen schwarzen Caret, nach dem ersten Tastendruck:

    void __fastcall TForm1::Memo1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
        POINT P = Memo1->CaretPos;
        CreateCaret(Memo1->Handle, (HBITMAP) NULL, 7, 17);
        SetCaretPos(P.x, P.y);
        ShowCaret(Memo1->Handle);
    
    }
    //---------------------------------------------------------------------------
    

    Beachte:
    Solltest ein Bitmap erstellen/laden, so beachte, dass die Farben des Bitmap invertiert werden.
    Die Schriftart/Zeichenbreite ist ebenfalls zu bedenken.

    mfg
    kpeter



  • kpeter,

    danke dir. Hast Recht, mit HideCaret() habe ich das Caret gleich wieder versteckt 😡
    Habe deinen Code auf den RichEdit umgebaut. Funktionalisiert leider auch nicht. Ich habe nach wie vor nur den senkrechten Strich.

    DG2003



  • Nachtrag, so sieht mein Code jetzt aus:

    void __fastcall TModultest::RichEdit1KeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
        POINT P = RichEdit1->CaretPos;
        CreateCaret(RichEdit1->Handle, (HBITMAP) NULL, 7, 17);
        SetCaretPos(P.x, P.y);
        ShowCaret(RichEdit1->Handle);
    }
    


  • Beim TRichEdit ist der Aufwand tatsächlich höher.

    Naja, machen wir ein SubClassing auf diese Komponente, um an die Messages WM_PAINT und WM_KEYDOWN zu kommen.
    Systemtasten und Mausklicks sind dabei noch nicht berücksichtigt.
    in die *.cpp-Datei

    WNDPROC OldRichEditProc;
    
    bool SetCaret(HWND hWnd)
    {
        HideCaret(hWnd);
        CreateCaret(hWnd, (HBITMAP) NULL, 7, 17);
        return ShowCaret(hWnd);
    }
    
    LRESULT CALLBACK NewRichEditProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
        switch( uMsg ) {
            case WM_PAINT :   SetCaret(hWnd); break;
            case WM_KEYDOWN : SetCaret(hWnd); break;
        }
        return ::CallWindowProc((FARPROC)OldRichEditProc, hWnd, uMsg, wParam, lParam );
    }
    //---------------------------------------------------------------------------
    // in den Konstruktor einfügen
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        OldRichEditProc = (WNDPROC)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
        SetWindowLong( RichEdit1->Handle, GWL_WNDPROC, (LONG)NewRichEditProc );
    }
    //---------------------------------------------------------------------------
    

    Wenn das RichEdit den Focus hat, sollte ein blinkender schwarzer Cursor 7x17 px zu sehen sein.



  • Moin kpeter,

    danke für die Info. Bin gerade anderweilig im Einsatz.
    Melde mich, sobald ich wieder am Projekt arbeite.

    MfG
    DG2003



  • Moin kpeter,

    bin nur kurz im Büro und dann wieder auf der Baustelle.
    Habe deinen Code in mein Projekt integriert, leider ohne die erhoffte Wirkung.

    Habe noch schnell ein paar Tests durchgeführt:
    SetWindowLong() im Konstruktor gibt einen Wert > 0 zurück
    In SetCaret() geben CreateCaret() und ShowCaret() jeweils false zurück
    In NewRichEditProc() geht er in kein case

    MfG
    DG2003



  • Hallo,

    entscheidend ist erstmal, dass überhaupt in die NewRichEditProc gegangen wird.

    Es sind einige Messages, die behandelt werden müssen, denn das System versucht ständig, wieder das Original-Caret zu setzen.
    CN_KEYUP, WM_LBUTTONUP sind zB solche Nachrichten. Setze die auch mal in den switch.



  • Moin kpeter,

    da es mir momentan zu mühselig ist alle Messages abzufangen habe ich die Sache etwas vereinfacht:

    WNDPROC OldRichEditProc;
    
    bool SetCaret(HWND hWnd)
    {
        bool bState;
        HideCaret(hWnd);
        bState = CreateCaret(hWnd, (HBITMAP) NULL, 7, 17);	// <bState> immer false
        bState = ShowCaret(hWnd);			// <bState> immer false
        return bState;
    }
    
    LRESULT CALLBACK NewRichEditProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
    
       SetCaret(hWnd);
       return ::CallWindowProc((FARPROC)OldRichEditProc, hWnd, uMsg, wParam, lParam );
    }
    
    __fastcall TModultest::TModultest(TComponent* Owner)
    	: TForm(Owner)
    {
        OldRichEditProc = (WNDPROC)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
        LONG bState = SetWindowLong( RichEdit1->Handle, GWL_WNDPROC, (LONG)NewRichEditProc );
    					// <bState> > 0
    }
    

    leider ohne Erfolg.
    Bin wieder auf der Baustelle

    MfG
    DG2003



  • DG2003 schrieb:

    leider ohne Erfolg

    Hmm. Welchen Wert gibt

    OldRichEditProc = (WNDPROC)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
    

    zurück?

    Möglicherweise muss deklariert werden

    long OldRichEditProc;
    
    // und im Konstruktor
    OldRichEditProc = (long)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
    

    Deinem Posting entnehme ich, dass das Programm NICHT in NewRichEditProc geht?
    Einfach mal im Debugger einen Haltepunkt setzen.



  • Moin,

    richtig, er geht nicht in NewRichEditProc.

    OldRichEditProc = (WNDPROC)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
    

    gibt 0x3c0482 zurück und

    SetWindowLong( RichEdit1->Handle, GWL_WNDPROC, (LONG)NewRichEditProc );
    

    gibt 3933314 zurück.

    Während das Prog hoch läuft kommt es mehrfach in NewRichEditProc mit lustig wechsenden Returnwerten von 0, 1, -1 ...
    Läuft mein Prog, kommt es nicht mehr in NewRichEditProc

    Habe noch folgende Änderung vorgenommen:

    long OldRichEditProc;
    OldRichEditProc = (long)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC );
    

    leider auch mit negativen Ergebnis 😞

    SetCaret(RichEdit1);
    

    rufe ich derzeit in RichEdit1SelectionChange auf. Ist aber egal wo ich es hin setze, das Ergebnis ist das Gleiche.

    Muß wieder los. Komme Montag erst wieder zurück.

    MfG
    DG2003



  • Hallo,

    kann ich momentan nicht nachvollziehen.
    Bei der CallWindowProc sind einige Dinge zu beachten, s. hier, und in der windef.h wird auch nach Windows-Versionen
    differenziert. Wie auch immer...

    Nachfolgend mal eine Variante, die den *Nachteil* hat, dass das RichEdit dynamisch/während der Laufzeit erzeugt
    wird, aber auf Anhieb gehen sollte. Als Font habe ich, wie zu sehen, einen mit gleicher Zeichenbreite gewählt.
    SetCaret ist jetzt eine Klassenfunktion.

    *.h

    .
    .
    .
    class TCaretRichEdit : public TRichEdit
    {
    private:
    	bool SetCaret();
    	Graphics::TBitmap* caret;
    protected:
    	void __fastcall WndProc(Messages::TMessage &Message);
    
    public:
    	__fastcall TCaretRichEdit(TComponent* Owner);
    	__fastcall ~TCaretRichEdit(void);
    
    };
    class TForm1 : public TForm
    {
    __published:
    
    private:
    	TCaretRichEdit* CRE;
    public:
    	__fastcall TForm1(TComponent* Owner);
    	__fastcall ~TForm1(void);
    };
    //---------------------------------------------------------------------------
    

    *.cpp

    .
    .
    .
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    
    __fastcall TCaretRichEdit::TCaretRichEdit(TComponent* Owner)
    	: TRichEdit(Owner)
    {
       caret = new Graphics::TBitmap;
       caret->Width  = 12;
       caret->Height = 20;
       caret->Canvas->Brush->Color = clWhite; // wird zu schwarz invertiert
       caret->Canvas->FillRect(Rect(0, 0, 12, 20));
       caret->Canvas->Brush->Color = clBlack; // wird zu weiss invertiert
       caret->Canvas->FillRect(Rect(1, 1, 11, 19));
    }
    //---------------------------------------------------------------------------
    
    __fastcall TCaretRichEdit::~TCaretRichEdit(void)
    {
       delete caret;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TCaretRichEdit::WndProc(Messages::TMessage &Message)
    {
       switch(Message.Msg) {
          case WM_SETFOCUS :  SetCaret(); break;
          case WM_KEYUP :     SetCaret(); break;
          case WM_KEYDOWN :   SetCaret(); break;
          case WM_LBUTTONUP : SetCaret(); break;
       }
       TRichEdit::WndProc(Message);
    }
    bool TCaretRichEdit::SetCaret()
    {
       HWND hWnd = this->Handle;
    
       HideCaret(hWnd);
       CreateCaret(hWnd, (HBITMAP) caret->Handle, 12, 20); 
       //CreateCaret(hWnd, (HBITMAP) NULL, 12, 20); // alternativ 
       return ShowCaret(hWnd);
    }
    //---------------------------------------------------------------------------
    
    __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
    {
       CRE				= new TCaretRichEdit(this);
       CRE->Parent 	= Form1;
       CRE->Align 	= alBottom;
       CRE->BorderStyle = bsNone;
       CRE->WordWrap = false;
       CRE->ScrollBars = ssBoth;
       CRE->Font->Name = "Courier New";
       CRE->Font->Size = 13;
       CRE->Font->Pitch = fpFixed, 27;
       CRE->Lines->Clear();
       CRE->Text = "Zeile1\nZeile2\nZeile3";
    }
    //---------------------------------------------------------------------------
    
    __fastcall TForm1::~TForm1(void)
    {
       delete CRE;
    }
    

    mfg
    kpeter



  • kpeter,

    danke für die letzte Info. Habe momentan leider keine Zeit. Uns ist eine Anlage abgeraucht. Hat Vorrang. Melde mich wieder.

    DG2003



  • Moin kpeter,

    bin wieder kurz im Büro.
    Habe ein neues Prog mit nur einem RichEdit erstellt und Deinen Code vom 7.6.2010 genommen, und ES FUNKTIONIERT 😋
    Werde demnächst meine eigentliche Anwendung untersuchen, wo ich meinen RichEdit so verbogen habe, das es nicht funktioniert.

    Hier für alle der Code:

    WNDPROC OldRichEditProc; 
    
    bool SetCaret(HWND hWnd) 
    { 
        HideCaret(hWnd); 
        CreateCaret(hWnd, (HBITMAP) NULL, 7, 17); 
        return ShowCaret(hWnd); 
    } 
    
    LRESULT CALLBACK NewRichEditProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
    { 
        switch( uMsg ) { 
    	case WM_NCHITTEST :	SetCaret(hWnd); break;	// Reaktion auf Maus
    	case WM_KEYUP :		SetCaret(hWnd); break;	// Reaktion auf Taste
        }
        return ::CallWindowProc((FARPROC)OldRichEditProc, hWnd, uMsg, wParam, lParam );
    }
    
    //---------------------------------------------------------------------------
    // im Konstruktor
    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
        OldRichEditProc = (WNDPROC)GetWindowLong( RichEdit1->Handle, GWL_WNDPROC ); 
        SetWindowLong( RichEdit1->Handle, GWL_WNDPROC, (LONG)NewRichEditProc ); 
    }
    

    Danke an kpeter


Log in to reply