Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

.onclick Event von Popup direkt in Funktion verarbeiten

Begonnen von maddhin, August 10, 2020, 06:21:07

⏪ vorheriges - nächstes ⏩

ebs17

#15
Ich stimme Phil vollständig zu.

Globale Variable heißt, ich lege einen Inhalt irgendwo ab, und irgendwo anders hole ich diesen Inhalt wieder ab. Auf dem Weg und in der Zeit kann allerhand passieren.

Objektorientierung heißt aber: Wenn ich mit dem Objekt arbeiten möchte, bekommt es unmittelbar einen solchen benötigten Inhalt als Parameter, Property (eine Schnittstelle des Objektes) usw. zugewiesen, also geliefert. Wenn sich ein Objekt einen Wert von irgendwo abholen soll, hat das mit Objektorientierung nichts zu tun.
Mit freundlichem Glück Auf!

Eberhard

ebs17

ZitatAccess ist m. E. eine "Spielwiese", auf der es auch erlaubt ist, Verfahren und Techniken anzuwenden, die in "echten" SQL-Datenbanken und Entwicklungs-Umgebungen nicht möglich oder erlaubt sind.
Das lese ich auch nicht zum ersten Mal.

Ich lasse mal anfängergemäßes Unwissen bei vielen Dingen unberücksichtigt. Der Satz oben lässt zumindest Methode und bewusstes Agieren vermuten: Weil in Access "Mist" möglich ist, wird das auch ausgiebig genutzt. Das neben Unwissenden auch von sogenannten Profis, die nach eigener Selbstdarstellung seit Jahrzehnten "erfolgreich" in Datenbanken & Co. agieren - es ist ja (nur) Access. Weitere Profis sehen solche Access-"Werke" und werten für sich ein: In Access kann man nur Mist machen. Die Neulinge sehen auch solche Werke und schreiben ab und vervielfältigen den Mist.

Wenn der Praktikant und der Werksstudent oder der sogenannte Profi seine Zeit abgetan hat, kommt der nächste Bearbeiter des Werkes, recht oft auch mit bestem Willen und besten Vorsätzen. Umstände und Zeit lassen aber nur ein Weiterwerkeln an dem vorhandenen zu, nicht eine wirkliche Besserstellung.

Jetzt frage man sich, woher der teilweise schlechte Ruf von Access zustande kommt.

Ich würde mal behaupten: Wenn Sebastian Vettel vom F1-Ferrari in einen Fiat Uno umsteigt, mutiert er nicht plötzlich zum Hut-Fahrer, sondern er bleibt Profi.

Man könnte auch sagen: Die Spielwiese wäre besser beschränkt auf wirkliche private Spielereien - was allemal besser ist als Ballerspiele.

Sofern man aber Anwendungen hat, die man auch als Entwickler weitergibt oder die gar dazu helfen sollen, dass eine Firma Geld verdient, sollte man nicht und vor allem nicht bewusst in die unterste Schublade greifen.
Mit freundlichem Glück Auf!

Eberhard

maddhin

#17
Um die Götter nicht zu erzürnen, habe ich mich diplomatisch für den 3. Weg entschieden... :)

...und im Modul ganz oben "dim frm2 as form" definiert (also Variable die über alle Funktionen/Subs im Module verfügbar ist) und mit "set frm2 = frm" in der Funktion festgelegt.

Option Compare Database
Option Explicit

Dim frm2 As Form

D.h. ich starte das ganze mit einem Buttonklick-Event via
Private Sub cmdGetInfo_Click()
Call Import(Me)
   
End Sub

die Funktion sieht (verkürzt & ohne webscraping) dann so aus:

Function Import(frm As Form)

Dim StrCorpName As String

'put frm in variable available in whole module
Set frm2 = frm

 'hier kann / soll / muss die Hauptfunktion wie z.B. das Herunterladen von Daten aus dem Internet oder Berechnungen, etc. eingefügt werden, die Variablen entsprechend füllt
  StrCorpName = irgendein-neuer-Wert-von-irgendwo
       
'--------------------------------------------------------------------------------------------------------------
'run the Import popup
'--------------------------------------------------------------------------------------------------------------

Dim oForm As Form

Set oForm = Form_fsubImport

    oForm.InsideHeight = 5000
    oForm.InsideWidth = 10000
    'make the form appear
    oForm.Visible = True

    'put CorpName into textbox on the popup
oForm.txtCorpName = StrCorpName
   
End Function

Auf dem Popup (fsubImport) mit Textboxen und OK/Cancel-Button kann man dann die Daten bearbeiten und via einer weiteren Funktion dann schreiben. Das wird durch Button-Klick auf den OK-Button ausgelöst, der Cancel-Button schließt das Popup ohne irgendwelche Änderungen vorzunehmen:

Option Compare Database
Option Explicit

Private Sub cmdCancel_Click()
    DoCmd.Close
End Sub

Private Sub cmdOK_Click()
    Call ParseImport(txtCorpName)
    DoCmd.Close
End Sub

Last but not least die Funktion (ParseImport, im gleichen Modul), die dann die Daten wieder an das richtige Formular übergibt (und dann in die richtige Tabelle schreibt):

Function ParseImport(txtCorpName As String)
    '---------------
    'Parsing
    frm2.Corp_Name = txtCorpName

End Function

Ob das jetzt - streng genommen - methodisch Mist ist, weiß ich nicht. In diesem Fall erscheint mir das als akzeptable, relativ unproblematische und unkomplizierte Lösung. Wenn frm bereits vorhanden ist, erscheint es das Effizienteste das einfach weiter zu benutzen :)

Bevor ich jetzt noch anfange über Seb, Seb spins und Ferrari zu plaudern:

Lieben Dank für all die sehr guten Antworten und v.a. auch Tipps, die ich sehr schätze! Das Parsing ohne IE werde ich mir auf jeden Fall genauer ansehen und generell nehme ich durch die Diskussionen hier viel mit. DANKE!

ebs17

Als einfache Überlegung:
Function Import(frm As Form)
   Dim StrCorpName As String
   ' ...
   StrCorpName = irgendein-neuer-Wert-von-irgendwo
   ' ...
Warum wird der "irgendein-neuer-Wert-von-irgendwo"-Wert nicht unmittelbar als Argument an die Funktion übergeben?
Diesen sollte man doch schon mit Aufruf der Funktion kennen und haben, also einige wenige Bruchteile einer Sekunde vorher auch schon.
Mit freundlichem Glück Auf!

Eberhard

maddhin

#19
Zitat von: ebs17 am August 11, 2020, 08:22:52Warum wird der "irgendein-neuer-Wert-von-irgendwo"-Wert nicht unmittelbar als Argument an die Funktion übergeben?
Diesen sollte man doch schon mit Aufruf der Funktion kennen und haben, also einige wenige Bruchteile einer Sekunde vorher auch schon.
Nein, StrCorpName und 7-8 weitere Variablen werden in der Import-Funktion über Webscraping gefüllt. Das ist ja die Hauptfunktion der Import-Funktion. Diesen Teil habe ich der Übersichtlichkeit halber weggelassen. Hier kann / soll ja jeder selbst seine gewünschte Funktion einbauen.

Ich könnte den variablen Teil der URL, den ich in me.CorpName temporär eingebe, übergeben. Aber das hole ich mit frm.CorpName direkt, da ich ohnehin prüfen muss, ob CorpName valide für die URL-Verarbeitung ist.

EDIT: ich habe das mit der Hauptfunktion oben im Thread mal als Kommentar hinzugefügt.

maddhin

Vielleicht noch kurz zum Verständnis was das alles soll:

Es gibt ja Webseiten, wie wlw.de, wo sich Hersteller präsentieren. Wenn ich auf einer solchen Webseite einen interessanten Hersteller gefunden habe und als neue Firma anlegen möchte, füge ich (anstatt alles einzeln copy & paste zu machen) einfach den variablen Teil der URL als Firmennamen in das Formular und drücke einen Button. Dieser Button löst dann die Import-Funktion aus, holt die Firmen-Daten von der Webseite und zeigt das Popup zum Überprüfen an.

PhilS

Zitat von: crystal am August 10, 2020, 17:42:45Denn es wird und muss schnell klar werden, dass solche globalen Variablen sinnvoll gekapselt werden müssen und nicht "einfach so" existieren sollten/dürften.
Es ist nicht möglich globale Variablen so zu kapseln, dass du einen unkontrollierten Zugriff darauf unterbindest. - Genau das ist der Kern meiner Kritik.

Zitat von: crystal am August 10, 2020, 17:42:45Deinen ersten Einwand kann ich auch nicht ganz teilen. Natürlich sind globale Variable per se nur schwierig zu überwachen und zu kontrollieren. Ich muss stets genau wissen, was ich tue (siehe mein einfaches Schema). Aber genau das sollte man als Entwickler ja immer wissen. Statt z. B. mühsam über verschachtelte Referenzen auf irgendwelche Formular-Bestandteile (z.B. mit .parent.form.parent) zuzugreifen, geht es unter Verwendung globaler Variablen oft etwas einfacher.

Eine globale Variable wird vor dem Öffnen eines Form gesetzt. Sie wird dann im Load-Event des geöffneten Forms ausgelesen und steuert dort das Verhalten des Codes.
Klingt harmlos, oder?

Ich habe Stunden mit der Fehlersuche verbracht, weil manchmal der Form-Load-Code nicht das tat was er sollte. Der Wert globalen Variable war geändert. - ?!

Ursache: Im Form_Current eines Unterformulars des o.g. Forms wurde unter bestimmten Umständen, gut versteckt in mehrfach verschachtelten Prozeduraufrufen, an dieser globalen Variable herumgefummelt.

Kein fiktives Beispiel, sondern real und nur ca. 10 Tage alt in eine Fremdprojekt, das ich temporär betreue.

Du könntest natürlich argumentieren, dass der Entwickler nicht wusste, was er tut. Das mag richtig sein. - Mein Kritikpunkt ist, dass es nahezu unmöglich ist zu überblicken, was man mit globalen Variablen tut.

Nebenbei, die von dir als Gegenbeispiel angeführten Referenz-Endlosketten aus Forms!form.UfoCtl1.Form!UfoCtl2.Form!UfoCtl.Form.Irgendwas sind keineswegs ein Gegenbeispiel. Sie haben im Kern genau dasselbe Problem.


Zitat von: crystal am August 10, 2020, 17:42:45Es gibt in Access nicht DEN richtigen oder falschen Weg. Access ist m. E. eine "Spielwiese", auf der es auch erlaubt ist, Verfahren und Techniken anzuwenden, die in "echten" SQL-Datenbanken und Entwicklungs-Umgebungen nicht möglich oder erlaubt sind.

Hier schließe ich mich @ebs17's Kritik voll und ganz an. Access/VBA hat einen miserablen Ruf, weil ein großer Teil der Access/VBA-Entwickler nur schauen, dass es halt irgendwie funktioniert, jetzt in diesem Moment. Darüber hinaus wird nicht nachgedacht und es besteht auch wenig Interesse sich damit auseinanderzusetzen.

Ein wesentliches Problem dabei ist aber nicht, dass diese Verfahren und Techniken in Access möglich sind, sondern dass es oft schwierig und teilweise unmöglich ist, ohne sie zu arbeiten.




Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

crystal

Liebe Leser*innen,

Danke für die rege Beteiligung an meinen Kommentaren, für die heftige Kritik und Sorry für diese nun folgenden Antworten und Erklärungen, wie üblich etwas länger...

Um es nochmal klarzustellen: natürlich haben globale Variable nichts mit objekt-orientierter Programmierung zu tun. Ich sagte ja auch nur, dass die Verwendung von g. V. letztlich zu Überlegungen führt oder führen kann, die stark in Richtung Objekt-Orientierung gehen, spätestens dann, wenn man g. V. "irgendwie" in einem dedizierten Kontext halten möchte, also "nur" als kontext-gemeine, kontext-spezifische Variable. Auch wird man sich überlegen, nur gewissen Funktionen Zugriff auf g. V. erteilen zu wollen. All diese zusätzlichen Wünsche und Bedingungen könnte man auch in prozeduralen Sprachen schaffen, erste OO-Ansätze (als inline-Erweiterungen bzw. Precompiler-Derektiven in C) haben das sehr ähnlich gemacht.

Übrigens kennt sicher jeder Access-Programmieren die Vorteile, Variable zumindest in einem Formular zu "globalisieren", um die Deklaration nicht in jeder Formular-Funktion oder -Sub wiederholen zu müssen. Dann sind diese Variablen nicht mehr komplett global, sondern nur noch Formular-global. Geht natürlich auch anders, indem man in jeder Funktion/jeder Sub vor die Referenz auf ein Formularfeld jeweils ein "me." oder "Me!" oder "Me.parent" oder oder davor schreibt. Alle Feld-Werte bzw. -Inhalte eines Formulars sind also "Formular-global", ja sogar Members der Formular-Klasse (oder der Sub-Formular-Klasse). Nur muss man eben (eigentlich) immer ein "Me" etc. davor setzen (obwohl es oft auch ohne geht, zumindest wenn man keine Subforms o.ä. hat).

Ob ich nun in irgendeiner Funktion des Formulars (genauer: einer Funktion, die innerhalb des Formular-Codes geschrieben wurde, auch ohne ein Event zu sein) einen Wert aus
"me.txtCustomer" oder
"g_sCustomer" (im Form_load oder current "formular-globalisiert" mit "g_sCustomer = me.txtCustomer" zugewiesen)
lese, ist nicht wirklich unterschiedlich, es sei denn, ich habe irgendeine Funktion, die z. B.
g_s_Customer = "irgendwas"
macht.
Das wäre aber identisch problematisch, wenn diese Funktion
me.txtCustomer = "irgendwas"
machen würde.
In beiden Fällen muss ich da aufpassen.
EIN Vorteil solcher "formular-globalisierten" Variablen könnte aber sein, das ich im Form-Close-Event ja noch beide Werte habe und vergleichen/reagieren kann. Geht natürlich auch anders mit Recordset-Clone oder .Oldvalue (was nicht immer klappt). Ist eben situations-abhängig. Und ich EMPFEHLE nicht grundsätzlich die Verwendung globaler Variablen. Es gibt halt Situationen, in denen sie Sinn machen, besonders wenn ich Funktionen selbst globalisiere und sie somit aus dem Formular-Kontext (der Formular-Klasse) entferne. (Ich spreche hier immer von "Funktionen" und meine damit sowohl "Function" als auch "Sub".)

Ich halte es für durchaus legitim, z. B. gewisse Daten eines komplexen Formulars mit mehreren Dutzend Feldern und/oder mehreren Tabs oder Seiten oder mehreren Subforms in "globale Variable" zu spiegeln, wenn es im betreffenden Formular (und SubFormular) auch noch viele Funktionen gibt, die solche "Basis-Variablen" benötigen (interessant auch bei so einfachen Werten wie der Id des Haupt-Records, wenn man Sub-Records in Sub-Forms ansprechen oder anlegen möchte).

Zugegeben benutze ich persönlich solche globalen Variablen immer nur "read-only", habe also implizit nie eine "Put-" oder "Set-"Methode bzw. eine Funktion, die sowas machen würde. Und sollte dies in Ausnahmefällen doch Mal nötig sein, bemühe ich eine zusätzliche globale Variable "Xyz_changed", "Me.Dirty = True"  oder ähnliches.

Etwas anderes möchte ich auch noch einmal wiederholen. Access ist sehr oft eine "Spielwiese", die häufig von Menschen benutzt wird, die von Datenbank-Theorie, Normalisierung, SQL usw. noch nie etwas gehört haben und oft aus der "Excel-Ecke" kommen oder "das schlaue Buch des vorigen Stellen-Inhabers 'datenbankmäßig' umsetzen wollen".

Interessanterweise kenne ich tatsächliche keine kommerzielle Access-Anwendung, die irgendeine Marktrelevanz oder -Präsenz erreicht hätte, einmal abgesehen von Tool-Sammlungen für Access-Entwickler.

Access ist berühmt fürs Rapid-Prototyping und schnelle, kleine Anwendungen in eng umschränkten Bereichen und ist mir als solches durchaus in kleinen Abteilungen oder Arbeitsgruppen (auch namhafter Großbetriebe wie Daimler-Benz, Porsche, BASF, Bayer, Nestlé, Coca-Cola, etc. pp.) immer wieder begegnet, wenn es etwa darum ging, umfangreiche Daten übergeordneter Systeme für den engen Arbeitsbereich anschaulicher und greifbarer für Kolleginnen und Kollegen darzustellen. Auch Excel wird in diesem Kontext sehr gern eingesetzt.

Solche Hilfs-Systeme waren und sind fast immer "Spielwiesen" engagierter Mitarbeiter, die sich oft private Stunden und Tage damit befasst haben, eine kleine feine Lösung für ihre Abteilung zu präsentieren. Es ist ja fast schon selbstverständlich, sich im Team über die Schön-Gestaltung von Word-Dokumenten und Powerpoint-Präsentationen hinaus auch mal in Excel oder ("hohe Schule") Access auszutoben. Das war und ist m. E. durchaus auch Strategie von Microsoft und dessen Office-Paket-Philosophie...

Natürlich gibt es auch sehr professionelle Access-Programmierer, die hervorragende Projekte bauen und auch pflegen können. Und einige von ihnen sind aktive Mitglieder dieses Forums.

Access ist m. E. auch "Spielwiese" bei Microsoft ("ja- wir brauchen noch irgendeine Datenbank für den einfachen End-Anwender, damit der Rezepte, Geburtstage und Adressen seiner Freunde und Bekannten verwalten kann und können möchte") und hat daher bei Microsoft eher selten einen professionellen Anstrich erhalten und kann professionellen Ansprüchen auch nicht genügen. Microsoft selbst hat es versäumt, Access als SQL-Frontend zu propagieren und setzt seit geraumer Zeit auf .Net und dessen Programmiersprachen mit Unterstützung für DB-Systeme jeglicher Herkunft. (übrigens gibt es da keine mit Access vergleichbaren Unterformulare mehr, sondern höchstens Datagrids.)

Access ist und bleibt für mich eine der vielen, schlecht umgesetzten und noch schlechter gepflegten Anwendungen aus dem Hause Microsoft. Das Objekt-Modell ist nie vollständig gewesen, s. auch die Frage "Zeilenhöhe in Comboboxen", erst kürzlich hier im Forum gestellt. Natürlich ist es möglich, die Zeilenhöhe der Comboboxen per Programm zu setzen - aber eben nicht per Property (wie zu erwarten wäre), sondern nur per direkter API-Programmierung, indem man die Paint-Funktion kompliziert abfängt und eigene Funktionalität implementiert (Hooking mit dem sogar individuelle Farben und Fonts je Zeile möglich werden) - mag aber durchaus sein, dass ich das irgendwo für VB gelesen habe und es in VBA nicht möglich ist. Hier z. B. hat Microsoft (wiedermal) versagt und schlicht vergessen, diese paar Properties Public zu definieren. Und zwangsweise führt das dazu, dass findige Kenner eben API-Funktionen direkt nutzen und in neue Klassen packen, als "EnhancedComboBox" vermarkten oder publik machen - und schon ist Access wieder zur "Spielwiese" geworden, diesmal mit Extensions, die sehr oft nur eine geringe Lebenszeit haben.

Ich könnte hier auch von meinen leidvollen Erfahrungen berichten, so einfache Dinge zu realisieren, wie Videos aus Access heraus abzuspielen - besser nicht. Einfacher ist es, Access dafür zu verlassen, auf Microsoft's "Mediaplayer ActiveX" zu verzichten (das ja auch schon seit vielen Jahren nicht mehr geflegt wird und jede Menge Bugs hat) und sich z. B. mühsam ein Explorer-Fenster zusammenzubasteln, in dem man Third-Party-Media-Player und HTML-5 benutzt (aber auch das ist wohl eine Sackgasse, denn wer weiß, wie lange das IE-ActiveX noch möglich sein wird, nachdem MS nun auf EDGE und die Google-Engine umgestiegen ist).

In Excel ist es recht einfach möglich, einen "Screenshot" zu erstellen und sogar als jpg oder png (statt nur als "gefühlt altbackenem" bmp wie in Access) zu speichern. So "simple" Methoden fehlen beim Access-Bild-Objekt. Auch hier hat MS mal wieder geschlampt und vergessen, so naheliegende Funktionen anzubieten, selbst das vielversprechende Screen-Objekt lässt entsprechende Methoden vermissen. Man muss es mühsam mit API-Aufrufen "zusammenbasteln" - und beim Wort "Basteln" sind wir dann auch wieder bei "Spielwiese".

Eines ist auch klar: Access ist eine schöne Anwendung für kleine, genau beschriebene Anforderungen UND eben auch in der Lage, all das "dann doch noch" und "mal eben schnell" zu realisieren oder "einzubasteln", was in der ursprünglichen Beschreibung und/oder Vorstellung eben nicht vorgesehen war. Selbst eine Migration zum "großen MS-SQL-Server" als Backend scheint möglich, wenn man "ein wenig Aufwand" investiert. Da kenne ich kein anderes Produkt, das auch nur ansatzweise so flexibel und einfach Änderungen/Erweiterungen zulassen und überhaupt ermöglichen würde. Genau diese Flexibilität ist die Existensberechtigung für Access. Und deshalb gefällt mir Access durchaus, schon seit Version 2.01... Aber irgendwie ist die im vorigen Satz genannte Flexibilität - leider oft nur durch "Erweiterungen" realisierbar - auch wie ein schleichendes Nervengift und man weiß nicht, ob es in der nächsten Access-Version noch funktionieren wird. Das wird dann (vielleicht) besonders schwierig, wenn man keine "boxed", sondern eine "Abo-"Version hat.

Und - wichtige, wenn nicht wichtigste Devise: ich möchte ja nur meine persönliche Sicht zur Diskussion stellen UND zum Denken anregen. Access ist - nicht zuletzt durch wohl einiges an "Spaghetti-Code" einiger (früherer?) Access-Entwickler bei MS - immer oder zumindest sehr oft geeignet, mehrere Lösungen für ein konkretes Problem zu bieten.

Gruß,
crystal
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!

Aus gesundheitlichen Gründen nur noch selten dabei...

ebs17

So viel "Lob" und Ansprüche einerseits und ein (immer noch) bewusstes Herumdoktoren andererseits - kriegt man das widerspruchsfrei zusammen?

Wenn ich andere und anderes einschätze und bewerte, gehe ich doch erst einmal bestmöglich aus dem Glashaus, um vor mir selber und vor anderen eine Glaubwürdigkeit aufzubauen.

Sowie: Man kann es zwar kritisieren, aber Microsoft hat neben dem Wunsch auf beste Produkte vor allem den Wunsch, erfolgreich zu verkaufen. Da gibt es Produkte, die leistungsfähiger (gerade für besondere Ansprüche) und aber auch teurer sind und auf die man da Schwerpunkte legt.
In dem Segment, in dem man Access sinnvoll einsetzt, ist es ziemlich einzigartig und konkurrenzfrei, trotz aller Mängel und  allem aufgestauten Verbesserungsbedarf. Man sollte vielleicht auch nicht dieses Segment verlassen.
Mit freundlichem Glück Auf!

Eberhard

Beaker s.a.

@crystal
ZitatInteressanterweise kenne ich tatsächliche keine kommerzielle Access-Anwendung, die irgendeine Marktrelevanz oder -Präsenz erreicht hätte
"Sage" kennst du?
Ich weiss zwar nicht wie weit das heute noch verbreitet ist, aber ich
selber arbeite damit jetzt seit gut 1 1/2 Jahren und kann nicht über
das Access-FE meckern.
gruss ekkehard
Alles, was geschieht, geschieht. - Alles, was während seines Geschehens etwas anderes geschehen lässt, lässt etwas anderes geschehen. - Alles, was sich selbst im Zuge seines Geschehens erneut geschehen lässt, geschieht erneut. - Allerdings tut es das nicht unbedingt in chronologischer Reihenfolge.
(Douglas Adams, Mostly Harmless)