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-DateiWNDPROC 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 caseMfG
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 BaustelleMfG
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 NewRichEditProcHabe 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