I was using search engine and not just here, and got tired of it; just want a simple answer (or a link) for a simple question:
How do I open a calc sheet and write 123 into cell A1 from Delphi (7) code? (Or any hello worlds for calc?)
You can take a look at this demo:
http://sourceforge.net/projects/ooomacros/files/Delphi%20OOo/Version%201.2/Delphi_OOo_v12en.zip/download
I tested the Document part a month ago (which works), and I there is also some spreadsheet code in the examples.pas.
Ok, after some research and using the informations above for I thank yas a lot, here is a simple answer:
uses part
Uses ComObj, OOoMessages, OOoTools, OOoConstants, OOoXray;
main code
open blank document, write 'hello 123' text into a1 then save it on desktop
procedure HelloWorldExample;
var
mentesiOpciok,oSheet,oSheets,myCalc : Variant;
begin
ConnectOpenOffice;
myCalc:=StarDesktop.loadComponentFromURL('private:factory/scalc', '_blank', 0, dummyArray);
oSheets:=myCalc.getSheets;
oSheet:=oSheets.getByIndex(0);
//oSheet.getCellByPosition(0, 0).SetValue(123);
oSheet.getCellByPosition(0, 0).SetFormula('hello 123!');
mentesiOpciok:=CreateProperties(['FilterName', 'MS Excel 97']);
myCalc.storeToURL('file:///C:/Documents and Settings/Zéiksz/Asztal/calcdoc.xls', mentesiOpciok);
showMessage('kész :)');
myCalc.close(true);
DisconnectOpenOffice();
end;
use getcellbyposition(...).setvalue to set numeric values, or setformula for strings (not really sure, but there is a string in it LOL).
Péter
edit: most useful information I found on the Internet is in this forum:
http://www.oooforum.org/forum/viewtopic.phtml?t=4996
Related
I have read multiple posts on the issue, and none seem to come to a decent conclusion to my question. (Perhaps I'm trying to see if anything has popped up lately.)
I have a small charity app that handles pledges. In doing so, it needs to work with and print documents.
Thing is, if Word is open in the background, the app thread will hang and won't respond to the closure of Word, and I have to roll back manually and close word. Sure, that all works fine, but I simply cannot guarantee that the end user will close Word, even if I put the instruction in a user manual.
I'm not too fussed about speed, but I guess that if it can be enhanced, it would be a nice little bonus.
Have any libraries been released for Delphi that will allow me to open, edit, print, and save documents? If not, is there a way to use Word Automation in such a way that it will not conflict with another open handle of Word when opened?
If you use GetActiveOleObject, you will get the running instance of Word.
By using CreateOleObject, you will get a new instance and shouldn't be troubled by other running instances.
In case you use the TWordApplication, wrapper you can set ConnectKind to ckNewInstance to accomplish this. By default, TWordApplication will try to connect with a running instance.
If you want to open edit and print Word documents and you don't mind using RTF format for what you're doing, investigate TRichView.
It will generate rich documents that are in RTF format, which is one of the formats MS word supports. I don't think it directly reads .DOC files but you can convert .DOC and .DOCX into RTF, for most simple files, but certain advanced formatting features would be lost in the conversion.
It has the advantage of working without any need for even any copy of MS Word to be installed on the machine that is going to do the document processing. For production of receipts and other simple documents, this would be the most reliable technique; Don't use Word directly, at all.
procedure PrintViaWord (const filename: string);
const
wdUserTemplatesPath = 2;
var
wrdApp, wrdDoc, wrdSel: variant;
begin
wrdApp:= CreateOleObject ('Word.Application'); // create new instance
sleep (5000); // this fixes a bug in Word 2010 to do with opening templates
wrdDoc:= wrdApp.documents.add (
wrdApp.Options.DefaultFilePath[wdUserTemplatesPath] + '\mytemplate.dot');
wrdDoc.Select;
wrdSel:= wrdApp.selection;
wrdApp.Options.CheckSpellingAsYouType:= 0;
wrdSel.paragraphformat.alignment:= 1;
wrdSel.typetext ('This is a program demonstrating how to open Word in the background'
+ ' and add some text, print it, save it and exit Word');
wrdDoc.SaveAs (filename + '.doc');
wrdApp.ActivePrinter:= 'Konica Minolta 211';
wrdApp.PrintOut;
WrdDoc.SaveAs (filename + '.doc');
wrdApp.quit;
wrdSel:= unassigned;
wrdDoc:= unassigned;
wrdApp:= unassigned
end;
I've been trying to use tomazy's FutureWindows infrastructure (see his answer at Delphi GUI Testing and Modal Forms or the home of the tool at https://github.com/tomazy/DelphiUtils), but would like to know if and how can it be used with standard Windows file open dialogs? They don't seem to be inheriting from TControl, which the FutureWindows infra seems to assume (unless I've misunderstood it).
What I'd like to do is basically to just select a file in an OpenFileDialog which is opened modally by a command within my testing, but haven't yet been able to figure out how to do this.
Use a tool like Spy++ to find out what the window class name is. For example, on my Windows 7 machine, the window class name for a system file open dialog is #32770 (Dialog).
My current solution is below:
TFutureWindows.Expect(MESSAGE_BOX_WINDOW_CLASS)
.ExecProc(
procedure (const AWindow: IWindow)
var
DlgHandle: HWND;
FileName: string;
begin
FileName := ExpandFileName('myFileToUse.txt');
DlgHandle := AWindow.GetHandle;
Windows.SetDlgItemText(DlgHandle, 1148, PChar(FileName));
end
)
.ExecSendKey(VK_RETURN);
So basically sending a message using Windows API. The ideas (and the ID 1148) were found from here: http://social.msdn.microsoft.com/forums/en-US/winforms/thread/62d5db14-5497-4ceb-8af0-d7f81732e937/
Possible better solutions are welcome, but this seems fine enough for me at least for now.
Thanks for the comments so far!
I'm using Delphi 7 and I'd like to export the contents of a list from my program to OpenOffice Calc using automation, instead of using files.
The task is simple: create new document, iterate through rows/columns and change cell data.
I've found some code but it's not complete, and I was hoping someone has some example code ready to accomplish this very simple task. It could save me a few hours of trying.
Thanks in advance!
Edit: I'd like to automate OpenOffice Calc to achieve what I wrote above. Thanks!
The easiest solution is to write CSV file output, and open that in OpenOffice.
There are also libraries to write .XLS files which both OpenOffice Calc and Excel can read. CSV is so simple, I wonder that you need an example. Create a TStringList, and add strings to it, in comma separated format. Save to file.
The so called "programmatic" method involves OLE automation.
uses
OleAuto;
var
mgr,calc,sheets,sheet1,dt,args:Variant;
begin
args = VarArrayCreate(...);
mgr := CreateOleObject('com.sun.star.ServiceManager');
dt := mgr.createInstance('com.sun.star.frame.Desktop')
calc = dt.loadComponentFromURL('private:factory/scalc', '_blank', 0, args)
sheets = calc.getSheets()
sheet1 = sheets.getByIndex(0)
...
Open Office supports Automation
see: http://udk.openoffice.org/common/man/tutorial/office_automation.html
Open Office info for Delphi can be found at:
http://development.openoffice.org/#OLE
The site ooomacros.org seems to be down, luckily the wayback machine still has a copy:
http://replay.web.archive.org/20090608051118/http://www.ooomacros.org/dev.php
Good luck.
Hello please help to translate the next line of basic code to Delphi for the OOoTools.pas interface.
oChart.Diagram.SymbolType = com.sun.star.chart.ChartSymbolType.SYMBOL1
I know that the SYMBOL1 part is an enumeration and I think I have to use the MakePropertyValue fumction but how?
Have you tried the simpler: oChart.Diagram.SymbolType := SYMBOL1;Just my first shot, btw.
I am an engineer and not a software programmer, so please excuse my ignorance.
I have written a Delphi(7SE) program to read “real” datatype from a USB port connected to two digital thermometers.
I have completed this much of the program.
What I have not completed as yet is explained by the following:
I wish to save this “real” data to a Binary File(s). A text file would be fine as well, but i'm concerned about having a big data file.
I also wish to read this data back from the Binary/Text File to display the data using my Delphi application.
I don’t think this would be too difficult. I currently save my data in .CSV format.
The twist here is that the binary file should contain data from different sessions initiated by the user of my application.
So when I click on say, a button called “ historical” data, a new window/form would pop up that would show different session times that I had started & stopped from earlier times. Then a session would be selected and data then retrieved for displaying.
Can this be done in one binary files or would you have to use 2 files: one for the “real” data and another which indexes the different session times?
My requirement for this way of saving binary data is that I would not have to keep typing in filenames and therefore keeping track of many data files.
For example a thermo.hst(historical data) and a thermo.idx (index file) file would contain all the information such as actual temp data, time of read data, session start & end times etc.
Any useful pointers and hopefully code with as much detail would be greatly appreciated.
I hope this sample code isn't too late to be helpful.
(I've added this as another answer from me so that I can cleanly list the code. If this or my previous post answers your question, please click the answer icon so I get reputation points!)
Below is some rough code that shows how to read the sections in an ini file and find the largest filename. I confirmed it compiles and seems to return valid values, but you'll need confirm it does what you need. It's more to show you the idea...
Note that if your data filenames have an extension, you'll have add code to remove the extension in my sample code using something like: FileName := ChangeFileExt(Filename, '').
// Call with an open inifile. Returns the name of the next filename, or '' if trouble
Function GetNextFileName( const IniFile: TInifile):String;
const
BASE_FILENAME = 'File.'; // sections in the ini file will be [File.1], [File.2], ... [File.100], etc.
var
Sections: TStringList;
NumericPartAsString: String;
NumericPartAsInteger: Integer;
ListIndex: Integer;
LargestFileNumberSeenSoFar: Integer;
begin
Result := '';
Sections := TStringList.Create;
IniFile.ReadSections(Sections); // fills StringList with the names of all sections in the ini file
if( Sections.Count = 0) then
Result := BASE_FILENAME + '1'
else
begin // find largest extension
LargestFileNumberSeenSoFar := -1;
ListIndex := 0;
while ListIndex <= (Sections.Count - 1) do // for every string (which is also a filename) in the string list:
begin
NumericPartAsString := StringReplace(Sections.Strings[ListIndex], BASE_FILENAME, '', []); // remove base filename
if (NumericPartAsString <> '') then
begin
NumericPartAsInteger := StrToIntDef(NumericPartAsString, -1);
if (NumericPartAsInteger > LargestFileNumberSeenSoFar) then
LargestFileNumberSeenSoFar := NumericPartAsInteger;
end;
inc(ListIndex);
end;
if (LargestFileNumberSeenSoFar > -1) then
Result := BASE_FILENAME + IntToStr(LargestFileNumberSeenSoFar + 1);
end;
Sections.Free;
end; { GetNextFileName }
procedure TForm1.Button1Click(Sender: TObject);
var
IniFile: TInifile;
NewFileName: String;
begin
IniFile := TInifile.Create('c:\junk\ini.ini');
NewFileName := GetNextFileName(Inifile);
if (NewFileName = '') then
ShowMessage('Error finding new filename')
else
ShowMessage('New filename is ' + NewFileName);
IniFile.Free;
end;
By using a database, you've in part just renamed part of the problem from "typing in file names and keeping track of many data files" to "typing in data set name and keeping track of many data sets."
In both cases, as an example, either the user or the program has to create a new file/data set name, and choose from a list of files/data sets to open later. And in both cases you have to make a call to a function named something like "DeleteDataSet".
You might re-consider whether you really need a database (with associated learning curve for API, how to define the data structure, update it in the field when something changes, browse the data in a viewer, access the data programatically, proprietary format, database maintenance, repair tools, installation, etc.) I'm sure that you could learn all these, and they might be valuable in future projects. But, maybe a simpler approach would be more appropriate and adequate for this one-time project by a non-software engineer.
If you're willing to have a proliferation of many unique, standalone data files on one folder, I'd encourage you to stick with what's working: use one CSV file per data set. (Have you run into speed or size issues with CSV files containing a single data set thus far? That would be an enormous amount of data!) One nice thing about CSV files is that you can just pop them into an editor to view or edit...
And, then, add a second file that contains filenames, and other descriptive information. This file would be a simple TIniFile:
[My Name one]
Date=06 June 2010
StartTime=12:30pm
StopTime=3:15pm
FileName=Data1.csv
[My Name two]
...
The tools available in Delphi for TIniFile will let you easily manage this list, including ReadSections into a string list that you can just assign to a combo box for the user to select a data set. (See example below) And, like the CSV files, you can just edit the .ini file in any text editor.
You'll need to build a UI to allow a user to delete a dataset (section in the ini file and associated .csv file). To give you an idea how the ini file would be used, here's the pseudo-code for deleting a data set:
(In IDE Object Inspector, set ComboBox.Style := csDropDownList to prevent user from typing in a name that doesn't exist.)
Load a combo-box that shows available data sets.
1. ComboBox.Items := IniFile.ReadSections;
In the combo-box's OnSelect event handler:
2. DeleteFile(IniFile.ReadString(CombBox.Text, 'FileName', ''));
3. IniFile.EraseSection(ComboBox.Text); // remove the section from the inifile
Heck, that's not a lot of code, even after you add a bit of protection and error checking!
Maybe the above solution will be voted down by others here as trying to put a round peg in a square hole or re-inventing the wheel. And I might agree with them. There are good arguments against this approach, including proliferation of many files. But, if it was me, I'd at least consider this approach as keeping-it-simple and not requiring anything new but that you learn the TIniFile object, which is quite powerful.
The data can be interleaved. Just start every block (a set of history) with a header that identifies the block and contains its length. When reading you can then easily separate that.
You can hold an additional index file next to this for fast access if you require, but if this is the case, I would start studying some embedded database. (TDBF, sqlite or embedded firebird).
I would also head in the database direction if I expected that my querying would get more complicated in the future.
If it is all about logging, the data doesn't get gigantic and the performance of the view is fine, I would keep the binary file and avoid the hassle of having users to install and maintain a databsae solution. (TDBF is maybe an exception to that, since it is completely statically linked)