THidepanel development is still putting many questions to me . I followed the instructions given here Other Help and Questions
I designed the inner panel now to have a red color and be a bit smaller as the outer panel. If I run the component in a test application only the outer panel is drawn and all components placed on the inner working panel and beeing visible at design time are no longer visible.
I assume the bug to be the following : the outedr panel is drawn as a last action and therefore at runtime I can not see the red inner panel and the components placed here?
Is this true, where is my assumption wrong, what should I do to fix this problem
The latest Create function for my component comes here :
constructor THidePanel.create(aOwner: TComponent);
begin
inherited;
padding.Left:= BorderSize;
padding.top:= BorderSize;
padding.right:= BorderSize;
padding.Bottom:= BorderSize;
// the inner panel
WorkingPanel := TPanel.create(self);
WorkingPanel.Caption := ' ';
WorkingPanel.BevelOuter := bvNone;
// WorkingPanel.BringToFront;
WorkingPanel.Color :=220;
WorkingPanel.ParentColor := false;
WorkingPanel.Parent := self;
WorkingPanel.Align := alClient;
// the button to mimimize / maximize
FActivateButton := TButton.create(self);
FActivateButton.Parent := self;
FActivateButton.Caption := '<';
FActivateButton.OnClick := H_ActivateButtonClick;
FActivateButton.Width := BorderSize;
FActivateButton.Height := BorderSize;
/// the restore values , correct setting
FLargeWidth := self.Width;
FLargeHeight := self.Height;
FHasCustomSize := false;
// here I draw the activate button on the outer panel
SetButtonPosition(topright);
// drop components only on the inner panel
ControlStyle := ControlStyle - [csAcceptsControls]
end;
Try setting WorkingPanel.Visible to True.
Related
I'm using Delphi 10.3-upd 1 with Teechart component .
At run-time I need to put marks for specific points and customize its texts, colors and sizes. I've succeded in changing texts using the following commands :
Chart1.[idxserie].Marks.Item[idxelement].Visible := True;
Chart1.[idxserie].Marks.Iidxelement]].Font.Color := clRed;
Chart1.[idxserie].Marks.item[idxelement].Text.Add('My text is here');
now I need to change the color of the line that links the text to the point in the graph curve. In design time, this property is located at :
Editing chart window :
Series -- myserie1 -
tab : Marks
-- tab Arrows
-- tab Border
tab -- Format
Button : Color
How do I access and change the value of this property on run-time ?
I've alreeady tried :
Chart1.[idxserie].Marks.Arrow.Color := clRed // ==> nothing changed !
This is where I change the property at design time :
In below picture, the dotted red line for some points I want it in different color. When I use Chart1.[idxserie].Marks.Arrow.Color := clRed it changes the color of all points .
I appreciate your support.
Thanks.
The Arrow is global.
You can overwrite it yourself using one of the AfterDraw events of Series or Chart.
An example:
Creation:
procedure TForm1.FormCreate(Sender: TObject);
begin
series1.FillSampleValues(5);
series1.Marks.Visible := true; // A global flag. if false, no Mark will be visible
series1.Marks[0].Visible := false;
series1.Marks[1].Visible := true;
series1.Marks[2].Visible := false;
series1.Marks[3].Visible := true;
series1.Marks[4].Visible := false;
series1.Marks[3].Font.Color := clRed;
series1.Marks[3].Font.Style := [fsBold];
series1.Marks[3].Transparent:= true;
series1.Marks.Arrow.Color := clGreen;
series1.Marks.ArrowLength := 24;
series1.Marks.Arrow.EndStyle := esFlat;
series1.Marks.Arrow.Visible := true;
end;
Now, draw a line on the Chart Canvas:
procedure TForm1.Series1AfterDrawValues(Sender: TObject);
var
nInx, nX, nY: integer;
begin
for nInx := 0 to Series1.Count-1 do
if Series1.Marks[nInx].Font.Color = clRed then
begin
nX := Series1.CalcXPos(nInx);
nY := Series1.CalcYPos(nInx);
Chart1.Canvas.Pen.Color := clRed;
Chart1.Canvas.MoveTo(nX, nY);
Chart1.Canvas.LineTo(nX, nY - series1.Marks.ArrowLength);
end;
end;
You will get:
I'm attempting to create a custom TToolbar at run-time that floats over the form (below the control it is associated with).
My issue is that the process of floating and positioning the toolbar at creation creates a hideous flicker where it is initially drawn at the top-left of the monitor before being moved to my desired position on the form.
I cannot find a way to avoid this. Is there a way?
procedure TMainForm.Button3Click(Sender: TObject);
var
newToolbar : TToolbar;
newButton : TToolButton;
begin
newToolbar := TToolbar.Create(Self);
newToolbar.Visible := False;
newToolbar.ManualFloat( Rect( 0, 0, newToolbar.Width, newToolbar.Height ));
newToolbar.Parent := Self;
newToolbar.left := 100;
newToolbar.Top := 100;
newToolbar.ShowCaptions := True;
newButton := TToolButton.Create(Self);
newButton.Parent := newToolbar;
newButton.Caption := 'Test';
newToolbar.Visible := True;
end;
References:
- Create TToolbutton runtime
- toolbutton with action created at runtime
- Delphi - Create a custom TToolBar component
I am a little puzzled with your solution, so I provide my two takes on the subject. Specifically I don't understand why you are using ManualFloat() and few lines later set the parent of the toolbar, which makes it non-floating.
Here is a solution for a floating toolbar, using ManualFloat().
The toolbar is floating above the form in its own temporary TCustomDockForm,
at the given location.
The record needed by ManualFloat() is setup for the final location, thus no flicker in the wrong place, and the control
is immediately correctly positioned.
procedure TForm1.Button3Click(Sender: TObject);
var
newToolbar : TToolbar;
newButton : TToolButton;
p: TPoint;
begin
newToolbar := TToolbar.Create(Self);
// calculate position in screen coordinates for the floating toolbar
p := ClientOrigin;
p.Offset(100, 100);
// and make it floating in final position
newToolbar.ManualFloat( Rect(p.X, p.Y, p.X+NewToolbar.Width, p.Y+newToolbar.Height) );
newToolbar.Visible := False; // really needed ?
// Then create the toolbar buttons
newToolbar.ShowCaptions := True;
newButton := TToolButton.Create(self);
newButton.Parent := newToolbar;
newButton.Caption := 'Test';
newToolbar.Visible := True;
end;
However, since you actually seem to want a non-floating toolbar, that is just
located anywhere you like on the form (and not in the default top of the form),
a better solution is to skip the ManualFloat() altogether and just set the
Align property of the toolbar to alNone. This enables it to be moved anywhere
on the parent form.
procedure TForm1.Button4Click(Sender: TObject);
var
newToolbar : TToolbar;
newButton : TToolButton;
begin
newToolbar := TToolbar.Create(Self);
newToolbar.Align := alNone; // constructor sets it to alTop
newToolbar.Visible := False; // really needed ?
newToolbar.Parent := Self;
newToolbar.Left := 100;
newToolbar.Top := 200;
newToolbar.ShowCaptions := True;
newButton := TToolButton.Create(self);
newButton.Parent := newToolbar;
newButton.Caption := 'Test';
newToolbar.Visible := True; //
end;
This gives you the same appearance as your own code, but omits the ManualFloat().
Finally, an image to show the appearances:
The bottom toolbar is created with Button4Click()
Thanks #TomBrunberg for your suggestion.
What was needed to make it position over the form without any pre-drawing:
Position it off-screen when ManualFloat is called
Set Visible to false after call to ManualFloat (because ManualFloat sets it true)
Revised code:
procedure TMainForm.Button3Click(Sender: TObject);
var
newToolbar : TToolbar;
newButton : TToolButton;
begin
newToolbar := TToolbar.Create(Self);
// Float with off-screen position
newToolbar.ManualFloat( Rect( 0, -200, newToolbar.Width, newToolbar.Height - 200 ));
// Must hide after ManualFloat call, as it resets Visible to true
newToolbar.Visible := False;
// Set parent so we can add buttons, sets props, etc.
newToolbar.Parent := Self;
// Move to desired position over form
newToolbar.left := 100;
newToolbar.Top := 100;
// Add our button content...
newToolbar.ShowCaptions := True;
newButton := TToolButton.Create(Self);
newButton.Parent := newToolbar;
newButton.Caption := 'Test';
// Now we can show it
newToolbar.Visible := True;
end;
Searching for a Delphi label component with basic format/markup support I came across Delphi Markup Label (MDLabel). As a bonus it supports links. Unfortunately I can't get it working. The component is provided as a single MD_Label.pas file. I've created a component package for it and installed it. I can now select it from the components list, but adding it to a form throws an error:
Control 'MDLabel1' has no parent window."
I traced it down to the call CreateWnd and found some topics for similar problems, but still wasn't able to solve this. Did I do something wrong or is this something that needs to be adjusted because the initial code was written for Delphi 2007 and I'm using XE?
The component is to large to post the whole source code here, but you can download it from the link above. Here's the creation part:
constructor TMDLabel.Create(AOwner: TComponent);
begin
FInitialized := False; // required for runtime creation of MDLabel
inherited;
ControlStyle := [csOpaque, csCaptureMouse, csClickEvents, csSetCaption];
FLinkFontNormal := TFont.Create;
FLinkFontNormal.Assign(Font);
FLinkFontNormal.Color := clBlue;
FLinkFontNormal.Style := [];
FLinkFontHover := TFont.Create;
FLinkFontHover.Assign(Font);
FLinkFontHover.Color := clRed;
FLinkFontHover.Style := [fsUnderline];
Width := 100;
Height := 13;
Cursor := crArrow;
TabStop := False;
DoubleBuffered := True;
FTextHeight := 0;
FAutoSizeWidth := True;
FAutoSizeHeight := True;
FTextAlignment := taLeftJustify;
FCompressSpaces := False;
FTabWidth := 8;
FParsingText := False;
FBuildingLines := False;
FRebuildLines := False;
FMaxWidth := 0;
FLinkFontNormal.OnChange := DoFontChange;
FLinkFontHover.OnChange := DoFontChange;
FOnLinkClicked := nil;
FOnPaintBackground := nil;
FOnHeightChanged := nil;
FOnWidthChanged := nil;
FLines := TList.Create;
FWords := TList.Create;
FLinkRCs := TList.Create;
FMouseDownMove := False;
FMouseWasDown := False;
FMouseDownIndex := - 1;
FInitialized := True;
end;
procedure TMDLabel.CreateWnd;
begin
inherited CreateWnd;
{$IFNDEF UNICODE}
if (inherited Caption <> '') and (FCaptionUTF8 = '') then CaptionUTF8 := inherited Caption;
{$ENDIF}
end;
Full source: http://pastebin.com/sxYvpqTy
As a side note: If you feel that there's a better component that supports formating text within labels, please feel free to share as a comment (TJvHTLabel and TJvMarkupLabel are not good).
This error is a very common one for component authors who don't understand how the VCL works internally.
The fact that the error occurs while dropping the component on the Form at design-time means that the component's constructor is doing something it should not be. One of the operations requires the component's Handle to have an allocated HWND, but that is not possible at the time of the error because the component's Parent property has not been assigned yet, or the Parent.Handle does not have an allocated HWND of its own. The Parent is not assigned until after the constructor exits.
So, you need to debug the code and find the offending constructor code that relies on the component's Handle property, and move it out of the constructor. Depending on which code it is, it either belongs in Loaded() or CreateWnd(), or even SetParent(), or it may even need to be disabled completely at design-time (sometimes run-time code should not be executed at design-time or during DFM streaming at all).
I already found much help for writing a components which allows Hiding of components here ( THIDEPANEL. Now I suffer a first issues:
During the OnCreate event of this class I take the Panel width and height, I want to restore to the original values while hidden / unhiding the panel. Actually the hide process always decrease the size of the panel
constructor THidePanel.Create(AOwner: TComponent);
begin
inherited;
// The inner panel
WorkingPanel := TPanel.Create(Self);
WorkingPanel.Caption := '***';
// The hide unhide
FActivateButton := TButton.Create(Self);
FActivateButton.Parent := self;
FActivateButton.Caption := '<';
FActivateButton.OnClick := H_ActivateButtonClick;
FActivateButton.Width := BoarderSize;
FActivateButton.Height := BoarderSize;
WorkingPanel.Caption := '';
// Grab the size of the hide panel, later restore to this values
FLargeWidth := Self.Width;
FLargeHeight := Self.Height;
SetButtonPosition(TopRight);
end;
It is because the FLargeWidth private field has an invalid value. You assign it with Self.Width during the constructor (and you presumably never update it). That is not the width you set at design time or at run time, but it is the hard coded width from TCustomPanel.Create, which is 185. Note that when a control's constructor is run, the control is not placed yet.
If you want to remember the set width, then you should "override TControl.SetWidth". But since that method is private (not virtual), you need to override either SetBounds or Resize in order to response to Width's change. I would choose the latter, probably with an additional condition:
procedure THidePanel.Resize;
begin
if not HasCustomWidth then //< Replace this with your own logic condition
FLargeWidth := Width;
inherited Resize;
end;
The only dock style in JVCL that I know that has the auto hide function (to pin the dock clients) is JvDockVSNetStyle. I'm using it but I can't set the size of the inactive pinned panes' tabs. When hidden, the tabs don't show the title of the pane, only the name of the active pane is shown. Sorry, I can't post an example image because that's my first question.
In the object inpector there is an option called ChannelOption with the ActivePaneSize property. Is there a way to set the inactive pane size so it can show its name? Or maybe there is another dock style that I'm missing that has the same functions?
I'm using C++Builder and JVCL 3.45.
i did it by commenting out these code parts:
procedure TJvDockVSChannel.GetBlockRect(Block: TJvDockVSBlock; Index: Integer;
var ARect: TRect);
var
BlockWidth: Integer;
begin
// HERE
// if Block.VSPane[Index] <> Block.ActivePane then
// BlockWidth := Block.InactiveBlockWidth
// else
BlockWidth := Block.ActiveBlockWidth;
<snip>
procedure TJvDockVSChannel.Paint;
var
I: Integer;
<snip>
begin
VisiblePaneCount := 0;
for I := 0 to Block.VSPaneCount - 1 do
begin
if not Block.VSPane[I].FVisible then
Continue;
GetBlockRect(Block, I, DrawRect);
Canvas.Brush.Color := TabColor;
Canvas.FillRect(DrawRect);
Canvas.Brush.Color := clGray;
Canvas.FrameRect(DrawRect);
AdjustImagePos;
Block.FImageList.Draw(Canvas, DrawRect.Left, DrawRect.Top, I, dsTransparent, itImage);
// HERE
// if Block.ActivePane = Block.VSPane[I] then
begin
if Align in [alTop, alBottom] then
Inc(DrawRect.Left, Block.InactiveBlockWidth)
else
if Align in [alLeft, alRight] then
begin
Inc(DrawRect.Top, Block.InactiveBlockWidth);
if Align = alLeft then
DrawRect.Left := 15
else
DrawRect.Left := 20;
DrawRect.Right := DrawRect.Left + (DrawRect.Bottom - DrawRect.Top);
end;
Canvas.Brush.Color := TabColor;
Canvas.Pen.Color := clBlack;
Dec(DrawRect.Right, 3);
OldGraphicsMode := SetGraphicsMode(Canvas.Handle, GM_ADVANCED);
Canvas.Brush.Style := bsClear;
// HERE (changed options)
DrawText(Canvas.Handle, PChar(Block.VSPane[I].FDockForm.Caption), -1, DrawRect, {DT_END_ELLIPSIS or} DT_NOCLIP);
There is an event in TJvDockServer called DoFinishSetDockPanelSize.
Within the function you create for that event you can access the size of a form using Dockpanel. There may be a way from here to set the size of the tabs.