How to dislay correct x-axis (bottom axis) label from datasource using Teechart (Delphi) - delphi-xe2

I would like to ask some help on displaying my datasource’s clientname at the bottom of my stacked bar chart. It seems from all the examples that I researched, the bottom chart axis label is set "automatically" by TeeChart looking at the datasource. However I cant seem to get it to work. Below is a picture of what I am trying to achieve.
Picture of what I am trying to achieve
I have three series' which I use to build the stacked chart. I have included a picture of each datasource I use for each query.
Datasources for three series' queries
From my research it seems I can also use the DBChart1GetAxisLabel() to custom set the labels. But I am struggling to understand how to ensure that the correct custom label name is associated with the correct "clientname" from my queries.
Here is a code sample of how I build the charts:
procedure TfrmSupplierAnalytics.btnOKClick(Sender: TObject);
var
S,NewTypeStr, test, clientSql : string;
var seriasNormalOrders:TBarSeries;
var seriasCreditNoteOrders:TBarSeries;
var seriasPartialOrders:TBarSeries;
N, i : integer;
begin
qCreditNoteOrders.Close;
qNormalOrders.Close;
qPartialOrders.Close;
qGetClientIdFromName.Close;
qClients.Close;
DBChart1.CleanupInstance;
DBChart1.ClearChart;
try
for N := 0 to clbClients.Items.Count-1 do
if clbClients.State[N] = cbChecked then begin
test := string(clbClients.Items[N]);
NewTypeStr := NewTypeStr + '(E.clientid = '+
IntToStr(FindClientID(test)) + ')';
clientSql := clientSql + NewTypeStr;
NewTypeStr := ' or ';
end;
except
on E : Exception do
ShowMessage(E.ClassName+' error raised, with message :
'+E.Message);
end;
OpenQueryCreditNoteOrders(clientSql);
OpenQueryPartialOrders(clientSql);
OpenQueryNormalOrders(clientSql);
seriasNormalOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasNormalOrders);
seriasCreditNoteOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasCreditNoteOrders);
seriasPartialOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasPartialOrders);
seriasNormalOrders.MultiBar := mbStacked;
seriasCreditNoteOrders.MultiBar := mbStacked;
seriasPartialOrders.MultiBar := mbStacked;
seriasNormalOrders.Marks.Visible := true;
seriasNormalOrders.MarksLocation:= mlCenter;
seriasNormalOrders.MarksOnBar := True;
seriasNormalOrders.YValues.ValueSource := 'NormalOrders';
seriasNormalOrders.DataSource := qNormalOrders;
seriasNormalOrders.Title := 'Correct Orders';
seriasNormalOrders.Marks.Visible := True;
seriasNormalOrders.Marks.AutoPosition := true;
seriasCreditNoteOrders.YValues.ValueSource := 'CreditNoteOrders';
seriasCreditNoteOrders.DataSource := qCreditNoteOrders;
seriasCreditNoteOrders.Title := 'Credit Note Orders';
seriasPartialOrders.YValues.ValueSource := 'PartialOrders';
seriasPartialOrders.DataSource := qPartialOrders;
seriasPartialOrders.Title := 'Short Orders';
seriasNormalOrders.CheckDataSource;
seriasCreditNoteOrders.CheckDataSource;
seriasPartialOrders.CheckDataSource;
end;
So, just to sum up, is there some setting in my code which I am missing that would show the "clientname" below each stacked bar, or must I use custom labels?
If I must use custom labels, I would appreciate some direction on how to ensure that I replace the correct "clientname" from the datasource to the correct ValueIndex in the DBChart1GetAxisLabel?
Thanks in advance.

I managed to get an answer.
You could set the XLabelsSource to show the text from the DataSource and then set the series Marks.Style to smsValue to force it showing values instead of showing the labels. Ie:
<pre>
procedure TForm1.FormCreate(Sender: TObject);
var ADOQuery1: TADOQuery;
i: Integer;
begin
ADOQuery1:=TADOQuery.Create(Self);
with ADOQuery1 do
begin
ConnectionString:='Provider=MSDASQL.1;Persist Security Info=False;Data
Source=TeeChart Pro Database';
SQL.Add('SELECT SALARY, LASTNAME from Employee WHERE LASTNAME='#39'Smith'#39);
end;
for i:=0 to 1 do
with DBChart1.AddSeries(TBarSeries) as TBarSeries do
begin
XLabelsSource:='LASTNAME';
DataSource:=ADOQuery1;
MultiBar:=mbStacked;
YValues.ValueSource:='SALARY';
Marks.Style:=smsValue;
end;
ADOQuery1.Open;
end;
</pre>
I tested it in my project and it works.

Related

Why doesn't the radio button on custom page checked in Inno Setup?

Why don't rbStandardInstallType and rbCustomInstallType radio buttons get checked even though I set the Checked property of one of those to True? On the other hand, rbDefaultMSSQLInstance and rbNamedMSSQLInstance radio buttons do get checked.
I create radio buttons like this:
function CreateRadioButton(
AParent: TNewNotebookPage; AChecked: Boolean; AWidth, ALeft, ATop, AFontSize: Integer;
AFontStyle: TFontStyles; const ACaption: String): TNewRadioButton;
begin
Result := TNewRadioButton.Create(WizardForm);
with Result do
begin
Parent := AParent;
Checked := AChecked;
Width := AWidth;
Left := ALeft;
Top := ATop;
Font.Size := AFontSize;
Font.Style := AFontStyle;
Caption := ACaption;
end;
end;
I have 2 custom pages where I must show my image on the left and some text and radio buttons on the right (2 radio buttons per page).
So, in my InitializeWizard procedure I've written this:
wpSelectInstallTypePage := CreateCustomPage(wpSelectDir, 'Caption', 'Description');
rbStandardInstallType := CreateRadioButton(WizardForm.InnerPage, True, WizardForm.InnerPage.Width, ScaleX(15), WizardForm.MainPanel.Top + ScaleY(30), 9, [fsBold], 'Standard');
rbCustomInstallType := CreateRadioButton(WizardForm.InnerPage, False, rbStandardInstallType.Width, rbStandardInstallType.Left, rbStandardInstallType.Top + rbStandardInstallType .Height + ScaleY(16), 9, [fsBold], 'Custom');
wpMSSQLInstallTypePage := CreateCustomPage(wpSelectInstallTypePage.ID, 'Caption2', 'Description2');
rbDefaultMSSQLInstance := CreateRadioButton(WizardForm.InnerPage, True, WizardForm.InnerPage.Width, ScaleX(15), WizardForm.MainPanel.Top + ScaleY(30), 9, [fsBold], 'DefaultInstance');
rbNamedMSSQLInstance := CreateRadioButton(WizardForm.InnerPage, False, rbDefaultMSSQLInstance.Width, rbDefaultMSSQLInstance.Left, rbDefaultMSSQLInstance.Top + rbDefaultMSSQLInstance.Height + ScaleY(10), 9, [fsBold], 'NamedInstance');
And finally, here's my CurPageChanged code in order to display all the controls properly:
procedure CurPageChanged(CurPageID: Integer);
begin
case CurPageID of
wpSelectInstallTypePage.ID, wpMSSQLInstallTypePage.ID:
WizardForm.InnerNotebook.Visible := False;
else
WizardForm.InnerNotebook.Visible := True;
end;
rbDefaultMSSQLInstance.Visible := CurPageID = wpMSSQLInstallTypePage.ID;
rbNamedMSSQLInstance.Visible := CurPageID = wpMSSQLInstallTypePage.ID;
rbStandardInstallType.Visible := CurPageID = wpSelectInstallTypePage.ID;
rbCustomInstallType.Visible := CurPageID = wpSelectInstallTypePage.ID;
end
You are adding the radio buttons to a wrong parent control (WizardForm.InnerPage). Not to the custom pages you are creating. And you then workaround that flaw by explicitly hiding/showing the radio buttons in CurPageChanged.
As all four radio buttons have the same parent (WizardForm.InnerPage), only one of them can be checked. So when you check the rbDefaultMSSQLInstance, the rbStandardInstallType is implicitly unchecked.
For the correct code, see:
Inno Setup Placing image/control on custom page
(make sure you remove your redundant CurPageChanged code)
You should also consider using CreateInputOptionPage instead of manually adding the radio buttons to a generic custom page.

fastreport returns blank page & unconnected header/footer

so I used fastreport for generating reports. I used a couple of them and it works just fine. however today I made another one and when being run, fast report return a blank page despite of having values inside.
I wonder what kind of error is that, so I made another in blank form. when being run, it returns error :
error : unconnected header/footer.
I don't know what happened. the error came suddenly. please help.
It seems you tried to rebuild report with vertical bands. You should reload report template for refreshing report with vertical bands, because of changing object's position on the vertical bands during report's preparing.
Create a second TfrxReport instance, load same report template to it and reload report template before refreshing
procedure TForm1.frxReport1Preview(Sender: TObject);
var Button: TSpeedButton;
begin
Button := TSpeedButton.Create(TfrxPreviewForm(TfrxReport(Sender).PreviewForm).ToolBar);
TfrxPreviewForm(TfrxReport(Sender).PreviewForm).ToolBar.InsertControl(Button);
Button.Caption := 'Refresh';
Button.Width := 60;
Button.OnClick := RefreshReport;
end;
procedure TForm1.RefreshReport(Sender: TObject);
var
idx: Integer;
begin
for idx := 0 to frxReport1.PagesCount - 1 do
if frxReport1.Pages[idx] is TfrxReportPage then
begin
frxReport1.Pages[idx].Clear;
frxReport1.Pages[idx].AssignAll(frxReport2.Pages[idx], True);
end;
TfrxPreviewForm(TSpeedButton(Sender).Owner.Owner).Report.ShowReport;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
frxReport2.AssignAll(frxReport1, True);
frxReport1.EngineOptions.DestroyForms := False;
frxReport1.ShowReport();
end;

Indexes don't work in FDQuery

I have a FDQuery that feeds data to a grid.
When the user clicks on a column I want the grid to order on that column.
Because I want to be able to sort on multiple columns, I cannot use the autosort option of the grid.
I tried the following code in my proof of concept.
However it does not work.
procedure TForm31.JvDBGrid1TitleBtnClick(Sender: TObject; ACol: Integer;
Field: TField);
const
sDesc = 1;
sASC = 2;
sNone = 0;
var
i: integer;
SortClause: string;
AField: TField;
AIndex: TFDIndex;
begin
case Field.Tag of
sDesc: Field.Tag:= sASC;
sASC: Field.Tag:= sNone;
sNone: Field.Tag:= sDesc;
end;
SortClause:= '';
FDQuery1.Indexes.BeginUpdate;
try
FDQuery1.Indexes.Clear;
for i:= 0 to JvDBGrid1.Columns.Count - 1 do begin
AField:= JvDBGrid1.Columns[i].Field;
if AField.Tag <> sNone then begin
AIndex:= FDQuery1.Indexes.Add;
AIndex.Name:= AField.FieldName;
AIndex.Fields:= AField.FieldName;
//AIndex.Options:= [soNoCase, soNullFirst, soDescNullLast, soDescending, soUnique, soPrimary, soNoSymbols]
case AField.Tag of
sDESC: AIndex.Options:= [soDescNullLast];
sASC: AIndex.Options:= [];
end;
AIndex.Active:= true;
end;
end;
finally
FDQuery1.Indexes.EndUpdate;
FDQuery1.Refresh;
end;
end;
It does not matter whether the Query already has an order by clause or not.
What am I doing wrong?
P.S. I'd rather not resort to constructing a custom order by clause but I know that's an option.
I think you may be missing a step, namely setting the FDQuery's IndexName to the name of the added index. Apparently. setting the added index's Active property is insufficient.
The following works fine for me against the MS Sql Server pubs database Authors table:
procedure TForm1.AddFDIndex;
var
AIndex : TFDIndex;
begin
AIndex := FDQuery1.Indexes.Add;
AIndex.Name := 'ByCityThenlname';
AIndex.Fields := 'city;au_lname';
AIndex.Active := True;
FDQuery1.IndexName := AIndex.Name;
end;
Btw, I'm not sure what your code is supposed to do if more than one column is tagged to be included in the index, but I'll leave that to you ;=)

How to change picture delphi timage in run time

I use a timage in a form which load a background image.
The problem is when i choose another picture in run time and change it by
Img_Bk.Picture.LoadFromFile( SaveFileName );
It doesnt work (Picture did n't change ). I mean it shows previous picture and doesn't show the new image during run time. Id like to change application background image during run time in my company by users which main form is a mdi form .
I use delphi 7 .
try
Img_Bk.Picture := nil ;
if FileSize > 100 then
begin
Img_Bk.Picture.LoadFromFile( SaveFileName );
end;
Img_Bk.Stretch := True ;
except
end;
LoadFromFile is known to work. So there must be a more prosaic explanation.
The first possible explanation is that FileSize is not greater than 100 and the if condition evaluates false.
Another possible explanation is that the image in the file that you specify is not the one you are expecting.
Otherwise, your code has a swallow all exception handler. And so when the call to LoadFromFile fails and raises an exception, your code ignores that and carries on as if nothing un-toward had happened. Remove the try/except, and deal with the error that will be revealed.
The real lesson for you to learn is never to write such an exception handler again.
This program should prove to you that LoadFromFile is just fine:
program ImageDemo;
uses
Types, Math, IOUtils, SHFolder, Forms, Controls, StdCtrls, ExtCtrls, jpeg;
var
Form: TForm;
Image: TImage;
Timer: TTimer;
ImageIndex: Integer = -1;
MyPictures: string;
Images: TStringDynArray;
type
THelper = class
class procedure Timer(Sender: TObject);
end;
class procedure THelper.Timer(Sender: TObject);
begin
inc(ImageIndex);
if ImageIndex>high(Images) then
ImageIndex := 0;
if ImageIndex>high(Images) then
exit;
Image.Picture.LoadFromFile(Images[ImageIndex]);
end;
function GetMyPictures: string;
var
Str: array[0..260] of Char;
begin
if SHGetFolderPath(0, CSIDL_MYPICTURES, 0, 0, Str) = S_OK then
Result := Str;
end;
procedure BuildForm;
begin
Form.ClientWidth := 700;
Form.ClientHeight := 500;
Image := TImage.Create(Form);
Image.Parent := Form;
Image.Align := alClient;
Image.Stretch := True;
Timer := TTimer.Create(Form);
Timer.OnTimer := THelper.Timer;
Timer.Interval := 100;
end;
begin
MyPictures := GetMyPictures;
Images := TDirectory.GetFiles(MyPictures, '*.jpg', TSearchOption.soAllDirectories);
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm, Form);
BuildForm;
Application.Run;
end.
I had the same problem today. After the call of LoadFromFile() the image does not change. I have tried Refresh, Repaint, Invalidate and Update -> nothing helped. Then I found that resizing the from immediately updated the image.
Finally I found that setting property Visible to false and back to true updates the image, too.
FormMain.Image1.Visible := false;
FormMain.Image1.Picture.LoadFromFile(newImageFileName);
FormMain.Image1.Visible := true;
Perhaps not the best but it works for me.

How to get images to show up on TExtButton in ExtPascal?

I've been trying for hours in Lazarus following from the sample code in the
AdvancedTabs unit, to make am image appear on a button.
The sample code has this:
constructor TAdvancedTabs.Create;
var
I : integer;
begin
inherited;
with SelfSession do begin
SetCodePress;
SetStyle('.new-tab{background-image:url(' + ExtPath + '/examples/feed-viewer/images/new_tab.gif) !important}');
SetStyle('.tabs{background:url(' + ExtPath + '/examples/desktop/images/tabs.gif)}');
end;
with TExtButton.Create do begin
RenderTo := 'body';
Text := 'Add Tab using AJAX!';
IconCls := 'new-tab';
Handler := Ajax(AddTab);
OnClick := HandleExtButtonClick; // Delphi style event handler
end;
...
I have this:
extPath := (CurrentFCGIThread as TExtThread).ExtPath;
(CurrentFCGIThread as TExtThread).SetStyle('.backbtn{background-image:url(' + ExtPath + '/basxv2/back.png) !important}');
btnClose := TV2ExtButton.Create;
with btnClose.AddTo(Items) do
begin
Id := 'frmManualOrder_btnClose';
X := MarginLeft;
Height := ButtonHeight;
Y := ScreenHeight-12*MarginLeft;
Width := ButtonWidth-10;
RenderTo := 'body';
IconCls := 'backbtn';
...
I have tried a number of different things, converting the image to a
gif, for example, and in most cases the button is either blank (if I
don't set the Text property) or shows the text nudged to the right a
few pixels as if making room for an invisible image. A few times the image appears with the top and bottom clipped.
Can anyone see what I am doing wrong?
TIA
Mark

Resources