Mehrmaliges Buttondrücken unterdrücken
-
Mauro77 schrieb:
1. Ganz einfach, wenn ich diese Komponenten nur unsichtbar stellen würde, dann
hätte ich dann 1000 Komponenten gleichzeitig im Speicher... Das muss nicht sein... Darum lösche ich diese...Das ist klar. Ich dachte, du bezögest dich auf das "dynamische Aufbauen":
das geschieht natürlich alles dynamisch, um Speicherplatz zu sparen
Darunter verstand ich, daß du alle Komponenten im Code erstellst und freigibst ("dynamisch"), anstelle einfach den Formdesigner zu benutzen, was ich nicht verstehen konnte. Aber wenn du nur das Freigeben an sich meinst - okay.
Mauro77 schrieb:
3. Es spricht wohl nichts dagegen, bzw. meine Unwissenheit, warum man hier mit aller Gewalt einen Thread bauen soll???
Wurde schon gesagt. Es ist einfach the right thing to do. Das Windows-Messaging-System rechnet - wie du sehen kannst - nicht mit Unterbrechungen jenseits der menschlichen Reaktionszeit. Dein Benutzer hätte vielleicht gerne die Möglichkeit, eine längere Aktion abzubrechen, oder auch sowas wie eine Fortschrittsmeldung. Und besonders unschön: wenn dein Programm keine Messages mehr verarbeitet, der Benutzer nervös wird und mehrfach darauf herumklickt, dann denkt sich Windows seinen Teil, blendet dein Anwendungsfenster seicht aus und konstatiert trocken "Anwendung XY reagiert nicht mehr". Wenn das nicht Grund genug ist, dann weiß ich auch nicht
Mauro77 schrieb:
Ein Beispiel für einen Thread hat wohl hier jemand schon gepostet...?
Da Multithreading nicht ganz trivial ist, wäre es nicht ungeschickt, hierfür eine existierende Lösung zu benutzen. Du kannst ja mal nach der OmniThreadLibrary oder nach AsyncCalls googlen. (Bei AsyncCalls mußt du allerdings die Unterstützung für Generics deaktivieren, weil der Delphi-Compiler sonst einen ungültigen Header generiert.) Gerade mit AsyncCalls ist die Sache eine Kleinigkeit. In Delphi wäre es etwa so (ungetestet):
procedure TMainForm.EnterBlockedState; begin Button42.Enabled := False; ... end; procedure TMainForm.LeaveBlockedState; begin Button42.Enabled := True; ... end; procedure TMainForm.MyButtonClick(Sender: TObject); begin TAsyncCalls.Invoke (procedure begin TAsyncCalls.VCLInvoke (EnterBlockedState); try // hier Speicherroutine aufrufen finally TAsyncCalls.VCLInvoke (LeaveBlockedState); end; end); eep(1000); end;
In C++ mußt du etwas mehr arbeiten, da es keine anonymen Methoden gibt.
-
@Mauro
Aber du gibst mir schon recht, dass du dir durch deinen Programmablauf Probleme einhandelst, die man normalerweise nicht hat?
Wofür brauchst du denn überhaupt 1.000 Controls? Ich glaube auch zu wissen, warum deine Funktion "Spielstand speichern" 5 Sekunden braucht. Wahrscheinlich dauert das Schreiben nur ein paar Millisekunden, aber 1.000 Controls zu löschen und neu zu erzeugen dauert eine Ewigkeit. Hast du mal getestet, wie lange das Speichern ohne Löschen/Erzeugen der Controls dauert?
-
Also der Reihe nach:
Die Speicherung von 9 MB auf die Festplatte dauert schon seine Zeit, wir sprechen hier von sehr vielen Daten eines Fußball Manager Spiels. Es sind wohl keine 5, sondern 2 - 3 Sekunden.
1000 Controls habe ich natürlich NIE zur gleichen Zeit. Da ich jedoch verschiedene Themenbereiche im Spiel habe, wie Transfermarkt, Training, Aufstellung usw. kommt es schon mal vor, daß ich zig Komponenten habe zur gleichen Zeit auf dem Screen. Da es von Thema abhängig immer andere Komponenten sind, Bilder, Grids, Labels, Buttons uvm. macht es hier durchaus Sinn, diese dynamisch zu löschen und neu zu erzeugen. (Der Speicher wird auch sauber aufgeräumt, habe ich schon öfters nachgeprüft).
Dein Vorschlag, hier einen einfachen Event Handler für den Button würde nur dann funktionieren, wenn ich ihn nicht lösche, das Löschen einer Komponente aus deren Event Handler führt zwangsläufig zu Abstürzen.
Dieses verhindere ich mit PostMessage aus dem EventHandler, dami tist gewährleistet, daß IMMER zuerst der Event Handler zu Ende geführt wird, bevor die Message Abarbeitung einsetzt.Darum meine Frage, was genau meinst Du mit Problemen hier? Ich programmiere das Spiel seit Jahren und habe seit etlichen Jahren keinen undefinierbaren Programmabsturz mehr.
Übrigens, kannst es Dir auf Ebay unter Mauro Manager anschauen, von was für Programmgrößenordnung wir hier sprechen, da sind etliche Bilder zu sehen mit den Komponenten drauf.
Mauro
-
Mauro77 schrieb:
das Löschen einer Komponente aus deren Event Handler führt zwangsläufig zu Abstürzen
Ist das so? Wenn ich mich nicht irre, sollte man innerhalb des Event-Handlers problemlos
delete TheButton;
machen können. In einem einfachen Test funktioniert das auch gut. Kannst du mal näher beschreiben, wie das zu einem Absturz führen kann?Mauro77 schrieb:
Übrigens, kannst es Dir auf Ebay unter Mauro Manager anschauen, von was für Programmgrößenordnung wir hier sprechen, da sind etliche Bilder zu sehen mit den Komponenten drauf.
Kurios - du verkaufst deine Software über eBay?
Sowas ist mir auch noch nie begegnetAber wenn's läuft, warum nicht.
-
Vor ungefähr 8 Jahren hatte ich immer wieder undefinierbare Abstürze.
Daraufhin habe ich mein Coding gepostet, wo ich eben aus dem Event Handler den Button gelöscht habe.
Daraufhin hat Damon Chandler (erfolgreicher C++ Buchautor) mich darauf aufmerksam gemacht. Der Grund ist wohl, daß man beim Löschen des Buttons die Absprungadresse zu der Ereignismethode mitlöscht in der man sich befindet und es nach Verlassen dieser Ereignismethode knallt, die Abstürze sind aber nicht zwingend!!!Ja, ich verkaufe es auf diese Weise, das Spiel macht auch mir selbst Spaß und außerdem die Erweiterungen, die ich immer wieder für dieses Spiel mache.
-
Mal ein wenig offtopic:
Muss man die Verwendung der original Vereinsnamen und Logos nicht lizensieren und hast du das? Sonst wird das u.U. verdammt teuer....
-
klar, ich zahle jeden Monat 150 Tausend an Alle Beteiligten...
Im Ernst: Solange ich das Spiel ohne Originalnamen/Wappen anbiete und es die Möglichkeit gibt, diese in Eigenregie runterzuladen und ins SPiel zu integrieren, ist alles in Butter...
So hat es damals schon Anstoss gehandhabt...
-
Mit Problem meine ich, dass die Lösung, die von mehreren Leuten hier unabhängig voneinander hier vorgestellt wurde, nicht funktioniert. Ich habe nicht behauptet, dass deine Software abstürzt. Wie dem auch sein, der Programmablauf ist schon eigenartig und in meinen Augen Frickelei, die durch ein unsauberes Design entstanden ist. Und dadurch hast du dir jetzt ein anderes Problem eingehandelt, dass du nicht hättest, wenn das Design sauber gewesen wäre. Aufgrund des Entwicklungsstandes scheint ein Redesign wohl unmöglich oder sehr aufwändig, also muss man sehen, wie man das Problem anders in den Griff bekommt.
Reicht es eigentlich nicht aus, den Button in seinem Eventhandler zu deaktivieren? Er muss ja gar nicht reaktiviert werden, da er im Laufe der Nachrichtenbehandlung gelöscht und später neu erzeugt wird.
@Audacia
Ich kann mir schon vorstellen, dass die Komponente, in deren Ereignishandler man sich gerade befindet, nicht im Ereignishandler gelöscht werden darf. Schließlich könnten nach dem Aufruf des Ereignishandlers weitere Methoden der Komponente aufgerufen oder auf Attribute zugegriffen werden , was dann zu UB führt. Hab jetzt gerade keine Zeit und Lust in den Delphi Source zu gucken, wie der Ereignishandler aussieht und ob nach dem Handler Aufruf noch irgendwas mit dem Objekt gemacht wird. Würde fast drauf wetten, dass da noch was passiert.Edit 1:
Gut, auf den zweiten Blick ist die Verwendung von PostMessage doch die einzige Möglichkeit, Funktionalität vom Click Event zu entkoppeln. Allerdings würde ich dazu nciht die Dispatch() Methode überschreiben, sondern Message Handler für benutzerdefinierte Nachrichten registrieren.Edit 2:
Hab gerade doch mal in den Delphi Source geschaut und hätte die Wette verloren ;). Der OnClick Handler wird tatsächlich am Ende der Nachrichtenverarbeitungskette aufgerufen und greift damit nicht mehr auf Elemente des auslösenden Objekts zu. Allerdings wird nach dem Klicken noch die WM_LMOUSEUP Nachricht durch dieDefaultHandler
Methode bearbeitet, was jetzt zu UB führt.
-
Ich habe nicht alle Anworten gelesen. Ich könnte mir vorstellen, den Button zu subclassen. Dann kriegt man vor der standardmässigen Verarbeitung alles zu sehen und kann geeignet reagieren. Ausprobiert habe ich das für Buttons aber noch nicht (nur für Edit-Controls). Auch wären mit SendMessage noch Nachrichten erforderlich: Button frei/gesperrt.
Soll nur ein Hinweis sein, falls sich nichts einfacheres findet. Viel Glück!
-
Hallo,
auch ich habe jetzt nicht alle Antwort komplett gelesen, aber das Problem hatte ich auch schon einmal.
Ein Application->ProcessMessages und dann erst Button->enabled = true hat bei mir funktioniert.
Gruß
Martin