Παρασκευή 1 Σεπτεμβρίου 2023

A more complicated Worksheet, for production (at my work)

The task was to pepare a sheet for each month of a year (for a decade of years), where the working days at each column hold the duration for overtime job, and a place under for signature, for a number of employers. There are two zones, one for the first 15 days and another for the rest days (up to last day of month) excluding Saturday and Sunday. So I have to place some ranges and adjust the lines between then, the width of some columns, the merging of some cells, the bagkround color of some cells, the alignment (Horizontal and Vertical) of some cells, the wrapping text property of some cells. Fibally I have to place the range for cells for one page, and the header/footer, plus the adjustment for resizing the sheet to adjust the landscape a4 page.

M2000 used for preparing the final Excel.

The WorkBook as we see it at Excel: 


Export (printing to Microsoft Print to Pdf):


First I make one module and make some runs until I found the proper final design, so I put it all in a module inside module (lets say that the non visible here module is A), changing Year=2026 to Read Year, so the statement OneYear 2026 make the specific workbook for 2026. Including this in a for next loop we can get all the books (about 2 minutes for each book on my PC at work).


The for This { } block used to delete any new variable we make there. The j variable get the type by ThisDate (a date type), so we don't want to use it as that type outside the block, so because j was first created at this block, at the exit of the block erased. So the j after this block is a double type.

Each time a module exit, all variables "Cleared", including those which are objects. The properties which we make using With statement have a hard link with the object which connected, so changing the object, reflect the changing to the property which we bound it. The release of all objects happen from the reverse order the way they created. Because Excel is a COM type object, the destroy of that object may happen after a while, and not exactly the time we set Nothing to Excel variable used to hold the object. When we call second time the OneYear an new Excel object created (independent from any other where still exist, but non connected to this code).

The ecxel application (the COM object) no swhowing GUI (but if  need to open a msgbox, can do it). As last command we run excel to open the specific xlsx file (same as the way we do on other examples, at this blog).


Module OneYear {

	Read Year
Month=1
Const xlVAlignBottom =-4107& //Bottom
Const xlVAlignCenter =-4108& //Center
Const xlVAlignDistributed =-4117& //Distributed
Const xlVAlignJustify =-4130& //Justify
Const xlVAlignTop =-4160& //Top

Const xlHAlignCenter =-4108& //Center
Const xlHAlignCenterAcrossSelection =7& // Center across selection
Const xlHAlignDistributed =-4117& //Distribute
Const xlHAlignFill =5& //Fill
Const xlHAlignGeneral =1& //Align according to data type
Const xlHAlignJustify =-4130& //Justify
Const xlHAlignLeft =-4131& //Left
Const xlHAlignRight =-4152 //Right


Const xlHairline =1& //Hairline (thinnest border)
Const xlMedium =-4138& //Medium
Const xlThick =4& //Thick (widest border)
Const xlThin =2& //Thin

Const xlDiagonalDown =5 'Border running from the upper-left corner to the lower-right of each cell in the range.
Const xlDiagonalUp =6 'Border running from the lower-left corner to the upper-right of each cell in the range.
Const xlEdgeBottom =9 'Border at the bottom of the range.
Const xlEdgeLeft =7 'Border at the left edge of the range.
Const xlEdgeRight =10 'Border at the right edge of the range.
Const xlEdgeTop =8 'Border at the top of the range.
Const xlInsideHorizontal =12 'Horizontal borders for all cells in the range except borders on the outside of the range.
Const xlInsideVertical =11 'Vertical borders for all the cells in the range except borders on the outside of the range.

// Const xlWBATChart=-4109& //Chart
// Const xlWBATExcel4IntlMacroSheet=4& //Excel version 4 macro
// Const xlWBATExcel4MacroSheet=3& //Excel version 4 international macro
Const xlWBATWorksheet =-4167& //Worksheet
boolean FalseB, first=True
mydir$=path$(5) // Documents folder
target$="βιβλιο υπερωριών "+Year+".xlsx"
// prepare c$() array (for 3 return C)
Declare withevents Excel "Excel.Application"
With Excel, "Workbooks" as WorkBooks
for Month=1 to 12
for this {
a=stack
stack a {
for i=65 to 65+25
data chr$(i)
next
for i=65 to 65+25
Data "A"+chr$(i)
next
}
push array$(a)
}
read C$()
dim c$(1 to len(c$()))

// prepare labels for days
dim a1$(), a2$()
date ThisDate="1/"+Month+"/"+Year
? ThisDate
k=ThisDate+30
while str$(thisDate, "MMMM")<> str$(k, "MMMM")
k--
end while
boolean once=true
double v=0, m=0
for this {
for j=ThisDate to k
v=val(str$(j,"w") )
m=val(str$(j, "d"))
if once then
if m>15 then once=false : a1$()=array$([])
end if
if v<>1 and v <>7 then
data ucase$(str$(j,"dddd - d"))
end if
next
a2$()=array$([])
}
If exist(mydir$+target$) Then
Try ok {
dos "del "+shortdir$(mydir$+target$);
}
If error or not ok Then break
End If

if first then
first=false
Method WorkBooks, "Add", xlWBATWorksheet
With Excel, "ActiveWorkbook" as ActiveWorkbook
With Excel, "ActiveSheet" as ActiveSheet
With ActiveWorkbook, "Sheets" set Sheets
else
Method Sheets, "Add", , ActiveSheet, 1, xlWBATWorksheet
end if
With ActiveSheet, "name", ucase$(locale$(55+Month))+" "+Year
Try {
With ActiveSheet, "Range" set Range0 ("A1:AH74")
With ActiveSheet, "Range" set Range1 ("A1:AH1")
With ActiveSheet, "Range" set Range2 ("A74:AH74")
With ActiveSheet, "Range" set Range3 ("A1:A74")
With ActiveSheet, "Range" set Range4 ("AH1:AH74")
Method Range1, "Merge"
Method Range2, "Merge"

Method Range1, "Select"
With Range1, "Interior" set Interior1
With Interior1, "Color", &HFFFF&
With Range2, "Interior" set Interior2
With Interior2, "Color", &HFFFF&
With Range3, "Interior" set Interior3
With Interior3, "Color", &HFFFF&
With Range4, "Interior" set Interior4
With Interior4, "Color", &HFFFF&

Rem {
With Range0, "Borders" set  Borders (xlEdgeBottom)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range0, "Borders" set  Borders (xlEdgeTop)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range0, "Borders" set  Borders (xlEdgeLeft)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range0, "Borders" set  Borders (xlEdgeRight)
With Borders, "LineStyle", 1, "Weight", xlMedium
}
With ActiveSheet, "Range" set Range00 ("B2:AG70")
With Range00, "HorizontalAlignment", xlHAlignCenter
With Range00, "Borders" set Borders (xlInsideHorizontal)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range00, "Borders" set Borders (xlInsideVertical)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range00, "Borders" set Borders (xlEdgeBottom)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range00, "Borders" set Borders (xlEdgeTop)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range00, "Borders" set Borders (xlEdgeLeft)
With Borders, "LineStyle", 1, "Weight", xlMedium
With Range00, "Borders" set Borders (xlEdgeRight)
With Borders, "LineStyle", 1, "Weight", xlMedium
With ActiveSheet, "Columns" set Column ("A")
With Column, "ColumnWidth", 1.71
With ActiveSheet, "Columns" set Column ("AH")
With Column, "ColumnWidth", 1.71
With ActiveSheet, "Rows" set Row0 (1)
With Row0, "RowHeight", 12.75
With ActiveSheet, "Rows" set Row0 (74)
With Row0, "RowHeight", 12.75
MakePrinterPage(ActiveSheet, "","A1:AH74", true)
With ActiveSheet, "Range" set Range0 ("B2:AG6")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignGeneral
With Range0, "Value" as ThisValue, "Value" as ThisValue$
ThisValue$={Οι υπογράφοντες το παρόν δηλώνουμε υπεύθυνα ότι:
1. Δεν λάβαμε υπερωριακή αποζημίωση από άλλη πηγή
2. Οι υπερωρίες πραγματοποιήθηκαν εκτός ωρών εργασίας και διενέργειας απογευματινών ελέγχων.
3. Κάθε είδους πρόσθετες αποδοχές ή απολαβές δεν είναι κατά μήνα ανώτερες από το σύνολο των αποδοχών της οργανικής μας θέσης σύμφωνα με το άρθρο 104, παρ. 2 του Συντάγματος, καθώς και
4. Οι πάσης φύσεως αποδοχές και πρόσθετες αμοιβές ή απολαβές ή σύνταξη, δεν υπερβαίνουν τις εκάστοτε αποδοχές του Γενικού Γραμματέα Υπουργείου, σύμφωνα με το άρθρο 28 του Ν. 4354/2015 (Α’ 176)}
With ActiveSheet, "Range" set Range0 ("A7:AH7")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignBottom
ThisValue$=" "+Year+" - "+ucase$(locale$(55+Month))+"- ΠΡΩΤΟ 15ΘΗΜΕΡΟ "

With ActiveSheet, "Range" set Range0 ("B1")
With Range0, "ColumnWidth", 4
With ActiveSheet, "Range" set Range0 ("B8:B10")
Method Range0, "merge"
ThisValue$="A/A"
With ActiveSheet, "Range" set Range0 ("C8:C10")
Method Range0, "merge"
With Range0, "ColumnWidth", 30
ThisValue$="ΕΠΩΝΥΜΟ - ΟΝΟΜΑ"
With ActiveSheet, "Range" set Range0 ("D8:D10")
Method Range0, "merge"
With Range0, "ColumnWidth", 12
ThisValue$="ΘΕΣΗ"
With ActiveSheet, "Range" set Range0 ("B10:D74")
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignCenter, "WrapText", true
With ActiveSheet, "Range" set Range0 ("E8:E38")
With Range0, "ColumnWidth", .5
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("E40:E70")
Method Range0, "merge"

i=8
c=0
for j=6 to 5+len(a1$())*2 step 2
With ActiveSheet, "Range" set Range0 (c$(j)+i+":"+c$(j+1)+i)
Method Range0, "merge"
ThisValue$=a1$(c)
c++
With ActiveSheet, "Range" set Range0 (c$(j)+(i+1)+":"+c$(j+1)+(i+1))
Method Range0, "merge"
ThisValue$="ΔΙΑΡΚΕΙΑ"
With ActiveSheet, "Range" set Range0 (c$(j)+(i+2))
ThisValue$="ΑΠΟ"
With ActiveSheet, "Range" set Range0 (c$(j+1)+(i+2))
ThisValue$="ΕΩΣ"
next j

i=40
c=0
for j=6 to 5+len(a2$())*2 step 2
With ActiveSheet, "Range" set Range0 (c$(j)+i+":"+c$(j+1)+i)
Method Range0, "merge"
ThisValue$=a2$(c)
c++
With ActiveSheet, "Range" set Range0 (c$(j)+(i+1)+":"+c$(j+1)+(i+1))
Method Range0, "merge"
ThisValue$="ΔΙΑΡΚΕΙΑ"
With ActiveSheet, "Range" set Range0 (c$(j)+(i+2))
ThisValue$="ΑΠΟ"
With ActiveSheet, "Range" set Range0 (c$(j+1)+(i+2))
ThisValue$="ΕΩΣ"

next j
c=1
for i=11 to 11+13*2 step 2
With ActiveSheet, "Range" set Range0 ("B"+i+":B"+(i+1))
Method Range0, "merge"
ThisValue=c
c++
With ActiveSheet, "Range" set Range0 ("C"+i+":C"+(i+1))
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("D"+i+":D"+(i+1))
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("AD"+i+":AE"+(i+1))
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignCenter
for j=6 to 5+len(a1$())*2 step 2
With ActiveSheet, "Range" set Range0 (c$(j)+(i+1)+":"+c$(j+1)+(i+1))
Method Range0, "merge"
next j
next
With ActiveSheet, "Range" set Range0 ("AD8:AE10")
Method Range0, "merge"
ThisValue$={ΥΠΕΡΩΡΙΕΣ
Α'
15ΘΗΜΕΡΟΥ}
With ActiveSheet, "Range" set Range0 ("AD40:AE42")
Method Range0, "merge"
ThisValue$={ΥΠΕΡΩΡΙΕΣ
B'
15ΘΗΜΕΡΟΥ}
With ActiveSheet, "Range" set Range0 ("AF40:AG42")
Method Range0, "merge"
ThisValue$={ΣΥΝΟΛΙΚΕΣ
ΥΠΕΡΩΡΙΕΣ
ΜΗΝΑ}
With ActiveSheet, "Range" set Range0 ("AF8:AG38")
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("A39:AH39")
Method Range0, "merge"
ThisValue$=" "+Year+" - "+ucase$(locale$(55+Month))+"- ΔΕΥΤΕΡΟ 15ΘΗΜΕΡΟ "
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignBottom
With ActiveSheet, "Range" set Range0 ("B40:B42")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignBottom
ThisValue$="A/A"
With ActiveSheet, "Range" set Range0 ("C40:C42")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignBottom
ThisValue$="ΕΠΩΝΥΜΟ - ΟΝΟΜΑ"
With ActiveSheet, "Range" set Range0 ("D40:D42")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignBottom
ThisValue$="ΘΕΣΗ"
c=1
for i=43 to 43+13*2 step 2
With ActiveSheet, "Range" set Range0 ("B"+i+":B"+(i+1))
Method Range0, "merge"
ThisValue=c
c++
With ActiveSheet, "Range" set Range0 ("C"+i+":C"+(i+1))
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("D"+i+":D"+(i+1))
Method Range0, "merge"
With ActiveSheet, "Range" set Range0 ("AD"+i+":AE"+(i+1))
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignCenter
With ActiveSheet, "Range" set Range0 ("AF"+i+":AG"+(i+1))
Method Range0, "merge"
ThisValue$="=AD"+i+"+AD"+(i-32)
With Range0, "HorizontalAlignment", xlHAlignCenter, "VerticalAlignment", xlVAlignCenter, "NumberFormat", "##0;;;"
for j=6 to 5+len(a2$())*2 step 2
With ActiveSheet, "Range" set Range0 (c$(j)+(i+1)+":"+c$(j+1)+(i+1))
Method Range0, "merge"
next j
next
// Q71
With ActiveSheet, "Range" set Range0 ("AA71:AC73")
Method Range0, "merge"
With Range0, "HorizontalAlignment", xlHAlignCenter
ThisValue$={Ο Προϊστάμενος της Δ/νσης

ΧΡΙΣΤΟΦΙΔΗΣ ΓΕΩΡΓΙΟΣ}
rem {
With Range0, "Value" as ThisValue, "Value" as ThisValue$
ThisValue=1000
With ActiveSheet, "Range" set Range0 ("A2")

With ActiveSheet, "Range" set Range0 ("A3")
ThisValue$="=A1" // is a formula
}
}
next
again:
Try ok {
Method ActiveWorkbook, "SaveAs", mydir$+target$, 51
}
If error or not ok Then If ask("File is open, close it and Try again")=1 Then Goto again
Method ActiveWorkbook, "Close", SaveChanges:=True
Method Excel, "Quit"
wait 1000
Declare Excel Nothing
Win "excel",quote$(mydir$+target$)
Print "Done"

Function CentimeterToPoints(x)
method Excel, "InchesToPoints", x*0.393700787 as ret
=ret
End Function
Sub MakePrinterPage(ThisSheet, t$, st$, check)
try ok {
with ThisSheet, "PageSetup" set PageSetup
with PageSetup, "Orientation", 2
Margins()
if check then with PageSetup, "PrintArea", st$
with PageSetup, "PrintTitleRows", "$1:$1"
with PageSetup,"Zoom" as myZoom, "FitToPagesWide" as PagesWide, "FitToPagesTall" as PagesTall
myZoom=FalseB
PagesWide=1
if check then
PagesTall=FalseB
else
PagesTall=1 'FalseB
end if
Margins()
}
if error or not ok then Print "??3??"+error$
End Sub
Sub Margins()
with PageSetup, "LeftMargin", @CentimeterToPoints(1.8) , "RightMargin",@CentimeterToPoints(1.8) , "TopMargin", @CentimeterToPoints(1.9)
with PageSetup, "BottomMargin", @CentimeterToPoints(1.7), "HeaderMargin", @CentimeterToPoints(1.3),"FooterMargin", @CentimeterToPoints(1.2)
with PageSetup,"CenterHeader", "&B&18&"+{"Arial Black"}+"&K00007DΒΙΒΛΙΟ"+chr$(13)+"&B&10&"+{"Arial Black"}+"ΥΠΕΡΩΡΙΑΚΗΣ ΑΠΑΣΧΟΛΗΣΗΣ ΤΑΚΤΙΚΩΝ && ΑΟΡΙΣΤΟΥ ΧΡΟΝΟΥ ΥΠΑΛΛΗΛΩΝ"
with PageSetup,"LeftHeader", "&B&12&"+{"Arial Black"}+"&K00007DΔ2 Δ/ΝΣΗ ΠΡΟΓΡΑΜΜΑΤΩΝ, ΜΕΘΟΔΩΝ ΔΙΔΑΣΚΑΛΙΑΣ && ΔΙΑΣΥΝΔΕΣΗΣ"
with PageSetup,"RightHeader", "&B&12&"+quote$("Arial Black")+"ΜΗΝΑΣ: "+ucase$(locale$(55+Month))+" "+Year
with PageSetup, "CenterFooter","&K000000Σελίδα &P από &N"
with PageSetup, "CenterHorizontally", true, "CenterVertically", true
End Sub
}
for i=2026 to 2026 '2040
OneYear i
next


Τετάρτη 30 Αυγούστου 2023

Make an Excel WorkBook with two WorkSheets

 We use this:

With ActiveWorkbook, "Sheets" set Sheets
Method Sheets, "Add", , ActiveSheet, 1, xlWBATWorksheet

Where the first parameter is not passed (it is optional by design for this method, so we put a comma without value and M2000 interpreter to the job, to pass a specific variant which used for not sending something).

Another way to call this method using  named parameters, so now we pass the optional parameter:

Method Sheets, "Add", After:=ActiveSheet, Count:=1, Type:=xlWBATWorksheet

Named parameters my have different order:

Method Sheets, "Add", Count:=1, After:=ActiveSheet, Type:=xlWBATWorksheet

Info: The After and Type identifiers are shown blue, because are known identifiers, they are command, for M2000, so the editor of M2000 show it using blue color, but aren't those commands at this context, they used as names for the parameters. 

The code is a variant from the previous post. Here we see that the A3 cell at Name2 WorkSheet has a link to A1 cell at Name1 WorkSheet.





// const xlWBATChart=-4109& //Chart
// const xlWBATExcel4IntlMacroSheet=4& //Excel version 4 macro
// const xlWBATExcel4MacroSheet=3& //Excel version 4 international macro
const xlWBATWorksheet=-4167& //Worksheet


mydir$=path$(5) // Documents folder
target$="TestA.xlsx"
If exist(mydir$+target$) Then
Try ok {
dos "del "+shortdir$(mydir$+target$);
}
If error or not ok Then break
End If


Declare withevents Excel "Excel.Application"
With Excel, "Workbooks" as WorkBooks
Method WorkBooks, "Add", xlWBATWorksheet
With Excel, "ActiveWorkbook" as ActiveWorkbook
With Excel, "ActiveSheet" as ActiveSheet
With ActiveSheet, "name", "Name1"
Try {
With ActiveSheet, "Range" set Range0 ("A1")
Method Range0, "Select"
With Range0, "Value" as ThisValue, "Value" as ThisValue$
ThisValue=1000
With ActiveSheet, "Range" set Range0 ("A2")
ThisValue$="Is a String"
With ActiveSheet, "Range" set Range0 ("A3")
ThisValue$="=A1" // is a formula
}
With ActiveWorkbook, "Sheets" set Sheets
Method Sheets, "Add", , ActiveSheet, 1, xlWBATWorksheet
With ActiveSheet, "name", "Name2"
Try {
With ActiveSheet, "Range" set Range0 ("A1")
Method Range0, "Select"
With Range0, "Value" as ThisValue, "Value" as ThisValue$
ThisValue=2000
With ActiveSheet, "Range" set Range0 ("A2")
ThisValue$="Is a String too"
With ActiveSheet, "Range" set Range0 ("A3")
ThisValue$="=Name1!A1" // is a formula
}
again:
Try ok {
Method ActiveWorkbook, "SaveAs", mydir$+target$, 51
}
If error or not ok Then If ask("File is open, close it and Try again")=1 Then Goto again
Method ActiveWorkbook, "Close", SaveChanges:=True
Method Excel, "Quit"
wait 1000
Declare Excel Nothing
Win "excel",quote$(mydir$+target$)
Print "Done"


The same using Version 15 handle of objects (I am working for named parameters and optional values like those in Method).

const xlWBATWorksheet=-4167& //Worksheet


mydir$=path$(5) // Documents folder
target$="TestA.xlsx"
If exist(mydir$+target$) Then
Try ok {
dos "del "+shortdir$(mydir$+target$);
}
If error or not ok Then break
End If


Declare withevents Excel "Excel.Application"
Excel=>WorkBooks=>Add xlWBATWorksheet
ActiveWorkbook=Excel=>ActiveWorkbook
ActiveSheet=Excel=>ActiveSheet
ActiveSheet=>name="Name1"
ActiveSheet=>Range("A1")=1000
ActiveSheet=>Range("A2")="Is a String"
ActiveSheet=>Range("A3")="=A1"
Sheets=ActiveWorkbook=>Sheets
Sheets=>Add , ActiveSheet, 1, xlWBATWorksheet


ActiveSheet=>name="Name2"
ActiveSheet=>Range("A1")=2000
ActiveSheet=>Range("A2")="Is a String too"
ActiveSheet=>Range("A3")="=Name1!A1" // is a formula
again:
Try ok {
ActiveWorkbook=>SaveAs mydir$+target$, 51
}
If error or not ok Then If ask("File is open, close it and Try again")=1 Then Goto again
ActiveWorkbook=>Close SaveChanges:=True
Excel=>Quit
wait 1000
Declare Excel Nothing
Win "excel",quote$(mydir$+target$)
Print "Done"



Another example (later versions of M2000 can use properties with many indexes like the cells(), and also get string or value)

try {
IF EXIST("MyTest.xlsx") THEN
DOS "DEL "+QUOTE$(DIR$+"MyTest.xlsx"), 300;
END IF
}
IF EXIST("MyTest.xlsx") THEN
PRINT "CLOSE EXCEL FILE..."
BREAK
END IF
DECLARE ExcelSheet "Excel.Sheet"
WITH ExcelSheet, "Application" set ExcelSheet.Application
WITH ExcelSheet.Application, "cells" as cells()
With ExcelSheet.Application, "ActiveSheet" as ActiveSheet
With ActiveSheet, "name", "MySheet1"
' row, line
cells(1,1)="Hello there"
s1=cells(1,1)
print s1, TYPE$(s1)="String"
cells(1,2)=TODAY ' date type
cells(1,3)=NOW ' date type
PRINT cells(1,2), TYPE$((cells(1,2)))="Date" ' need enclosed parenthesis, without these return the object under cells
cells(2,1)=100.3
cells(3, 1)=200.5
cells(4, 1)="=Sum(A2:A3)"  ' type
cells(2,2)=1234& ' we place a long type 32 bit, but converted to Double
PRINT cells(4,1)=300.8 ' executed immediate
PRINT TYPE$((cells(4,1)))="Double"
PRINT TYPE$((cells(2,2)))="Double"  ' this is the proof of conversion to Double
REM PRINT TYPE$(ExcelSheet.Application)
METHOD ExcelSheet, "SaveAs", dir$+"MyTest.xlsx"
DECLARE ExcelSheet NOTHING
TRY {
WIN DIR$+"MyTest.xlsx"
}

Τρίτη 29 Αυγούστου 2023

Make an Excel WorkBook

This is an example of using COM objects from M2000. We will make an excel file, with three values in a worksheet called Name1.


Open M2000, write Edit A press Enter, then paste this code, press Esc, then write A and press enter.

As you see we have two different type of values for writing numeric and string values on selection. Because variables defining using With on objects are bound to objects via a hard link, when we set new object on Range0, variables (properties of object) reflect the new object (just using inside the hard link).


// const xlWBATChart=-4109& //Chart
// const xlWBATExcel4IntlMacroSheet=4& //Excel version 4 macro
// const xlWBATExcel4MacroSheet=3& //Excel version 4 international macro
const xlWBATWorksheet=-4167& //Worksheet


mydir$=path$(5) // Documents folder
target$="TestA.xlsx"
If exist(mydir$+target$) Then
Try ok {
dos "del "+shortdir$(mydir$+target$);
}
If error or not ok Then break
End If


Declare withevents Excel "Excel.Application"
With Excel, "Workbooks" as WorkBooks
Method WorkBooks, "Add", xlWBATWorksheet
With Excel, "ActiveWorkbook" as ActiveWorkbook
With Excel, "ActiveSheet" as ActiveSheet
With ActiveSheet, "name", "Name1"
Try {
With ActiveSheet, "Range" set Range0 ("A1")
Method Range0, "Select"
With Range0, "Value" as ThisValue, "Value" as ThisValue$
ThisValue=1000
With ActiveSheet, "Range" set Range0 ("A2")
ThisValue$="Is a String"
With ActiveSheet, "Range" set Range0 ("A3")
ThisValue$="=A1" // is a formula
}
again:
Try ok {
Method ActiveWorkbook, "SaveAs", mydir$+target$, 51
}
If error or not ok Then If ask("File is open, close it and Try again")=1 Then Goto again
Method ActiveWorkbook, "Close", SaveChanges:=True
Method Excel, "Quit"
wait 1000
Declare Excel Nothing
Win "excel",quote$(mydir$+target$)
Print "Done"


Πέμπτη 17 Αυγούστου 2023

Slide Show Wallpapers (at Windows Desktop - New)

Let say there is a galactica-wallpaper.jpg at My Documents folder. We can change desktop background image using SystemParametersInfoW function of User32. (tested on Windows 11 Pro 22H2).

Module TestMe {
module changeWallPaper (strImagePath$){
declare SystemParametersInfo lib "User32.SystemParametersInfoW" {Long action, Long Param, &pvParam$, Long fWinIni}
const SPI_SETDESKWALLPAPER = 20&
const SPIF_SENDWININICHANGE = &H2
const SPIF_UPDATEINIFILE = &H1
Call void SystemParametersInfo(SPI_SETDESKWALLPAPER, 0&, &strImagePath$, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
}
// 0x5 for Documents Folder - see: help path$()
changeWallPaper path$(0x5)+"galactica-wallpaper.jpg"
}
TestMe

Now what if we have some jpg files at My Documents and we wish to cbange desktop background every half minute ?

This is the slide show. We get file names and put them to menu, without showing menu. We just read the menu items one by one.



Module TestMe {
module changeWallPaper (strImagePath$){
declare SystemParametersInfo lib "User32.SystemParametersInfoW" {Long action, Long Param, &pvParam$, Long fWinIni}
const SPI_SETDESKWALLPAPER = 20&
const SPIF_SENDWININICHANGE = &H2
const SPIF_UPDATEINIFILE = &H1
Call void SystemParametersInfo(SPI_SETDESKWALLPAPER, 0&, &strImagePath$, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
}
// 0x5 for My Documents Folder - see: help path$()
Title "SlideShow", 0
Try {
Repeat
dir path$(0x5)
menu
files + "jpg"
dir user
if menuitems>0 then
for i=1 to menuitems
try {
changeWallPaper path$(0x5)+menu$(i)+".jpg"
}
wait 30000
next
end if
Until menuitems=0
}
Title "M2000", 1
}
TestMe


And the best of all (using 0% processor for most time):

Module TestMe {
module changeWallPaper (strImagePath$){
declare SystemParametersInfo lib "User32.SystemParametersInfoW" {Long action, Long Param, &pvParam$, Long fWinIni}
const SPI_SETDESKWALLPAPER = 20&
const SPIF_SENDWININICHANGE = &H2
const SPIF_UPDATEINIFILE = &H1
Call void SystemParametersInfo(SPI_SETDESKWALLPAPER, 0&, &strImagePath$, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
}
// 0x5 for My Documents Folder - see: help path$()
flush
Title "SlideShow", 0
Try {
every 30000 {
if empty then
dir path$(0x5)
menu
files + "jpg"
dir user
if menuitems>0 then
for i=1 to menuitems
try {
data path$(0x5)+menu$(i)+".jpg"
}
next
end if
end if
if not empty then changeWallPaper
}
}
Title "M2000", 1
}
TestMe



And final, using a mutex to run only once and without using a window at taskbar (running like a service).  When the first (which create the mutex) exit delete the mutex. (We have to clode by task manager, or automatic close at shutdown of windows.


Module TestMe {
Declare m Mutex
boolean pass
try {
method m, "CREATE", "Global\SLIDE10101001"
pass=true
}
if pass else exit
module changeWallPaper (strImagePath$){
declare SystemParametersInfo lib "User32.SystemParametersInfoW" {Long action, Long Param, &pvParam$, Long fWinIni}
const SPI_SETDESKWALLPAPER = 20&
const SPIF_SENDWININICHANGE = &H2
const SPIF_UPDATEINIFILE = &H1
Call void SystemParametersInfo(SPI_SETDESKWALLPAPER, 0&, &strImagePath$, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)
}
// 0x5 for My Documents Folder - see: help path$()
flush
Title "", 0
Try {
every 30000 {
if empty then
dir path$(0x5)
menu
files + "jpg"
dir user
if menuitems>0 then
for i=1 to menuitems
try {
data path$(0x5)+menu$(i)+".jpg"
}
next
end if
end if
if not empty then changeWallPaper
}
}
Title "M2000", 1
}
TestMe: End


Πέμπτη 10 Αυγούστου 2023

Some examples from kotlinlang.org as M2000 programs

Asynchronous




Its not the same type under the hood, so we have to adjust it:
Using stack of values (each trhead has one)
module threads1 {
profiler
for i=1 to 10
thread {
print "i="; number, "time=";timecount
refresh
thread this erase
} as k interval 3000-i*200
thread k execute push i
next
wait 4000
}
threads1

Using static variables (different set for each thread)

module threads2 {
profiler
for i=1 to 10
thread {
print "i="; j, "time=";timecount
refresh
thread this erase
} as k interval 3000-i*200
thread k execute static j=i
next
wait 4000
}
threads2

Object-Oriented




module ObjectOriented {
class Person {
private:
name$
public:
module greed {
error "abstract"
}
class:
module Person (.name$){
}
}

class FoodConsumer {
module eat {
error "abstract"
}
module pay (amount as currency) {
print format$("Delicious! Here's {0} bucks!", amount)
}
}
class RestaurantCustomer as Person as FoodConsumer {
private:
dish$=""
public:
module order {
print format$("{0}, please!", .dish$)
}
module final eat {
print format$("*Eats {0}*", .dish$)
}
module final greed {
print format$("It's me, {0}", .name$)
}
class:
module RestaurantCustomer (.name$, .dish$) {
}
}
sam = RestaurantCustomer("Sam", "Mixed salad")
sam.greed
sam.order
sam.eat
sam.pay 10
}
ObjectOriented


Functional

The Kotlin Example



The M2000 example using tuple.

Module Functional {
function message(sender as string, body as string, isRead as boolean=false) {
=((Sender, body, isRead),) // array in an array - need for using append (an array to an array)
}
// define messages as a pointer to an array with zero items:
messages=(,)
Append messages, message("Ma", "Hey! Where are you?")
Append messages, message("Adam", "Everything going according to plan today?")
Append messages, message("Ma", "Please reply. I've lost you!")
// filter items by the Sender name to be unique
distinct =lambda ->{
mylist=list
=lambda myList ( k as array)->{
=true
if not exist(mylist, k#val$(0)) then append mylist, k#val$(0) else =false
}
}
// return the Sender with most messages on a fold function
MostMessages =lambda ->{
mylist=list
=lambda myList (k as array, which$)->{
if not exist(mylist, k#val$(0)) then
append mylist, k#val$(0):=1
else
return mylist, k#val$(0):=mylist(k#val$(0))+1
end if
if len(which$)>1 then
if mylist(which$)<mylist(k#val$(0)) then which$=k#val$(0)
else
which$=k#val$(0)
end if
push which$
}
}
// get an array and extract only the Sender
map1 =lambda (k as array)->{
push k#val$(0)
}
print "Sender with most messages:";messages#fold$(MostMessages(), "")
print "Senders:";"["+messages#filter(distinct(),(,))#map(map1)#Sort()#str$(", ")+"]"
}
Functional


Παρασκευή 4 Αυγούστου 2023

Revision 34, Version 12

For this revision I do these:

1. Remove a bug from rev 33, so now eertree module run as expected.

2. Now print to One Note for Windows 10 works (also works fir any printer). I found the need for placing a document name to printer, which some other printers not needed - like "Microsoft Print to PDF" which works with empty document name. So now M2000 insert a dummy documen name "M2000 printing" and we get the printout.


Check CAL module from Info (just execute Printer ? to choose One Note for Windows ... and then write CAL and press enter to execute this module, which print calendars to printer)

A simple example for printing:
// choose One Note for Windows...
Printer ?
//
Printer {
    form 80, 66
    Pen 9
    Print "This is a line of text"
    // use 2 for center text
    Report 2, {Proportional spacing also
    }
}