Changing font color using TColorBox - delphi

Delphi v7
I have yet another remedial question.
Using a TColorBox I would like to change the font color in each of 4 RichEdit controls. I am using an OnClick event of the color box.
This procedure works fine for one rich edit control.
procedure TForm1.cmbFColorClick(Sender: TObject);
begin
reProc.SelAttributes.Color := cmbFColor.Selected;
end;
If I try to write the same code for each of the richedit controls it will change the font color in all of the richedit control at the same time.
Example: I select and change the text color on one richedit control, then I change the text color on a different control the text color on both richedit controls is changed at the same time.
Example
procedure TForm1.cmbFColorClick(Sender: TObject);
begin
reProc.SelAttributes.Color := cmbFColor.Selected;
reApp.SelAttributes.Color := cmbFColor.Selected;
reServ.SelAttributes.Color := cmbFColor.Selected;
end;
This procedure does not work at all
procedure TForm1.cmbFColorClick(Sender: TObject);
begin
if ActiveControl is TDBRichEdit then
with ActiveControl as TDBRichEdit do
SelAttributes.Color := cmbFColor.Selected;
end;
Is there a way I can change the text color on all of the richedit controls without affecting any of the other controls?

i think the active control is your TColorBox not the richeditboxes, because only one control can be the active control. If i remember right, this control which have the focus.
So you have to implement a procedure like this.
and you have remember by code, which was the last, active richedit.
procedure changeColor(edit : Trichedit) ;
begin
procedure changeColor(edit:Trichedit);
begin
edit.SelAttributes.Color := cmbFColor.Selected;
end;
Kind Regards

Problem solved. In a PageControl OnChange event I set the RichEdit SelLength to "0" for each rich edit control.
Thank you for your help. It gave me the idea.

I'm piecing things together from this question, your last question, the comments to those questions, and your answers to those questions.
What you are trying to do is modify SelAttributes.Color for a single rich edit control. The problem is working out which rich edit control to operate on.
Let us suppose you had the following function available:
function ActiveRichEdit: TRichEdit;
Then you could simply write:
ActiveRichEdit.SelAttributes.Color := NewColor;
Or, if there was a possibility that there was no rich edit control active:
if ActiveRichEdit<>nil then
ActiveRichEdit.SelAttributes.Color := NewColor;
So, how do we implement ActiveRichEdit? Well, it seems that you have a control with multiple pages, each containing a distinct rich edit. That sounds very much like a page control to me.
I'm going to assume that your page control is called PageControl, and the tab sheets called TabSheet1, TabSheet2 etc., and rich edit controls are named RichEdit1, RichEdit2 etc. But if your names are different then you'll need to adapt this code.
function TForm1.ActiveRichEdit: TRichEdit;
begin
if PageControl.ActivePage=TabSheet1 then
Result := RichEdit1
else if PageControl.ActivePage=TabSheet2 then
Result := RichEdit2
else if PageControl.ActivePage=TabSheet3 then
Result := RichEdit3
// etc. etc.
else
Result := nil;
end;
Now, there are other ways to do this. You could make an array of rich edit references that could be indexed by PageControl.ActivePageIndex. And there are indeed yet more possible solutions.
But the key is to use the ActivePage or ActivePageIndex properties of the page control to work out which rich edit control to operate on.

Related

Delphi - How to copy the text from one tedit to another, while the user is typing in the first one?

There are two tedit
One is enabled for the user, and the other disabled.
The moment user types anything in the tedit, the same thing gets typed in the disabled tedit, while the user is typing.
I don't want to use any buttons for this.
How to implement this in Delphi?
You can use the OnChange event of your first TEdit and set text of the second edit to the text of the first. This should look like
procedure TForm1.Edit1Change(Sender: TObject);
begin
Edit2.Text := Edit1.Text;
end;

TListView doesn't hide selection when using explorer style

In Delphi XE4 if you set HideSelection to true and use an explorer style TListView (when the selection rectangle has a gradient background like Windows Explorer) clicking on another control will not hide the selection rectangle. It will stay there as if nothing has happened - it will not even turn into a gray rectangle like normally when the Listview doesn't have focus.
Is this a Delphi bug or a "feature" of the MS Listview control? Are there any known workarounds or fixes for this? It's really annoying...
This is a feature of the underlying control. The delphi code does nothing with the property beyond passing on the LVS_SHOWSELALWAYS list view style to the underlying control.
Initially I was surprised by your question. I've never seen the behaviour that you describe. Upon closer inspection I realise that is because all my list views are virtual. That is they set OwnerData to True and supply content in response to OnData events. Doing that is the only workaround that I know of.
This "feature" is explained by David, and here is a workaround.
By utilizing the OnExit event to save the selection and set selection to nil, you would mimic the wanted behavior. When the ListView is focused, restore the selection.
To make it react on the mouse, make the ListView focused in the OnMouseEnter event.
Type
TForm1 = class(TForm)
...
private
FSelected: TListItem;
...
end;
procedure TForm1.ListView1Enter(Sender: TObject);
begin
if (ListView1.SelCount = 0) and Assigned(FSelected) then
ListView1.Selected := FSelected;
end;
procedure TForm1.ListView1Exit(Sender: TObject);
begin
FSelected := ListView1.Selected;
if Assigned(FSelected) then ListView1.Selected := Nil;
end;
procedure TForm1.ListView1MouseEnter(Sender: TObject);
begin
ListView1.SetFocus;
end;
Having mentioned this solution, why not go for the simple one, set HideSelection = false, and the selected item will turn gray when unfocused, just like Sertac mentioned in a comment.

Right click(popup menu) does not work when change diretion of treeview with SetWindowLong Command

When I use SetWindowLong command to change direction of treeview, popupmenu on its node dose not show. Full Code is here :
Procedure SetWinControlBiDi(Control: TTreeView);
var
ExStyle: Longint;
begin
ExStyle := GetWindowLong(Control.Handle, GWL_EXSTYLE);
SetWindowLong(Control.Handle, GWL_EXSTYLE, ExStyle or WS_EX_RTLREADING or WS_EX_RIGHT or WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT );
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
SetWinControlBiDi(TreeView1);
end;
The standard way to do this is to use the Delphi BiDiMode property. It's best to do it this way so that the VCL is aware that you want right-to-left. You need to change the BiDiMode property on the popup menu too.
Now, the correct way to do this is not to change the properties on the individual components. Doing it that way is laborious and very error prone. Set Application.BiDiMode somewhere in your application's initialization and the change will propagate through to all your components.
For example you can make the change in your application's .dpr file:
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.BiDiMode := bdRightToLeft;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
You need to make sure that you have not modified any component's BiDiMode or ParentBiDiMode in any .dfm file. If you have simply remove those lines from your .dfm file and that will allow the single application wide Application.BiDiMode setting to control everything.
Your approach of setting GWL_EXSTYLE is problematic. The VCL is in control of that setting and if you do need to change it, doing so in TForm.OnShow will lead to strange bugs. Sometimes windows need to be re-created and when this happens your code to set GWL_EXSTYLE will not run and your tree view will revert to left-to-right. If you do need to modify the window styles then you need to override TWinControl.CreateParams for the component. However, in this case the VCL has direct support for BiDi and that is the best solution.
This is an alternative solution to show TPopupMenu In this case
1- Use OnMouseDown Event
2- Write this code to show a TPopupMenu when you click the right mouse button
var
pt : TPoint;
begin
pt := Mouse.CursorPos;
if Button = mbRight then
APopupMenu.Popup(pt.X, pt.Y);
Good luck !

XP Style Glyph annoyance in ActionBars

I dont like to ask too many questions in relation to the appearance of components, but these days appearance in Applications seems just as important.
Anyway, please see the below images:
Both are using the TActionManager and TActionMainMenuBar to create my main menu. The menu in the left of the image is using the Platform Default Style, the menu on the right is using the XP style defined by my TActionManager.
Notice how when the left menu is highlighted, the glyph remains the same which is perfect.
Now look at the XP style menu on the right, the glyph draws a drop shadow, pops out slightly and you can see the transparency makes the glyph appear slightly odd.
I want to enable the XP style for my UI, but the way the glyphs are painted I do not like. I also want to change my TToolbar to a TActionToolBar and apply the same XP style, but this will render the glyphs the same too.
How can I make the XP style menu defined in the TActionManager, not render the glyphs like this?
Thanks.
EDIT
This is now the result, having applied some of the techniques from the answers below:
Craig.
Here is some sample code that overrides the XP STYLE, creating a derived class that you can tweak as you like. First step here is to substitute your own derived menu item class, and change its DrawGlyph code, as David told you. I figured you could maybe use some sample code.
This is just a quick demo. It doesn't draw a box around checked items with glyphs, so this custom style is not compatible with Checked items, unless they have no glyphs. You would have to figure out how you want to draw the checked-glyph items (Where I wrote the DrawGlyphFrame would be a good place to add something to draw a checked-state rectangle around a glyph if the Action.Checked property is set).
unit MyActionControlStyle;
// Using this unit: Add it to your project. In your project set your
// style at runtime, add the unit to your uses clause and then set the style
// in that form's formcreate event:
// ActionManager1.Style := MyActionControlStyle.MyStyle;
interface
uses Forms,
Types,
Controls,
XPActnCtrls,
XPStyleActnCtrls,
ActnMan,
ActnList,
ActnMenus,
ActnCtrls;
type
TMyStyleMenuItem = class(TXPStyleMenuItem)
protected
procedure DrawGlyph(const Location: TPoint); override;
// procedure DrawGlyphFrame(const Location:TPoint);
end;
TMyStyleMenuButton = class(TXPStyleMenuButton)
end;
TMyStyleActionBars = class(TXPStyleActionBars)
// override the stuff that I want different than XP Style:
function GetControlClass(ActionBar: TCustomActionBar;
AnItem: TActionClientItem): TCustomActionControlClass; override;
end;
var
MyStyle:TMyStyleActionBars;
implementation
uses ToolWin, Classes, Windows, Graphics, GraphUtil, ImgList;
{ TMyStyleActionBars }
function TMyStyleActionBars.GetControlClass(ActionBar: TCustomActionBar;
AnItem: TActionClientItem): TCustomActionControlClass;
begin
if ActionBar is TCustomActionPopupMenu then
Result := TMyStyleMenuItem
else
if ActionBar is TCustomActionMainMenuBar then
Result := TMyStyleMenuButton
else
Result := inherited GetControlClass(ActionBar,AnItem);
end;
{ TMyStyleMenuItem }
procedure TMyStyleMenuItem.DrawGlyph(const Location: TPoint);
var
ImageList: TCustomImageList;
DrawEnabled: Boolean;
begin
// DrawGlyphFrame(Location);
if not HasGlyph and IsChecked then
begin
Canvas.Pen.Color := ActionBar.ColorMap.FontColor;
DrawCheck(Canvas, Point((TextBounds.Left - 5) div 2, Height div 2), 2);
end;
if not HasGlyph then exit;
if Assigned(Action) then
ImageList := ActionClient.Action.ActionList.Images
else
ImageList := ActionClient.OwningCollection.ActionManager.Images;
if not Assigned(ImageList) then exit;
DrawEnabled := Enabled and (ActionClient.ImageIndex <> -1) or
(csDesigning in ComponentState);
ImageList.Draw(Canvas, Location.X, Location.Y, ActionClient.ImageIndex,
dsTransparent, itImage, DrawEnabled);
end;
initialization
MyStyle := TMyStyleActionBars.Create;
RegisterActnBarStyle(MyStyle);
finalization
UnregisterActnBarStyle(MyStyle);
MyStyle.Free;
end.
This is done by design in the VCL code. The pertinent code is TXPStyleMenuItem.DrawGlyph() in XPActnCtrls.pas.
The easiest way to change the behaviour is to register your own version of the XP action bar style based on TXPStyleActionBars. There are plenty of hooks that would allow you to override TXPStyleMenuItem.DrawGlyph().

Making a TPageControl flat in Delphi 7

I don't know whether this question can be answered here, but I hope it will.
I wrote a simple text editor in Delphi 7 that serves as my primary IDE for writing C code under Windows. I run Windows in a VM and I needed something light.
In any case, it uses a TpageControl that gets a new tab whenever you open or create a new file. Pretty standard.
Now, the TPageControl under Delphi has no flat property.
NO I don't mean setting the tab style to tsButtons or tsFlatButtons
the borders cannot be set to "none" and it looks pretty bad when you add a text editor into the tab control.
Is there any way to make a TpageControl flat?
EDIT:
On an open source PageControl that supports flat here's what I found:
procedure TCustomTabExtControl.WndProc(var Message: TMessage);
begin
if(Message.Msg=TCM_ADJUSTRECT) and (FFlat) then
begin
Inherited WndProc(Message);
Case TAbPosition of
tpTop : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Top:=PRect(Message.LParam)^.Top-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpLeft : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Left:=PRect(Message.LParam)^.Left-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpBottom : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Bottom:=PRect(Message.LParam)^.Bottom-4;
PRect(Message.LParam)^.Top:=0;
end;
tpRight : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=PRect(Message.LParam)^.Right-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
end;
end else Inherited WndProc(Message);
end;
The thing is when I tried something similar on the main application it won't work. It won't even compile.
When the tabs are drawn as buttons, no border is drawn around the display area, so set the Style property to tsButtons or tsFlatButtons. (For non-VCL programmers, this is equivalent to including the tcs_Buttons window style on the tab control.)
An alternative is to use a TNotebook. It holds pages, but it doesn't do any painting at all. You'd have to provide the tabs yourself, such as by setting the tab control's height equal to the height of the tabs, or by using a TTabSet. (TTabSet is available in Delphi 2005; I'm not sure about Delphi 7.)
Regarding the code you found, it would be helpful if you indicated why it doesn't compile, or if you gave a link to where you found it, since I suppose the compilation error was because it refers to fields or properties of the custom class rather than the stock one. Here's what you can try to put it in your own code, without having to write a custom control.
Make two new declarations in your form like this:
FOldTabProc: TWndMethod;
procedure TabWndProc(var Msg: TMessage);
In the form's OnCreate event handler, assign that method to the page control's WindowProc property:
FOldTabProc := PageControl1.WindowProc;
PageControl1.WindowProc := TabWndProc;
Now implement that method and handle the tcm_AdjustRect messsage:
procedure TForm1.TabWndProc(var Msg: TMessage);
begin
FOldTabProc(Msg);
if Msg.Msg = tcm_AdjustRect then begin
case PageControl1.TabPosition of
tpTop: begin
PRect(Msg.LParam)^.Left := 0;
PRect(Msg.LParam)^.Right := PageControl1.ClientWidth;
Dec(PRect(Msg.LParam)^.Top, 4);
PRect(Msg.LParam)^.Bottom := PageControl1.ClientHeight;
end;
end;
end;
end;
You can fill in the other three cases if you need them. Tcm_AdjustRect is a message identifier declared in the CommCtrl unit. If you don't have that message in that unit, declare it yourself; its value is 4904.
I suspect this doesn't stop the control from drawing its borders. Rather, it causes the contained TTabSheet to grow a little bigger and cover up the borders.
I'm using Delphi XE8 and the following seems to do the trick:
ATabControl.Tabs.Clear;
ATabControl.Style := TTabStyle.tsFlatButtons;
ATabControl.Brush.Color := clWhite;
You could always use a commercial solution. I would strongly recommend Raize components, which support flat TPageControls with tabs. The component set is very easy to work with, and supports numerous visual enhancements which in my opinion give a better feel to any application.
(source: raize.com)
Drop two TPageControls, one with tabs as Tabs, with a global height equal to the tabs, and one with flatbuttons and Tabvisible properties set to false, which would be aligned under the first one. Then make sure the tab change on the first TPagecontrol makes the tabs also change in the second one.

Resources