i have a TDBWPRichText linked to a MemoField on my Database.
when i press a Button i want the formated text to prepend some text.
the visual component shows the the prepended string, but when i Post, the Value of the memo doesnt change.
MyTable.Edit;
DBRichedit1.SelLength := 0;
DBRichedit1.CPPosition := 0;
DBRichedit1.Inserting := True;
DBRichedit.InputString('Test:' + #13);
//it shows the value on the component here
MyTable.Post;
in the MyTableBeforePost the Field has the old value though apparently
Field.Value <> Field.OldValue
If i enter text manually it works just fine
i also tried to save it manually (where the comment is) but the String is the old value
DBRichedit.SaveToString(MyTable.FieldByName('MyMemo').AsString,False);
Is there anyway i can get the prepended String into my Table?
This was a lot trickier than I was expecting it to be, even though I recalled that working with RichText in Delphi code can be a bit of a pain.
Anyway, the following works for me, to add an Rtf header stored in a disk file; see if it does for you. It isn't pretty and I can't help thinking that it's inordinately
long-winded.
procedure TForm1.InsertHeader;
// Prepend an RTF header to an existing RTF DB field
var
TL : TStringList;
ExistingText : String;
RE : TRichEdit;
MS : TMemoryStream;
begin
MS := TMemoryStream.Create;
TL := TStringList.Create;
// The reason for using a temporary RichEdit is to enlist its assistance
// in manipulating the rich text
RE := TRichEdit.Create(Nil);
RE.Parent := Self;
try
ExistingText := AdoQuery1.FieldByName('Memo').AsString;
RE.Clear;
// The reason for using the richedit's SelText in the following is that my
// initial naive attempt to assign to its Lines.Text provoked a "Line Insertion Error"
RE.SelStart := 0;
RE.SelText := ExistingText + #13#10;
TL.LoadFromFile('\d7\demos\richedit\header.rtf');
RE.SelStart := 0;
RE.SelText := RE.SelText + TL.Text;
RE.Lines.SaveToStream(MS);
MS.Position := 0;
AdoQuery1.Edit;
TMemoField(AdoQuery1.FieldByName('Memo')).LoadFromStream(MS);
AdoQuery1.Post;
finally
TL.Free;
RE.Free;
MS.Free;
end;
end;
Btw, there is an answer to how to insert RTF into pre-existing RTF in a TRichEdit here: http://delphidabbler.com/tips/57
After some hours i resorted to the dev of WPtools and he promptly provided me with the answer which is incredible simple:
you have to call
RichEdit.Changing
before interacting with it within the code
Related
I am stuck for past 5 - 6 hours in figuring this out that why this code is generating array index out of bound error on run time. I am unable to find out the reason. Can you please tell what modifications are required to correct this code?
spotsArr := make(map[int][]map[int64][]int)
for ind, availableSpot := range availableSpots {
spotsArr[availableSpot.Uid][ind] = make(map[int64][]int)
spotsArr[availableSpot.Uid][ind][availableSpot.Date] = []int{availableSpot.SpotSlug}
}
fmt.Println(spotsArr)
Edit 1: View the full code here https://play.golang.org/p/Smm0BFgtNp
Edit 2: Actually what I need to do is to get output in format something like:
{ uid: { date: {spot_slug, spot_slug} } }
{ 86: { 1536710400: {1000, 1200, 900},
{ 1536105600: {900} } }
The error is, as the error message suggests, because you tried to assign element on the index greater than the slice length. For the sake of getting the error away, you can just initialize the slice to the length, at least, as much as the index you wanted to use :
....
spotsArr[availableSpot.Uid] = make([]map[int64][]int, ind+1, ind+1)
spotsArr[availableSpot.Uid][ind] = make(map[int64][]int)
....
But as you clarified further about the desired output, it seems that you don't need slice in the first place. You need map of Uid where each key has value of map of Date :
spotsArr := make(map[int]map[int64][]int)
for _, availableSpot := range availableSpots {
if _, ok := spotsArr[availableSpot.Uid]; !ok {
spotsArr[availableSpot.Uid] = make(map[int64][]int)
}
spotsArr[availableSpot.Uid][availableSpot.Date] = append(spotsArr[availableSpot.Uid][availableSpot.Date],availableSpot.SpotSlug)
}
fmt.Println(spotsArr)
playground
Given the last two data have the same date, the output is as follows :
map[86:map[1534896000:[900] 1535500800:[900] 1536105600:[900] 1537315200:[900 900]]]
spotsArr is a map of int to an array of maps - map[int][]...
spotsArr := make(map[int][]map[int64][]int)
On this line, you try to assign to an index of that array which has no members yet:
spotsArr[availableSpot.Uid][ind] = make(map[int64][]int)
You're saying set this spot availableSpot.Uid to something (fine) but then set the index ind in an array which doesn't have members to something else (not fine). To fix this I'd recommend trying to do less on each line so that it's much clearer where and what the problem is. You could do this to fix the grammar error:
spotsArr[availableSpot.Uid] = []map[int64][]int{make(map[int64][]int)}
But I can't think why you want to set an index on the map to the index of the Uids you're traversing (your code doing [Ind]). I'd try to make this less complex and confusing if you can and spread it out on several lines to make the intent clear.
PS Give people a code sample which runs (i.e. include all the structs used), it makes it easier to help.
PPS Thanks for code sample, that makes it clearer.
I am creating a project at delphi(RAD Studio). There are images stored at database table at some rows. I want to extract images at runtime (for which I am using Array of TMemoryStream) and show them at frxReport.
My code snippet as follows
Public variable TStream is declared as
Stream2 : Array of TStream; i,k: integer
Code segment for view button click event, which is placed on MainForm and expected to show frxReport.
`
procedure TFrmMain.btnViewClick(Sender: TObject);
begin
i := 0;
k := 0;
UniTable1.SQL.Text := 'Select * from userplays order by id';
UniTable1.Execute;
rowcount := UniTable1.RecordCount;
SetLength(myid, rowcount);
SetLength(mydesc, rowcount);
SetLength(myimg, rowcount);
SetLength(Stream2, rowcount);
while not UniTable1.Eof do
begin
try
Stream2[k] := TMemoryStream.Create;
myid[k] := UniTable1.FieldByName('id').Value;
Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
mydesc[k] := UniTable1.FieldByName('description').Value;
UniTable1.Next;
inc(k);
finally
//Stream2[k].Free;
end;
end;
frxUserDataSet1.RangeEnd := reCount;
frxUserDataSet1.RangeEndCount := rowcount;
frxReport1.ShowReport;
i := 0;
end;
`
However this method is not loading any image to Stream2 array. There is an option to use array of JPEGImage however if JPEGImage array used then it would be problem to display it on frxRaport at
procedure TFrmMain.frxReport1GetValue(const VarName: string; var Value: Variant);
`
Graphic := TJPEGImage.Create;
Graphic.LoadFromStream(Stream2[j]);
TfrxPictureView(frxreport1.FindObject('Picture1')).Picture.Graphic := Graphic;
`
Kindly let me know how to do this.
However this method is not loading any image to Stream2 array
In your current code you are first assigning a newly created TMemoryStream to Stream2[k]:
Stream2[k] := TMemoryStream.Create;
then you are throwing the TMemoryStream away (creating a memory leak) and replacing it with the blob stream you create:
Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
But you never read from the blob stream.
Here's the while loop rewritten (untested)
var
blobstream: TStream;
Stream2: array of TMemoryStream;
....
// read 'id', 'description' and 'image' fields to respective arrays
while not UniTable1.Eof do
begin
myid[k] := UniTable1.FieldByName('id').Value;
mydesc[k] := UniTable1.FieldByName('description').Value;
blobstream := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
try
Stream2[k] := TMemoryStream.Create;
Stream2[k].LoadFromStream(blobstream);
finally
blobstream.Free;
end;
UniTable1.Next;
inc(k);
end;
Btw, I would recommend to define a record to hold the id, description and image together, and then an array of those records, instead of three separate arrays. Much simpler to manage only one array instead of three.
I think in your situation most obvious thing would be just connect existing DataSet ( Unitable1) directly into DataBand in frxReport. I don't see why you would need to use frxUserDataset instead of frxDBDataset with its DataSet property set to Unitable1 since you created it anyway.
If you really need a list of objects then I would take a different approach.
Your multiple global variables look ugly and are dangerous (i,k...)
I would create a class that holds your data and populate this data into a
TObjectList from System.Generics.Collection:
unit DataPack;
interface
uses ExtCtrls...System.SysUtils;
type
TMyDataPack = class(TObject)
private
Query: TFDQuery; //O r TUniQery
_MyId: Integer;
_MyDescription: String;
_MyImage: TImage;
_Loaded: Boolean;
function LoadData: boolean;
protected
public
constructor Create(Data: TFDQuery); //Or Uniquery
property MyId: Integer read _MyId;
property MyDescription: String read _MyDescription;
property MyImage: TImage read _MyImage;
property Loaded: Boolean read _Loaded;
end;
implementation
{ TMyDataPack }
constructor TMyDataPack.Create(Data: TFDQuery);
begin
Inherited Create;
Query:=Data;
_Loaded:=true;
if not (LoadData) then
_Loaded:=false;
end;
function TMyDataPack.LoadData: boolean;
var
Stream: TStream;
begin
Stream:= TStream.Create;
Stream:=Query.CreateBlobStream(TBlobField(Query.FieldByName('image')), bmRead);
try
_MyImage:=TImage.Create(nil);
_MyImage.Picture.Bitmap.LoadFromStream(Stream);
_MyDescription:=Query.FieldByName('description').AsString;
_MyId:=Query.FieldByName('CategoryId').AsInteger;
except on E: Exception do
begin
FreeAndNil(Stream);
FreeAndNil(_MyImage);
Exit(false);
end;
end;
FreeAndNil(Stream);
Result:=true;
end;
end.
Then in your main code:
procedure TMain.Button2Click(Sender: TObject);
var
DataRow: TMyDataPack;
List: TObjectList<TMyDataPack>;
Num: integer;
CurrentImage: TImage;
CurrentDescription: String;
CurrentId: integer;
begin
UniTable1.SQL.Text:='SELECT * FROM Userplays';
UniTable1.Open();
List:=TObjectList<TMyDataPack>.Create;
while not (UniTable1.Eof) do
begin
DataRow:=TMyDataPack.Create(UniTable1);
if(DataRow.Loaded) then
List.Add(DataRow);
UniTable1.Next;
End;
for Num:=0 to List.Count do
begin
CurrentDescription:=List[Num].MyDescription;
CurrentImage:=List[Num].MyImage;
CurrentId:=List[Num].MyId;
//List[Num].MyImage.Picture.SaveToFile('Some'+IntToStr(Num)+'.bmp');
// You might save it to file then...
end;
end;
end.
Then pass an ObjectList further, just remember to free it at the end.
You might further expand it by creating class factory to create different objects if you'd need for example use different database with same data,
perform check if image is actually Bmp or Jpg and so on.
You might even just pass a query without setting it's SQL and get TobjectList as property.
This question already has answers here:
How can I use Go append with two []byte slices or arrays?
(2 answers)
Closed 7 years ago.
I'm new to Go, so I apologise if this has already been answered, I'm trying to append a byte slice in Go and I am not having any luck finding a solution. I need to split off the first line of the file, which I've done; And write the rest into a byte slice to be parsed after the fact. So far the code looks like this:
// Here we extract the first line to name our title and category
var title, category string
var content []byte
in, err := os.Open(file)
utils.CheckErr(err, "could not open file: "+file)
defer in.Close()
// open file
scanner := bufio.NewScanner(in)
lineCount := 1
for scanner.Scan() {
if lineCount == 1 {
// assign title and category
splitString := strings.Split(scanner.Text(), "::")
title = splitString[0]
category = splitString[1]
fmt.Println("title: " + title + "category" + category) // usage to prevent compiler whine
} else {
// push the rest into an array to be parsed as jade
line := scanner.Bytes()
content = append(content, line) // The question is what goes here?
}
lineCount++
}
I've tried using append but that only gives me the error that
cannot use line (type []byte) as type byte in append
I believe you're simply looking for; content = append(content, line...)
See https://golang.org/ref/spec#Appending_and_copying_slices
There is probably a duplicate but until I find it...
Your problem is solved by adding "..." to the end of line so it looks like:
content = append(content, line...)
New to golang. Im trying to store all the waypoints sent over from our app side, but with a batch size of 100, here's my code
json.NewDecoder(r.Body).Decode(payload)
// seperate waypoints into groups
limit := 100
seperated := [][]*waypoint.Waypoint{}
// payload is from api call, basically plain json data
for i, wp := range payload.Batch {
if i%limit == 0 {
seperated = append(seperated, []*waypoint.Waypoint{})
}
last := seperated[len(seperated)-1]
last = append(last, wp)
}
Not sure what went long but seems i cant what i expected..
You're making a copy of your slice when you assign it to last, so when you append that isn't reflected in the outer seperated slice.
Assign it directly like so:
last := len(seperated)-1
seperated[last] = append(seperated[last], wp)
I'm very new to delphi, doing a project for my A level. When I run my code the images just don't show, I've looked everywhere and my teacher can't help me. Can anyone tell me what I'm missing?
const
Animal : array[0..6] of string = ('Bears','Dogs','Cats','Chickens','Horses','Cows','Monkeys');
ImagePaths : array [0..6] of string
= ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG',
'img6.JPG');
var i:integer;
Images : array [0..11] of TImage;
procedure LoadImages;
var
k,l:integer;
begin
Randomize;
k:=Random(11);
for l:= 0 to k do
begin
Images[l] := TImage.Create(nil);
Images[l].Picture.LoadFromFile(ImagePaths[i])
end
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
randomize;
i:=random(6);
QuestionLbl.Caption:=Format('How many %s are there?',[Animal[i]]);
LoadImages;
end;
The idea is that a random number of images of the same randomly selected animal is displayed for a child to then count and input, if that helps. Much appreciate any help.
edit.
as this is only a prototype I have copied it all to a new application and this is all the code I didn't include:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,jpeg, ExtCtrls;
type
TForm1 = class(TForm)
QuestionLbl: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
The same error is occurring and I'm afraid I'm too ignorant to follow what I'm sure were very clear instructions.
What appears to be missing is that you need to tell the image which control is its parent so that it can appear on screen. Do that like this:
Images[l].Parent := TheForm;
Obviously your form variable will have a different name, but I'm sure you know what it's called.
When you do this you will find that they all end up on top of each other. Assign to the Top and Left properties to position then. Finally you will likely want to set the Height and Width properties of the images to match the dimensions of the images, Images[l].Picture.Height and Images[l].Picture.Width.
I can't imagine why your code produces an access violation but it's presumably unrelated to the question you asked. The following code proves that what I say above is correct:
procedure TMyForm.FormCreate(Sender: TObject);
var
Image: TImage;
begin
Image := TImage.Create(Self);
Image.Parent := Self;
Image.Picture.LoadFromFile('C:\desktop\image.jpg');
Image.Top := 0;
Image.Left := 0;
Image.Height := Image.Picture.Height;
Image.Width := Image.Picture.Width;
end;
Without your full code I cannot debug your AV.
Why you just don't put your TImages on the form, and just LoadFromFile the ones you want to show ?
Appear to me that would be easier.
But: what you trying to accomplish? From the code, I can imagine you were trying to show a number of images to people count them and answer the question...
So, if you add (and position) the 11 empty(no image) TImages in the form, you can do:
// Any trouble in copying your FormCreate header, David? ;-)
procedure TMyForm.FormCreate(Sender: TObject);
begin
Images[0] := Image_N1; // First TImage
Images[1] := Image_N2;
Images[2] := Image_N3;
// Do that until the 12 slots are filled
// As a exercise for Danny Robinson( the OP ), you can do that in a for..do using
// the Form.Components array property to automate it instead of
// doing one-at-a-line
end;
procedure ClearImages;
var I: Integer;
begin
for I = Low(Images) to High(Images) do
begin
Images.Picture.Graphic := Nil;
end;
end;
procedure LoadImages;
var
k,l:integer;
begin
ClearImages;
Randomize;
k:=Random(11);
for l:= 0 to k do
begin
Images[l].Picture.LoadFromFile(ImagePaths[i])
end;
end;
If you still need to create the TImages on the fly, just create the 12 TImages
once on FormCreate (as in David's answer) and keep calling the LoadImages.
EDIT:
Some ideas, since you are learning.
Creating visual controls on-the-fly is a very boring(in my opinion, of course) task that involves:
Creating the object, obviously
Assigning it to a parent control (forms doesn't need this pass)
Sizing it accordingly to your visual planning
Positioning it in the place of the parent control you want it to be
Set it's anchors, for it to reposition and/or resize when the parent control is resized (if needed)
Only after all this, make it do what you want it to do (in this case, showing images).
Almost all those steps David Heffernan's answer show the code for it. But, unless you really need a dynamic layout, doing all those on design-time is more practical ;-)
You need to set the Parent property of each TImage in order to see them onscreen. You can't use the global Form pointer variable, though, because it has not been assigned yet when the OnCreate event is triggered. So pass in the form's Self pointer as a parameter of LoadImages() instead.
You have another bug - you declared a 12-element TImage array but declared a 7-element String array for the image paths. The way you are using Random(), if it generates a value above 6, you will go out of bounds of the String array.
Try this instead:
const
...
ImagePaths : array [0..6] of string = ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG', 'img6.JPG');
var
i: integer;
Images : array [0..6] of TImage;
procedure LoadImages(AParent: TWinControl);
var
i, k: integer;
begin
Randomize;
k := Random(7);
for i := 0 to k do
begin
Images[i] := TImage.Create(nil);
Images[I].Parent := AParent;
// set other properties, like Left/Top...
Images[l].Picture.LoadFromFile(ImagePaths[i]);
end;
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
...
LoadImages(Self);
end;
TImage component must to be painted on the screen,
for do so make a 1pixel panel as the parent to load the graphics.
like in a loading screen so the images can be used as default TImage procedures.