Adding a TeeChart function datasource causes access violation - delphi

I am using Delphi 10 Seattle Subscription Update 1 and TeeChart Standard v2015.15.150420 which came bundled with Delphi.
I drop a TDBChart component on a new VCL application's blank form. I then use the sample code as outlined in the "Adding a Function" tutorial found at http://www.teechart.net/docs/teechart/vclfmx/tutorials/UserGuide/Tutorials/tutorial7.htm#AddFunction in the form's OnCreate event. With this code everything works as it should and I get two bar series populated with sample values and one line series which represents the average of the two bar series.
The problem comes in if I don't want the average represented by a line series, but rather by, say, a bar series. If I change the TLineSeries to a TBarSeries and run the program, it causes an "access violation at 0x0066d665: read of address 0x00000198" on adding the first bar series as a datasource to the function series (tmpLineSeries), eg. tmpLineSeries.DataSources.Add( tmpBarSeries1 );.
Here's the problem code (see "AV occurs here" below). Note that the only code that changed from the working tutorial example was, as explained, tmpLineSeries that had been changed to a TBarSeries type instead of a TLineSeries type :
procedure TForm1.FormCreate(Sender: TObject);
var tmpBarSeries1,
tmpBarSeries2 : TBarSeries;
tmpLineSeries : TBarSeries;
begin
//Add 2 data Series
tmpBarSeries1:=TBarSeries.Create(Self);
tmpBarSeries2:=TBarSeries.Create(Self);
DBChart1.AddSeries(tmpBarSeries1);
DBChart1.AddSeries(tmpBarSeries2);
//Populate them with data (here random)
tmpBarSeries1.FillSampleValues(10);
tmpBarSeries2.FillSampleValues(10);
//Add a series to be used for an Average Function
tmpLineSeries:=TBarSeries.Create(Self);
DBChart1.AddSeries(tmpLineSeries);
//Define the Function Type for the new Series
tmpLineSeries.SetFunction(TAverageTeeFunction.Create(Self));
//Define the Datasource for the new Function Series
//Datasource accepts the Series titles of the other 2 Series
tmpLineSeries.DataSources.Clear;
tmpLineSeries.DataSources.Add( tmpBarSeries1 ); ////// AV occurs here!!!
tmpLineSeries.DataSources.Add( tmpBarSeries2 );
// *Note - When populating your input Series manually you will need to
// use the Checkdatasource method
// - See the section entitled 'Defining a Datasource'
//Change the Period of the Function so that it groups averages
//every 2 Points
tmpLineSeries.FunctionType.Period := 2;
end;
It seems to either be a bug in TeeChart or I am missing a configuration step necessary for BarSeries that is not necessary for LineSeries.
Can anyone see what I am doing wrong, or alternatively suggest a workaround for the bug? I don't think upgrading to the latest version of TeeChart is an option at this stage because, as I understand it, this can only be done by upgrading Delphi (I'm already at the latest update of Delphi), or alternatively purchasing the standalone version of TeeChart.

This looks like a bug to me. I have add it (bug #1484) to Steema Software's bugzilla. The only workaround I can think of is setting TTeeFunction.Period property to a value greater than zero so the offending code is not executed. For example:
//workaround
tmpLineSeries.FunctionType.Period:=1;
tmpLineSeries.DataSources.Add( tmpBarSeries1 ); ////// AV occurs here!!!
tmpLineSeries.DataSources.Add( tmpBarSeries2 );
UPDATE: This has been fixed for the next TeeChart release.

Related

Vaadin 14 FlagItems not aligned correctly on ListSeries

I've got a problem regarding the FlagItem in Vaadin 14.
I'm trying to set a FlagItem for a specific point in a ListSeries, I'm doing this the following way:
PlotOptionsFlags plotOptionsFlags = new PlotOptionsFlags();
plotOptionsFlags.setOnSeries(wageEntry.getEmployeeCode());
plotOptionsFlags.setShape(FlagShape.SQUAREPIN);
plotOptionsFlags.getTooltip().setPointFormat("Wage: {point.y}");
plotOptionsFlags.getTooltip().setHeaderFormat("");
plotOptionsFlags.setShowInLegend(false);
DataSeries flagsSeries = new DataSeries();
flagsSeries.setName(wageEntry.getEmployeeCode().concat(" Current Wage"));
flagsSeries.setPlotOptions(plotOptionsFlags);
for (WageEntry wage : employeeWageEntries) {
if (wage.getWageYear() == LocalDate.now().getYear()) {
flagsSeries.add(new FlagItem(wage.getAge() - 22, wage.getEmployeeCode().concat(" - ").concat(String.valueOf(wage.getWageAmount()))));
}
}
comparisonChartConfiguration.addSeries(flagsSeries);
As you can see, I set the x value relative to the age of an entry, and the text. More over the FlagItem is only created when a certain condition is met. (I used the Vaadin Chart Demo as reference: https://demo.vaadin.com/charts/Flags)
The problem now is, that when the chart is being built, the FlagItem appear on the x axis instead as you can see here:
I really don't understand why this happens.
Maybe it's useful to know, that on the chart three RangeSeries and multiple ListSeries are being drawn.
Thanks for the help!
So I've found out where the problem was. It was something that wasn't added to the code above, so please have mercy.
The issues lied withing the fact that I didn't add the ListSeries to the comparisonChartConfiguration before creating the flagsSeries.
In short, you need to add the Series you want to append flags on to the ChartConfiguration before you can attach the flagsSeries onto another.

Why this code do not work in second time click button

I write this code for button click event . the first time I click the button every thing work correctly but when click for the second time on button it raise an error. whats the problem?
procedure TfrmMain.Button1Click(Sender: TObject);
var
B : Boolean;
begin
DM.tblTemp.DisableControls;
B:= DM.tblTemp.Locate('FoodName', DM.tblAsli.FieldByName('FoodName').AsString,[]) ;
if B then
begin
DM.tblTemp.Edit;
DM.tblTemp.FieldByName('Number').AsInteger:= DM.tblTemp.FieldByName('Number').AsInteger + 1;
DM.tblTemp.Post;
end
else
begin
DM.tblTemp.insert;
DM.tblTemp.FieldByName('FoodName').AsString := DM.tblAsli.FieldByName('FoodName').AsString;
DM.tblTemp.FieldByName('UnitPrice').AsInteger := DM.tblAsli.FieldByName('FoodPrice').AsInteger;
DM.tblTemp.FieldByName('Number').AsInteger := 1;
DM.tblTemp.Post;
end;
TotalPrice:= TotalPrice + DM.tblTemp.FieldByName('TotalPrice').AsInteger;
DM.tblTemp.EnableControls;
end;
the Error is
Row cannot be located for updating. Some values may have been changed
since it was last read
DM is data madual
tmbTbl is ADOTable
It is a pity you haven't said which DBMS you are using (e.g. Sql Server or MS Access,
nor told us a full list of the table's column types and indexes, if any.
The most likely answer to your q is that the variable B is set to False the first time
because the call to tblTemp.Locate fails to locate the Food name in question, so the Insert branch executes and the food's data is
added to the table but the second time the Edit branch executes and the error occurs,
though you have not said where, exactly. My guess would be on the call to .Post, because
the error message is one the ADO layer, which sits between the DBMS provider and your app,
emits when it attempts to post a change to the table but cannot identify which table row to update.
As I mentioned in a comment, the fix to this is usually at add a primary key index to the table, and I gather from your latest comment that this has succeeded for you. For the record and benefit of future readers it would be helpful if you could confirm which DBMS you are using and which Ole Driver you are using in your connection string.
Fwiw, I've tested your code using a table on MS Sql Server and MS Access and do not get the
error with either database.
Btw there is an obvious q, "How is it that tblTemp.Locate succeeds, but ADO is unable to
identify the correct record to post the update?" The answer is that tblTemp.Locate works in
a different way than identifying the relevant row to post the update.

Pharo Smalltalk: How to create an input field using TextMorph and then get the data off the input field?

I am completely new to Pharo, Smalltalk. I'm developing a small app that will convert temperature from Fahrenheit to Celsius. Can anyone give me any idea on how to create an input field using TextMorph and display it on a window as shown in the screen shot. In addition, being able to get the data back from the input field when the button is clicked. The below code is what I have done so far.
Screenshot
The class TemperatureMorph
BorderedMorph subclass: #TemperatureMorph
instanceVariableNames: 'tempInputField counter'
classVariableNames: ''
package: 'Assignment'
The initialize method: Contains a label, textbox and a button.
initialize
| headingLabel converterButton|
super initialize.
self bounds: (0#0 corner:300#300).
self color: Color gray.
headingLabel := StringMorph contents: 'Converter'.
headingLabel position: 130#20.
self addMorph: headingLabel.
tempInputField := TextMorph new.
tempInputField position: 50#50.
self addMorph: tempInputField.
Thanks
On a side not, if you're doing UI stuff in Pharo for anything other than learning (It looks like OP /is/ learning, so this probably doesn't apply). You should be looking at either Glamour or Spec. Both of which have really easy text input and control systems.
Spec
Glamour
You can already see the necessary code in your screenshot, you only have to replace the construction of a StringMorph with that of a TextMorph. I suggest you take a look at the Pharo by Example book. It has a chapter on Morphic, which is the UI framework in Pharo.
yourTextMorph := TextMorph new.
yourTextMorph contents: 'initial text'.
ownerMorph addMorph: yourTextMorph.
I guess you will also want to read the contents back out of the TextMorph. You can use yourTextMorph contents to achieve that. See also Pharo Smalltalk: Reading from TextMorph

TListView DynamicAppearance with TImageObjectAppearance will not view image when using LiveBindingsDesigner with TFDMemTable

I am welcoming Embarcaderos efforts to make TListView more dynamically, and was exited to see Sarina Duponts post here where you could just link the imageindex to the TListView properties in LiveBindings Designer, and even the image property to a datafield (integer) when using DynamicAppearance and TImageObjectAppearance.
But... I tried, and did almost succeed.
In my challenge I have an application where I use TFDMemTable with TREST* function to populate the TFDMemTable. All works well if I don't use the DynamicAppearance and use i.e. ImageListItem and links the datafield I want to use to the imageindex property in TListView using LiveBindings Designer.
With DynamicApperance though, there are no imageindex property to link to, but Sarina Dupont says in here post that you could link the integer field directly to the image property (and IDE/compiler will figure it out).
Well... I figured following out: My data fields (semicreated from TREST* and TFDMemTable) are not neccesserely what they seems to be. Since I am using REST/JSON, the fieldtypes are "anonymized" to WideString, actually the FieldDefs->'dataitem'->DataType is set to "ftWideString". I tried to change this value to ftInteger in hope that this would help, but I did just get this errormessage: "FDMemtTable1: Type mismatch in field for 'datafield', exepecting: WideString actual: Integer".
So... I was nearly there, and I really want to use DynamicAppearance and view several images and textfields for each TListViewItem...
...or is it easier to make a ListViewItem 'Template' dynamically and populate it with data instead, and what is the best way to do that ?
I usually try to avoid LiveBindings. The fastest, most stable and easiest way is to add items using code.
ListView1->BeginUpdate();
try {
for (int i = 0; i < arrayOfThings->item.Length; i++) {
TListViewItem* item = ListView1->Items->Add();
item->Text = arrayOfThings->item[i]->item_name;
item->Data["itemName"] = TValue::From<UnicodeString>( arrayOfThings->item[i]->item_name);
item->Data["itemId"] = TValue::From<UnicodeString>( IntToStr( arrayOfThings->item[i]->id ));
item->Data["itemDate"] = TValue::From<UnicodeString>(arrayOfThings->item[i]->item_date);
// adding the image - imgClock is name of the image field [TImageObjectAppearance ] added to items in ItemAppearance in the TListView object that uses DynamicAppereance
const UnicodeString imgClock = L"imgClock";
dynamic_cast<TListItemImage*>(item->Objects->FindDrawable(imgClock))->Bitmap = //bitmap source;
}
} catch (...) {
}
ListView1->EndUpdate();

Strange behavior using TPointSeries.Clear

(Delphi 6 with TChart, Win XP)
I'm getting erratic behavior trying to clear the points from a point series, and of course, this code used to work.
Basically, this part of my program generates 5 data points and plots them. When I try to clear them using OSC_Series.Clear I get a "List index out of bounds [0]" error.
I checked to make sure there was nothing odd about the values I was plotting. All is good there. Then I tried different things to try to isolate and work around the problem.
Here's some code.
type
TksGraph_DataFrm = class(TForm)
.
.
.
private
OSC_Series: TPointSeries
public
end;
procedure TksGraph_DataFrm.cat7AnalysisInitialize(var P:TTest_Project);
begin
// Do a bunch of stuff.
// Set up the analysis data points series.
OSC_Series:=TPointSeries.Create(self);
AnalysisChart.AddSeries(OSC_Series);
with OSC_Series do
begin
Title:='';
HorizAxis:=aBothHorizAxis;
VertAxis:=aBothVertAxis;
SeriesColor:=clRed;
Pointer.Brush.Color:=clYellow;
Pointer.HorizSize:=4;
Pointer.VertSize:=4;
Pointer.Style:=psRectangle;
Pointer.Visible:=true;
LinePen.Color:=clBlack;
LinePen.Width:=1;
Linepen.Visible:=true;
ShowInLegend:=false;
XValues.Order:=LoNone;
end;
end;
procedure TksGraph_DataFrm.cat7AnalysisRefresh(var P:TTest_Project);
var X,Y:single;
begin
X:= some value
Y:= some value
// Plot the result.
OSC_Series.AddXY(X,Y);
showmessage(
'Count = '+inttostr(OSC_Series.Count)+#13+
'X = '+FloatToStr(X)+#13+
'Y = '+FloatToStr(Y)+#13+
'Plot-X = '+FloatToStr(OSC_Series.XValue[OSC_Series.Count-1])+#13+
'Plot-Y = '+FloatToStr(OSC_Series.YValue[OSC_Series.Count-1]));
end;
Here is the routine I to use to reset the series. I'm including code that does and does not work.
procedure TksGraph_DataFrm.cat7AnalysisClear(var P:TTest_Project);
var i:integer;
begin
// This should work, but it gives me the list out of bounds error
// unless the count is 0.
OSC_Series.Clear;
// This does not work, for obvious reasons. I get a "list out of
// bounds [3] for this one.
for i:=0 to OSC_Series.Count - 1 do OSC_Series.Delete[0];
// It seems this should work, but again I get the out of bounds [0]
// error.
repeat
OSC_Series.Delete(0);
until OSC_Series.Count = 0;
// This works. Don't ask me why.
showmessage('A - '+inttostr(OSC_Series.Count));
OSC_Series.Clear;
showmessage('B - '+inttostr(OSC_Series.Count));
// This also works.
sleep(2000);
OSC_Series.Clear;
// This does not work.
sleep(1000);
OSC_Series.Clear;
end;
I'm stumped, obviously.
This smells like the code is working with an object (OSC_Series) which has been destroyed and the memory then re-used for something else. When you then use the stale reference to that memory you get unexpected and unpredictable results.
Where is OSC_Series free'd ?
I would check all such places and make sure that you do not attempt to use the OSC_Series reference after it has been free'd.
Note also that since the series is owned by the form it could be that the form itself is contriving to executing code in events after it has destroyed its owned components (including this series).
OK, dumb and not dumb.
I experimented with where I put the showmessage statement. I found I could only avoid the error if that statement came after the OSC_Series.Clear statement. I kept moving that statement back until it was after the call to the AnalysisRefresh routine, which is in a button's OnClick event handler. This means that none of the code in the refresh, enable, or update routines was causing this.
Stepping back a bit, if the AnalysisRefresh routine fails the user is shown a message. After that box is closed OSC_Series.Clear is called. If I close the box by pressing SPACE or ENTER on the keyboard... no error. If I use the mouse, error.
The chart behind the mouse has an OnMouseMove event where I display the mouse position on a status bar. I also display a hint if the mouse is near a plotted point. After clicking the message box with a mouse to close it the OnMouseMove event is called and by the time it gets to where it can display the hint, the plotted point is gone, and... error.
So, it seemed like an almost random error, but it wasn't. The trigger was just somewhere else entirely. That's you my try/except block wasn't catching the error. EurekaLog was catching it, but in a different procedure far, far away. (Deltics' answer was pretty close.)
Thanks for your help and suggestions.
Dang it if some days I can push hundreds of lines of code with no problems, then something like this pops up and it costs me near two days.

Resources