Erarbeitung eines "POS-Kassenbuchs"

Forumsregeln
Dieses Unterforum versteht sich als Plattform zur Diskussion/Bearbeitung komplexerer Anfragen bzw. konkret verabredeter Projekte. Das können Dinge sein wie eine komplexere Calc-Datei oder auch die gemeinsame Programmierung eines größeren Makros, wichtig ist immer die Absicht ein Thema über längere Zeit (z.B. 3 Monate) fortlaufend zu besprechen.

Antwort erstellen


BBCode ist eingeschaltet
[img] ist ausgeschaltet
[url] ist eingeschaltet
Smileys sind ausgeschaltet

Die letzten Beiträge des Themas
   

Ansicht erweitern Die letzten Beiträge des Themas: Erarbeitung eines "POS-Kassenbuchs"

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Fr, 03.03.2017 20:31

Hallo Julia,

Code: Alles auswählen

DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
		if oData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Ja Upsi! Is mir da doch ein winzig kleiner Fehler unterlaufen. Ich beziehe mich aber auf den Variablennamen, und was ich bis jetzt immer so erklärt habe. Korrekter weise müsste das nämlich so aussehen.

Code: Alles auswählen

DIM aData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   aData= oData1.getDataArray()			
	for iGF = LBound(aData()) to UBound(aData())
		if aData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  aData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(aData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(aData(iGF)(3)) '<- Spalte D'

Nämlich hatte der ursprüngliche Code das Manko, dass man nicht die zuletzt eingegebene Zeile korrigieren konnte - die hat er nicht gefunden.
Wenn ich das jetzt so mal auf die schnelle betrachte, dann kan ich nur folgendes dazu erklären.

Es ist ein Unterschied ob man NACH der letzten benutzen Zeile weiter etwas eintragen will. Oder ob man IN der letzten benutzen Zeile etwas eintragen/ändern möchte. Und je nachdem was man machen will, muss man entweder mit einem Korrekturwert arbeiten oder nicht.

Im ersten Falle muss ein Korrekturwert angegeben werden. Denn wenn eine dementsprechende Suchroutine erstellt wurde, egal ob die von mir gezeigte verkürzte Version oder deine, so geben sie normalerweise die letzte benutze Zeile zurück. Das heißt sie ist ja schon besetzt. Und da soll ja nix eingetragen werden, sondern eine Zeile weiter darunter. Also Korrekturwert Plus 1 (+1).

Im zweiten Falle entfällt der Korrekturwert, da die gefundene letzte Zeile ja die ist die man ändern möchte.

Lediglich der Korrekturwert muss so angepasst werden, damit er zu der Methode der Zelladressierung passt.

Code: Alles auswählen

getCellByPosition(0, 0) 
getCellRangeByName("A" +1)
Egal welche Methode man nimmt, am besten auf einfache Art und Weise vergleichen ob die richtige Zelle/Zeile gefunden wird. Dies macht man entweder mit PRINT oder MsgBox, ganz wie man will.


Julia NuN hat geschrieben: Ich hab hierzu dann noch diese Deklaration im Modul Artikel vor der Sub Dlg_Neuer_Artikel eingefügt:

Code: Alles auswählen

' Zellbereich'
Dim oCellRange_Mitarbeiter as Object, oData as Object, oData1 as Object
Dim oIDData as Object, oIDData1 as Object
Siehe hierzu auch meine oben ausgeführte Entschuldigung.
Jedoch:
oIDData1 ist korrekt deklariert, da getCellRangeByName ein Object ist.
oIDData ist aber nicht korrekt, da es es sich um ein Array handelt, getDataArray.


Es läuft aber auch ohne das, hab´s probiert
Verlass dich nicht darauf das es auch ohne läuft.

(ob ich das jemals mit der Deklaration begreifen werde, bezweifle ich...).
Kopf hoch. Wird schon werden. Ich weiss doch selber wie schwer das manchmal seien kann, und von daher bist Du ja nicht alleine damit.

Und hier noch einmal ein verwandtes Thema mit Bezug zu deinem letzten Post:
Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.
Ich hab aus Neugier bei Pitonyak CDec nachgeschaut. In der Kurzdefinition steht folgendes:
CDec :Generate a Decimal type; implemented only on Windows.
Könnten wir da vielleicht Probleme unter Ubuntu Mate bekommen?
Ob wir da Probleme bekommen, weiss ich noch nicht. Denn ich habe momentan leichte Schwierigkeiten auf meine VirtualBox zuzugreifen wo ich eine Linux-Mint installiert habe.
Aber das finde ich echt Klasse das Du bei Pitonyak nachgeschaut hast, hätte ich nicht mit gerechnet. Und ja, in der deutschen Version habe ich den gleichen Hinweis gelesen. Ich glaube da muss ich mich nochmal miteinander aussetzen.

Puuhh, also das war für mich ganz schön schwierig, die richtigen Teile hier reinzukopieren - ich brauch einen größeren Bildschirm... Oder eine Brille.
Nix Bildschirm! Nimm lieber gleich einen Beamer :lol:
Sorry, der musste sein. Auch wenn ich im Glashaus sitze, so werfe ich dennoch den ersten Stein. Ist doch nur Glas, und kein Spiegel.


Und nochmals sorry für die falsche schreibweise der Variablennamen.

Bis bald, Kapitän
Aye Aye, Smutje ;-)


Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Mo, 27.02.2017 01:34

Hallo balu,

hui, das war spannend!
Im Anhang befindet sich die überarbeitet Datei. An den meisten Stellen war das neue Array ja einfach nur einzufügen und anzupassen. Hab ich gemacht.

Aber dann wollte ich das auch noch bei der Korrektur einzelner Zeilen im Zusammenhang mit der ID-Suche anwenden. Man braucht ja auch ein wenig Übung, Vertiefung und eine kleine Eigenkreation… ;-)
Es hatte aber auch noch einen anderen Grund. Nämlich hatte der ursprüngliche Code das Manko, dass man nicht die zuletzt eingegebene Zeile korrigieren konnte - die hat er nicht gefunden. Die Frage, woran das liegt, war eine, die ich irgendwann mal stellen wollte (das musst du dir aber nicht im Detail ansehen, denn der Code ist jetzt schon veraltet - nur wenn du Lust hast).

Hier der alte Code aus der Sub Artikel_Korrektur. Irgendwie könnte das Problem beim iRowIndex liegen, den er nicht findet, wenn die Such-ID NrID_Korr sich in der letzten Zeile befindet:

Code: Alles auswählen

Sub Artikel_Korrektur
	oAktuellesBlatt = ThisComponent.getcurrentcontroller.activesheet

	NrID_Korr = oID_IDEingabe.value()
	ZeileID_Korr = NrID_Korr +1

For iRowIndex = 500 to 11 step -1 'rückwärts iterieren

If 	oAktuellesBlatt.getCellByPosition(0, iRowIndex).Value = ZeileID_Korr then
	Dlg_Korrektur.title = "Korrektur von ID Nr: " & NrID_Korr & ""
	Dlg_Korrektur.execute
	...
	oAktuellesBlatt.getCellRangeByName("B" & iRowIndex).String = sTxt_Korr
	oAktuellesBlatt.getCellRangeByName("F" & iRowIndex).Value = iArtikelnummer_Korr	
	oAktuellesBlatt.getCellRangeByName("G" & iRowIndex).Value = sgAnzahl_Korr
	oAktuellesBlatt.getCellRangeByName("H" & iRowIndex).Value = Einnahme_Korr
	...
Jedenfalls habe ich hier jetzt auch den neuen Code eingesetzt und das Problem ist weg:

Code: Alles auswählen

Sub Artikel_Korrektur
	oAktuellesBlatt = ThisComponent.getcurrentcontroller.activesheet
	NrID_Korr = oID_IDEingabe.value()

REM NEU******************************************************************************************		
' oAktuellesBlatt nach der Korrektur-ID durchsuchen
	With oAktuellesBlatt ' Letzte Zeile der Spalte A im Aktuellen Blatt ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With

   	oIDData1 = oAktuellesBlatt.getCellRangeByName("A11:A" & iLZ)
   	oIDData = oIDData1.getDataArray()			
	for iIDK = LBound(oIDData()) to UBound(oIDData())
		if oIDData(iIDK)(0) = NrID_Korr then
	iRowIndex = NrID_Korr +10
REM NEU Ende**************************************************************************************
	
	Dlg_Korrektur.title = "Korrektur von ID Nr: " & NrID_Korr & ""
	Dlg_Korrektur.execute
	...
	oAktuellesBlatt.getCellRangeByName("B" & iRowIndex).String = sTxt_Korr
	oAktuellesBlatt.getCellRangeByName("F" & iRowIndex).Value = iArtikelnummer_Korr	
	oAktuellesBlatt.getCellRangeByName("G" & iRowIndex).Value = sgAnzahl_Korr
	oAktuellesBlatt.getCellRangeByName("H" & iRowIndex).Value = Einnahme_Korr
	...
Ich hab hierzu dann noch diese Deklaration im Modul Artikel vor der Sub Dlg_Neuer_Artikel eingefügt:

Code: Alles auswählen

' Zellbereich'
Dim oCellRange_Mitarbeiter as Object, oData as Object, oData1 as Object
Dim oIDData as Object, oIDData1 as Object
Es läuft aber auch ohne das, hab´s probiert (ob ich das jemals mit der Deklaration begreifen werde, bezweifle ich...).
Und du hattest ja eine Deklaration angefangen mit deinem Code, den Du gepostet hast für die Sub Flaschenverkauf. Die Deklaration hab ich denn weggelassen... ;)

Code: Alles auswählen

...
DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
	...

Und jetzt ein kleiner Rückgriff, da die Schwierigkeit mit den kryptischen Zahlen, wie z.B. „-2,22044604925031E-016“ wieder aufgetaucht ist:

Code: Alles auswählen

DIM MindEinnahme_Art AS Currency
Ich habe das jetzt nicht überall eingefügt. Ich schätze mal, das Phänomen wird noch anderweitig auftauchen. Aber das mache ich dann.
Weil die Ursache hier wohl in der Verwendung der Preis-Elemente liegt, habe ich den Störenfried jetzt in der Deklaration am Schopfe gepackt und üble Auswirkungen im Keim erstickt (hoffe ich):

Code: Alles auswählen

' Preis - Elemente'
Dim oEP_PreisEingabe as Object, oPreis_Flaschen as Object, oListBox_Preis as Object
Dim cListenpreis_Fl as Currency, cPreis_Fl as Currency
Dim cEP_Korr as Currency, cEP_Ki as Currency

Und hier noch einmal ein verwandtes Thema mit Bezug zu deinem letzten Post:
Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.
Ich hab aus Neugier bei Pitonyak CDec nachgeschaut. In der Kurzdefinition steht folgendes:
CDec :Generate a Decimal type; implemented only on Windows.
Könnten wir da vielleicht Probleme unter Ubuntu Mate bekommen?

Puuhh, also das war für mich ganz schön schwierig, die richtigen Teile hier reinzukopieren - ich brauch einen größeren Bildschirm... Oder eine Brille. 8)
... Ich hoffe, ich habe überall die richtigen Teile reinkopiert. :roll:

Bis bald, Kapitän - und gute Nacht!
LG Julia
Dateianhänge
POS_Kassenbuch_Forum_9.ods
(58.19 KiB) 745-mal heruntergeladen

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Sa, 25.02.2017 17:57

Hallo Julia,

also dann wolln ma mal wieder.

Finde ich ja echt Klasse von dir das Du ein extra Icon für die kleine Sub erstellt hast. Ich hatte in der Icon Sammlung von OO.o eins gefunden welches mir sofort zusagte. Das wird wohl anscheind in einem anderen Modul irgendwo angewendet, aber es ist mir bis jetzt noch nicht untergekommen und deshalb verwende ich dieses dafür.
Icon.jpg
Icon.jpg (1.1 KiB) 19800 mal betrachtet
Es erinnert mich irgendwie an einem Scheibenwischer von einem Auto. Per Knopfdruck wird Regen und sonstiger Schmutz einfach weggewischt. ;-)

Und wer nicht hören will...
Nun ja, jedem passieren manchmal die dollsten Fehler. Da meint man das man alles richtig gemacht hat, und "PÄNG" machts, weil man doch mal was übersehen hat. Ergeht mir doch nicht anders.

A-propo Fehler.
Du hast vergessen etwas zu deklarieren. Defeniert hattest Du es ja, aber halt nicht deklariert. Und zwar gehts um sgPreis_Fl. Also bitte nachholen.


So, und nun mal wieder zurück zum Thema Array.

"Schon wieder Array!?"

Yep! Und diesmal wirds etwas "Abstarkter".

Denn heute wollen wir eine elegantere Version für die schon von dir ersetzte SVERWEIS anwenden. Doch leider ist sie auch etwas Umfangreicher. Aber dafür hat sie auch einige Vorteile, die einem doch so einiges erleichtern kann.

Mit einer reinen Makroaktion kann man sehr vieles bedeutend schneller erledigen, als eine ständige Interaktion zwischem Makro und Tabellenblatt. Jedoch ist der Preis dafür der, das der Makrocode länger wird. Ist leider so.

Du weißt ja wie eine SVERWEIS in einem Tabellenblatt funktioniert. Und dein Ersatz im Makro ist für dich auch leicht nachvollziehbar. Auch ist das bisherige Thema Array, so wie ich es dir erklärt hatte, auch nicht so sehr schwer zu verstehen. Doch jetzt musst Du dich ein wenig zusammenreißen, weil es von der Logik her etwas schwerer wird.

Dein bisheriger SVERWEIS Ersatz arbeitet ja nach folgendem Prinzip.
Im Makro Suchbedingung nehmen. Im Tabellenblatt eine Zeile untersuchen. Wenn nix im Tabellenblatt in einer Zeile gefunden, nächste Aktion vom Makro starten, was bedeutet die nächste Zeile im Tabellenblatt untersuchen.
Und diese Spielchen wird Zeile für Zeile im Tabellenblatt durchgeführt. Und je länger eine Liste im Tabellenblatt ist, um so Länger dauert diese ganze Aktion.

Jetzt müsste es eine Möglichkeit geben die Liste aus dem Tabellenblatt blitzschnell in den Arbeitsspeicher zu laden um die Liste dort zu untersuchen.


Und diese Möglichkeit gibt es. Und das sieht wie folgt aus.

Wir befinden uns im Modul *Flaschenverkauf* in der "Sub Neuer_Flaschenverkauf".

Code: Alles auswählen

DIM oData
oData1  = oBlattStamm.getCellRangeByName("A3:D199")
oData = oData1.getDataArray()
Damit haben wir den gesamten Inhalt aus dem Datenbereich A3 bis D199 in den Arbeitsspeicher geladen. Wir haben jetzt also 4 Spalten und 197 Zeilen dort plaziert. Und in Makrosprech heißt das: Spalten 0 bis 3, und Zeilen 0 bis 196.

So, und nun wollen wir die Daten aber auch untersuchen/vergleichen und auslesen.
Dazu wird das alt bekannte Prinzip FOR...NEXT gekoppelt mit IF...THEN angewendet. Anfangen tun wir mit der Schleife. Da es sich hierbei ja um ein Array handelt, und wir schon das Grundprinzip dafür besprochen haben, dürfte die folgende Zeile nicht unverständlich sein.

Code: Alles auswählen

for iGF = LBound(oData()) to UBound(oData())
Und ab jetzt wird es im IF Teil ein wenig verwirrend.

Code: Alles auswählen

if oData(iGF)(0) = iArtikelnummer_Fl then
Bis jetzt warst Du es ja eigentlich gewohnt das bei Arrays hinter dem Arraynamen nur eine Klammer zu sehen war. Doch jetzt sind es gleich 2 Klammerpaare.

Nun, das muss ja so sein, weill wir ja eine Mehrspaltige und Mehrzeilige Liste im Arbeitsspeicher haben. Ist klar, oder?

Jetzt gibt es aber eine Besonderheit gegenüber der normal üblichen Zelladressierung per Makro die ja wie folgt aussehen kann.

Code: Alles auswählen

getCellByPosition(0, 0)
getCellRangeByName("A9")
Hier ist es selbstverständlich das erst die Spalte, und dann die Zeile benannt wird.

In diesem Array fall ist das aber anders.

Code: Alles auswählen

oData(iGF)(0)
Denn hier kommt erst die Zeile (erstes Klammerpaar), und dann die Spalte (zweites Klammerpaar). Hier heißt es also Umdenken. Aber auch nur in diesem speziellem Falle, die anderen besprochenen Arrays sind nicht davon betroffen.

Damit wäre die erste Hürde genommen, die auch für den Anfang etwas schwer zu verdauen ist. Und glaub mir, das gilt auch aktuell für mich, da ich erst seit ein paar wochen mich mal grob damit befasst habe.

Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Jetzt dürfte es eigentlich nicht mehr arg so schwer zu verstehen sein, was alles rechts neben dem Gleichheitszeichen (=) steht.

Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.


Jetzt machen wir etwas was eigentlich zu erst hätte kommen sollen, aber das ist im Prinzip ein anderes Thema, und deshalb kommts jetzt ausnahmsweise fast zum Schluß.

Du arbeitest ja intensiv mit der Ermittelung der letzten Zeile in einem aktiven Tabellenblatt. Und um den neuen SVERWEIS flexibler einzusetzen, wenn es um die Größe der Liste geht, brauchen wir auch eine Ermittelung der letzten benutzen Zeile. Diese Zeile befindet sich aber immer im gleichem Tabellenblatt, wodurch sich deine bisherige Lösung nicht anwenden lässt. Also muss etwas anderes her, was ich ja auch schon parat habe. Nur kann ich dir nicht sehr viele dazu erzählen, wie der Aufbau so ist, da sie nicht von mir stammt, sondern von unserem Stephan.

Und hier ist das was ich meine.

Code: Alles auswählen

	With oBlattStamm ' Letzte Zeile der Spalte A  im Tabellenblatt Stamm ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With
iLZ gibt in diesem Falle die tatsächliche Zeilennummer zurück. Und diese Variable bauen wir dann auch noch in meine vorhin besprochene Änderung ein. Doch jetzt kommt erstmal die Passage im genannten Modul und in der dementsprtechenden Sub wie sie bis jetzt war.

Code: Alles auswählen

' Sheet "Preise" nach Text, der Getränkegröße in Liter und dem ListenPreis durchsuchen
	for tt40 = 0 to 500
	if oBlattStamm.getCellByPosition(0, tt40).Value = iArtikelnummer_Fl then
	sTxt_Fl =  oBlattStamm.getCellByPosition(1, tt40).String
	sgEinheit_Fl = oBlattStamm.getCellByPosition(2, tt40).Value
	sgListenpreis_Fl = oBlattStamm.getCellByPosition(3, tt40).Value
	
' Berechnung der Werte 
	sgAnzahl_Fl = sgFuellmenge_Fl/sgEinheit_Fl* iAnzahl_Fl
	Einnahme_Fl = sgPreis_Fl* iAnzahl_Fl
    EPRabatt_FL = sgPreis_Fl/sgAnzahl_Fl* iAnzahl_Fl
    sgRabatt_Fl = 100 - (EPRabatt_Fl * 100 / sgListenpreis_Fl)
    MindEinnahme_Fl = (sgListenpreis_Fl - EPRabatt_Fl)* sgAnzahl_Fl
    endif
    next tt40
Und nun die gesamte Überarbeitung.

Code: Alles auswählen

' Sheet "Preise" nach Text, der Getränkegröße in Liter und dem ListenPreis durchsuchen
	With oBlattStamm ' Letzte Zeile der Spalte A  im Tabellenblatt Stamm ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With
'	PRINT ILZ
	
DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
		if oData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
	
' Berechnung der Werte 
	sgAnzahl_Fl = sgFuellmenge_Fl/sgEinheit_Fl* iAnzahl_Fl
	Einnahme_Fl = sgPreis_Fl* iAnzahl_Fl
	EPRabatt_FL = sgPreis_Fl/sgAnzahl_Fl* iAnzahl_Fl
	sgRabatt_Fl = 100 - (EPRabatt_Fl * 100 / sgListenpreis_Fl)
	MindEinnahme_Fl = (sgListenpreis_Fl - EPRabatt_Fl)* sgAnzahl_Fl
    endif
    next iGF

Und somit kommen wir zum heutigem Ende der Vorstellung. :lol:

Ich hoffe Du weißt wo Du jetzt im Makro was löschen und ersetzen kannst. Denke aber auch daran das Du das nicht nur in diesem einen Modul machen kannst, sondern auch noch wo anders.

Viel Glück und Spaß beim anwenden. ;-)
Bis die Tage.



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Fr, 17.02.2017 15:34

Hallo balu,
Jetzt erstmal ein klein wenig Kritik.
Es hilft mir doch schon sehr, wenn Du erklärst was Du aufrufst, was Du wo eingibst und welche Subs daran beteiligt sind. Denn so musste ich erstmal suchen welche Sub und welche Zeile innerhalb dieser Sub etwas einträgt.
Eijeijei - das tut mir Leid! Recht hast du. Ich werde mich bessern.

Code: Alles auswählen

DIM MindEinnahme_Art AS Currency
Ich habe das jetzt nicht überall eingefügt. Ich schätze mal, das Phänomen wird noch anderweitig auftauchen. Aber das mache ich dann.
Aber achte dringends darauf das Du aus der anderen Datei nix, aber auch absolt reine weg gar nix per "Strg + C" -> "Strg + V" reinkopierst. Denn dadurch kopierst Du dann ansonsten wieder alles aus der alten Datei darein. Und das muss ja unbedingt vermieden werden.

Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".

Aber auf gar keinen Fall irgendwelche Bedingte Formastierungen, Zellformatierungen oder Formatvorlagen. All die sind einfach Tabu. Du musst die dann halt alle in der neuen Datei neu erstellen.

Eine kleine Arbeitserleichterung.
Lege in *Meine Makros* -> *Standard* ein Modul an, und kopiere folgendes kleines Makro in dies Modul rein.

Code: Alles auswählen

sub Unformatiert
dim document   as object
dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "SelectedFormat"
args2(0).Value = 1
dispatcher.executeDispatch(document, ".uno:ClipboardFormatItems", "", 0, args2())
end sub
Anschließend fügst Du der Symbolleiste einen neuen Eintrag hinzu der auf dies Makro zugreift, suchst dir ein Symbol aus, und schon kannst Du per "Knopfdruck" Unformatierten Text einfügen.
Das habe ich hinbekommen. Für alle, die das hier lesen und kein passendes Icon haben, lade ich hier das meinige hoch.
icon_unformatierter_text.png
icon_unformatierter_text.png (1.04 KiB) 19889 mal betrachtet
Naja, sieht ein bisschen schief aus... aber es hat die gefragten 26x26 Pixel.
Das war ein ganz schöner Ausflug in etwas, womit ich mich noch nie beschäftigt habe, obwohl ich es längst hätte müssen: Anpassen der Symbolleisten.

Und wer nicht hören will... Ich hab tatsächlich, ungeduldig wie ich war, folgenden unterstrichenen Teil überlesen:
Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".
:evil:
Das habe ich dann bemerkt, als ich fertig war mit der Neuerstellung. Wobei das vllt. nicht Not getan hätte - ich hatte die Formeln aus der Eingabezeile in die Eingabezeile kopiert. Aber ich wollte dann doch auf Nummer sicher gehen und habe alles noch einmal gemacht.

Zum automatischen Scrollen:

Code: Alles auswählen

sub SprungZurZelle
	oDok = thisComponent
	oViewController = oDok.CurrentController

	oAktSheet = oDok.sheets().getbyName(oViewController.activesheet.getName)
	aAktCursor = oAktSheet.getCellByPosition(0, 10) 'die gewünschte ZellPosition'
	
	oViewController.Select(aAktCursor) 'Der eigentliche Sprung zu der Zelle'
  
end sub
Das ist wirklich gar nicht so einfach. Ich hatte das zwar auch beim Dannenhöfer gefunden, aber nicht verstanden, dass es der richtige Code war.
Ich habe ihn jetzt so angepasst:

Code: Alles auswählen

aAktCursor = oAktSheet.getCellByPosition(0, iEnd_Row+10) 'die gewünschte ZellPosition'
Das funktioniert prima. Vielen Dank!
Übrigens hast du mir ja die ganze Arbeit abgenommen! Ich hatte den Code "SprungZurZelle" in die Sub "Funktionen" hineinkopiert und dabei gar nicht gemerkt, dass du das ja schon erledigt hattest. Beim Ausführen hat er dann gemault, weil doppelt.

So, jetzt lade ich das mal hoch - wird auch Zeit.

Liebe Grüße Julia
Dateianhänge
POS_Kassenbuch_Forum_8.ods
(52.79 KiB) 756-mal heruntergeladen

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Di, 31.01.2017 02:24

Hallo Julia,

Du hasts gut. Du kannst deinen Akku wieder voll aufladen. Ich jedoch habe zur Zeit das Problem, das mein Akku unter dem Memory-Effekt leidet. Na ja, wird schon wieder.

Ich hatte echt Probleme, mich in die Arrays hineinzudenken.
Dabei hast du es perfekt erklärt
Danke schön.

… öhhmm… zumal ich zu meiner Schande feststellen musste, dass eine solche Rabatt-Text-Festlegung gar nicht sinnvoll ist… Leider brauchen wir das hier gar nicht, weil es im Grunde nur den Rabatt-Text „Sonstige“ geben wird.
Auch wenn mir das noch nicht so ganz verständlich ist, so ist das gezeigte Array ja nicht weggeschmissen/umsonst, da es ja immer wieder mal irgendwie gebraucht werden kann.

Denn Mitarbeiter und Chefetage, die eine ganze Flasche einer Spirituose entnehmen, ersetzen sie einfach später. Und es wäre auch fast unmöglich für Mitarbeiter, den Flaschenpreis von 50% über den Dialog herauszubekommen.
Sag das nicht, das das unmöglich ist. Es ist sehr vieles möglich, man muss es nur mal halt ausprobieren. Aber das können wir uns eventuell später noch mal vornehmen, da dies jetzt noch nicht so richtig hier rein passt.

Ich habe es jetzt trotzdem drin gelassen, weil´s so schön ist.
Das ist natürlich auch ein Argument :lol:

UND – weil ich denke, das war ein klasse Beispiel, wie Arrays funktionieren.
Bedenke aber, das dies noch nicht die letzte Art von Array war, kommen noch andere. ;-)

Ich hab ein bisschen darauf herumgedacht, ob es für den Lichtschalter auch noch andere Aggregatzustände geben kann als „an“ und „aus“. Ja, nä?
Doch gibt es, aber damit erzeugt man an einem echten Lichtschalter unter Umständen einen Kurzschluß. *grins*

Code: Alles auswählen

aUnterGrenze(4) = 150 : aOberGrenze(4) = 200 : aRabattText(4) = "Freies Gelage"
aUnterGrenze(5) = 200 : aOberGrenze(5) = 300 : aRabattText(5) = "Kater Stimmung"
Haha! Das gefällt mir!
Schön, schön!

Deshalb habe ich das hier stattdessen eingefügt, s.o. und hier:

Code: Alles auswählen

oListBox_AusserHaus.SelectItemPos((0), True) ' Listbox-Wert Voreinstellung auf "Nein"
Du musst die 0 in diesem Falle nicht in Klammern setzen, da dies jetzt eine Position ist. Deshalb steht da ja auch SelectItemPos.
Etwas anders siehts ja hierbei aus.

Code: Alles auswählen

oListBox_Preis.SelectItem(aKistenPreise(0), True)
Denn hier ist es keine Position, sondern ein ausgewählter Eintrag aus einem Array welches ja aKistenPreise heißt.


Jetzt habe ich noch eine andere Frage:
Es wurde der Wunsch geäußert, dass im Tabellenblatt immer automatisch etwas hochgescrollt wird während der Eingabe. Jetzt muss man dafür ja immer erst die Dialog schließen.
Ich hab auch vielleicht die entsprechende Anweisung dazu gefunden, jedoch krieg ich das nicht so hingebastelt, dass es funktioniert.

Code: Alles auswählen

oAktuellesBlatt.getCellRangeByName("A" & iEnd_Row).Select
Während der Eingabe hochsrollen geht nicht. Aber wenn eine Eingabe im Dialog fertig getätigt wurde, kann man anschließend den Cursor auf eine bestimmte Position setzen. Jedoch gibts da eine kleine, aber wohl unbedeutende Einschränkung. Der Cursor springt wohl die Zelle an, sie wird aber so gesehen "zentriert". Das heißt, wenn z.B. 25 Zeilen zu sehen sind, dann wird die gewünschte Zelle nicht ganz oben am Anfang stehen, sondern irgendwo in der mitte der sichtbaren Zeilen. Das ist aber immer noch besser, als wenn man zu "Fuß" zu der gewünschten Zelle gehen muss.

Ich weiß nicht wie Du auf diese Code Anweisung gekommen bist, aber ganz so einfach ist das nun wiederum doch nicht.
Das müsste dann schon wie folgt aussehen.

Code: Alles auswählen

sub SprungZurZelle
	oDok = thisComponent
	oViewController = oDok.CurrentController

	oAktSheet = oDok.sheets().getbyName(oViewController.activesheet.getName)
	aAktCursor = oAktSheet.getCellByPosition(0, 10) 'die gewünschte ZellPosition'
	
	oViewController.Select(aAktCursor) 'Der eigentliche Sprung zu der Zelle'
  
end sub
Diesen Code kannst Du so nehmen und direkt testen. Bei getCellByPosition kannst Du die 10 gegen andere Werte tauschen, und dich dadurch überzeugen das er wirklich funktioniert.

Beim Dannenhöfer gibts wohl ein anderes kleines Breispiel dazu, welches ich auch genommen und dementsprechend angepasst habe, aber es basiert auf einem fest vorgegebenen Blattindex. Guckst Du hier: 7.1.9 Wie kann man den aktuellen Cursor auf eine Zelle setzen?
Da es hier aber um wechselnde Blätter geht, also dynamisch anstatt statisch wie bei Dannenhöfer, musste ich auch erstmal etwas Knobeln bis das ich es hinbekommen habe. Und aus diesem Grunde sieht der Code jetzt etwas anders aus.

Wie, und was Du jetzt an diesem Code änder musst damit das auch mit der festgestellten "Letzten Zeile" funktioniert, das müsstest Du ja wohl alleine hinbekommen. ;-)

Was mich schon recht lange beschäftigt hat, ist folgendes:

Code: Alles auswählen

oAktuellesBlatt = thiscomponent.getcurrentcontroller.activesheet
oCellCursor = oAktuellesBlatt.createCursor()
oCellCursor.GotoEndOfUsedArea(True)
iEnd_Row = oCellCursor.getRangeAddress.EndRow
Nach einigen Tests habe ich den Eindruck, dass der Cursor, wenn er gebraucht wird, immer neu „created“ werden muss.
Jetzt habe ich, weil das so oft vorkam und so eine unschöne Verlängerung des Codes in den einzelnen Subs verursacht hat, ein Modul „Funktionen“ angelegt und das dahin verschoben.
Die Funktion wird jetzt mit ClZ aufgerufen (Cursor letzte Zeile).

Dank deiner Erläuterungen zu unserem vor Kurzem ebenfalls neu erstellten Modul „Text-Mitteilungen“ klappt der Aufruf auch.
:D
Nein wie wunderschön, das Du selber auf die Idee gekommen bist. Doch, das erfreut mich wirklich sehr. *schön-schön*

Das freche an der ganzen Sache ist aber, GENAU DAS hatte ich mir für heute schon vorbereitet gehabt. Und jetzt hast Du mir meine Arbeit einfach so mir-nix-dir-nix geklaut. Frechheit. Bild

Jetzt aber ernsthaft.
Ich wollte dir anhand genau dieser "Problematik" etwas anderes zeigen und Erklären, aber dann dachte ich mir; warum das? Das geht genau so gut auf diese einfache und funktionierende Weise, als wenn man das technisch "hochfrisieren" würde. Und ja, mein vorbereiteter Beitrag hatte wirklich deine selbst erstellten Codezeilen drin gehabt.

Das Du jetzt das ganze selber in Angriff genommen hast, zeugt doch davon das Du was gelernt hast und das auch nutzbringend anzuwenden weißt. Das ist doch gut so.


Wenn man in die von mir zuletzt eingegebene Zeile in die Spalte "Mindereinnahmen" klickt, sieht man oben in der Leiste nicht den eigentlichen, einfachen Wert „0“, sondern einen negativen, nämlich „-2,22044604925031E-016“.
Dadurch ändert sich in diesem Fall auch die Darstellung in -0,00 € statt - €.
Diesbezüglich habe ich damals das Internet tagelang durchforstet, weil ich nämlich alle Werte mit Null wegfiltern wollte und das dann deswegen nicht ging und ich es per Hand erledigen musste.

Ich wage gar nicht zu hoffen, dass du die Lösung kennst…!?
Jetzt erstmal ein klein wenig Kritik.
Es hilft mir doch schon sehr, wenn Du erklärst was Du aufrufst, was Du wo eingibst und welche Subs daran beteiligt sind. Denn so musste ich erstmal suchen welche Sub und welche Zeile innerhalb dieser Sub etwas einträgt. Aber nun gut, ich bin ja weitestgehend fündig geworden, wer was wo. Und die Problemlösung folgt anschließend.

Also es geht ab in die Sub Neuer_Artikel im Modul Artikel.

Das Problem liegt darin, das die Berechnungen dort mit Single-Variablen durchgeführt wird. Und diese Variable kann eine ganz schön lange Zahl hinterm Komma aufnehmen. Und das Makro rechet auch damit immer schön weiter. Und so kommt dann am Ende schlußendlich diese Gigantische Nachkommastelle zustande.

Beseitigung des Problemsd ist recht einfach.
Vor dem Kommentar

Code: Alles auswählen

' Sheet "Stamm" nach Artikeltext (sTxt_Art) und ListenPreis(sgEP_Art) durchsuchen
setzt Du noch eine Variablen Deklaration ein.

Code: Alles auswählen

	DIM MindEinnahme_Art AS Currency
Und schon ist auch dies Problem gelöst.


Tja, und nun kommt es ganz Dicke, leider.
Erst heute habe ich eine Sache festgestellt, wonach ich eigentlich sonst immer sehr früh und rechtzeitig nachgeschaut habe, doch diesmal leider nicht.

Ich habe nämlich festgestellt, das die Datei entweder auf irgendeine Art und Weise Kontakt mit Excel hatte, oder aber sie als *.xls zwischendurch mal gespeichert wurde.

Und das geht in diesem Falle aboslut überhaupt gar-nie-nie-nicht!

Die Datei darf aus Sicherheitsgründen nur noch als *.ods gespeichert werden. Alle anderen Dateiformate wie z.B. *.xls sind absolut Tabu.

Und das bedeutet jetzt für dich, mach die Datei komplett NEU. Denn nur so sind wir auf der sicheren Seite. Aus Erfahrung weiß ich das es ansonsten zu merkwürdigem Verhalten der Datei kommen kann.

Um dir aber wenigsten etwas arbeit abzunehmen, habe ich im Anhang eine fast Blanko-Datei wo nur die ganzen BASIC-Module und die Dialoge schon drin sind. Du musst jetzt nur zusehen das Du die Tabellenblätter neu erstellst.

Aber achte dringends darauf das Du aus der anderen Datei nix, aber auch absolt reine weg gar nix per "Strg + C" -> "Strg + V" reinkopierst. Denn dadurch kopierst Du dann ansonsten wieder alles aus der alten Datei darein. Und das muss ja unbedingt vermieden werden.

Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".

Aber auf gar keinen Fall irgendwelche Bedingte Formastierungen, Zellformatierungen oder Formatvorlagen. All die sind einfach Tabu. Du musst die dann halt alle in der neuen Datei neu erstellen.

Eine kleine Arbeitserleichterung.
Lege in *Meine Makros* -> *Standard* ein Modul an, und kopiere folgendes kleines Makro in dies Modul rein.

Code: Alles auswählen

sub Unformatiert
dim document   as object
dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "SelectedFormat"
args2(0).Value = 1
dispatcher.executeDispatch(document, ".uno:ClipboardFormatItems", "", 0, args2())
end sub
Anschließend fügst Du der Symbolleiste einen neuen Eintrag hinzu der auf dies Makro zugreift, suchst dir ein Symbol aus, und schon kannst Du per "Knopfdruck" Unformatierten Text einfügen.

Jetzt ist aber Schluß. Will in die Heia.
Bild


Gruß
balu
Dateianhänge
TEMPORAERES-POS_0.0.ods
(23.99 KiB) 715-mal heruntergeladen

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Mo, 30.01.2017 13:59

Hallo balu,

am Wochenende hatte ich einen Durchhänger – die Woche war anscheinend zu voll und der Akku leer.
Ich hatte echt Probleme, mich in die Arrays hineinzudenken.
Dabei hast du es perfekt erklärt, wie ich mit vollem Akku heute morgen feststellen konnte. :)
Und somit kommt hier endlich eine überarbeitete Fassung, siehe Anhang.

Code: Alles auswählen

aUnterGrenze(0) = 0 : aOberGrenze(0) = 0 : aRabattText(0) = " - "
aUnterGrenze(1) = 50 : aOberGrenze(1) = 50 : aRabattText(1) = "Mitarbeiter"
aUnterGrenze(2) = 50 : aOberGrenze(2) = 100 : aRabattText(2) = "Sachentnahme"
aUnterGrenze(3) = 100 : aOberGrenze(3) = 100 : aRabattText(3) = "Kostenfreie Abgabe"
Du siehst jetzt so betrachtet eigentlich 4 Zeilen. Aber in wirklichkeit sind das jedoch 12 Zeilen. Der Grund für diese Art der Zeilenkomprimierung ist der Doppelpunkt (:). Denn durch dem wird dem Makro in diesem speziellen Falle gesagt, das das folgende eine weitere Zeile ist.
Jo!
Durch diese spezielle Anordnung der einzelnen Arrays kann man sich nun auch leichter merken, und vor allem auch nachvollziehen, das ein Array starke ähnlichkeit mit einem Tabellenblatt hat. Im Tabellenblatt kann man einzelne durchgehende Spalten mit einem Titel versehen, wie z.B. Untergrenze. Das ist jetzt im Array auch so, blos hier habe ich ein Array verständlicherweise als aUntergrenze benannt. Also 3 einzel Arrays mit 3 unterschiedlichen Titeln. Aber alle haben, und das ist extrem wichtig zu beachten, die gleiche Anzahl an Zeilen.
Alles klar!
Als erstes habe ich, ich sags mal so rum, ein "Wechselschalter" iTmp eingebaut. Vergleichbar mit einem Lichtschalter. Dieser hat, wie zu sehen, vor der Auswertung den Wert 0 (Null), das Licht bleibt aus.
Super Vergleich! Der Lichtschalter ist eine Komponente, von der ich befürchten würde, sie nicht immer gleich parat zu haben. Aber hier ist sie jetzt ja zum Glück ins Netz gemeißelt...

… öhhmm… zumal ich zu meiner Schande feststellen musste, dass eine solche Rabatt-Text-Festlegung gar nicht sinnvoll ist… Leider brauchen wir das hier gar nicht, weil es im Grunde nur den Rabatt-Text „Sonstige“ geben wird. Denn Mitarbeiter und Chefetage, die eine ganze Flasche einer Spirituose entnehmen, ersetzen sie einfach später. Und es wäre auch fast unmöglich für Mitarbeiter, den Flaschenpreis von 50% über den Dialog herauszubekommen.
Ich habe es jetzt trotzdem drin gelassen, weil´s so schön ist.

UND – weil ich denke, das war ein klasse Beispiel, wie Arrays funktionieren.

Ich hab ein bisschen darauf herumgedacht, ob es für den Lichtschalter auch noch andere Aggregatzustände geben kann als „an“ und „aus“. Ja, nä?
Mir ist bloß in dem Zusammenhang hier keine geeignete Variante eingefallen, die ich einsetzen kann.

Code: Alles auswählen

aUnterGrenze(4) = 150 : aOberGrenze(4) = 200 : aRabattText(4) = "Freies Gelage"
aUnterGrenze(5) = 200 : aOberGrenze(5) = 300 : aRabattText(5) = "Kater Stimmung"
Haha! Das gefällt mir!

Bezüglich der Vorauswahl von Listbox-Werten in der Sub „Dlg_Neuer_Artikel“ (andere bzw. früher aufgerufene Sub als der Dialogaufruf selbst):

Code: Alles auswählen

' Listbox für Astrakistenverkauf mit Preisen füllen:
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
oListBox_Preis.SelectItem(aKistenPreise(0), True) ' vorausgewählter Listbox-Wert, hier der erste: 35,-€
Hast Du auch überprüft das bei jedem erneuten Aufruf von *Verkauf Kiste Astra* in der dementsprechenden Listbox immer die richtge Vorauswahl steht?
Jetzt schon. ;) Guter Hinweis!

Na gut, denn doch wieder ab ins Modul „Kiste_Astra“:

Code: Alles auswählen

Sub Dlg_KastenAstra ' Dialog zur Artikeleingabe aufrufen
Dlg_Astrakiste.title = "Verkauf ganzer Kästen Astra"
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise() ' Kistenpreise aus Tabelle in Listbox eintr.
oListBox_Preis.SelectItem(aKistenPreise(0), True) ' Listbox-Wert Voreinstellung, hier der erste: 35,-€
oListBox_AusserHaus.SelectItemPos((0), True) ' Listbox-Wert Voreinstellung auf "Nein"
Dlg_Astrakiste.execute
End Sub
Gleiches Problem bestand sowieso auch schon bei der „Ausser Haus“-Vorauswahl, die ich nämlich im Dialog selbst festgelegt hatte (Auswahl „0“ - falls ich mich nicht verständlich ausgedrückt habe, unten ein Screenshot mit der entsprechenden Dialogvoreinstellung). Auch hier stellte sich der Wert nach Beendigung und Wiederaufruf des Dialogs nicht wieder auf den eingestellten Wert „0“ zurück.

Deshalb habe ich das hier stattdessen eingefügt, s.o. und hier:

Code: Alles auswählen

oListBox_AusserHaus.SelectItemPos((0), True) ' Listbox-Wert Voreinstellung auf "Nein"

Jetzt habe ich noch eine andere Frage:
Es wurde der Wunsch geäußert, dass im Tabellenblatt immer automatisch etwas hochgescrollt wird während der Eingabe. Jetzt muss man dafür ja immer erst die Dialog schließen.
Ich hab auch vielleicht die entsprechende Anweisung dazu gefunden, jedoch krieg ich das nicht so hingebastelt, dass es funktioniert.

Code: Alles auswählen

oAktuellesBlatt.getCellRangeByName("A" & iEnd_Row).Select

Was mich schon recht lange beschäftigt hat, ist folgendes:

Code: Alles auswählen

oAktuellesBlatt = thiscomponent.getcurrentcontroller.activesheet
oCellCursor = oAktuellesBlatt.createCursor()
oCellCursor.GotoEndOfUsedArea(True)
iEnd_Row = oCellCursor.getRangeAddress.EndRow
Nach einigen Tests habe ich den Eindruck, dass der Cursor, wenn er gebraucht wird, immer neu „created“ werden muss.
Jetzt habe ich, weil das so oft vorkam und so eine unschöne Verlängerung des Codes in den einzelnen Subs verursacht hat, ein Modul „Funktionen“ angelegt und das dahin verschoben.
Die Funktion wird jetzt mit ClZ aufgerufen (Cursor letzte Zeile).

Dank deiner Erläuterungen zu unserem vor Kurzem ebenfalls neu erstellten Modul „Text-Mitteilungen“ klappt der Aufruf auch.
:D

iiiiiiiiiiiiiiiih!
Jetzt kurz vor „Abschicken“ taucht etwas auf, womit ich mich schon einmal in einer ganz anderen Tabelle verzweifelt herumgeschlagen habe UND keine Lösung gefunden habe. Das habe ich seitdem völlig vergessen!

Wenn man in die von mir zuletzt eingegebene Zeile in die Spalte "Mindereinnahmen" klickt, sieht man oben in der Leiste nicht den eigentlichen, einfachen Wert „0“, sondern einen negativen, nämlich „-2,22044604925031E-016“.
Dadurch ändert sich in diesem Fall auch die Darstellung in -0,00 € statt - €.
Diesbezüglich habe ich damals das Internet tagelang durchforstet, weil ich nämlich alle Werte mit Null wegfiltern wollte und das dann deswegen nicht ging und ich es per Hand erledigen musste.

Ich wage gar nicht zu hoffen, dass du die Lösung kennst…!?

Ganz liebe Grüße
Julia
Dateianhänge
POS_Kassenbuch_Forum_7.ods
(65.76 KiB) 593-mal heruntergeladen
Vorauswahl im Dialog.PNG
Vorauswahl im Dialog.PNG (4.65 KiB) 22748 mal betrachtet

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Mo, 23.01.2017 14:34

Hallo Julia,

ja alles klar, jetzt verstehe ich "verständlich" besser. :lol:

Boah, also das mit den Arrays ist wirklich eine Herausforderung für mich.
Da brauch ich mit Sicherheit noch ein bisschen Übung, bis der Groschen fällt.
Das glaube ich dir sofort.

Ich gehe davon aus, dass ich auf aSource() in diesem Fall nur zugreifen kann, wenn dies in derselben Sub passiert, weil das Element ja lokal und nicht global deklariert wurde.
Korrekt.


Und eine Auslagerung von

Code: Alles auswählen

Dim aSource(UBound(aSourceDataArray())) as String 
an den Anfang des Moduls geht nicht, weil das aSourceDataArray() und die oZellenMitarbeiter ja auch erst später in der Sub Dlg_Neuer_Artikel definiert werden. Oder?
Man kann vieles machen, aber manche Dinge sollte man doch zusammenhängend erledigen, also nicht auseinander reißen.

Du hast den betroffenen Code-Abschnit wie folgt tituliert: ' Listbox für Mitarbeiter-Rabatt mit Namen füllen:
Was dir aber noch nicht ersichtlich ist, weil Du es noch nicht kennst, dieser Code-Abschnitt ist so gesehen eine "Routine". Und damit meine ich nicht eine Routine in der Form von; Ich bin geübt im Briefe schreiben. Viel mehr heißt das, das dies in gewisser Hinsicht ein abgeschlossener Code ist, den man auch noch anders einsetzen kann. Doch ich will jetzt nicht an dieser Stelle etwas vorweg greifen, was demnächst noch dran kommt.

Ui, kompliziert.
Tja, das stimmt. Und dabei ist das Thema Array hier noch nicht abgehakt. Aber bange machen gillt nicht. Wirt schon alles gut gehen ;-)

Jedenfalls habe ich wegen des logischen Aufbaus dann die Vorauswahl eines Astrakisten-Preises auch in der Sub Dlg_Neuer_Artikel vorgenommen:

Code: Alles auswählen

' Listbox für Astrakistenverkauf mit Preisen füllen:
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
oListBox_Preis.SelectItem(aKistenPreise(0), True) ' vorausgewählter Listbox-Wert, hier der erste: 35,-€
Also nicht hier, wie vorgeschlagen (was in diesem Fall natürlich auch funktioniert):

Code: Alles auswählen

Sub Dlg_KastenAstra ' Dialog zur Artikeleingabe aufrufen
Dlg_Astrakiste.title = "Verkauf ganzer Kästen Astra"
oListBox_Preis.SelectItem(aKistenPreise(1), True)
Dlg_Astrakiste.execute
End Sub
Hast Du auch überprüft das bei jedem erneuten Aufruf von *Verkauf Kiste Astra* in der dementsprechenden Listbox immer die richtge Vorauswahl steht?
Mach mal folgendes.

Den "Hauptdialog" (Artikel eingeben) aufrufen, in verschiedenen Dialogen Daten eingeben inklusive *Verkauf Kiste Astra*, den Hauptdialog nicht beenden. Dann weiter Daten eingeben ohne den Hauptdialog zu beenden und auch wieder in *Verkauf Kiste Astra* reinschauen. Beobachte wie sich die Vorauswahl der dementsprechenden Listbox verhällt.



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Mo, 23.01.2017 12:36

Hallo balu,

diesmal poste ich mal schon was vorneweg ohne die Datei hochzuladen. Denn noch habe ich die Formel nicht als makro umgeschrieben. Aber deinen vorherigen Beitrag habe ich abgearbeitet. :D
Das du Andrew noch nicht kanntest, dachte ich mir schon fast. Und deshalb der Link.
Und es ist sehr ausführlich und verständlich erklärt.
Ausführlich, ja.
Aber bei verständlich leben wir beide wohl in zwei verschiedenen Welten .
Hehe, ich glaube, aus meiner Anfänger-Sicht ist es so: Je mehr drin steht, umso mehr Anhaltspunkte habe ich, um das Richtige woanders nachzugucken. Somit ist umfangreicher=verständlicher. Ich habe gerade bei genauerer Betrachtung festgestellt, dass ich da keinen Unterschied mache, weil ich bei solcher Lektüre eh erstmal nix verstehe. Soviel zum Thema „verständlich“… :P

Boah, also das mit den Arrays ist wirklich eine Herausforderung für mich.
Da brauch ich mit Sicherheit noch ein bisschen Übung, bis der Groschen fällt.
Ja, eine so genannte Vorauswahl gibt es. ...
Hinzugekommen ist lediglich: oListBox_Preis.SelectItem(aKistenPreise(1), True)
Okay, das habe ich „verstanden“, höhö. ;)

Wichtig war weiterführend deine Erläuterung:
Und wenn man sich mit getDataArray ein Array holt, und in diesem Falle das umbenennt in aSourceDataArray, dann weiss das Makro das das Array eine bestimmte Größe (Anzahl an Einträgen) hat, die man mittels UBound auslesen kann.
Denn jetzt wollte ich das Ganze auch bei den Mitarbeiter-Namen machen. Mir schien, dass das hier wegen der erst lokal in der Sub Dlg_Neuer_Artikel deklarierten Größe des Arrays nur geht, wenn ich die Voreinstellung auf einen Mitarbeiter genau in dieser Sub vornehme und nicht erst beim Aufruf des Dialogs selbst (was ja in einer anderen Sub geschieht).

Hier habe ich es deshalb jetzt so gemacht, dass ich im Anschluss an die Definition für die Mitarbeiter-Listbox-Inhalte direkt die Vorauswahl festlege:

Code: Alles auswählen

' Listbox für Mitarbeiter-Rabatt mit Namen füllen:
aSourceDataArray() = oZellenMitarbeiter.getDataArray() 
Dim aSource(UBound(aSourceDataArray())) as String  
For c3po = LBound(aSource()) To UBound(aSource())
   aDataArrayRow() = aSourceDataArray(c3po)
aSource(c3po) = aDataArrayRow(0)
Next c3po
Dlg_Rabatt50.Model.getByName("RabattArt_50").StringItemList = aSource()
oListBox_Rabatt50.SelectItem(aSource(0), True) ' Erster Listbox-Eintrag vorausgewählt
Ich gehe davon aus, dass ich auf aSource() in diesem Fall nur zugreifen kann, wenn dies in derselben Sub passiert, weil das Element ja lokal und nicht global deklariert wurde.
Und eine Auslagerung von

Code: Alles auswählen

Dim aSource(UBound(aSourceDataArray())) as String 
an den Anfang des Moduls geht nicht, weil das aSourceDataArray() und die oZellenMitarbeiter ja auch erst später in der Sub Dlg_Neuer_Artikel definiert werden. Oder?

Ui, kompliziert.

Jedenfalls habe ich wegen des logischen Aufbaus dann die Vorauswahl eines Astrakisten-Preises auch in der Sub Dlg_Neuer_Artikel vorgenommen:

Code: Alles auswählen

' Listbox für Astrakistenverkauf mit Preisen füllen:
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
oListBox_Preis.SelectItem(aKistenPreise(0), True) ' vorausgewählter Listbox-Wert, hier der erste: 35,-€
Also nicht hier, wie vorgeschlagen (was in diesem Fall natürlich auch funktioniert):

Code: Alles auswählen

Sub Dlg_KastenAstra ' Dialog zur Artikeleingabe aufrufen
Dlg_Astrakiste.title = "Verkauf ganzer Kästen Astra"
oListBox_Preis.SelectItem(aKistenPreise(1), True)
Dlg_Astrakiste.execute
End Sub
Okay, sie sind enttarnt und entdeckt worden.

Code: Alles auswählen

For c3po
for r2d2
Find ich voll gut und echt Luschdich .
Freut mich! Ich hatte auch meinen Spaß dabei! :D

LG Julia

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » So, 22.01.2017 19:27

Hallo Julia,

Eins vorweg.
Ich zeige hier jetzt keine alternative für die letztens genannte Formel, so wie ich es angesprochen hatte, sondern sie wird jetzt komplett ersetzt und direkt im Makro ausgeführt.

Auch wenn es sich "nur" um eine einzige Formel handelt, die zudem auch nicht immer im Tabellenblatt eingetragen wird, so ist sie doch dafür Ideal geeignet um eine bestimmte Technik zu zeigen. Und damit meine ich *eine IF...THEN in eine Schleife zu packen*. Du wirst nacher noch sehen und verstehen was ich damit meine. Und das ist etwas was man durchaus immer wieder mal irgendwo gebrauchen kann.

Also denn, los gehts!


Thema: Ersatz für eine Formel

Um die Formel zu ersetzen können, muss einiges im Makro ergänzt werden. Es kommen so einige Codezeilen hinzu. Aber da die Arbeit im Arbeitsspeicher erledigt wird, und das auch nur wenn die dementsprechende Sub abgearbeitet wird, ist kein Geschwindigkeitseinbruch zu erwarten. Und außerdem wird dadurch die Ladezeit der Datei verringert, da beim öffnen keine Neuberechnung der Zellinhalte vorgenommen werden muss. Und das entlastet ja wohl den kleinen Arduino bei seiner Arbeit ;-)

Um das Ziel zu erreichen arbeite ich jetzt wieder mit Array.

Diese Formel

Code: Alles auswählen

=WENN(K11=0;"";WENN(K11=50;"Mitarbeiter";WENN(UND(K11>50;K11<100);"Sachentnahme";WENN(K11=100;"Kostenfreie Abgabe";"Sonstige"))))
soll jetzt nicht mehr im Tabellenblatt erscheinen, aber dennoch soll im Makro deren Funktion nachgebildet werden, so das in der dementsprechenden Zelle der richtige Text ausgegeben wird wie z.B. Sachentnahme.

Auf den ersten Blick, so dachte ich zumindest für mich, stört der folgende Vergleich.

Code: Alles auswählen

UND(K11>50;K11<100)
Denn wenn sich alle Wahrheitsüberprüfungen der WENN() auf z.B. (=) beziehen würden, wäre ein abzufragendes Array recht schnell aufgebaut. Aber dem ist ja nicht so, und folglich muss ein kleiner Trick herhalten.

Doch bevor es zum Trick geht, schauen wir uns noch mal kurz die Funktionsweise einer WENN(PRÜFUNG;DANN;SONST) Funktion im Tabellenblatt und einer IF ... THEN ... ELSE... END IF Anweisung an.
Sie machen beide das gleiche. Es findet eine Wahrheitsüberprüfung statt, und je nachdem wie die Überprüfung ausgefallen ist, geht es dann dementsprechend weiter.

Die Überprüfung ergibt WAHR:
Bei der Funktion gehts mit DANN weiter.
Bei der Makro Anweisung geht es mit THEN weiter.

Beide kann man sehr stark ineinander verschachteln, bei der Funktion ist ja die obige gezeigte Formel (die ja jetzt auch ersetzt werden soll) der Beweis dafür. Und auch die Makro Anweisung liese sich sehr stark verschachteln. Jedoch kann sich das unter Umständen zu einem wahrlichem *Makro-Code Monster* entwickeln. Und manchmal bleibt einem so ein Monster nicht erspart. Aber hier kann man sich mit der richtigen Überlegung einiges an Arbeit ersparen, vorausgesetzt man hat eine gewisse Erfahrung. ;-)

Die WENN-Formel hat in diesem Falle einen doch großen Vorteil, der uns sehr entgegen kommt. Da sie nur auf fest vorgegebene Werte hin ein Vergleich anstellt, lässt sich das jetzt recht leicht direkt im Makro ausführen. Anders würds aussehen, wenn verschiedene zwischenberechnungen mit variablem Ergebnis durchgeführt würden. Doch dem ist ja nicht so.


Aber zerpflücken wir erstmal die Formel in die wichtigsten Bestandteile.

Code: Alles auswählen

WENN(K11=0;"";
WENN(K11=50;"Mitarbeiter";
WENN(UND(K11>50;K11<100);"Sachentnahme";
WENN(K11=100;"Kostenfreie Abgabe";
Es fällt auf, das ich etwas ausgelassen habe, und zwar das hier.

Code: Alles auswählen

"Sonstige"))))
Das hat auch seinen Grund. Denn das sind alles Überprüfungen und deren Reaktionen darauf, wenn WAHR zurückgegeben wird. Das ausgelassene jedoch kommt erst dann zum tragen, wenn FALSCH zurückgegeben wird.

Jetzt kommen wir zu dem eben angesprochenen störenden Vergleich, und zu meinem Trick.
Wie wir ja wissen, kann eine IF ... THEN z.B wie folgt aufgebaut sein.

Code: Alles auswählen

IF a= xx OR  (a> xx AND a< xx) THEN
Das heißt, es können verschiedene und/oder mehrere Vergleichsoperanten angewendet werden.
Diese Vergleichsform wollen wir auch tatsächlich so anwenden. Denn schließlich spiegelt sie das wieder, was in der WENN-Formel passiert. Dort wird ja auch auf (=) hin überprüft, aber auch einmal auf UND. Da Du ja diese Technik ja selber schon angewendet hast, brauch ich jetzt nicht mehr viel was dazu sagen.

Jetzt kommen wir zum Punkt *Array*.
Ich hatte letztens schon mal diesen Punkt kurz erklärt, und vorgeführt. Und diesmal brauchen wir 3 solcher einfachen Arrays.


Bevor es weiter geht, solltest Du ein neues Modul anlegen. Denn in dieses Modul kommt zu testzwecken alles rein was gleich noch folgt. Das hat den Vorteil das Du dadrin selber ein wenig experimentieren kannst, ohne jedesmal den Dialog auszuführen. Und wenn Du dich so weit davon überzeugt hast, das alles korrekt funktioniert, kopierst Du dann alles in das richtige Modul.


Als erstes müssen diese Arrays Deklariert werden. Doch diesmal machen wir das nicht öffentlich, also so wie bisher, sondern Lokal. Und das bedeutet, das in dem neu angelegten Modul in der *Sub Main* Deklariert wird.

Code: Alles auswählen

Sub Main
Dim aUnterGrenze(3) as Integer, aOberGrenze(3) as Integer
Dim aRabattText(3) as String
Jetzt werden die Arrays definiert und mit Leben befüllt.

Code: Alles auswählen

aUnterGrenze(0) = 0 : aOberGrenze(0) = 0 : aRabattText(0) = " - "
aUnterGrenze(1) = 50 : aOberGrenze(1) = 50 : aRabattText(1) = "Mitarbeiter"
aUnterGrenze(2) = 50 : aOberGrenze(2) = 100 : aRabattText(2) = "Sachentnahme"
aUnterGrenze(3) = 100 : aOberGrenze(3) = 100 : aRabattText(3) = "Kostenfreie Abgabe"
Das kopierst Du genau so in die Sub rein, und zwar direkt unter der Deklaration.
Achte aber unbedingt darauf das mindestens 1 Leerzeichen VOR und HINTER dem Doppelpunkt (:) steht. Denn wenn das nicht der Fall ist, gibts garantiert Probleme.

Du siehst jetzt so betrachtet eigentlich 4 Zeilen. Aber in wirklichkeit sind das jedoch 12 Zeilen. Der Grund für diese Art der Zeilenkomprimierung ist der Doppelpunkt (:). Denn durch dem wird dem Makro in diesem speziellen Falle gesagt, das das folgende eine weitere Zeile ist. So kann man leichter verstehen was wo zugeordnet ist. Das jetzt aber der RabattText "Sonstige" fehlt, hat wiederum seinen Grund, das wirst Du aber nachher noch verstehen warum das so ist.

Durch diese spezielle Anordnung der einzelnen Arrays kann man sich nun auch leichter merken, und vor allem auch nachvollziehen, das ein Array starke ähnlichkeit mit einem Tabellenblatt hat. Im Tabellenblatt kann man einzelne durchgehende Spalten mit einem Titel versehen, wie z.B. Untergrenze. Das ist jetzt im Array auch so, blos hier habe ich ein Array verständlicherweise als aUntergrenze benannt. Also 3 einzel Arrays mit 3 unterschiedlichen Titeln. Aber alle haben, und das ist extrem wichtig zu beachten, die gleiche Anzahl an Zeilen.


Jetzt sind so gesehen alle grundlegenden Bedingungen erfüllt, um eine Abfrage und Auswertung zu starten, die die Formel ersetzen soll. Also ran an den Feind :-)

Die folgende Auswertung ist nicht vollständig ausgefüllt, da Du jetzt nicht abgelenkt werden sollst. Und ferner dient das jetzt nur der Erklärung, also nicht in die Sub eingeben.

Code: Alles auswählen

iTmp = 0
    For iFE = LBound(aUnterGrenze()) to UBound(aUnterGrenze())
        If sgRabatt_Fl= aOberGrenze(iFE) OR (sgRabatt_Fl> aUnterGrenze(iFE) AND sgRabatt_Fl< aOberGrenze(iFE))

        End If
    Next iFE
         
    If iTmp = 0 then
        sZellRabatt = "Sonstige"
    end If

    MsgBox sZellRabatt 
"Was geschieht dort?"

Als erstes habe ich, ich sags mal so rum, ein "Wechselschalter" iTmp eingebaut. Vergleichbar mit einem Lichtschalter. Dieser hat, wie zu sehen, vor der Auswertung den Wert 0 (Null), das Licht bleibt aus.
Nun wird die Schleife (For Next) ausgeführt. Und innerhalb der Schleife wird überprüft ob die zu sehende Vergleichsbedingung zutrifft. Und wir sagen jetzt mal das alle 4 Durchläufe negativ ausgefallen sind. Und auf Grund dessen kommt bei der IF gar nicht der THEN Teil zum tragen, es bleibt also vorläufig im Dunkeln was dort steht.

Kurz dazwischen. iFE heißt integerFormelErsatz (meine Kreation, die Du aber nicht übernehmen musst).

Jetzt wird wieder ein Vergleich angestellt, ob iTmp gleich 0 (Null) ist. Und da das offensichtlich der Fall ist, wird jetzt der Variable sZellRabatt der Text Sonstige zugewiesen.
Anschließend wird der Inhalt der Variable in der MsgBox ausgegeben.


So, und nun fast das gleiche noch mal, aber diesmal ist die Auswertung vollständig komplett, also nix mehr ausgeblendet oder so. Und diesmal kopierst Du jetzt alles so wie zu sehen in die *Sub Main* rein.

Code: Alles auswählen

sgRabatt_Fl = '<- dort zu testzwecken verschiedene Werte eingeben'
iTmp = 0
    For iFE = LBound(aUnterGrenze()) to UBound(aUnterGrenze())
        If sgRabatt_Fl= aOberGrenze(iFE) OR (sgRabatt_Fl> aUnterGrenze(iFE) AND sgRabatt_Fl< aOberGrenze(iFE)) Then
           iTmp = 1
           sZellRabatt = aRabattText(iFE)
        End If
    Next iFE

    If iTmp = 0 then
        sZellRabatt = "Sonstige"
    end If

    MsgBox sZellRabatt 
In die erste Zeile kannst Du, wie zu lesen, Werte eingeben um die Funktion zu überprüfen.

Prinzipiell das gleiche wie vorhin. Jedoch sagen wir jetzt diesmal, das im 2. Schleifendurchlauf der Vergleich in der IF positiv ist und dementsprechend der THEN Teil zum tragen kommt. Dadurch wird iTmp auf 1 geschaltet, das Licht geht also jetzt an, und es wird jetzt der Variable sZellRabatt der Text aus dem passenden Array aRabattText(1) zugewiesen.

Wenn jetzt die Schleife (FOR...NEXT) fertig durchgelaufen ist, so hat ja iTmp den Wert 1. Und es geht weiter mit dem jetzt folgenden Vergleich.

Diesmal ist iTmp aber nicht gleich 0 (Null), wurde ja vorhin auf 1 geschaltet/gesetzt, und folglich kommt hier jetzt NICHT der THEN Teil zum tragen. Dadurch wird jetzt die schon beschriebene Variable sZellRabatt nicht noch mal beschrieben, beziehungsweise überschrieben. Also wird jetzt der Inhalt der Variable in der MsgBox ausgegeben.

Code: Alles auswählen

For iFE = LBound(aUnterGrenze()) to UBound(aUnterGrenze())
Warum habe ich das so gemacht, und nicht einfach *0 TO 3*?

Nun, da die Arrays ordnungsgemäß Deklariert wurden, haben sie eine Untere und eine Obere Begrenzung. Und diese Begrenzungen kann man mit LBound (Untere) und UBound (Obere) auslesen lassen. Man kann sich z.B. so gesehen nicht veschreiben, also anstatt 0 to 3 hätte man 0 to 4 geschrieben. Die Folge bei dem vertuer ist nämlich der, das es zwangsläufig zu einer Fehlermeldung kommt.

Ferner besteht der Vorteil auch dadrin, das bei einer Erweiterung, oder Verkürzung des Array die Schleife nicht geändert werden muss. Man muss lediglich die Deklaration anpassen und die Array Einträge erweitern oder reduzieren. Kurzes Beispiel dazu, was lediglich zeigt wo was geändert werden muss.

Code: Alles auswählen

Dim aUnterGrenze(5) as Integer, aOberGrenze(5) as Integer
Dim aRabattText(5) as String
aUnterGrenze(0) = 0 : aOberGrenze(0) = 0 : aRabattText(0) = " - "
aUnterGrenze(1) = 50 : aOberGrenze(1) = 50 : aRabattText(1) = "Mitarbeiter"
aUnterGrenze(2) = 50 : aOberGrenze(2) = 100 : aRabattText(2) = "Sachentnahme"
aUnterGrenze(3) = 100 : aOberGrenze(3) = 100 : aRabattText(3) = "Kostenfreie Abgabe"
aUnterGrenze(4) = 150 : aOberGrenze(4) = 200 : aRabattText(4) = "Freies Gelage"
aUnterGrenze(5) = 200 : aOberGrenze(5) = 300 : aRabattText(5) = "Kater Stimmung"
Die Auswertung bleibt unberührt, die bleibt so wie sie ist.

Jetzt muss natürlich nach erfolgreichen Tests alles noch an seinen richtigen Platz hinkommen.
Also, es kommt alles in das Modul *Flachenverkauf*. Und zwar wie folgt.
In die Sub Neuer_Flaschenverkauf kommt gleich zu Anfang das hier rein.

Code: Alles auswählen

Dim aUnterGrenze(3) as Integer, aOberGrenze(3) as Integer
Dim aRabattText(3) as String

aUnterGrenze(0) = 0 : aOberGrenze(0) = 0 : aRabattText(0) = " - "
aUnterGrenze(1) = 50 : aOberGrenze(1) = 50 : aRabattText(1) = "Mitarbeiter"
aUnterGrenze(2) = 50 : aOberGrenze(2) = 100 : aRabattText(2) = "Sachentnahme"
aUnterGrenze(3) = 100 : aOberGrenze(3) = 100 : aRabattText(3) = "Kostenfreie Abgabe"
Dann schmeißt Du folgende Zeile raus, einfach löschen.

Code: Alles auswählen

sFormulaRabattArt_Fl = "=IF(K" & iEnd_Row & "=0;"""";IF(K" & iEnd_Row & "=50;""Mitarbeiter"";IF(AND(K" & iEnd_Row & ">50;K" & iEnd_Row & "<100);""Sachentnahme"";IF(K" & iEnd_Row & "=100;""Kostenfreie Abgabe"";""Sonstige""))))"
Dann kommt ja der Block: ' Prüfen, ob Rabatt kleiner 0
Und nach dem dortigem Endif kommt dann das folgende rein, also noch vor ' Ausschluss vorhandener Flaschen-Artikelnummern.

Code: Alles auswählen

iTmp = 0
    For iFE = LBound(aUnterGrenze()) to UBound(aUnterGrenze())
        If sgRabatt_Fl= aOberGrenze(iFE) OR (sgRabatt_Fl> aUnterGrenze(iFE) AND sgRabatt_Fl< aOberGrenze(iFE)) Then
           iTmp = 1
           sZellRabatt = aRabattText(iFE)
        End If
    Next iFE

    If iTmp = 0 then
        sZellRabatt = "Sonstige"
    end If
Ein paar Zeilen tiefer kommt ja das hier.

Code: Alles auswählen

	oAktuellesBlatt.getCellRangeByName("L" & iEnd_Row).Formula = sFormulaRabattArt_Fl
Das änderst Du nun wie folgt um.

Code: Alles auswählen

	oAktuellesBlatt.getCellRangeByName("L" & iEnd_Row).String = sZellRabatt
Jetzt löscht Du das temporär eingefügte Modul, speicherst die Datei, und öffnest sie erneut.
Anschließend den Dialog aufrufen und testen ob auch mit dem Dialog die vorgenommenen Änderungen so weit alles funktioniert.


Eigentlich wollte ich dir ja noch zeigen wo Du das neue System mit dem Array noch anwenden kannst, aber ich habs mir noch mal überlegt und komme zu folgendem Entschluß: Für heute solls das gewesen sein.
Wenn Du alles so weit zufrieden stellend nachbauen konntest, dann sag bescheid, und dann hole ich das jetzt ausgelassene nach.

Viel Spaß, und Erfolg 8)



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Sa, 21.01.2017 23:56

Hallo Julia,
Oh, die kannte ich noch nicht.
Das du Andrew noch nicht kanntest, dachte ich mir schon fast. Und deshalb der Link.

Und es ist sehr ausführlich und verständlich erklärt.
Ausführlich, ja.
Aber bei verständlich leben wir beide wohl in zwei verschiedenen Welten :lol:.
Das bezieht sich aber mehr auf die Beispielcodes. Sie sind mir stellenweise doch zu abstrakt. Aber dennoch besserr als gar nichts. Das wollen wir jetzt aber hier nicht weiter ausdiskutieren.

Bislang habe ich immer bei Wollmux im Makro-Kochbuch geguckt.
Wollmux ist namentlich nicht grad unbekannt. Aber so weit ich micht recht entsinne, ist es aber auch eine etwas schwerere Kost. Und dennoch, Respekt das Du dich damit befasst hast, liest man hier seeeeehr selten.

Ich bedanke mich für deine Lobende Worte, und auch dafür das Du dich intensiv mit meinen Beiträgen auseinander setzt. Das erfreut mich doch sehr. *schöööön*

Aber zurück an die Arbeit.
so umgeschrieben:

Code: Alles auswählen

oCellRange.clearContents(21) ' (21) = (1+4+16)
Na Prima! Sehr gut aufgepasst.


… Da hätt ich jetzt mal ne Frage, die sich mir auch schon bei meinem anderen Array gestellt hat:
Wenn ich ein Array deklariere, dann müsste das eigentlich immer Integer sein, oder?
Tja, das Thema Array ist sehr umfangreich. Aber so viel sei schon mal gesagt. NEIN! Es muss nicht immer als Integer deklariert werden. Es gibt da verschiedene möglichkeiten es zu deklarieren, als Integer, String oder aber auch als Variant. Und je nach dem was da rein kommen kann/soll muss es dementsprechend deklariert werden.

Bedenke, das Dim aKistenPreise(1) nur angibt wieviele Eintäge aufgenommen werden können. Das sagt aber nichts über den Typ der Einträge aus, wie z.B. Integer. Man muss das in diesem Falle getrennt betrachten.


Mein schon vorbereiteter Beitrag befasst sich auch wider mit dem Thema Array, aber es ist wohl etwas Umfangreicher dafür aber hoffentlich leichter nachzuvollziehen. Dafür mache ich dann hier im Anschluß einen weiteren seperaten Beitrag auf.

Ich hab hier

Code: Alles auswählen

aSourceDataArray() = oZellenMitarbeiter.getDataArray()
Dim aSource(UBound(aSourceDataArray())) as String 
For j = LBound(aSource()) To UBound(aSource())
aDataArrayRow() = aSourceDataArray(j)
aSource(j) = aDataArrayRow(0)
nämlich gar keine Deklaration vorgenommen, weil mir

Code: Alles auswählen

Dim aSourceDataArray as Array
doch etwas spanisch vorkam.
Man muss nicht alles deklarieren, auch wenn es nicht verkehrt wäre. Theoretisch könnte man das ganze auch so schreiben,

Code: Alles auswählen

Dim aSource(UBound(oZellenMitarbeiter.getDataArray())) as String 
For j = LBound(aSource()) To UBound(aSource())
aDataArrayRow() = oZellenMitarbeiter.getDataArray(j)
aSource(j) = aDataArrayRow(0)
aber das dann zu lesen fällt dann wohl schon einem etwas schwerer, weil die Übersicht verloren gegangen ist.

Was Du vielleicht noch nicht weisst, ist die Tatsache das getDataArray per se schon ein Array ist. Eigentlich ist DataArray auch ein Array, blos mit den Vornamen get holt man sich das Array und mit set schreibt man das Array.
Vor allem wegen der Zeile

Code: Alles auswählen

Dim aSource(UBound(aSourceDataArray())) as String 
Korrekt.
Und das ist jetzt auch ein gutes Beispiel dafür, das man nicht immer zum Anfang eines Moduls oder einer Sub etwas deklarieren muss. Denn bei einem Array weiss man wohl schon oft im Vorfeld was für Daten da rein kommen, z.B. String, aber man weiss nicht immer wie Groß das Array sein wird. Es ist also ungewiss ob das Array 2 oder 99 "Datensätze" umfasst.

Und wenn man sich mit getDataArray ein Array holt, und in diesem Falle das umbenennt in aSourceDataArray, dann weiss das Makro das das Array eine bestimmte Größe (Anzahl an Einträgen) hat, die man mittels UBound auslesen kann.

Und hierfür bräuchte ich noch eine Tüte Logik:

Code: Alles auswählen

For iKP = 0 To UBound(aKistenPreise())
aKistenPreise(iKP) = aKistenPreise(iKP) 
Next iKP
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
iKP ist ja dann „0“ und „1“, denke ich mal, weil wir ja am Anfang aKistenPreise()
wie folgt deklariert haben:

Code: Alles auswählen

Dim aKistenPreise(1) as Integer
Die Zeile

Code: Alles auswählen

aKistenPreise(iKP) = aKistenPreise(iKP)
löst bei mir so etwas aus, wie ein Wort, das einem auf der Zunge liegt, aber es fällt einem trotzdem nicht ein...
Es wäre super, wenn du mir da noch einmal auf die Sprünge helfen könntest. :P
Ja, ich verstehe deine Verwirrung. Und da habe ich mir auch mal erlaubt Bockmist zu machen. Ich hab es da echt mal etwas übertieben. Hatte es leider nicht auf eine andere Methode hin überprüft. Kurz und gut, die Schleife, also das hier

Code: Alles auswählen

For iKP = 0 To UBound(aKistenPreise())
aKistenPreise(iKP) = aKistenPreise(iKP) 
Next iKP
kannst Du getrost löschen. Habe es eben in einer Testdatei ausprobiert, und es funktioniert ohne diese Codezeilen. Habe schlicht zu kompliziert gedacht.

Im Zusammenhang mit den sich selbst befüllenden Listboxen hätte ich noch den Wunsch, dass es einen vorausgewählten Wert/Text gibt. Geht das?
Weil jetzt ist die Listbox ja immer erstmal ohne Inhalt, wenn man den Dialog aufruft.
Ja, eine so genannte Vorauswahl gibt es.
Im Modul *Kiste_Astra*, in der Sub Dlg_KastenAstra hast Du ja dort das hier stehen.

Code: Alles auswählen

Sub Dlg_KastenAstra ' Dialog zur Artikeleingabe aufrufen
	Dlg_Astrakiste.title = "Verkauf ganzer Kästen Astra"
	Dlg_Astrakiste.execute
End Sub
Und das änderst Du auf das hier.

Code: Alles auswählen

Sub Dlg_KastenAstra ' Dialog zur Artikeleingabe aufrufen
	Dlg_Astrakiste.title = "Verkauf ganzer Kästen Astra"
	oListBox_Preis.SelectItem(aKistenPreise(1), True)
	Dlg_Astrakiste.execute
End Sub
Hinzugekommen ist lediglich: oListBox_Preis.SelectItem(aKistenPreise(1), True)
Es ist dir überlassen ob Du die 1 übernimmst, oder ob Du die 0 nimmst.


Also ich musste auch erstmal nach sofort auffälligen Fehlern suchen, hatte aber auf den ersten Blick nix gefunden. ...
Ohje, da hab ich dir aber viel Arbeit gemacht!
Ach halb so wild, und auch nicht weiter tragisch. Da ich ja im groben mit der Datei schon gut vertraut bin, ist eine Fehlersuche nicht ganz so tragisch.

Nächstes Mal wende ich deine Fehlersuche an.
Tja, manchmal muss man sich schon für eine Fehlersuche eine gewisse Strategie zurecht legen.
Ich hatte eben auch ein kleines nicht zu verstehendes Problemchen beim testen mit der "oListBox_Preis.SelectItem". Der erste Versuch klappte wunderbar, allerdings im Modul *Artikel*. Dann dachte ich mir das dies nicht der Ideale Ort ist, also habe ich die gezeigte Codezeile in das nun richtige Modul und in die passende Sub eingetragen. Anschließend in der anderen Sub die Codezeile geREMt.

Dialog aufgerufen, und in der Listbox war kein Eintrag vorausgewählt. Komisch, hatte doch vorhin noch funktioniert. Also ab an die Fehlersuche. Aber mir war das ein Rätsel, da doch alles Ordnungsgemäß Deklariert und Defeniert ist.

Und dann musste ich auch noch feststellen, das überhaupt kein Eintrag in der Listbox vorhanden war, sie war schlicht leer. Ja jetzt schaute ich wie ein kaputtes Auto, blos nicht so schnell.

Also noch mal alles genau durchsuchen. Und dann sah ich den Fehler.
Ich blödie hatte die Falsche Zeile zuvor geREMt. War um eine Zeile zu hoch gerutscht.
Also das richtig gestellt, und schon funktionierte es wie ich gedacht hatte.

Ja ja!
Was nützt einem die besste Strategie zur Fehlersuche, wenn man sich selber ein Bein gestellt hat vor lauter Routine? *lach-lach-lach*


Okay, sie sind enttarnt und entdeckt worden.

Code: Alles auswählen

For c3po
for r2d2
Find ich voll gut und echt Luschdich :-D.

Und ich habe auch gesehen, das Du doch schon das ein oder andere im Makro umgeschrieben hast. Und das finde ich echt klasse.

Mein vorbereitetes Thema war eigentlich nur für einen ganz bestimmten Punkt ausgelegt, aber bei genauerer Betrachtung ist dir das auch an anderer Stelle nützlich, wenn Du dann das System verstanden hast. Wie schon gesagt geht es da auch wieder um Array. Und ich werde dann auch erklären wo und wie Du dann das "neue System" noch einsetzen kannst. Jedoch heute nicht mehr, das mache ich morgen am Sonntag.



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Sa, 21.01.2017 18:39

Hallo balu,
Jetzt schlägt die "Vor-Formatierung" aber auch so richtig zu. Denn durch die 4 in FormatDateTime wird gesagt, stelle auf "Stunden und Minuten(hh:mm, Stunden im 24-Stunden-Format)" ein. Nachzulesen in "Andrew Pitonyak", das Buch findest Du hier: http://www.uni-due.de/~abi070/ooo.html
Das ist wirklich eine sehr wichtige Lektüre.
Oh, die kannte ich noch nicht. Und es ist sehr ausführlich und verständlich erklärt. Bislang habe ich immer bei Wollmux im Makro-Kochbuch geguckt. Da hatte ich manchmal aber zu große Wissenslücken, um es tatsächlich nachvollziehen zu können.
Dannenhöfer habe ich auch schon häufig frequentiert.

Aha!!!

Jetzt habe ich es so

Code: Alles auswählen

oAktuellesBlatt.getCellRangeByName("K" & iEnd_Row).Value = sgRabatt_Fl
oAktuellesBlatt.getCellRangeByName("K" & iEnd_Row).Numberformat = 2
und so

Code: Alles auswählen

antwort = MsgBox (… "Somit hast du einen Rabatt von " & Format(sgRabatt_Fl, "###.00") & " % vergeben."… 
gemacht.

Dann habe ich noch das hier von dir aufgegriffen

Code: Alles auswählen

oBlattNo1.getCellRangeByName("A1:D1").clearContents(255)
und meine Zeilen

Code: Alles auswählen

oCellRange.clearContents(com.sun.star.sheet.CellFlags.VALUE)
oCellRange.clearContents(com.sun.star.sheet.CellFlags.FORMULA)
oCellRange.clearContents(com.sun.star.sheet.CellFlags.STRING)
so umgeschrieben:

Code: Alles auswählen

oCellRange.clearContents(21) ' (21) = (1+4+16)
Ein Ziel ist es, dir so nebenbei Step-by-Step einiges beizubringen was Du noch öfters anwenden kannst.
Das machst du erstklassig!!!

Ich hab daher auch ein bisschen länger gebraucht, weil ich halt nicht nur einfach was rauskopieren möchte, was ich so gerade noch im Ansatz verstehe. Ich teste auch immer brav deine Beispiel-Codes und guck alle Links nach. Dein Einsatz wird seeeeehr geschätzt! ;)
"Und warum 2, und nicht 1?"

Ganz einfach, weil es sich automatisch dabei um eine Null-Basierte Zählung handelt. Und damit hast Du ja wohl schon öfters im Makro zu tun gehabt, mit der Null-Basierten Zählung. Also brauche ich wohl nix mehr dazu zu sagen…
Jupp!

Code: Alles auswählen

Dim aKistenPreise(1) as Integer
… Da hätt ich jetzt mal ne Frage, die sich mir auch schon bei meinem anderen Array gestellt hat:
Wenn ich ein Array deklariere, dann müsste das eigentlich immer Integer sein, oder?

Ich hab hier

Code: Alles auswählen

aSourceDataArray() = oZellenMitarbeiter.getDataArray()
Dim aSource(UBound(aSourceDataArray())) as String 
For j = LBound(aSource()) To UBound(aSource())
aDataArrayRow() = aSourceDataArray(j)
aSource(j) = aDataArrayRow(0)
nämlich gar keine Deklaration vorgenommen, weil mir

Code: Alles auswählen

Dim aSourceDataArray as Array
doch etwas spanisch vorkam.
Vor allem wegen der Zeile

Code: Alles auswählen

Dim aSource(UBound(aSourceDataArray())) as String 
Und hierfür bräuchte ich noch eine Tüte Logik:

Code: Alles auswählen

For iKP = 0 To UBound(aKistenPreise())
aKistenPreise(iKP) = aKistenPreise(iKP) 
Next iKP
Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
iKP ist ja dann „0“ und „1“, denke ich mal, weil wir ja am Anfang aKistenPreise()
wie folgt deklariert haben:

Code: Alles auswählen

Dim aKistenPreise(1) as Integer
Die Zeile

Code: Alles auswählen

aKistenPreise(iKP) = aKistenPreise(iKP)
löst bei mir so etwas aus, wie ein Wort, das einem auf der Zunge liegt, aber es fällt einem trotzdem nicht ein...
Es wäre super, wenn du mir da noch einmal auf die Sprünge helfen könntest. :P

Im Zusammenhang mit den sich selbst befüllenden Listboxen hätte ich noch den Wunsch, dass es einen vorausgewählten Wert/Text gibt. Geht das?
Weil jetzt ist die Listbox ja immer erstmal ohne Inhalt, wenn man den Dialog aufruft.

Die Erneuerung der Listbox für die Mitarbeiterauswahl bei Rabattwert = 50% habe ich jetzt auch in der Sub Dlg_Neuer_Artikel untergebracht.
Bei dem Versuch, hier Teile zu ersetzen bzw. umzuschreiben, habe ich mir einen Knoten ins Gehirn gedacht, daher habe es erstmal so gelassen, wie es war. Ich bin heute im logischen Denken auch nicht so auf der Höhe, hab ich gemerkt.
Kann man eigentlich, wenn man "sgRabatt_Art = oRabatt_Artikel.Value()" in Klammern setzt, auch damit rechnen? Fällt mir grad spontan ein - hab's nicht ausprobiert.

Das solltest Du noch mal genauer erklären.
Ich habs in der Sub Neuer_Artikel gemacht und es funktioniert:

Code: Alles auswählen

MindEinnahme_Art = (oEP_PreisEingabe.Value())*sgAnzahl_Art - Einnahme_Art
oAktuellesBlatt.getCellRangeByName("M" & iEnd_Row).Value = MindEinnahme_Art
Also ich musste auch erstmal nach sofort auffälligen Fehlern suchen, hatte aber auf den ersten Blick nix gefunden. ...
Ohje, da hab ich dir aber viel Arbeit gemacht!
Nächstes Mal wende ich deine Fehlersuche an.

So, damit ich endlich mal wieder etwas hochladen kann, mache ich hier jetzt Schluss, obwohl ich noch viel mehr schreiben könnte. Aber das kann auch warten.

LG Julia
Dateianhänge
POS_Kassenbuch_Forum_6.ods
(65.92 KiB) 569-mal heruntergeladen

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » Mo, 09.01.2017 22:22

Hallo Julia,
Wow! Cool!
Daaankee!
Gern geschehen :D

Das mit dem Auslagern hat's mir besonders angetan.
Ich hab so'n Gefühl, dass man da noch viel mehr auslagern kann.
Och jo! Da gibt es noch das eine oder andere ;-)

Also denn! Es gibt viel zu tun. Packen wir es an.


Bitte gewöhne dir bei "For ... next" (Kurz: Schleife) folgendes an.

Code: Alles auswählen

For i = 1 to 10
    [tu irgendetwas]
next i
Denn Du schreibst das next bisher immer ohne den "Zähler". Und das kann unter Umständen durchaus mal zu Problemen führen, wenn mehrere Schleifen ineinander verschachtelt sind. Und beim durchlesen eines Codes kannst Du dann selber ins Stolpern geraten, wenn Du nicht wirklich nachvolziehen kannst welche Schleife abgearbeitet wurde und welche nicht.

Ferner empfehle ich dir auch aus Sicherheitsgründen dabei nicht immer den gleichen Zähler zu benutzen. Also nicht immer nur next i, sondern auch andere Buchstaben, Buchstabenkombinationen oder auch Wörter.

Code: Alles auswählen

For r2d2 = 0 to 5
    [tu irgendetwas]
next r2d2

Code: Alles auswählen

For KistenIndex = 0 to 5
    [tu irgendetwas]
next KistenIndex 
Das sind Erfahrungswerte die sich wirklich lohnen zu merken.


Thema: Fehleranalyse
Frage:
Ich habe versucht, so viel wie möglich in der Sub „Dlg_neuer_Artikel“ vorzudefinieren.
Und manchmal erklärt es sich mir nicht, wieso es dann nicht funktioniert.
Z.B. greife ich im Modul „Flaschenverkauf“ in der MsgBox unten auf Daten zu, deren Werte in der Sub „Dlg_neuer_Artikel“ definiert wurden. Das klappt.

Aber wenn ich Ähnliches im Modul „Kiste_Astra“ versuche, geht das nicht. Vielleicht, weil mit den Werten dort gerechnet werden soll?
Und so was auf nüchteren Magen :-)

Also ich musste auch erstmal nach sofort auffälligen Fehlern suchen, hatte aber auf den ersten Blick nix gefunden.

Dann bin ich daher gegangen und habe den von dir markierten Code-Abschnitt in die "Sub Dlg_neuer_Artikel" kopiert, und in der Problem Sub alles geREMt. Dann den dementsprechenden Dialog gestartet, Testwerte eingegeben und ausgewählt. Es erschien eine Fehlermeldung. Diese konnte ich aber nicht wirkklich nachvollziehen. Also eine Händische Fehlersuche durchgeführt.

Und bei der Fehlersuche ist mir aufgefallen, das Du eine kleinigkeit vergessen hast. Kann vorkommen, kenne das selber. Der Fehler ist nämlich, das Du wohl richtig definiert hast

Code: Alles auswählen

iNrAstra_Ki = oBlattStamm.getCellRangeByName("F27").value
ABER iNrAstra_Ki nicht DEKLARIERT hast. Also füge das zu deiner deklaration noch hinzu.

Code: Alles auswählen

Dim iNrAstra_Ki as Integer
Danach kannst Du den kommentierten Block aus der "Sub Kiste_Astra" komplett in die "Sub Dlg_neuer_Artikel" verschieben.

Das folgende baut nicht der Reihe nach auf dessen auf was Du gesagt hast, sondern es wird Thematisch vorgegangen da das eine auf das andere aufbaut. Arbeite jedes Thema der Reihe nach ab.

Thema. Verbesserung Teil 1
Modul „Kiste_Astra“
Ich wollte eigentlich die zwei möglichen Preise (30€/35€) für den Verkauf einer Kiste Astra ebenfalls im Stammblatt hinterlegen.
Das geht, und das machen wir jetzt auch.

Auch wenn es eine andere Methode gibt, so zeige ich dir eine relativ einfache Methode.
Fangen wir mit der deklaration an.

Code: Alles auswählen

Dim aKistenPreise(1) as Integer
Kommt dir bekannt vor, oder?
Okay, es gibt einen Unterschied. Durch die Klammer mit Inhalt signalisiert man das es sich um ein Array handelt.

"Array? Array? Array? War da nicht etwas?"

Wirst Du dich zu Recht fragen, und JA das hatte ich vor kurzem schon angesprochen. Und außerdem hast Du ja selber schon etwas mit Array eingebaut. Du erinnerst dich an das hier?
balu hat geschrieben: Ich sehe Du hast hier im Forum etwas gefunden, was sehr nützlich ist.

Code: Alles auswählen

   aSourceDataArray() = oZellenMitarbeiter.getDataArray()
   Dim aSource(UBound(aSourceDataArray())) as String 
   For j = LBound(aSource()) To UBound(aSource())
      aDataArrayRow() = aSourceDataArray(j)
   aSource(j) = aDataArrayRow(0)
Find ich echt klasse wie Du doch so aktiv bist.
Ja, dieser Code arbeitet auch mit Array. Ist ja auch gar nicht so schwer zu identifizieren, gelle!
Da dieser Code aber auf ein Tabellenblatt zugreift, und nur mit String arbeitet, können wir vorläufig nicht sehr viel damit anfangen. Also nehmen wir eine andere Methode, ist vom Prinzip eigentlich nicht anders.

Und so nebenbei gibts jetzt einen sehr kleinen Mini Crash-Kurs zum Thema ARRAY.

Das Array aKistenPreise (1) wurde ja jetzt so deklariert. Und die 1 in den Klammern sagt, es handelt sich um 2 Elemente die das Array aufnehmen soll.

"Und warum 2, und nicht 1?"

Ganz einfach, weil es sich automatisch dabei um eine Null-Basierte Zählung handelt. Und damit hast Du ja wohl schon öfters im Makro zu tun gehabt, mit der Null-Basierten Zählung. Also brauche ich wohl nix mehr dazu zu sagen. Es gibt wohl auch noch Ausnahmen davon, aber das passt jetzt nicht zum *Mini Crash-Kurs*, kommt vielleicht später.

Und jetzt muss noch das Array mit Leben befüllt werden.

Code: Alles auswählen

aKistenPreise(0) = 35
aKistenPreise(1) = 30
Im groben kannst Du das jetzt mit einer Spalte in einem Tabellenblatt vergleichen. Und die Zahlen in Klammern wären dann jetzt die Zeilennummern. Und auf ein Tabellenblatt angepasst hätten wir jetzt also folgende Situation.
A1 hat den Wert 35
A2 hat den Wert 30

Nun könnte man folgendes im Makro machen.

Code: Alles auswählen

Print aKistenPreise(1)
Das Ergebnis wäre 30. Tauscht man die 1 gegen die 0, würde beim erneuten ausführen die 35 ausgegeben.
Also vom Prinzip her nix anderes, als wenn man im Tabellenblatt in der Zelle H1 einfach =A2, oder =A1 eingeben würde. Ist doch für den Anfang gar nicht so extrem schwer, oder ;-)

Okay, jetzt muss aber damit die Listbox befüllt werden, und das machen wir hiermit.

Code: Alles auswählen

    For iKP = 0 To UBound(aKistenPreise())
        aKistenPreise(iKP ) = aKistenPreise(iKP )
    Next iKP
        Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
Aber Achtung!
Es gibt einen sehr wichtigen Punkt den man berücksichtigen muss.

Du hast wohl korrekt die Listbox wie folgt deklariert,

Code: Alles auswählen

oListBox_Preis = Dlg_Astrakiste.GetControl("Preis")
jedoch das befüllen geschieht nicht über GetControl, sondern mit Model.getByName. Das darf auf gar keinen Fall durcheinander geworfen werden. Denn sonst erlebt man böse Überraschungen.


Das ist kurz, einfach und für den Anfang reicht das für die 2 einzutragenden Werte.
Und hier jetzt noch mal alles zusammen.

Code: Alles auswählen

Dim aKistenPreise(1) as Integer

' Ab hier in die Sub Dlg_neuer_Artikel eintragen'

aKistenPreise(0) = 30
aKistenPreise(1) = 35

    For iKP = 0 To UBound(aKistenPreise())
        aKistenPreise(iKP ) = aKistenPreise(iKP ) 
    Next iKP
        Dlg_Astrakiste.Model.getByName("Preis").StringItemList = aKistenPreise()
 

Thema: Verbesserung Teil 2:
Aber ich hab mir scheinbar durch die Anwendung von .SelectedItemPos selbst ein Bein gestellt. Das müsste man sonst wohl nochmal ganz anders machen.
Stimmt!
Du musst nicht für alles eine zwischenvariable heranziehen, besonders dann, wenn sie nur einmal gebraucht wird. Dadurch wirst Du noch den Überblick verlierern.
Hier ein Beispiel.

Code: Alles auswählen

	LBox_AstraPreis_Ki = oListBox_Preis.selecteditempos()
[...]
If  LBox_AstraPreis_Ki = 0 Then
	LBoxWert_AstraPreis_Ki = 35
Else
 LBoxWert_AstraPreis_Ki = 30
Endif
Das muss nicht wirklich sein.

Das kommende baut auf Verbesserung Teil 1 auf, und ohne dies würde es nicht richtig funktionieren

Mit selecteditempos wird nur die Position ermittelt, also beispielsweise die 2 für die 3. Zeile (Null-Basierte Zählung).

Jedoch mit selecteditem wird der gewählte Eintrag (Text) übernommen.

Und das ganze machen wir uns jetzt zu Nutze. Und zwar kurz und schmerzlos.

Code: Alles auswählen

    LBoxWert_AstraPreis_Ki = VAL(oListBox_Preis.selecteditem)
Da selecteditem einen Text zurückgibt, muss dieser "Text" in einen Wert umgewandelt werden. Und das geschieht mittels VAL.
Mehr brauchts nicht. Also nix mit irgendeiner Schleife drunherum. Anstatt 5, jetzt nur noch 1 Zeile.
Hier ein weiterer Link zu Dannenhöfer. 4.3.9 Welches sind die Besonderheiten von Listboxen?


Thema: Zur kentniss genommen:
Modul „Flaschenverkauf“:
[...]
Das ist übrigens ein Modul, durch das ich selbst noch nicht recht durchsteige. Ich schätze mal, da geht noch ganz gut was zu verbessern.
Wenn du all die MsgBoxen ausgelagert hast, wie ja schon von mir schon erklärt, dann lässt sich das doch schon bestimmt besser lesen. Ni war? ;)

Modul „Flaschenverkauf“:
Hier ist jetzt doch noch eine Formel drin – ich habe es nicht hinbekommen, die zu ersetzen. Das ist allerdings auch nicht notwendig, das wird nicht so oft benutzt.
Ach Du meinst z.B. das hier!

Code: Alles auswählen

"=IF(K" & iEnd_Row & "=0;"""";IF(K" & iEnd_Row & "=50;""Mitarbeiter"";IF(AND(K" & iEnd_Row & ">50;K" & iEnd_Row & "<100);""Sachentnahme"";IF(K" & iEnd_Row & "=100;""Kostenfreie Abgabe"";""Sonstige""))))"
Nun, da hätte ich wohl eine alternative, aber nicht mehr heute.


Thema: Das letzte für heute
Kann man eigentlich, wenn man "sgRabatt_Art = oRabatt_Artikel.Value()" in Klammern setzt, auch damit rechnen? Fällt mir grad spontan ein - hab's nicht ausprobiert.
Das solltest Du noch mal genauer erklären.

Und dann habe ich noch versucht, das hier umzuschreiben:

Code: Alles auswählen

   oAktuellesBlatt = thiscomponent.getcurrentcontroller.activesheet
   oCellCursor = oAktuellesBlatt.createCursor()
   oCellCursor.GotoEndOfUsedArea(True)
Mit meiner Kreation

Code: Alles auswählen

   oAktuellesBlatt = thiscomponent.getcurrentcontroller.activesheet.createCursor().GotoEndOfUsedArea(True)
war ich aber nicht erfolgreich.
Ganz Kurz: Nicht alles kann man als Einzeiler schreiben.


Und nun hoffe ich das die letzten Aktuellen "Weh-Wehchen" erstmal abgehakt sind. Wenn Du auch dieses erledigt hast, dann hänge die aktuellste Version - {inklusive der gestrigen Aktionen} - hier beim nächten mal an. Und dann schaun ma mal wie es weiter geht, falls Du dann nicht noch aktuellere Probleme hast.



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von Julia NuN » Mo, 09.01.2017 01:01

Wow! Cool! :D
Daaankee!

Das mit dem Auslagern hat's mir besonders angetan.
Ich hab so'n Gefühl, dass man da noch viel mehr auslagern kann.
Aber ich werde mich beherrschen und auf deine Eingaben warten, sonst kommen wir hier noch völlig durcheinander.

Jetzt kann ich mir auch Zeit lassen, die Alpha-Version läuft ja schon. :)

Mit der Verschnaufpause hast du Recht - bei mir ist so einiges anderes liegen geblieben.
Da muss ich morgen auch ran, sonst fliegt mir das um die Ohren... :roll:

CU und Guts Nächte
Julia

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » So, 08.01.2017 23:07

So, und nun zum letzten Beitrag für heute.

Auch wenn es dir jetzt vielleicht ein wenig unsinnig, verwirrend oder blöde vorkommt, so verfolge ich doch durchaus ganz bestimmte Ziele mit dem was jetzt kommt.

Ein Ziel ist es, dir so nebenbei Step-by-Step einiges beizubringen was Du noch öfters anwenden kannst. Mir geht es hier dabei auch nicht darum das ich dir jetzt schon Fix und Fertig zeige wie die Dialoge und der dazugehörige Makro-Code komplett überarbeitet aussehen könnten, denn dann könnten wir das Projekt innerhalb weniger Tage abschließen, sondern vielmehr darum zu zeigen wie man aus dem schon vorhandenen etwas ausbauen und verändern kann. Und deshalb sage ich jetzt auch nichts zu den anderen Zielen die ich verfolge. ;-)


Wir nehmen uns jetzt etwas vor, was auf den ersten Blick als "nicht so wichtig" eingestuft werden kann, aber ein gewisser Grundstein für was anderes dient was noch kommen wird, und ferner als ein Lernziel dient.

Als erstes legst Du ein neues Basic Modul an, mit dem Namen:

Text_Mitteilungen

In diesem Modul benennst Du die

Code: Alles auswählen

Sub Main
In das hier um.

Code: Alles auswählen

Sub PoaFaw
Nicht wegen den Namen wundern, Erklärung folgt gleich noch.
Doch nun ein wechsel zum:

Modul: Flaschenverkauf

Du arbeitest ja generell mit der MsgBox, wenn die Datei auf etwas reagieren soll. Das kenne ich selber, und das habe ich früher auch mal so gemacht. Habe das aber mittlerweile aufgegeben und ein anderes System dafür genommen. Doch so weit wollen wir jetzt bei dir noch nicht gehen, aber dennoch uns der MsgBox annehmen.

In diesem besagten Modul hast Du mehrere MessageBoxen.
Fangen wir mit der 1. an, und zwar diese.

Code: Alles auswählen

' Prüfen, ob alle Felder ausgefüllt wurden	    
    If iArtikelnummer_Fl = 0 Or iAnzahl_Fl = 0 Or sgFuellmenge_Fl = 0 Or sgPreis_Fl = 0 Then
	antwort = MsgBox("Du hast nicht alle Felder ausgefüllt.",0," ;-)")
	If antwort = 1 Then exit sub
	Endif
Der Sub Name PoaFaw in dem vorhin angelegten neuen Modul beruht auf die Anfangsbuchstaben in deinem Kommentar, aber ohne Satzzeichen.

PoaFaw = Prüfen ob alle Felder ausgefüllt wurden

Er hat so gesehen momentan einen Wiedererkennungswert wegen Orientierungsmöglichkeit.

Benenne jetzt antwort in iPoaFaw_Antwort um.
Der geänderte Code-Ausschnitt müsste jetzt wie folgt aussehen.

Code: Alles auswählen

' Prüfen, ob alle Felder ausgefüllt wurden'
    If iArtikelnummer_Fl = 0 Or iAnzahl_Fl = 0 Or sgFuellmenge_Fl = 0 Or sgPreis_Fl = 0 Then
    iPoaFaw_Antwort = MsgBox("Du hast nicht alle Felder ausgefüllt.",0," ;-)")
    If iPoaFaw_Antwort = 1 Then exit sub
    Endif
Und aus diesem Ausschnitt kopierst Du folgende Zeile in die Zwischenablage.

Code: Alles auswählen

    iPoaFaw_Antwort = MsgBox("Du hast nicht alle Felder ausgefüllt.",0," ;-)")
 
Und diese Zeile fügst Du nun, - na wohin wohl? - ....... in das Modul Text_Mitteilungen in die

Code: Alles auswählen

Sub PoaFaw
ein.
Dadurch müsste jetzt die dortige Sub wie folgt aussehen.

Code: Alles auswählen

Sub PoaFaw
    iPoaFaw_Antwort = MsgBox("Du hast nicht alle Felder ausgefüllt.",0," ;-)")
end Sub
Okay, noch mal zurück in das Modul Flaschenverkauf.
Dort wird die eben kopierte Zeile wie folgt geändert.

Code: Alles auswählen

' Prüfen, ob alle Felder ausgefüllt wurden'
    If iArtikelnummer_Fl = 0 Or iAnzahl_Fl = 0 Or sgFuellmenge_Fl = 0 Or sgPreis_Fl = 0 Then
        PoaFaw
    If iPoaFaw_Antwort = 1 Then exit sub
    Endif
Wie Du jetzt siehst, hat sich die Anzahl der Zeilen nicht geändert, aber eine Zeile sieht jetzt doch ganz anders aus. Vorher stand da ein etwas längerer "Text", und jetzt nur noch ein "Wort".

Nun, dir ist sicherlich aufgefallen, das das einzelne "Wort" der Name der einen Sub entspricht. Und das soll auch so sein, und das ist auch richtig so.
Denn wenn der Sub-Name so alleine in einer Zeile steht, wird dadurch diese Sub automatisch vom Programm aufgerufen und ausgeführt.

Prinzipiell könntest du jetzt einwänden:

"Wegen einer einzigen Code-Zeile so einen Aufwand?"

Theoretisch hättest Du ja auch recht. Aber das ist ja jetzt nur eine MsgBox mit nur einer Zeile, während ja noch mehrere MsgBoxen mit mehreren Code-Zeilen folgen. Und außerdem ist das jetzt das erste Lernziel:

Wie ruft man auf einfache Art eine andere Sub auf?

Aber damit diese Änderungen und Ergänzungen auch funktionieren, muss noch eine Kleinigkeit gemacht werden. Und dazu gehts ab ins Modul Artikel.
Dort ergänzt Du jetzt die Variablen deklarationen, und zwar um folgendes.

Code: Alles auswählen

' Temporäres'
Dim iPoaFaw_Antwort as Integer
Jetzt speicherst du die geänderte Datei ausm Basic-Editor heraus, nicht aus Calc heraus. Schließt sie, und öffnest sie erneut. Und nur zur Sicherheit kontrollierst Du ob auch die Änderungen gespeichert wurden. Ich empfehle diese Vorgehensweise, weil dadurch sichergestellt werden kann das nicht irgendwelche Variablen sich noch im Arbeitsspeicher befinden, die das Makro durcheinander bringen können.

Danach startest Du den Dialog wie gehabt, gehst auf "Verkauf ganzer Flaschen" und dort klickst Du auf "Übernehmen", ohne irgendein Feld auszufüllen. Daraufhin müsste die dir wohl bekannte MsgBox mitsamt ihrem Text erscheinen.

Und das ist der Beweis das durch den Aufruf des Sub-Namen die dementsprechende Sub nicht nur aufgerufen, sondern auch ausgeführt wird. Es wird jetzt so gesehen wohl nur eine einzige ausgelagerte Zeile abgearbeitet, aber das ist der erste kleine Schritt in Richtung Umfangreichere Sub aufrufe, was sehr viel später noch kommen wird.

In den Dialogen rufst Du ja auch per "Knopfdruck" die eine oder andere Sub auf. Das ist hier im wesentlichen nix anderes, blos das der Auslöser für den Sub-Aufruf etwas anders ist, im Dialog per Knopf, hier per Code.


Und jetzt drückst Du den *großen-imaginären-geistigen-Pause-Button*, und gönnst dir erstmal eine solche.


Wenn Du dich wieder erholt hast, dann gehst Du daher und lagerst ALLE MsgBoxen wie eben gezeigt in das Modul Text_Mitteilungen aus. Achte aber darauf das jede MsgBox ihr eigene Sub bekommt. Und überprüfe auch ob jede MsgBox nach der Auslagerung noch genau so funktioniert wie von dir gedacht und geplant ist.

So! Das wars für heute.
Viel spaß beim "Abarbeiten" :lol:



Gruß
balu

Re: Erarbeitung eines "POS-Kassenbuchs"

von balu » So, 08.01.2017 22:44

So, jetzt hatte ich mir etwas Zeit gönnen können.
Dann hat er [...] aber in der Tabelle einen auf eine ganze Zahl gerundeten Wert eingetragen --> aus "56,5217399597168" wurde "56". Das hab ich nicht verstanden und wieder herausgenommen
Tja, da gibt es einige Regeln zu beachten, wenn man per Makro ausgerechnete Werte in ein Tabellenblatt eintragen will.

1.
Im Makro schon eine Art "Vor-Formatierung" vornehmen

2.
Eintragen

3.
Formatieren

Hört sich einfacher an als es in wirklichkeit ist.
Punkt 1 braucht man nicht immer, aber durchaus öfters.
Handelt es sich um eine Ganzzahl, also ohne Nachkommastellen, dann braucht man da eigentlich nicht viel machen. Mal ein theoretische Grundlagenbeispiel.

Code: Alles auswählen

oBlattStamm.getCellRangeByName("B99").value = sgEP_Korr.value
Und fertig.
Komme gleich nochmal darauf zurück.

Punkt 2 habe ich ja schon grad eben mit dem Grundbeispiel gezeigt.

Punkt 3 kann durchaus seeehr kompliztierter werden.
Will man eine Ganzzahl eintragen, so braucht man eigentlich nix mehr weiter zu machen. Man muss lediglich drauf achten das man sich bei der Zuordnung nicht vertut, also nicht die Zelle als String vorbereiten und dann einen echten Wert eintragen, denn das ergibt dann nämlich einen String. Gemeint ist folgendes Verbot.

Code: Alles auswählen

oBlattStamm.getCellRangeByName("B99").string = sgEP_Korr.value
Anders sieht es aber aus, wenn man Beispielsweise die aktuelle Uhrzeit eintragen will. Denn dann muss vom Makro nach dem eintragen in die Zelle gleich noch eine weitere Aktion durchgeführt werden. Und diese Aktion heißt:

Die Tabellenzelle mit dem richtigen Zahlenformat formatieren.

Und das ist vom Prinzip her nix anderes, als wenn Du von Hand die Zelle z.B. auf Format Uhrzeit: "HH:MM" formatierst. Im Makro ist das aber etwas komplizierter, da man das Format anders einstellt. Hier ein Beispiel.

Code: Alles auswählen

Sub Main
oBlattNo1 = ThisComponent.Sheets.GetByName("Tabelle1")
oBlattNo1.getCellRangeByName("A1:D1").clearContents(255)
oBlattNo1.getCellRangeByName("A1").FormulaLocal =  NOW

oBlattNo1.getCellRangeByName("B1").FormulaLocal =  TimeValue(NOW)

oBlattNo1.getCellRangeByName("C1").FormulaLocal =  NOW
oBlattNo1.getCellRangeByName("C1").Numberformat = 40

oBlattNo1.getCellRangeByName("D1").FormulaLocal =  TimeValue(NOW)
oBlattNo1.getCellRangeByName("D1").Numberformat = 40
End Sub
Nimm eine neue und leere Datei, und starte dies Makro.

Und so ganz nebenbei kommt jetzt auch der Punkt 1 zum tragen. Denn es findet eine "Vor-Formatierung" statt, und zwar durch TimeValue. Und die Zellformatierung wird durch Numberformat = 40 vorgenommen.

Nimm dir ruhig einen Moment Zeit dafür, und schau nicht nur was in der Zelle angezeigt wird, sondern auch oben in der Eingabezeile.



Zelle A1 ist fast identisch zur Eingabezeile.
Zelle B1 ist identisch zur Eingabezeile.
Zelle C1 & D1 sind nicht mehr identisch zur Eingabezeile.

Mit den Zellen C1 & D1 würde ich jetzt so nicht weiterrechnen wollen, wenn man sich nur auf das Aussehen der Zelle beschränkt. Denn es wird etwas anderes angezeigt, als das was wirklich in der Zelle steht. Und das kann sehr schnell zu bösen Problemen führen. Also muss eine andere Lösung daher. Und die kommt jetzt.

Code: Alles auswählen

Sub Mimi
CompatibilityMode(True)
oBlattNo1 = ThisComponent.Sheets.GetByName("Tabelle1")
oBlattNo1.getCellRangeByName("C4:D4").clearContents(255)
oBlattNo1.getCellRangeByName("C4").FormulaLocal =  FormatDateTime(TimeValue(NOW), 4)

oBlattNo1.getCellRangeByName("D4").FormulaLocal =  FormatDateTime(TimeValue(NOW), 4)
oBlattNo1.getCellRangeByName("D4").Numberformat = 40
CompatibilityMode(FALSE)
End Sub
Führe dieses Makro ruhig in der gleichen Datei aus. Ich habe dafür extra andere Zellen genommen damit Du dir die Unterschiede zum ersten Code in Ruhe anschauen und vergleichen kannst.

Es sind jetzt wohl "nur" 2 Dinge dazu gekommen, aber die haben es in sich.
Als erstes wird ein "Kompatibilitäts Modus" aktiviert -{CompatibilityMode}- - (und später wieder deaktiviert), und zweitens können wir dadurch, und zwar nur dadurch, auf eine zusätzliche Funktion drauf zugreifen. Und diese Funktion lautet: FormatDateTime.

Jetzt schlägt die "Vor-Formatierung" aber auch so richtig zu. Denn durch die 4 in FormatDateTime wird gesagt, stelle auf "Stunden und Minuten(hh:mm, Stunden im 24-Stunden-Format)" ein. Nachzulesen in "Andrew Pitonyak", das Buch findest Du hier: http://www.uni-due.de/~abi070/ooo.html
Das ist wirklich eine sehr wichtige Lektüre.

Es gibt aber auch noch eine sehr gute und emfehlenswerte Seite, und das ist Dannenhöfer. Bei dem ist auch dieses Thema vom grundsätzlichen eigentlich schon ganz gut beschrieben. Schau dir mal folgende Links an.
7.1.22 Wie kann man das Zahlenformat auf Standardformate einstellen?
7.1.26 Wie kann man das Zellenformat einstellen?

Besonders der Punkt (7.1.26) ist dir dabei behiflich ein "Zellenformat-Kode" auszulesen, da dort ein kleines aber effektives Hilfsmakro vorhanden ist. Dazu musst Du erstmal eine Zelle selber von Hand Formatieren, also über ->rechtsklick ->Zellen formatieren ..., na den Weg kennst Du ja wohl ;-). Anschließend führst Du das Hilfsmakro von dort aus, und schon bekommst Du die Formatnummer die Du dann weiter verwenden kannst.

Klar hätte ich sofort auf die beiden genannten (Pitonyak, Dannenhöfer) verweisen können, aber so hast Du schon mal etwas womit Du das von mir gesagte ausprobieren kannst, und außerdem gleichzeitig einen sehr schweren Broken von den Füßen. Ich habe jetzt hier wohl nur von der Uhrzeit gesprochen, aber beim Thema Datum verhält es sich nicht wesentlich anders, bis auf folgende kleinigkeiten.

Code: Alles auswählen

FormatDateTime(DateValue(NOW), 2)
Und Numberformat kann entfallen, wenn das Datum beispielsweise so aussehen soll 06.01.17. Damit müsstest Du jetzt eigentlich gut gerüstet sein um Zellen selber per Makro zu formatieren.


Anderes Thema.

Ich glaube das ich jetzt verstanden habe wie Du die SVERWEIS im Makro ersetzt hast. Einfach dadurch das Du durch die Zeilen suchst, und bei einem Treffer dann dementsprechend reagierst. Das ganze mit einer einfachen For...Next.

Ist wohl soweit in Ordnung. Jedoch in deiner jetzigen Testdatei mit mal grad eben 11 Testzeilen spürst Du noch nicht was passiert wenn wirklich 500 Zeilen durchsucht werden müssen. Denn dann macht die Uhr *tick-tack-tick-tack-tick-tack-tick-tack-*

Ich hatte mich schon mal so zwischendurch mit diesem Thema selber befasst, da ich in dieser Art noch keine richtige Erfahrung gesammelt habe, und ich habe da auch eine Lösung für mich gefunden. Ich sage nur eins: Array. Und das ist eine ganz andere Hausnummer. Aber heute gehe ich nicht weiter darauf ein, das kommt später.


Ich sehe Du hast hier im Forum etwas gefunden, was sehr nützlich ist.

Code: Alles auswählen

	aSourceDataArray() = oZellenMitarbeiter.getDataArray() 
	Dim aSource(UBound(aSourceDataArray())) as String  
	For j = LBound(aSource()) To UBound(aSource())
   	aDataArrayRow() = aSourceDataArray(j)
	aSource(j) = aDataArrayRow(0)
Find ich echt klasse wie Du doch so aktiv bist. :mrgreen:
Jedoch
Aber ich hab mir scheinbar durch die Anwendung von .SelectedItemPos selbst ein Bein gestellt.
wird das auch erst später besprochen.

Keine Bange - ich glaub', du wirst dich über einen Mangel an Arbeit nicht beklagen können. :D
Oh jeh! Wie recht Du hast. Da gibts noch so einiges an Arbeit ;-)

Aber, nach einem "Smal-Talk" und einem ausgewachsenen Beitrag von mir, mach ich hier jetzt schluß, und stelle gleich meinen teilweise vorbereiteten Beitrag hier rein. Das wäre dann der dritte in Folge. Dadurch habe ich dann wieder etwas Zeit mich deiner jetzigen unbehandelten Probleme zu befassen, während Du meine Beiträge Abarbeitest.
Och-Mennoooo! Ich brauch doch mal wieder einen kleinen Vorsprung :-)


Gruß
balu

Nach oben