C++ Builder TTabControl tabs displayed right to left [duplicate] - c++builder

I am programming in a Hebrew environment and so I want the tabs on the top of a TTabControl to be displayed from right to left. The BiDiMode property doesn't affect the tabs, but rather text contained within the control.
I have tried the following code
SetWindowLong (tc.Handle, GWL_EXSTYLE,
GetWindowLong(tc.Handle, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
which gets the tabs displayed correctly, but prevents the controls held within the ttabcontrol from appearing, and so its use is somewhat limited.
Any ideas? BTW, I'm using Delphi 7.
TIA,
No'am

This isn't my code. Something I found, but it seems to work.
procedure TForm1.FormCreate(Sender: TObject);
const
LVM_FIRST = $1000;
LVM_GETHEADER = LVM_FIRST + 31;
var
header: thandle;
begin
header:= SendMessage (TabControl1.Handle, LVM_GETHEADER, 0, 0);
SetWindowLong (header, GWL_EXSTYLE,
GetWindowLong (header, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
SetWindowLong (TabControl1.Handle, GWL_EXSTYLE,
GetWindowLong (lv.Handle, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
lv.invalidate;
end;

I tried the code with D2007 and it's working fine on windows7.
But you could use Raize controls, their PageControl and TabControl could be showed from RightToLeft without any code.

I've found a solution, which while not ideal, is better than nothing. I'm using TabAlign = tbRight, and owner drawing the tabs so that their text appears on the screen as horizontal. Here's a link to the screen shot of the tab control as it is at the moment:
http://4.bp.blogspot.com/_rdlpltE1gDQ/SyNFvVNNe5I/AAAAAAAAAEQ/2DNVlKqRlWE/s1600-h/screen5.JPG)
I would still be appreciative of an answer which has the tabs on the top of the control, but aligned to the right of the control instead of to the left.

I used the following code and just worked fine
procedure TfrmCustomer.FormCreate(Sender: TObject);
const
LVM_FIRST = $1000;
LVM_GETHEADER = LVM_FIRST + 31;
var
header: thandle;
begin
header := SendMessage(pgTypes.Handle, LVM_GETHEADER, 0, 0);
SetWindowLong(header, GWL_EXSTYLE, GetWindowLong(header, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
SetWindowLong(pgTypes.Handle, GWL_EXSTYLE, GetWindowLong(pgTypes.Handle,
GWL_EXSTYLE) or WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
pgTypes.Invalidate;
end;
pgTypes is name of the TPageControl

Related

Virtual TreeView problem in placing vertical scrollbar on the right side in the RightToLeft bidimode

I use the following code to place VirtualTreeView vertical scrollbar on the right side in the RightToLeft bidimode and place it on the left side in the LeftToRight mode.
procedure TForm1.Button2Click(Sender: TObject);
const
LSB = WS_EX_LEFTSCROLLBAR;
var
ExStyle: LONG_PTR;
begin
ExStyle := GetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE);
// Check if RTL alignment specified for you component
if AVTV.BiDiMode = bdRightToLeft then
begin
// If so, then exclude LSB-constant and allow Windows place
// scrollbar on the right side of window
if (ExStyle and LSB) = LSB then
SetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE, ExStyle and not LSB);
end
else
if AVTV.BiDiMode = bdLeftToRight then
begin
// The same as operation above but for LTR order
if (ExStyle and LSB) <> LSB then
SetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE, ExStyle or LSB);
end;
end;
It works correctly but there is a problem when tree is in grid mode and has header columns. Please see screenshot:

Virtual treeview place the vertical scrollbar on right side in the RightToLeft bidimode

Is it possible to place the vertical scrollbar of Virtual treeview on right side in the RightToLeft bidimode and place it on left side in the LeftToRight mode?
Why not? If TVirtualTreeView uses system scrollbars it could be done with setting appropriate extended style.
procedure TForm1.Button2Click(Sender: TObject);
const
LSB = WS_EX_LEFTSCROLLBAR;
var
ExStyle: LONG_PTR;
begin
ExStyle := GetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE);
// Check if RTL alignment specified for you component
if AVTV.BiDiMode = bdRightToLeft then
begin
// If so, then exclude LSB-constant and allow Windows place
// scrollbar on the right side of window
if (ExStyle and LSB) = LSB then
SetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE, ExStyle and not LSB);
end
else
if AVTV.BiDiMode = bdLeftToRight then
begin
// The same as operation above but for LTR order
if (ExStyle and LSB) <> LSB then
SetWindowLongPtr(AVTV.Handle, GWL_EXSTYLE, ExStyle or LSB);
end;
end;
LSB constant is used to make code more compact in post.
See also
GetWindowLongPtrA function
SetWindowLongPtrA function
Extended Window Styles

Delphi. Remove a border of TabSheet of PageControl

Is it possible to remove a border of TabSheet (~4px)? I am using PageControl as a switch-panel instead of frames, windows etc. I want everything will be straight.
unit Unit1;
interface
uses
...,
CommCtrl;
type
TPageControl = class(ComCtrls.TPageControl)
private
procedure TCMAdjustRect(var Msg: TMessage); message TCM_ADJUSTRECT;
end;
TForm1 = class(TForm)
...
end;
...
procedure TPageControl.TCMAdjustRect(var Msg: TMessage);
begin
inherited;
if Msg.WParam = 0 then
InflateRect(PRect(Msg.LParam)^, 4, 4)
else
InflateRect(PRect(Msg.LParam)^, -4, -4);
end;
...
end.
If you don't mind using third-party tools then the easiest solution would probably be to use TjvPageControl from JVCL. It has ClientBorderWidth property which you are looking for.
An alternative is to use a TTabSet with a TPageControl: In the onCreate event of the form, place this code to hide the tab.
procedure TMainForm.FormCreate(Sender: TObject);
var
I : Integer;
begin
for I := 0 to Pred(PageControl1.PageCount) do
PageControl1.Pages[I].TabVisible := False;
PageControl1.Style := tsFlatButtons;
PageControl1.ActivePageIndex := 0;
TabSet1.Style := tsModernPopout;
TabSet1.SelectedColor := clMoneyGreen;
TabSet1.UnselectedColor := clGradientActiveCaption;
TabSet1.SelectedColor := clGradientActiveCaption;
end;
procedure TMainForm.TabSet1Change(Sender: TObject; NewTab: Integer;
var AllowChange: Boolean);
begin
PageControl1.ActivePageIndex := NewTab;
end;
nowadays, that is the answer. No need any code hacks Probably you use themes, if not, you should use that technology:
Project Options > Application> Appearance
Check on one of them as Default Style) than :
Tools > Bitmap Style Designer > Open Style
Navigate your vsf style file
(probably right here
"C:\Users\Public\Documents\Embarcadero\Studio[VERSION]\Styles
Now In Bitmap Style Designer.. navigate to:
Objects > Tabs > Frame > Bitmap
Click [...] three dot button of Bitmap In Inspector
Zoom to 800%
Pan/Scroll and Focus on to bitmap rectangle range.
Right Mouse Click to change Upper-Left, Left Mouse Click to change Lower-Right
region.
(so select inner rectangle to eliminate border bitmap
now you have borderless page controls)

Right to left TListView

I am programming a tlistview so that it displays its columns from right to left (so as to properly display Hebrew text). I am using the following code in the form's create method, where 'lv' is the listview
SetWindowLong (lv.Handle, GWL_EXSTYLE,
GetWindowLong(lv.Handle, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
lv.invalidate;
Whilst this code makes the lines in the listview display correctly, the header line displays from left to right! The columns don't match up and the heading for each column is wrong.
Does anyone have an idea how to get the header line to display right to left?
I am using Delphi 7, not that this should make much difference.
TIA,
No'am
Here is the full code to set the header and the lines:
procedure TForm1.FormCreate(Sender: TObject);
const
LVM_FIRST = $1000; // ListView messages
LVM_GETHEADER = LVM_FIRST + 31;
var
header: thandle;
begin
header:= SendMessage (lv.Handle, LVM_GETHEADER, 0, 0);
SetWindowLong (header, GWL_EXSTYLE,
GetWindowLong (header, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
SetWindowLong (lv.Handle, GWL_EXSTYLE,
GetWindowLong (lv.Handle, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
lv.invalidate; // get the list view to display right to left
end;
I hope this sample'll be useful for you :
var
aCol: TListColumn;
tmp: TListView;
i: integer;
begin
tmp := TListView.Create(Self);
LV.Columns.BeginUpdate;
try
for i := LV.Columns.Count-1 downto 0 do
begin
aCol := tmp.Columns.Add;
aCol.Width := LV.Columns[i].Width;
aCol.Caption := LV.Columns[i].Caption;
end;
LV.Columns := tmp.Columns;
finally
LV.Columns.EndUpdate;
tmp.Free;
end;
end;

Child form to use whole client area?

I'd like to show an MDI child window that will use the whole client area, ie. the grey part no the right-side of the taskpane, and have the child window show its titlebar and borders:
http://img149.imageshack.us/img149/3204/delphimdichildwindowwit.jpg
Here's the code, which doesn't work as planned:
procedure TForm1.RzGroup1Items0Click(Sender: TObject);
var
Form2 : TForm2;
begin
Form2 := TForm2.Create(Application);
//BAD : doesn't start at 0,0, and triggers horizontal scrollbar
Form2.Align := alClient;
//BAD : doesn't show titlebar and borders
Form2.WindowState := wsMaximized;
//BAD : window exceeds width -> horizontal scrollbar shown
Form2.top := 0;
Form2.Left := 0;
Form2.Width := Self.ClientWidth;
Form2.Height := Self.ClientHeight;
end;
Is there a way to do this, besides computing the coordinates myself (eg. ClientWidth, etc.)?
Thank you.
The following code will give you the rect of the MDI client area. Please note that fighting MDI is hard.
Form2.BoundsRect := GetMDIClientAreaBoundsRect(Form1);
function GetMDIClientAreaBoundsRect(MDIForm: TForm): TRect;
begin
if MDIForm.FormStyle = fsMDIForm then begin
if not Windows.GetClientRect(MDIForm.ClientHandle, Result) then
RaiseLastOSError;
end
else
raise Exception.Create('MDIForm is not an MDI form');
end;
The quickest way to do that would be the TILE command.
var
wFrm : TChildMDI;
begin
wFrm := TChildMDI.create(self);
wFrm.Show;
Tile;
end;
TILE is a method of TForm and if you only have 1 MDI child window it will do exactly what you want. With more that 1 it will then arrange all the visible child windows to fit in a similar layout.
Ryan.

Resources