Board index » cppbuilder » How should I move the cursor??

How should I move the cursor??


2006-10-18 07:48:04 PM
cppbuilder68
We use Borland Developer Studio 2006 C++ Builder. In our program we use
TStringGrid to display data.
BiDiMode = bdRightToLeft, Options>>goEditing.
We need to move the cursor ourselves using WindowProc. When we used C++
Builder 5, it worked perfectly.
In BDS 2006 the cursor moves as if BiDiMode = bdLeftToRight while SelectCell
is marked properly.
In order to check, please, build a project and copy
to unit:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
StringGrid1 = new TStringGrid(this);
StringGrid1->Parent = this;
StringGrid1->BiDiMode = bdRightToLeft;
StringGrid1->Align = alClient;
StringGrid1->Options << goTabs;
gridOrigProc = StringGrid1->WindowProc;
StringGrid1->WindowProc = gridWindowProc;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::gridWindowProc(TMessage &Message)
{
int x, y, ACol, ARow;
if(Message.Msg == WM_LBUTTONDOWN || Message.Msg == WM_LBUTTONDBLCLK)
{
x = Message.LParamLo;
y = Message.LParamHi;
StringGrid1->MouseToCell(x, y, ACol, ARow);
StringGrid1->Row = ARow;
StringGrid1->Col = ACol;
TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
return;
}
gridOrigProc(Message);
if(Message.Msg == WM_KEYDOWN && (int) Message.WParam == VK_TAB)
{
TGridRect AGridRect = StringGrid1->Selection;
ACol = AGridRect.Left;
ARow = AGridRect.Top;
TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
return;
}
}
//---------------------------------------------------------------------------
void TForm1::CaretSetPosAndShow(int x, int y)
{
bool ret;
try
{
HideCaret(StringGrid1->Handle);
DestroyCaret();
CreateCaret(StringGrid1->Handle, NULL, 4, 15);
ret = SetCaretPos(x, y);
ShowCaret(StringGrid1->Handle);
}
catch(...)
{;
}
}
//---------------------------------------------------------------------------
to header file
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
public: // User declarations
TStringGrid *StringGrid1;
__fastcall TForm1(TComponent* Owner);
virtual void __fastcall gridWindowProc(TMessage &);
void __fastcall (__closure *gridOrigProc)(TMessage &Message);
void CaretSetPosAndShow(int x, int y);
};
Click on a Cell and keep moving while pressing TAB.
We will be greatfull for any help.
Best regards,
Oleg
 
 

Re:How should I move the cursor??

"Oleg" < XXXX@XXXXX.COM >wrote:
Quote

We use Borland Developer Studio 2006 C++ Builder. [...]
BiDiMode = bdRightToLeft, [...] When we used C++ Builder 5,
it worked perfectly.
Check the docks for the win32 API CreateWindowEx and look at
the dwExStyle parameter. More specifically look at the
WS_EX_RIGHT and WS_EX_RTLREADING flags. Note that it says:
" [...] This style has an effect only if the shell
language is Hebrew, Arabic, or another language that
supports reading order alignment; otherwise, the style
is ignored and not treated as an error. "
If your system isn't set to one such language, that could very
well be the problem and it only worked in BCB5 because of a
bug that has been fixed in BCB6 (I have BCB6 and see the same
problem).
Keeping with the assumption that it was a bug in BCB5, I found
that setting the BiDiMode property is persistant (meaning that
it still returns bdRightToLeft) but when I used GetWindowLong,
none of the RightToLeft ExStyles are set. It seems reasonable
to me that BCB5 was checking the BiDiMode when it should have
been checking the ExStyle instead and has since been corrected.
If you have the language set (or if you change the language),
the problem might be with the grid's ParentBiDiMode property.
According to the docs, the ParentBiDiMode must be false or the
BiDiMode is ignored. I tested this and received the same
results but I also didn't change the language.
Ultimately, you can work around the problem by changing your
code to accomplish what you need:
//-------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
void __fastcall CaretSetPosAndShow(int x, int y);
public: // User declarations
TStringGrid *StringGrid1;
TWndMethod OldGridWndProc;
void __fastcall NewGridWndProc( TMessage &Message );
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//-------------------------------------------------------------
//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
StringGrid1 = new TStringGrid( this );
StringGrid1->Parent = this;
StringGrid1->Align = alClient;
StringGrid1->ParentBiDiMode = false;
StringGrid1->BiDiMode = bdRightToLeft;
// this is the correct way to set a property
StringGrid1->Options = StringGrid1->Options << goTabs;
OldGridWndProc = StringGrid1->WindowProc;
StringGrid1->WindowProc = NewGridWndProc;
}
//-------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
// needs to be restored before the object is destroyed
StringGrid1->WindowProc = OldGridWndProc;
}
//-------------------------------------------------------------
void __fastcall TForm1::NewGridWndProc(TMessage &Message)
{
int x, y, ACol, ARow;
if(Message.Msg == WM_LBUTTONDOWN || Message.Msg == WM_LBUTTONDBLCLK)
{
x = Message.LParamLo;
y = Message.LParamHi;
StringGrid1->MouseToCell(x, y, ACol, ARow);
StringGrid1->Row = ARow;
StringGrid1->Col = ACol;
TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
}
else if( Message.Msg == WM_KEYDOWN && Message.WParam == VK_TAB )
{
if( StringGrid1->BiDiMode == bdRightToLeft )
{
// Set the key to zero
Message.WParam = 0;
if( (GetKeyState(VK_SHIFT) & 0x80) != 0x80 )
{
if( StringGrid1->Col>StringGrid1->FixedCols ) StringGrid1->Col = StringGrid1->Col - 1;
else
{
StringGrid1->Col = StringGrid1->ColCount - 1;
if( StringGrid1->Row>StringGrid1->FixedRows ) StringGrid1->Row = StringGrid1->Row - 1;
else StringGrid1->Row = StringGrid1->RowCount - 1;
}
}
else
{
if( StringGrid1->Col < StringGrid1->ColCount - 1 ) StringGrid1->Col = StringGrid1->Col + 1;
else
{
StringGrid1->Col = StringGrid1->FixedCols;
if( StringGrid1->Row < StringGrid1->RowCount - 1 ) StringGrid1->Row = StringGrid1->Row + 1;
else StringGrid1->Row = StringGrid1->FixedRows;
}
}
// Scroll the selected cell into view
if( StringGrid1->Row < StringGrid1->TopRow ) StringGrid1->TopRow = StringGrid1->Row;
else if( StringGrid1->Row>(StringGrid1->TopRow + StringGrid1->VisibleRowCount) ) StringGrid1->TopRow = StringGrid1->Row - StringGrid1->VisibleRowCount;
if( StringGrid1->Col < StringGrid1->LeftCol ) StringGrid1->LeftCol = StringGrid1->Col;
else if( StringGrid1->Col>(StringGrid1->LeftCol + StringGrid1->VisibleColCount) ) StringGrid1->LeftCol = StringGrid1->Col - StringGrid1->VisibleColCount;
}
OldGridWndProc( Message );
TGridRect AGridRect = StringGrid1->Selection;
ACol = AGridRect.Left;
ARow = AGridRect.Top;
TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
}
else OldGridWndProc( Message );
}
//-------------------------------------------------------------
void __fastcall TForm1::CaretSetPosAndShow(int x, int y)
{
// there is nothing in this function that needs a try/catch block
::HideCaret(StringGrid1->Handle);
::DestroyCaret();
::CreateCaret(StringGrid1->Handle, NULL, 4, 15);
::SetCaretPos(x, y);
::ShowCaret(StringGrid1->Handle);
}
//-------------------------------------------------------------
BTW: You need to turn your warnings back on and clear them
instead of ignoring them.
~ JD
 

Re:How should I move the cursor??

Hi JD,
I want to thank you for the work you put into looking for a solution
for the problem I presented.Unfortunately it didn't bring the desired
result. It took us a while to realize that we should to use Borland support
to resolve this problem.
"JD" < XXXX@XXXXX.COM >wrote in message
Quote


"Oleg" < XXXX@XXXXX.COM >wrote:
>
>We use Borland Developer Studio 2006 C++ Builder. [...]
>BiDiMode = bdRightToLeft, [...] When we used C++ Builder 5,
>it worked perfectly.

Check the docks for the win32 API CreateWindowEx and look at
the dwExStyle parameter. More specifically look at the
WS_EX_RIGHT and WS_EX_RTLREADING flags. Note that it says:

" [...] This style has an effect only if the shell
language is Hebrew, Arabic, or another language that
supports reading order alignment; otherwise, the style
is ignored and not treated as an error. "

If your system isn't set to one such language, that could very
well be the problem and it only worked in BCB5 because of a
bug that has been fixed in BCB6 (I have BCB6 and see the same
problem).

Keeping with the assumption that it was a bug in BCB5, I found
that setting the BiDiMode property is persistant (meaning that
it still returns bdRightToLeft) but when I used GetWindowLong,
none of the RightToLeft ExStyles are set. It seems reasonable
to me that BCB5 was checking the BiDiMode when it should have
been checking the ExStyle instead and has since been corrected.

If you have the language set (or if you change the language),
the problem might be with the grid's ParentBiDiMode property.
According to the docs, the ParentBiDiMode must be false or the
BiDiMode is ignored. I tested this and received the same
results but I also didn't change the language.

Ultimately, you can work around the problem by changing your
code to accomplish what you need:

//-------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
void __fastcall CaretSetPosAndShow(int x, int y);
public: // User declarations
TStringGrid *StringGrid1;
TWndMethod OldGridWndProc;
void __fastcall NewGridWndProc( TMessage &Message );
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//-------------------------------------------------------------


//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
StringGrid1 = new TStringGrid( this );
StringGrid1->Parent = this;
StringGrid1->Align = alClient;
StringGrid1->ParentBiDiMode = false;
StringGrid1->BiDiMode = bdRightToLeft;

// this is the correct way to set a property
StringGrid1->Options = StringGrid1->Options << goTabs;

OldGridWndProc = StringGrid1->WindowProc;
StringGrid1->WindowProc = NewGridWndProc;
}
//-------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
// needs to be restored before the object is destroyed
StringGrid1->WindowProc = OldGridWndProc;
}
//-------------------------------------------------------------
void __fastcall TForm1::NewGridWndProc(TMessage &Message)
{
int x, y, ACol, ARow;

if(Message.Msg == WM_LBUTTONDOWN || Message.Msg == WM_LBUTTONDBLCLK)
{
x = Message.LParamLo;
y = Message.LParamHi;

StringGrid1->MouseToCell(x, y, ACol, ARow);
StringGrid1->Row = ARow;
StringGrid1->Col = ACol;

TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
}
else if( Message.Msg == WM_KEYDOWN && Message.WParam == VK_TAB )
{
if( StringGrid1->BiDiMode == bdRightToLeft )
{
// Set the key to zero
Message.WParam = 0;

if( (GetKeyState(VK_SHIFT) & 0x80) != 0x80 )
{
if( StringGrid1->Col>StringGrid1->FixedCols )
StringGrid1->Col = StringGrid1->Col - 1;
else
{
StringGrid1->Col = StringGrid1->ColCount - 1;
if( StringGrid1->Row>StringGrid1->FixedRows )
StringGrid1->Row = StringGrid1->Row - 1;
else StringGrid1->Row = StringGrid1->RowCount -
1;
}
}
else
{
if( StringGrid1->Col < StringGrid1->ColCount - 1 )
StringGrid1->Col = StringGrid1->Col + 1;
else
{
StringGrid1->Col = StringGrid1->FixedCols;
if( StringGrid1->Row < StringGrid1->RowCount -
1 ) StringGrid1->Row = StringGrid1->Row + 1;
else StringGrid1->Row = StringGrid1->FixedRows;
}
}
// Scroll the selected cell into view
if( StringGrid1->Row < StringGrid1->TopRow )
StringGrid1->TopRow = StringGrid1->Row;
else if( StringGrid1->Row>(StringGrid1->TopRow +
StringGrid1->VisibleRowCount) ) StringGrid1->TopRow = StringGrid1->Row -
StringGrid1->VisibleRowCount;
if( StringGrid1->Col < StringGrid1->LeftCol )
StringGrid1->LeftCol = StringGrid1->Col;
else if( StringGrid1->Col>(StringGrid1->LeftCol +
StringGrid1->VisibleColCount) ) StringGrid1->LeftCol = StringGrid1->Col -
StringGrid1->VisibleColCount;
}
OldGridWndProc( Message );
TGridRect AGridRect = StringGrid1->Selection;
ACol = AGridRect.Left;
ARow = AGridRect.Top;
TRect ARect = StringGrid1->CellRect(ACol, ARow);
CaretSetPosAndShow(ARect.Right - 5, ARect.Top);
}
else OldGridWndProc( Message );
}
//-------------------------------------------------------------
void __fastcall TForm1::CaretSetPosAndShow(int x, int y)
{
// there is nothing in this function that needs a try/catch block
::HideCaret(StringGrid1->Handle);
::DestroyCaret();
::CreateCaret(StringGrid1->Handle, NULL, 4, 15);
::SetCaretPos(x, y);
::ShowCaret(StringGrid1->Handle);
}
//-------------------------------------------------------------

BTW: You need to turn your warnings back on and clear them
instead of ignoring them.

~ JD


 

{smallsort}